Clone the busybox_0_60_stable branch from the old busybox.stable CVS tree 0_60_stable
authorEric Andersen <andersen@codepoet.org>
Sat, 16 Jul 2005 01:57:20 +0000 (01:57 -0000)
committerEric Andersen <andersen@codepoet.org>
Sat, 16 Jul 2005 01:57:20 +0000 (01:57 -0000)
740 files changed:
.cvsignore [new file with mode: 0644]
.indent.pro [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
Changelog [new file with mode: 0644]
Changelog.full [new file with mode: 0644]
Config.h [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
adjtimex.c [new file with mode: 0644]
applets.c [new file with mode: 0644]
applets.h [new file with mode: 0644]
ar.c [new file with mode: 0644]
ash.c [new file with mode: 0644]
basename.c [new file with mode: 0644]
busybox.c [new file with mode: 0644]
busybox.h [new file with mode: 0644]
busybox.mkll [new file with mode: 0755]
busybox.sh [new file with mode: 0755]
busybox.spec [new file with mode: 0644]
busybox/.cvsignore [deleted file]
busybox/.indent.pro [deleted file]
busybox/AUTHORS [deleted file]
busybox/Changelog [deleted file]
busybox/Config.h [deleted file]
busybox/INSTALL [deleted file]
busybox/LICENSE [deleted file]
busybox/Makefile [deleted file]
busybox/README [deleted file]
busybox/TODO [deleted file]
busybox/adjtimex.c [deleted file]
busybox/applets.c [deleted file]
busybox/applets.h [deleted file]
busybox/applets/applets.c [deleted file]
busybox/applets/busybox.c [deleted file]
busybox/applets/busybox.mkll [deleted file]
busybox/applets/busybox.sh [deleted file]
busybox/applets/install.sh [deleted file]
busybox/applets/usage.c [deleted file]
busybox/applets/usage.h [deleted file]
busybox/ar.c [deleted file]
busybox/archival/ar.c [deleted file]
busybox/archival/cpio.c [deleted file]
busybox/archival/dpkg.c [deleted file]
busybox/archival/dpkg_deb.c [deleted file]
busybox/archival/gunzip.c [deleted file]
busybox/archival/gzip.c [deleted file]
busybox/archival/libunarchive/decompress_unzip.c [deleted file]
busybox/archival/libunarchive/unzip.c [deleted file]
busybox/archival/rpm2cpio.c [deleted file]
busybox/archival/tar.c [deleted file]
busybox/ash.c [deleted file]
busybox/basename.c [deleted file]
busybox/busybox.c [deleted file]
busybox/busybox.h [deleted file]
busybox/busybox.mkll [deleted file]
busybox/busybox.sh [deleted file]
busybox/busybox.spec [deleted file]
busybox/cat.c [deleted file]
busybox/chgrp.c [deleted file]
busybox/chmod.c [deleted file]
busybox/chown.c [deleted file]
busybox/chroot.c [deleted file]
busybox/chvt.c [deleted file]
busybox/clear.c [deleted file]
busybox/cmdedit.c [deleted file]
busybox/cmdedit.h [deleted file]
busybox/cmp.c [deleted file]
busybox/console-tools/chvt.c [deleted file]
busybox/console-tools/clear.c [deleted file]
busybox/console-tools/deallocvt.c [deleted file]
busybox/console-tools/dumpkmap.c [deleted file]
busybox/console-tools/loadacm.c [deleted file]
busybox/console-tools/loadfont.c [deleted file]
busybox/console-tools/loadkmap.c [deleted file]
busybox/console-tools/reset.c [deleted file]
busybox/console-tools/setkeycodes.c [deleted file]
busybox/coreutils/basename.c [deleted file]
busybox/coreutils/cat.c [deleted file]
busybox/coreutils/chgrp.c [deleted file]
busybox/coreutils/chmod.c [deleted file]
busybox/coreutils/chown.c [deleted file]
busybox/coreutils/chroot.c [deleted file]
busybox/coreutils/cmp.c [deleted file]
busybox/coreutils/cp.c [deleted file]
busybox/coreutils/cut.c [deleted file]
busybox/coreutils/date.c [deleted file]
busybox/coreutils/dd.c [deleted file]
busybox/coreutils/df.c [deleted file]
busybox/coreutils/dirname.c [deleted file]
busybox/coreutils/dos2unix.c [deleted file]
busybox/coreutils/du.c [deleted file]
busybox/coreutils/echo.c [deleted file]
busybox/coreutils/env.c [deleted file]
busybox/coreutils/expr.c [deleted file]
busybox/coreutils/head.c [deleted file]
busybox/coreutils/hostid.c [deleted file]
busybox/coreutils/id.c [deleted file]
busybox/coreutils/length.c [deleted file]
busybox/coreutils/ln.c [deleted file]
busybox/coreutils/logname.c [deleted file]
busybox/coreutils/ls.c [deleted file]
busybox/coreutils/md5sum.c [deleted file]
busybox/coreutils/mkdir.c [deleted file]
busybox/coreutils/mkfifo.c [deleted file]
busybox/coreutils/mknod.c [deleted file]
busybox/coreutils/mv.c [deleted file]
busybox/coreutils/printf.c [deleted file]
busybox/coreutils/pwd.c [deleted file]
busybox/coreutils/rm.c [deleted file]
busybox/coreutils/rmdir.c [deleted file]
busybox/coreutils/sleep.c [deleted file]
busybox/coreutils/sort.c [deleted file]
busybox/coreutils/stty.c [deleted file]
busybox/coreutils/sync.c [deleted file]
busybox/coreutils/tail.c [deleted file]
busybox/coreutils/tee.c [deleted file]
busybox/coreutils/test.c [deleted file]
busybox/coreutils/touch.c [deleted file]
busybox/coreutils/tr.c [deleted file]
busybox/coreutils/tty.c [deleted file]
busybox/coreutils/uname.c [deleted file]
busybox/coreutils/uniq.c [deleted file]
busybox/coreutils/usleep.c [deleted file]
busybox/coreutils/uudecode.c [deleted file]
busybox/coreutils/uuencode.c [deleted file]
busybox/coreutils/wc.c [deleted file]
busybox/coreutils/whoami.c [deleted file]
busybox/coreutils/yes.c [deleted file]
busybox/cp.c [deleted file]
busybox/cpio.c [deleted file]
busybox/cut.c [deleted file]
busybox/date.c [deleted file]
busybox/dc.c [deleted file]
busybox/dd.c [deleted file]
busybox/deallocvt.c [deleted file]
busybox/debian/Config.h-deb [deleted file]
busybox/debian/Config.h-static [deleted file]
busybox/debian/Config.h-udeb [deleted file]
busybox/debian/README.debian [deleted file]
busybox/debian/changelog [deleted file]
busybox/debian/control [deleted file]
busybox/debian/copyright [deleted file]
busybox/debian/rules [deleted file]
busybox/df.c [deleted file]
busybox/dirname.c [deleted file]
busybox/dmesg.c [deleted file]
busybox/docs/.cvsignore [deleted file]
busybox/docs/autodocifier.pl [deleted file]
busybox/docs/busybox.net/.cvsignore [deleted file]
busybox/docs/busybox.net/busybox-growth.ps [deleted file]
busybox/docs/busybox.net/images/busybox.jpeg [deleted file]
busybox/docs/busybox.net/images/busybox2.jpg [deleted file]
busybox/docs/busybox.net/images/fm.mini.png [deleted file]
busybox/docs/busybox.net/images/gfx_by_gimp.png [deleted file]
busybox/docs/busybox.net/images/ltbutton2.png [deleted file]
busybox/docs/busybox.net/images/sdsmall.png [deleted file]
busybox/docs/busybox.net/images/written.in.vi.png [deleted file]
busybox/docs/busybox.net/index.html [deleted file]
busybox/docs/busybox.net/oldnews.html [deleted file]
busybox/docs/busybox.net/screenshot.html [deleted file]
busybox/docs/busybox.sgml [deleted file]
busybox/docs/busybox_footer.pod [deleted file]
busybox/docs/busybox_header.pod [deleted file]
busybox/docs/contributing.txt [deleted file]
busybox/docs/new-applet-HOWTO.txt [deleted file]
busybox/docs/style-guide.txt [deleted file]
busybox/dos2unix.c [deleted file]
busybox/dpkg.c [deleted file]
busybox/dpkg_deb.c [deleted file]
busybox/du.c [deleted file]
busybox/dumpkmap.c [deleted file]
busybox/dutmp.c [deleted file]
busybox/echo.c [deleted file]
busybox/editors/sed.c [deleted file]
busybox/editors/vi.c [deleted file]
busybox/env.c [deleted file]
busybox/examples/bootfloppy/bootfloppy.txt [deleted file]
busybox/examples/bootfloppy/display.txt [deleted file]
busybox/examples/bootfloppy/etc/fstab [deleted file]
busybox/examples/bootfloppy/etc/init.d/rcS [deleted file]
busybox/examples/bootfloppy/etc/inittab [deleted file]
busybox/examples/bootfloppy/etc/profile [deleted file]
busybox/examples/bootfloppy/mkdevs.sh [deleted file]
busybox/examples/bootfloppy/mkrootfs.sh [deleted file]
busybox/examples/bootfloppy/mksyslinux.sh [deleted file]
busybox/examples/bootfloppy/quickstart.txt [deleted file]
busybox/examples/bootfloppy/syslinux.cfg [deleted file]
busybox/examples/busybox.spec [deleted file]
busybox/examples/depmod.pl [deleted file]
busybox/examples/inittab [deleted file]
busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel [deleted file]
busybox/examples/kernel-patches/devps.patch.9_25_2000 [deleted file]
busybox/examples/mk2knr.pl [deleted file]
busybox/examples/undeb [deleted file]
busybox/examples/unrpm [deleted file]
busybox/expr.c [deleted file]
busybox/fbset.c [deleted file]
busybox/fdflush.c [deleted file]
busybox/find.c [deleted file]
busybox/findutils/find.c [deleted file]
busybox/findutils/grep.c [deleted file]
busybox/findutils/which.c [deleted file]
busybox/findutils/xargs.c [deleted file]
busybox/free.c [deleted file]
busybox/freeramdisk.c [deleted file]
busybox/fsck_minix.c [deleted file]
busybox/getopt.c [deleted file]
busybox/grep.c [deleted file]
busybox/gunzip.c [deleted file]
busybox/gzip.c [deleted file]
busybox/halt.c [deleted file]
busybox/head.c [deleted file]
busybox/hostid.c [deleted file]
busybox/hostname.c [deleted file]
busybox/hush.c [deleted file]
busybox/id.c [deleted file]
busybox/ifconfig.c [deleted file]
busybox/include/applets.h [deleted file]
busybox/include/busybox.h [deleted file]
busybox/include/grp.h [deleted file]
busybox/include/libbb.h [deleted file]
busybox/include/pwd.h [deleted file]
busybox/include/usage.h [deleted file]
busybox/init.c [deleted file]
busybox/init/halt.c [deleted file]
busybox/init/init.c [deleted file]
busybox/init/poweroff.c [deleted file]
busybox/init/reboot.c [deleted file]
busybox/insmod.c [deleted file]
busybox/install.sh [deleted file]
busybox/kill.c [deleted file]
busybox/klogd.c [deleted file]
busybox/lash.c [deleted file]
busybox/length.c [deleted file]
busybox/libbb/.cvsignore [deleted file]
busybox/libbb/Makefile [deleted file]
busybox/libbb/README [deleted file]
busybox/libbb/arith.c [deleted file]
busybox/libbb/ask_confirmation.c [deleted file]
busybox/libbb/chomp.c [deleted file]
busybox/libbb/concat_path_file.c [deleted file]
busybox/libbb/copy_file.c [deleted file]
busybox/libbb/copy_file_chunk.c [deleted file]
busybox/libbb/copyfd.c [deleted file]
busybox/libbb/create_icmp_socket.c [deleted file]
busybox/libbb/device_open.c [deleted file]
busybox/libbb/dirname.c [deleted file]
busybox/libbb/error_msg.c [deleted file]
busybox/libbb/error_msg_and_die.c [deleted file]
busybox/libbb/fgets_str.c [deleted file]
busybox/libbb/find_mount_point.c [deleted file]
busybox/libbb/find_pid_by_name.c [deleted file]
busybox/libbb/find_root_device.c [deleted file]
busybox/libbb/full_read.c [deleted file]
busybox/libbb/full_write.c [deleted file]
busybox/libbb/get_console.c [deleted file]
busybox/libbb/get_last_path_component.c [deleted file]
busybox/libbb/get_line_from_file.c [deleted file]
busybox/libbb/gz_open.c [deleted file]
busybox/libbb/herror_msg.c [deleted file]
busybox/libbb/herror_msg_and_die.c [deleted file]
busybox/libbb/human_readable.c [deleted file]
busybox/libbb/inode_hash.c [deleted file]
busybox/libbb/interface.c [deleted file]
busybox/libbb/isdirectory.c [deleted file]
busybox/libbb/kernel_version.c [deleted file]
busybox/libbb/last_char_is.c [deleted file]
busybox/libbb/libbb.h [deleted file]
busybox/libbb/libc5.c [deleted file]
busybox/libbb/loop.c [deleted file]
busybox/libbb/make_directory.c [deleted file]
busybox/libbb/messages.c [deleted file]
busybox/libbb/mk_loop_h.sh [deleted file]
busybox/libbb/mode_string.c [deleted file]
busybox/libbb/module_syscalls.c [deleted file]
busybox/libbb/mtab.c [deleted file]
busybox/libbb/mtab_file.c [deleted file]
busybox/libbb/my_getgrgid.c [deleted file]
busybox/libbb/my_getgrnam.c [deleted file]
busybox/libbb/my_getpwnam.c [deleted file]
busybox/libbb/my_getpwnamegid.c [deleted file]
busybox/libbb/my_getpwuid.c [deleted file]
busybox/libbb/parse_mode.c [deleted file]
busybox/libbb/parse_number.c [deleted file]
busybox/libbb/perror_msg.c [deleted file]
busybox/libbb/perror_msg_and_die.c [deleted file]
busybox/libbb/print_file.c [deleted file]
busybox/libbb/process_escape_sequence.c [deleted file]
busybox/libbb/read_package_field.c [deleted file]
busybox/libbb/real_loop.h [deleted file]
busybox/libbb/recursive_action.c [deleted file]
busybox/libbb/remove_file.c [deleted file]
busybox/libbb/safe_read.c [deleted file]
busybox/libbb/safe_strncpy.c [deleted file]
busybox/libbb/simplify_path.c [deleted file]
busybox/libbb/syscalls.c [deleted file]
busybox/libbb/syslog_msg_with_name.c [deleted file]
busybox/libbb/time_string.c [deleted file]
busybox/libbb/trim.c [deleted file]
busybox/libbb/u_signal_names.c [deleted file]
busybox/libbb/unarchive.c [deleted file]
busybox/libbb/unzip.c [deleted file]
busybox/libbb/vdprintf.c [deleted file]
busybox/libbb/verror_msg.c [deleted file]
busybox/libbb/vherror_msg.c [deleted file]
busybox/libbb/vperror_msg.c [deleted file]
busybox/libbb/wfopen.c [deleted file]
busybox/libbb/xfuncs.c [deleted file]
busybox/libbb/xgetcwd.c [deleted file]
busybox/libbb/xgethostbyname.c [deleted file]
busybox/libbb/xreadlink.c [deleted file]
busybox/libbb/xregcomp.c [deleted file]
busybox/ln.c [deleted file]
busybox/loadacm.c [deleted file]
busybox/loadfont.c [deleted file]
busybox/loadkmap.c [deleted file]
busybox/logger.c [deleted file]
busybox/logname.c [deleted file]
busybox/logread.c [deleted file]
busybox/ls.c [deleted file]
busybox/lsmod.c [deleted file]
busybox/makedevs.c [deleted file]
busybox/md5sum.c [deleted file]
busybox/miscutils/adjtimex.c [deleted file]
busybox/miscutils/dc.c [deleted file]
busybox/miscutils/dutmp.c [deleted file]
busybox/miscutils/makedevs.c [deleted file]
busybox/miscutils/mktemp.c [deleted file]
busybox/miscutils/mt.c [deleted file]
busybox/miscutils/readlink.c [deleted file]
busybox/miscutils/update.c [deleted file]
busybox/miscutils/watchdog.c [deleted file]
busybox/mk_loop_h.sh [deleted file]
busybox/mkdir.c [deleted file]
busybox/mkfifo.c [deleted file]
busybox/mkfs_minix.c [deleted file]
busybox/mknod.c [deleted file]
busybox/mkswap.c [deleted file]
busybox/mktemp.c [deleted file]
busybox/modprobe.c [deleted file]
busybox/modutils/insmod.c [deleted file]
busybox/modutils/lsmod.c [deleted file]
busybox/modutils/modprobe.c [deleted file]
busybox/modutils/rmmod.c [deleted file]
busybox/more.c [deleted file]
busybox/mount.c [deleted file]
busybox/msh.c [deleted file]
busybox/mt.c [deleted file]
busybox/mv.c [deleted file]
busybox/nc.c [deleted file]
busybox/networking/hostname.c [deleted file]
busybox/networking/ifconfig.c [deleted file]
busybox/networking/nc.c [deleted file]
busybox/networking/nslookup.c [deleted file]
busybox/networking/ping.c [deleted file]
busybox/networking/route.c [deleted file]
busybox/networking/telnet.c [deleted file]
busybox/networking/tftp.c [deleted file]
busybox/networking/traceroute.c [deleted file]
busybox/networking/wget.c [deleted file]
busybox/nfsmount.c [deleted file]
busybox/nfsmount.h [deleted file]
busybox/nslookup.c [deleted file]
busybox/pidof.c [deleted file]
busybox/ping.c [deleted file]
busybox/pivot_root.c [deleted file]
busybox/poweroff.c [deleted file]
busybox/printf.c [deleted file]
busybox/pristine_setup.sh [deleted file]
busybox/procps/free.c [deleted file]
busybox/procps/kill.c [deleted file]
busybox/procps/pidof.c [deleted file]
busybox/procps/ps.c [deleted file]
busybox/procps/renice.c [deleted file]
busybox/procps/uptime.c [deleted file]
busybox/ps.c [deleted file]
busybox/pwd.c [deleted file]
busybox/rdate.c [deleted file]
busybox/readlink.c [deleted file]
busybox/reboot.c [deleted file]
busybox/renice.c [deleted file]
busybox/reset.c [deleted file]
busybox/rm.c [deleted file]
busybox/rmdir.c [deleted file]
busybox/rmmod.c [deleted file]
busybox/route.c [deleted file]
busybox/rpm2cpio.c [deleted file]
busybox/scripts/depmod.pl [deleted file]
busybox/scripts/inittab [deleted file]
busybox/scripts/mk2knr.pl [deleted file]
busybox/scripts/undeb [deleted file]
busybox/scripts/unrpm [deleted file]
busybox/sed.c [deleted file]
busybox/setkeycodes.c [deleted file]
busybox/shell/ash.c [deleted file]
busybox/shell/cmdedit.c [deleted file]
busybox/shell/cmdedit.h [deleted file]
busybox/shell/hush.c [deleted file]
busybox/shell/lash.c [deleted file]
busybox/shell/msh.c [deleted file]
busybox/sleep.c [deleted file]
busybox/sort.c [deleted file]
busybox/stty.c [deleted file]
busybox/swaponoff.c [deleted file]
busybox/sync.c [deleted file]
busybox/sysklogd/klogd.c [deleted file]
busybox/sysklogd/logger.c [deleted file]
busybox/sysklogd/logread.c [deleted file]
busybox/sysklogd/syslogd.c [deleted file]
busybox/syslogd.c [deleted file]
busybox/tail.c [deleted file]
busybox/tar.c [deleted file]
busybox/tee.c [deleted file]
busybox/telnet.c [deleted file]
busybox/test.c [deleted file]
busybox/tests/.cvsignore [deleted file]
busybox/tests/Makefile [deleted file]
busybox/tests/cp_tests.mk [deleted file]
busybox/tests/ln_tests.mk [deleted file]
busybox/tests/multibuild.pl [deleted file]
busybox/tests/multifeat.pl [deleted file]
busybox/tests/mv_tests.mk [deleted file]
busybox/tests/sh.testcases [deleted file]
busybox/tests/syslog_test.c [deleted file]
busybox/tests/testcases [deleted file]
busybox/tests/tester.sh [deleted file]
busybox/tests/tst-syslogd.c [deleted file]
busybox/tftp.c [deleted file]
busybox/touch.c [deleted file]
busybox/tr.c [deleted file]
busybox/traceroute.c [deleted file]
busybox/true_false.c [deleted file]
busybox/tty.c [deleted file]
busybox/umount.c [deleted file]
busybox/uname.c [deleted file]
busybox/uniq.c [deleted file]
busybox/update.c [deleted file]
busybox/uptime.c [deleted file]
busybox/usage.c [deleted file]
busybox/usage.h [deleted file]
busybox/usleep.c [deleted file]
busybox/util-linux/dmesg.c [deleted file]
busybox/util-linux/fbset.c [deleted file]
busybox/util-linux/fdflush.c [deleted file]
busybox/util-linux/freeramdisk.c [deleted file]
busybox/util-linux/fsck_minix.c [deleted file]
busybox/util-linux/getopt.c [deleted file]
busybox/util-linux/mkfs_minix.c [deleted file]
busybox/util-linux/mkswap.c [deleted file]
busybox/util-linux/more.c [deleted file]
busybox/util-linux/mount.c [deleted file]
busybox/util-linux/nfsmount.c [deleted file]
busybox/util-linux/nfsmount.h [deleted file]
busybox/util-linux/pivot_root.c [deleted file]
busybox/util-linux/rdate.c [deleted file]
busybox/util-linux/swaponoff.c [deleted file]
busybox/util-linux/umount.c [deleted file]
busybox/uudecode.c [deleted file]
busybox/uuencode.c [deleted file]
busybox/vi.c [deleted file]
busybox/watchdog.c [deleted file]
busybox/wc.c [deleted file]
busybox/wget.c [deleted file]
busybox/which.c [deleted file]
busybox/whoami.c [deleted file]
busybox/xargs.c [deleted file]
busybox/yes.c [deleted file]
cat.c [new file with mode: 0644]
chgrp.c [new file with mode: 0644]
chmod.c [new file with mode: 0644]
chown.c [new file with mode: 0644]
chroot.c [new file with mode: 0644]
chvt.c [new file with mode: 0644]
clear.c [new file with mode: 0644]
cmdedit.c [new file with mode: 0644]
cmdedit.h [new file with mode: 0644]
cmp.c [new file with mode: 0644]
cp.c [new file with mode: 0644]
cpio.c [new file with mode: 0644]
cut.c [new file with mode: 0644]
date.c [new file with mode: 0644]
dc.c [new file with mode: 0644]
dd.c [new file with mode: 0644]
deallocvt.c [new file with mode: 0644]
debian/Config.h-deb [new file with mode: 0644]
debian/Config.h-static [new file with mode: 0644]
debian/Config.h-udeb [new file with mode: 0644]
debian/README.debian [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
df.c [new file with mode: 0644]
dirname.c [new file with mode: 0644]
dmesg.c [new file with mode: 0644]
docs/.cvsignore [new file with mode: 0644]
docs/autodocifier.pl [new file with mode: 0755]
docs/busybox.sgml [new file with mode: 0644]
docs/busybox_footer.pod [new file with mode: 0644]
docs/busybox_header.pod [new file with mode: 0644]
docs/contributing.txt [new file with mode: 0644]
docs/new-applet-HOWTO.txt [new file with mode: 0644]
docs/style-guide.txt [new file with mode: 0644]
dos2unix.c [new file with mode: 0644]
dpkg.c [new file with mode: 0644]
dpkg_deb.c [new file with mode: 0644]
du.c [new file with mode: 0644]
dumpkmap.c [new file with mode: 0644]
dutmp.c [new file with mode: 0644]
echo.c [new file with mode: 0644]
env.c [new file with mode: 0644]
expr.c [new file with mode: 0644]
fbset.c [new file with mode: 0644]
fdflush.c [new file with mode: 0644]
find.c [new file with mode: 0644]
free.c [new file with mode: 0644]
freeramdisk.c [new file with mode: 0644]
fsck_minix.c [new file with mode: 0644]
getopt.c [new file with mode: 0644]
grep.c [new file with mode: 0644]
gunzip.c [new file with mode: 0644]
gzip.c [new file with mode: 0644]
halt.c [new file with mode: 0644]
head.c [new file with mode: 0644]
hostid.c [new file with mode: 0644]
hostname.c [new file with mode: 0644]
hush.c [new file with mode: 0644]
id.c [new file with mode: 0644]
ifconfig.c [new file with mode: 0644]
init.c [new file with mode: 0644]
insmod.c [new file with mode: 0644]
install.sh [new file with mode: 0755]
kernel-patches/Will_devps_GoIntoTheKernel [new file with mode: 0644]
kernel-patches/devps.patch.9_25_2000 [new file with mode: 0644]
kill.c [new file with mode: 0644]
klogd.c [new file with mode: 0644]
lash.c [new file with mode: 0644]
length.c [new file with mode: 0644]
libbb/.cvsignore [new file with mode: 0644]
libbb/Makefile [new file with mode: 0644]
libbb/README [new file with mode: 0644]
libbb/arith.c [new file with mode: 0644]
libbb/ask_confirmation.c [new file with mode: 0644]
libbb/chomp.c [new file with mode: 0644]
libbb/concat_path_file.c [new file with mode: 0644]
libbb/copy_file.c [new file with mode: 0644]
libbb/copy_file_chunk.c [new file with mode: 0644]
libbb/copyfd.c [new file with mode: 0644]
libbb/create_icmp_socket.c [new file with mode: 0644]
libbb/device_open.c [new file with mode: 0644]
libbb/dirname.c [new file with mode: 0644]
libbb/error_msg.c [new file with mode: 0644]
libbb/error_msg_and_die.c [new file with mode: 0644]
libbb/fgets_str.c [new file with mode: 0644]
libbb/find_mount_point.c [new file with mode: 0644]
libbb/find_pid_by_name.c [new file with mode: 0644]
libbb/find_root_device.c [new file with mode: 0644]
libbb/full_read.c [new file with mode: 0644]
libbb/full_write.c [new file with mode: 0644]
libbb/get_console.c [new file with mode: 0644]
libbb/get_last_path_component.c [new file with mode: 0644]
libbb/get_line_from_file.c [new file with mode: 0644]
libbb/gz_open.c [new file with mode: 0644]
libbb/herror_msg.c [new file with mode: 0644]
libbb/herror_msg_and_die.c [new file with mode: 0644]
libbb/human_readable.c [new file with mode: 0644]
libbb/inode_hash.c [new file with mode: 0644]
libbb/interface.c [new file with mode: 0644]
libbb/isdirectory.c [new file with mode: 0644]
libbb/kernel_version.c [new file with mode: 0644]
libbb/last_char_is.c [new file with mode: 0644]
libbb/libbb.h [new file with mode: 0644]
libbb/libc5.c [new file with mode: 0644]
libbb/loop.c [new file with mode: 0644]
libbb/make_directory.c [new file with mode: 0644]
libbb/messages.c [new file with mode: 0644]
libbb/mode_string.c [new file with mode: 0644]
libbb/module_syscalls.c [new file with mode: 0644]
libbb/mtab.c [new file with mode: 0644]
libbb/mtab_file.c [new file with mode: 0644]
libbb/my_getgrgid.c [new file with mode: 0644]
libbb/my_getgrnam.c [new file with mode: 0644]
libbb/my_getpwnam.c [new file with mode: 0644]
libbb/my_getpwnamegid.c [new file with mode: 0644]
libbb/my_getpwuid.c [new file with mode: 0644]
libbb/parse_mode.c [new file with mode: 0644]
libbb/parse_number.c [new file with mode: 0644]
libbb/perror_msg.c [new file with mode: 0644]
libbb/perror_msg_and_die.c [new file with mode: 0644]
libbb/print_file.c [new file with mode: 0644]
libbb/process_escape_sequence.c [new file with mode: 0644]
libbb/read_package_field.c [new file with mode: 0644]
libbb/real_loop.h [new file with mode: 0644]
libbb/recursive_action.c [new file with mode: 0644]
libbb/remove_file.c [new file with mode: 0644]
libbb/safe_read.c [new file with mode: 0644]
libbb/safe_strncpy.c [new file with mode: 0644]
libbb/safe_write.c [new file with mode: 0644]
libbb/simplify_path.c [new file with mode: 0644]
libbb/syscalls.c [new file with mode: 0644]
libbb/syslog_msg_with_name.c [new file with mode: 0644]
libbb/time_string.c [new file with mode: 0644]
libbb/trim.c [new file with mode: 0644]
libbb/u_signal_names.c [new file with mode: 0644]
libbb/unarchive.c [new file with mode: 0644]
libbb/unzip.c [new file with mode: 0644]
libbb/vdprintf.c [new file with mode: 0644]
libbb/verror_msg.c [new file with mode: 0644]
libbb/vherror_msg.c [new file with mode: 0644]
libbb/vperror_msg.c [new file with mode: 0644]
libbb/wfopen.c [new file with mode: 0644]
libbb/xfuncs.c [new file with mode: 0644]
libbb/xgetcwd.c [new file with mode: 0644]
libbb/xgethostbyname.c [new file with mode: 0644]
libbb/xreadlink.c [new file with mode: 0644]
libbb/xregcomp.c [new file with mode: 0644]
ln.c [new file with mode: 0644]
loadacm.c [new file with mode: 0644]
loadfont.c [new file with mode: 0644]
loadkmap.c [new file with mode: 0644]
logger.c [new file with mode: 0644]
logname.c [new file with mode: 0644]
logread.c [new file with mode: 0644]
losetup.c [new file with mode: 0644]
ls.c [new file with mode: 0644]
lsmod.c [new file with mode: 0644]
makedevs.c [new file with mode: 0644]
md5sum.c [new file with mode: 0644]
mk_loop_h.sh [new file with mode: 0755]
mkdir.c [new file with mode: 0644]
mkfifo.c [new file with mode: 0644]
mkfs_minix.c [new file with mode: 0644]
mknod.c [new file with mode: 0644]
mkswap.c [new file with mode: 0644]
mktemp.c [new file with mode: 0644]
modprobe.c [new file with mode: 0644]
more.c [new file with mode: 0644]
mount.c [new file with mode: 0644]
msh.c [new file with mode: 0644]
mt.c [new file with mode: 0644]
mv.c [new file with mode: 0644]
nc.c [new file with mode: 0644]
nfsmount.c [new file with mode: 0644]
nfsmount.h [new file with mode: 0644]
nslookup.c [new file with mode: 0644]
pidof.c [new file with mode: 0644]
ping.c [new file with mode: 0644]
pivot_root.c [new file with mode: 0644]
poweroff.c [new file with mode: 0644]
printf.c [new file with mode: 0644]
pristine_setup.sh [new file with mode: 0755]
ps.c [new file with mode: 0644]
pwd.c [new file with mode: 0644]
pwd_grp/.indent.pro [new file with mode: 0644]
pwd_grp/__getgrent.c [new file with mode: 0644]
pwd_grp/__getpwent.c [new file with mode: 0644]
pwd_grp/config.h [new file with mode: 0644]
pwd_grp/fgetgrent.c [new file with mode: 0644]
pwd_grp/fgetpwent.c [new file with mode: 0644]
pwd_grp/getgrgid.c [new file with mode: 0644]
pwd_grp/getgrnam.c [new file with mode: 0644]
pwd_grp/getpw.c [new file with mode: 0644]
pwd_grp/getpwnam.c [new file with mode: 0644]
pwd_grp/getpwuid.c [new file with mode: 0644]
pwd_grp/grent.c [new file with mode: 0644]
pwd_grp/grp.h [new file with mode: 0644]
pwd_grp/initgroups.c [new file with mode: 0644]
pwd_grp/putpwent.c [new file with mode: 0644]
pwd_grp/pwd.h [new file with mode: 0644]
pwd_grp/pwent.c [new file with mode: 0644]
pwd_grp/setgroups.c [new file with mode: 0644]
rdate.c [new file with mode: 0644]
readlink.c [new file with mode: 0644]
reboot.c [new file with mode: 0644]
renice.c [new file with mode: 0644]
reset.c [new file with mode: 0644]
rm.c [new file with mode: 0644]
rmdir.c [new file with mode: 0644]
rmmod.c [new file with mode: 0644]
route.c [new file with mode: 0644]
rpm2cpio.c [new file with mode: 0644]
scripts/depmod.pl [new file with mode: 0755]
scripts/inittab [new file with mode: 0644]
scripts/mk2knr.pl [new file with mode: 0755]
scripts/undeb [new file with mode: 0644]
scripts/unrpm [new file with mode: 0644]
sed.c [new file with mode: 0644]
setkeycodes.c [new file with mode: 0644]
sleep.c [new file with mode: 0644]
sort.c [new file with mode: 0644]
stty.c [new file with mode: 0644]
swaponoff.c [new file with mode: 0644]
sync.c [new file with mode: 0644]
syslogd.c [new file with mode: 0644]
tail.c [new file with mode: 0644]
tar.c [new file with mode: 0644]
tee.c [new file with mode: 0644]
telnet.c [new file with mode: 0644]
test.c [new file with mode: 0644]
tests/.cvsignore [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/cp_tests.mk [new file with mode: 0644]
tests/ln_tests.mk [new file with mode: 0644]
tests/multibuild.pl [new file with mode: 0755]
tests/multifeat.pl [new file with mode: 0755]
tests/mv_tests.mk [new file with mode: 0644]
tests/sh.testcases [new file with mode: 0644]
tests/syslog_test.c [new file with mode: 0644]
tests/testcases [new file with mode: 0644]
tests/tester.sh [new file with mode: 0755]
tests/tst-syslogd.c [new file with mode: 0644]
tftp.c [new file with mode: 0644]
time.c [new file with mode: 0644]
top.c [new file with mode: 0644]
touch.c [new file with mode: 0644]
tr.c [new file with mode: 0644]
traceroute.c [new file with mode: 0644]
true_false.c [new file with mode: 0644]
tty.c [new file with mode: 0644]
umount.c [new file with mode: 0644]
uname.c [new file with mode: 0644]
uniq.c [new file with mode: 0644]
update.c [new file with mode: 0644]
uptime.c [new file with mode: 0644]
usage.c [new file with mode: 0644]
usage.h [new file with mode: 0644]
usleep.c [new file with mode: 0644]
uudecode.c [new file with mode: 0644]
uuencode.c [new file with mode: 0644]
vi.c [new file with mode: 0644]
watchdog.c [new file with mode: 0644]
wc.c [new file with mode: 0644]
wget.c [new file with mode: 0644]
which.c [new file with mode: 0644]
whoami.c [new file with mode: 0644]
xargs.c [new file with mode: 0644]
yes.c [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..71269c5
--- /dev/null
@@ -0,0 +1,4 @@
+busybox
+busybox.links
+_install
+applet_source_list
diff --git a/.indent.pro b/.indent.pro
new file mode 100644 (file)
index 0000000..492ecf1
--- /dev/null
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..9cee037
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,93 @@
+List of the authors of code contained in BusyBox.
+
+If you have code in BusyBox, you should be listed here.  If you should be
+listed, or the description of what you have done needs more detail, or is
+incorect, _please_ let me know.
+
+ -Erik
+
+-----------
+
+Erik Andersen <andersen@codepoet.org>, <andersee@debian.org>
+    Tons of new stuff, major rewrite of most of the
+    core apps, tons of new apps as noted in header files.
+
+Edward Betts <edward@debian.org>
+    expr, hostid, logname, tty, wc, whoami, yes
+John Beppu <beppu@codepoet.org>
+    du, head, nslookup, sort, tee, uniq
+
+Brian Candler <B.Candler@pobox.com>
+    tiny-ls(ls)
+
+Randolph Chung <tausq@debian.org>
+    fbset, ping, hostname, and mkfifo
+
+Dave Cinege <dcinege@psychosis.com>    
+    more(v2), makedevs, dutmp, modularization, auto links file, 
+    various fixes, Linux Router Project maintenance
+
+Magnus Damm <damm@opensource.se>
+    tftp client
+    insmod powerpc support
+
+Larry Doolittle <ldoolitt@recycle.lbl.gov>
+    pristine source directory compilation, lots of patches and fixes.
+
+Gennady Feldman <gfeldman@cachier.com>
+    Sysklogd (single threaded syslogd, IPC Circular buffer support,
+    logread), various fixes.
+
+Karl M. Hegbloom <karlheg@debian.org>
+    cp_mv.c, the test suite, various fixes to utility.c, &c.
+
+Daniel Jacobowitz <dan@debian.org>
+    mktemp.c
+
+Matt Kraai <kraai@alumni.carnegiemellon.edu>
+    documentation, bugfixes, test suite
+
+John Lombardo <john@deltanet.com>      
+    dirname, tr
+
+Glenn McGrath <bug1@optushome.com.au>
+    ar, dpkg, dpkg-deb
+
+Vladimir Oleynik <dzo@simtreas.ru>
+    cmdedit; ports: ash, stty, traceroute; locale, various fixes
+    and irreconcilable critic of everything not perfect.
+
+Bruce Perens <bruce@pixar.com>
+    Original author of BusyBox. His code is still in many apps.
+
+Tim Riker <Tim@Rikers.org>
+    bug fixes, member of fan club
+
+Kent Robotti <robotti@metconnect.com>
+    reset, tons and tons of bug reports and patchs.
+
+Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
+    wget - Contributed by permission of Covad Communications
+
+Pavel Roskin <proski@gnu.org>
+    Lots of bugs fixes and patches.
+
+Gyepi Sam <gyepi@praxis-sw.com>
+    Remote logging feature for syslogd
+
+Linus Torvalds <torvalds@transmeta.com>
+    mkswap, fsck.minix, mkfs.minix
+
+Mark Whitley <markw@codepoet.org>
+    grep, sed, cut, xargs, style-guide, new-applet-HOWTO, bug fixes, etc.
+
+Charles P. Wright <cpwright@villagenet.com>
+    gzip, mini-netcat(nc)
+
+Enrique Zanardi <ezanardi@ull.es>
+    tarcat (since removed), loadkmap, various fixes, Debian maintenance
+
+Emanuele Aina <emanuele.aina@tiscali.it>
+       run-parts
+
diff --git a/Changelog b/Changelog
new file mode 100644 (file)
index 0000000..46590b5
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,1452 @@
+0.60.5
+
+    Stable Release
+
+    Bugfixes:
+       * Fixed a race that could cause init to hang
+       * Fixed init orphan process reaping 
+       * Fixed init to always attempt to provide a controlling tty.
+           This should fix most cases where ash would print
+           "job control disabled" -- the other cases are user error.
+       * Fixed 'gunzip -c' to not delete the source source file
+       * Fixed a silly math problem in the time applet
+       * Fixed 'cp -a' so it will once again copy symlinks properly 
+       * Fixed a long standing problem in tftp with freeing memory
+       * Fixed Makefile largefile settings
+       * Fixed a buffer overflow in vi
+       * Cosmetic cleanups in lsmod, lash, init, swapon/off, and hostname 
+       * Set the close-on-exec flag on files opened by init
+       * The updated top applet was backported from unstable
+       * Several ash bugfixes were backported from unstable
+       * Several warnings in ash, md5sum, and ifconfig
+
+        -Erik Andersen, 26 October 2002
+
+
+
+0.60.4
+
+    Stable Release
+
+    New Applets & New Features:
+       * Added new a 'top' applet (by special request)
+       * Lots of small uClinux adjustments
+
+    Bugfixes:
+       * This release has _lots_ of bugfixes.  See Changelog.full 
+           for the complete list of what was changed.
+
+        -Erik Andersen, 18 September 2002
+
+
+
+0.60.3
+
+    Stable Release
+
+    New Applets & New Features:
+       * Added new a 'time' applet (by special request)
+       * Added new a 'losetup' applet
+       * The tftp has been fixed to work
+       * Default shell is now ash.
+       * msh shell should work properly on mmu-less systems again
+       * ls can now do color
+
+    Bugfixes:
+       * Erik Andersen
+           -- Hacked together a new time applet
+           -- Fixed dangling comma in init.c (s390 arch only)
+           -- Fixed more so when it is run on files in the procfs that 
+               claim 0 length, it will not do weird things i.e. more /proc/pci
+           -- Copyright message cleanups.  Fixed sash attributions.
+           -- Backporting of fixes and general maintenance.
+           -- Fixed several cases where reboot, halt, and poweroff would fail
+               to function properly when Linux is booted into an initrd.
+           -- Fixed a silly compile bug in cpio
+           -- nslookup now works properly with uClibc, remove old workaround
+           -- Added conv=noerror support to dd
+           -- Fixed ash and msh cmdedit to properly account for the current 
+               PATH setting
+           -- Document netcat options and add -e support
+           -- Fixed insanely broken insmod endianness handling
+           -- Update init.c for better syle conformance, properly detach from 
+               terminal when necessary, better code reuse, FIFO inittab file 
+               reading/executing, allow init to be halted and restarted, etc.
+           -- Allow gunzip to work on multiple archives, add -v option
+           -- Updated x86 optimizations to save over 10k.
+       * Edward Betts
+           -- added -x switch to du.c
+       * Cliff L. Biffle
+           -- Added memory usage to the ps listings
+       * Przemyslaw Czerpak
+           -- Made telnet 8-bit clean, handle screen size, and is now RFC
+               compliant.  Works nicely now. 
+       * Wolfgang Denk
+           -- hush now supports shell loops (for, while, until) and control 
+               operators (||, &&)
+       * Russ Dill
+           -- Added an 'restart' inittab action, allowing init to re-exec
+               itself (or call a script which calls pivot_root then exec...) 
+       * Larry Doolittle
+           -- Made syslogd not give up when errno is EINTR
+       * Geoffrey Espin
+           -- support find -newer <file>
+       * Robert Griebl
+           -- Reworked modprobe so it now reads and uses modules.dep
+       * Karl M. Hegbloom
+           -- Fixed a silly bug where CONTEXT and EGREP_ALIAS were coupled.
+       * Kevin Hilman
+           -- Fixed memory corruption from long pathnames in /etc/fstab
+       * J.W.Janssen
+           -- color ls support!
+       * Matt Kraai
+           -- Fixed get_line_from_file() so that NULL is treated as end of 
+               line, thereby fixing cut, grep, sed, etc. when working on binary
+               files or anything that might contain a NULL.
+           -- Fixed wget to do DNS initial DNS lookups, and do that only once
+               to avoid skipping to a different server when round-robin DNS is
+               in use (bug found by Mike Coleman <mkc@mathdogs.com>)
+           -- Several sed fixes
+           -- Added new losetup applet
+       * Ben Low
+           -- allow tftp to work with stdin as well as stdout.
+       * Frank P. MacLachlan <fpm-plutus@tgs.indyme.com> avoid a potential 
+               NULL pointer problem in mount.
+       * Glenn McGrath
+           -- gunzip was incorrectly reporting a failed crc and length
+               (Discovered by Change, Shu-Hao).  The problem was the bitbuffer
+               needs to be unwound after decompression as it was eating into the
+               crc/size field.
+           -- Reworked wc.c to fix severe efficiency problems and make it 
+               smaller.  When just counting file chars, simply stat the file 
+               instead of reading the whole thing.  (Fixes Debian bug #103302)
+           -- Updated dmalloc options
+       * Manuel Novoa III
+           -- rewrote get_last_path_component() so it would not be so
+               horrible, and would behave correctly in several important corner
+               cases.
+       * Vladimir Oleynik
+           -- Fixed ash problem where ^C could be blocked
+           -- Several command line editing updates (cmdedit now supports
+               CTRL-K and CTRL-L,  fixed a segfault, etc)
+           -- Fixed ash problem where ^C could be blocked
+           -- Several size optimizations for various applets
+       * Tim Riker
+           -- make ash prompt the same as other shells if cmdedit and
+               fancyprompt are enabled.
+       * Jeff Studer
+           -- tftp now generates default values for localfilename and
+               remotefilename based on provided file names when possible.
+       * Stefan Soucek and Miles Bader
+           -- Re-add mmu-less support to msh
+       * Jim Treadway
+           -- Fixed a buffer overflow in the local group handling code.
+           -- Fixed a missing "\" in usage.h
+           -- Made pidof not add trailing spaces
+           -- Fixed msh bugs so things like "A = 1; B = `eval $A`; echo $B"
+               can now work.
+       * Mike Voytovich
+           -- insmod big endian ARM support
+
+
+        -Erik Andersen, 27 April 2002
+
+
+
+
+
+0.60.2
+
+    Stable Release
+
+       * Please support busybox and help us buy busybox.net.  See the
+           (current) busybox webpage for details.
+
+    New Applets & New Features:
+       * msh was reworked by Vladimir Oleynik's so it can handle things like
+               for i in `ls *.c` ; do echo $i ; done
+           unfortunately, this also means that msh is no-longer uClinux safe,
+           and will require some surgery to make it use vfork() again.
+       * Charles Steinkuehler <charles@steinkuehler.net> -- reworked hostname
+               so it behaves as expected (backport from busybox unstable)
+
+    Known Problems
+       none.  :)
+
+    Bugfixes:
+       * Erik Andersen
+           -- Fixed grep -E and egrep so they actually behave as expected
+           -- init cleanups and (theoretical) uClinux support
+           -- Fixed large file (>2Gig) support (enable in the Makefile)
+           -- Always enable test when a shell is enabled (least surprise)
+           -- Made 'mount -a' use proc to avoid a static noauto list
+           -- lots of source tree cleanups
+       * Laurence Anderson
+           -- Removed some traces of no-longer existant rpmunpack (which
+               has been obsoleted by the rpm2cpio applet).
+           -- Fixed unarchive.c to use the correct buffer when calling 
+               dirname, improve an error message, and plug some memory leaks.
+           -- Fixed rpm2cpio.c mkfs_minix.c fsck_minix.c fbset.c to use
+               standard types (s/u16/u_int16_t/g  s/u32/u_int32_t/g  etc)
+       * ASA <llb@udm.net.ru> -- fixed ash handling of command line args 
+           when sourcing ('.') commands.
+       * Ethan Benson <erbenson@alaska.net>
+           -- Fix mount's noauto option to not automount as "usbdevfs"
+       * David Kimdon <dwhedon@instant802.com> -- fixed md5sum binary sums
+       * Matt Kraai
+           -- Fix sed s/[/]// handling (noted by Dumas Patrice).
+           -- Fix dirname(3) improper consts, allow libc version to override.
+           -- Fixed invoking applets when their names contain a leading dash 
+               and a full pathname.
+           -- Fix ash exec
+           -- Fixed basename to be SUSv2 compliant (which specifies that the
+               extension should stay if it is identical to the basename.
+           -- Fixed rmdir, since SuS2 says rmdir must provide -p
+           -- Fixed sed empty line substitutions (noted by Joshua Hudson).
+       * Steve Merrifield <steve@labyrinth.net.au> -- make vi use xmalloc
+       * Glenn McGrath
+           -- dpkg cleanups, various bugfixes
+       * Vladimir Oleynik
+           -- Add support for `busybox --help APPLET'
+           -- Fixed route so it properly displays all route entries
+           -- Fix for ash leading redirections (i.e. '2>/dev/null ls rubbish')
+       * Andrew Tipton <andrew@cadre5.com> -- enable vi cursor keys when in
+               edit mode as vim does.
+        
+        
+        -Erik Andersen, 20 November 2001
+
+
+
+
+
+0.60.1
+
+    Stable Release
+
+
+    New Applets & New Features:
+       none.  :)
+
+    Known Problems (to be fixed in 0.60.2)
+       * msh can segfault on constructs such as
+               for i in `ls *.c` ; do echo $i ; done
+         due to a memory allocation problem.  This only seems to cause
+         problems when the backtick expands to be several k in size.
+
+
+    Bugfixes:
+       * Matt Kraai
+           -- Fixed msh to support underscores in variable names.
+           -- Fixed a sed problem with unsatisfied backrefs (the problem was
+               noted by Martin Bene).
+           -- Removed BB_SH define entirely.  Now one simply picks the shell
+               or shells they want as BB_<foo> in Config.h
+           -- Fixed head to use ferror(3) to check for errors, not errno.
+       * Shu-Hao Chang <shuhao_chang@trend.com.tw>
+           -- Fixed sed handling of multiple -e commands
+       * Magick <magick@linux-fan.com>
+           -- Fixed an init bug with AskFirst and /dev/null
+       * Jaspreet Singh <jsingh@somanetworks.com>
+           -- Fixed both a segfault and cosmetic bug in route
+       * Erik Andersen
+           -- Made the insmod options BB_FEATURE_NEW_MODULE_INTERFACE and 
+               BB_FEATURE_OLD_MODULE_INTERFACE mutually exclusive
+           -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined
+           -- Fixed a potential segfault with lash + BB_FEATURE_CLEAN_UP
+           -- Removed uint64_t from dos2unix, avoiding C lib compat. problems.
+       * Glenn McGrath
+           -- Rewrite of tftp (commands match atftp, accepts -b, can use 
+               non-standard ports, and is smaller).
+           -- Fixed unarchive exclude list handling
+       * Manuel Novoa III
+           -- rewrite of simplify_path so it behaves itself (fixing some
+               problems with mount and other applets).
+           -- Fixed ifconfig 'broadcast +' handling and disabled it by default
+       * Matthias ? <matthias@corelatus.com>
+           -- Fixed syslogd to log all messages from a single connection, not
+               just the first.
+        
+        
+        -Erik Andersen, 23 August 2001
+
+
+
+
+0.60.0
+
+    Note: 
+
+       For this release I have bumped the version number to 0.60.0.  This
+       reflects the fact that this release is intended to form a new stable
+       BusyBox release series.  If you need to rely on a stable version of
+       BusyBox, you should plan on using the stable 0.60.x series.  If bugs
+       show up then I will release 0.60.1, then 0.60.2, etc...  This is also
+       intended to deal with the fact that the BusyBox build system will be
+       getting a major overhaul for the next release and I don't want that to
+       break products that people are shipping.  To avoid that, the new build
+       system will be released as part of a new BusyBox development series
+       that will have some not-yet-decided-on odd version number.  Once things
+       stabablize and the new build system is working for everyone, then I
+       will release that as a new stable release series. 
+
+    Critical Bugfixes:
+       * Matt Kraai 
+           -- Fixed wget output file opening (wget failed in 0.52).
+           -- Fixed a memory leak in syslogd (found by Adam Slattery).
+       * Vladimir Oleynik, Matt Kraai, Erik Andersen
+           -- several nasty bugs in ash and msh.  msh could not assign
+               any variables and had debug code still enabled.  ash
+               had several compile errors (depending on selected options)
+               and variable assignment problems as well.
+
+    New Applets:
+       * David McCullough <davidm@lineo.com> -- modprobe
+       * Vladimir Oleynik -- traceroute
+       * Erik Andersen -- pidof
+
+    New Scripts:
+       * David Schleef, Erik Andersen, Stuart Hughes -- depmod.pl
+           This is a replacement for the depmod program from the modutils 
+           package, but is fully cross platform and is designed to run on 
+           your host system (not on the target).
+
+    Other Changes:
+       * Erik Andersen 
+           -- fixed busybox.spec so it should now work on redhat systems
+           -- fixed dos2unix and unix2dos so they should work once again
+           -- Adjustments to make busybox more uClinux friendly.  Busybox
+               should now work on uClinux systems without needing and source
+               code changes (applets that won't work on uClinux systems are 
+               now automagicaly disabled).
+           -- various things (cleanups, libc compatibility work, etc, etc)
+       * Jim Gleason <jimg@lineo.com>
+           -- Fixed for sed, where it failed to preserve whether or not the 
+               line was previously altered when running a subst command.
+       * Matt Kraai 
+           -- Made tar read 20 512byte blocks at a time (like GNU tar)
+           -- Allow msh.c assignments with the export and readonly commands.
+           -- Added BB_FEATURE_DEVFS to enable devfs device names.
+           -- Better devfs support
+           -- Don't save/restore vi readonly flag if vi is compiled read-only.
+           -- Reworked rdate option handling (is now smaller).
+           -- Size reduction in ping
+           -- Always write dd counts to stderr
+           -- Allow multiple shells to be enabled
+       * Aaron Lehmann 
+           -- slimmed down md5sum 
+           -- contributed a nice new (hand written, not lex/yacc) Posix math 
+               support for ash, which is once again a full posix shell.
+       * Felix von Leitner <leitner@convergence.de> -- patches to make busybox 
+           work with dietlibc.
+       * David McCullough
+           -- Adjustments to make busybox more uClinux friendly
+       * Glenn McGrath 
+           -- Fixed gzip so when a filename is '-' it will use stdin/stdout
+           -- dpkg rewrite.  Should now be compatable with the real dpkg, 
+               but needs more testing.
+           -- Updates to archiving tools (gunzip/gzip/cpio/ar/etc) 
+           -- Rewrote uuencode, will allow base64 encoding to be used by wget
+       * Vladimir Oleynik 
+           -- Fixed tr to support 'tr a-z A-Z' syntax,
+           -- Many ash corrections, optimizations, and cleanups.
+           -- optimizations for traceroute, md5sum, chown, ping
+           -- cmdedit updates and API change
+           -- Namespace cleanup (i.e. adding 'static' private function calls)
+           -- added "stopped jobs" warning to ash on exit
+       * Adam Slattery
+           -- Fixed ping compile problem
+       * Robert J. Osborne <rj@resourceinternational.com>
+           -- fixed a vi bug with delete and escape sequences on empty files.
+
+
+        -Erik Andersen, 31 July 2001
+
+
+
+0.52
+       
+    Critical Bugfixes:
+       * Glenn McGrath -- Fixed gunzip, zcat when reading from stdin
+       * Marc Karasek and Kanoj (kernel serial.c maintainer) -- fixed init
+           problem on serial consoles with 2.4.3+ kernels.
+       
+    New Applets:
+       * Laurence Anderson -- rpm2cpio applet, this obsoletes rpmunpack 
+           which has now been removed from BusyBox 
+       * Laurence Anderson and Glenn McGrath -- cpio applet, currently 
+           only supports unpacking the ascii cpio format.
+       * Vladimir Oleynik and Erik Andersen -- added ash, the most correct
+           busybox shell.
+       * Larry Doolittle -- hush, small shell designed specifically
+           for busybox.  Quite usable but still a work in progress.
+       * Erik Andersen -- msh, minix shell.  A very small but capable shell
+           that only uses vfork, so it can be used on uClinux systems.
+
+    Other Changes:
+       * Sterling Huxley -- Several bugfixes for the vi applet.
+       * Glenn McGrath -- Restructure unarchiving code to make more code
+           common to the ar, cpio, dpkg, dpkg-deb applets.
+           tar applet has not yet been assimilated...
+       * Matt Kraai -- Rewrote cp, dirname, mkdir, mv, and rm.
+       * Paul J.Y. Lahaie <pjlahaie@linuxcare.com> -- Fixed an endian-ness
+           bug in md5sum (in 0.51, md5sum on big endian machines was broken)
+       * Mark Whitley -- rewrote cut, major updates to grep and sed. 
+       * Erik Andersen -- bunches of insmod fixes.  It should now always 
+           work (no more segfault or missing symbols problems).
+       * Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de> and Jinux Kim
+           added uClinux/m68k insmod support.
+       * Manuel Novoa III -- rewrote make_human_readable so ls, du, and df
+           should work as expected.  Eliminated use of floats.
+       * Aaron Lehmann <aaronl@vitelus.com> -- Scrubbed gzip.c
+       * Alan Modra <amodra@bigpond.net.au> -- fixed an hard to spot
+           bug breaking gunzip checksum checking.
+       * Gennady Feldman -- Fixed 'syslog -C' 
+       * Gernot Poerner <gp@it-netservice.de> -- Added mount bind support.
+       * Adam Heath <doogie@debian.org>  -- wget arbitrary header support
+       * John Beppu -- updated the automagical doc generator
+       * Zillions of other bugfixes, optimizations, and cleanups.
+
+
+
+        -Erik Andersen, 7 July 2001
+
+
+0.51
+    Critical Bugfixes:
+       * Erik Andersen -- Fixed a bug that could crash the shell in 0.50
+           when pressing <Enter> on an empty line.
+       * Gennady Feldman -- Fixed a bug that could crash the shell in 0.50
+           when performing an 'export' in the shell.
+       * Gennady Feldman -- fixed a syslogd bug where syslogd could cause
+           the init process to block (which can break systems badly).
+
+    New Applets:
+       * Sterling Huxley -- contributed a new vi applet!  This is a very
+           functional vi implementation in Only 22k.
+       * Erik Andersen -- added env applet
+       
+    Other changes:
+       * Erik Andersen -- Split utility.c into libbb, which provides a
+           much cleaner was for us to include shared functionality.
+       * Erik Andersen -- Reorganized how and when busybox includes 
+           syscalls, aiding portability and (in this case) making the
+           busybox work on ia64 systems.
+       * Erik Andersen -- dpkg.c cleanup to use the updated gunzip interface.
+       * Erik Andersen -- Cleanups for libc5, glibc, and uClibc.
+       * Erik Andersen and Matt Kraai -- Cleanups for the human-readable
+           output from ls, du, and df.
+       * Laurence Anderson <laurence@zxmail.com> -- Fixed wget HTTP 1.1
+           support and added chunked encoding so it is now RFC compliant.
+       * John Beppu -- The busybox.pod documentation is now automagically
+           generated from the source code.  This makes it _much_ simpler.  
+           Now to update the docs, just update the usage message...
+       * Dirk Behme <dirk.behme@de.bosch.com> -- Adjusted MIPS insmod 
+           support a bit for Mips RS3.
+       * Christophe Boyanique -- egrep invoked the "init" applet in 0.50!
+       * Larry Doolittle -- Added -Wshadow and fixed a number of shadowed
+           variables
+       * David Douthitt -- fixed 'find -print' 
+       * Gennady Feldman -- fixes for the syslogd circular buffer code 
+       * Jeff Garzik -- a number of structural cleanups, fixes for -Wshadow 
+           bugs, and similar problems.
+       * Matt Kraai -- Added a new 'shutdown' action to busybox init.  Now
+           you can specify arbitrary behavior for 'ctrlaltdel' so now
+           pressing CTL-ALT-DEL can do something else (or nothing).
+       * Andreas Neuhaus <andy@fasta.fh-dortmund.de> -- fix for merging
+           kernel command line environment variables into child environment
+           for init.c
+       * Glenn McGrath -- Fixed problems with dpkg and dpkg-deb applets
+       * Glenn McGrath -- Don't try to automount devfs 
+       * Vladimir Oleynik -- optimizations for more.c
+       * Vladimir Oleynik -- Added locale support to the shell, and fixed
+           locale support in several other places
+       * Vladimir Oleynik -- moved struct applet from busybox.c to applets.c
+       * Vladimir Oleynik -- A size optimization for rdate
+       * Vladimir Oleynik -- Fixed printf applets's locale handling
+       * Vladimir Oleynik -- More cmdedit updates
+       * Vladimir Oleynik -- Fixed `du' applet so it continues running 
+           after permission errors.
+       * Vladimir Oleynik -- Reduced stack usage in recursive_action()
+       * Pierre Peiffer <pierre.peiffer@sxb.bsf.alcatel.fr> -- made
+               find_pid_by_name() cope with swapped out processes.
+       * Jari Ruusu <jari.ruusu@pp.inet.fi> -- updates so that setting
+           D_FILE_OFFSET_BITS=64 now works as expected. 
+       * Anthony Towns <aj@azure.humbug.org.au> -- fixed a bug with 
+           sed address range handling
+       * Dmitry Zakharov <dmit@crp.bank.gov.ua> -- a number of updates
+           to wget: support for ftp downloads, basic HTTP basic auth, handling
+           of http redirects, when attempting to continue an aborted download
+           but server doesn't support restarts then reopen output file in
+           write mode, bugfix: when content-length not given, wget didn't
+           download anything, if -c is not specified, it no longer default to
+           restarting an aborted download. 
+
+
+        -Erik Andersen, 10 April 2001
+
+
+0.50
+       * Erik Andersen -- added ifconfig interface status reporting 
+       * Erik Andersen -- Debian packaging updates
+       * Erik Andersen -- lash environment variable expansion rewritten,
+           with lots of help/fixes/testing from Larry Doolittle.
+       * Erik Andersen -- Fix use of busybox with dmalloc debugging lib
+       * Erik Andersen -- fixed ls behavior for broken or very narrow terminals
+       * Erik Andersen -- stub umount2 and pivot_root if they are not available
+       * Erik Andersen -- libc5 fixes
+       * Erik Andersen -- make init work with devfsd
+       * Erik Andersen -- fixed df for nfs and dos where blksize = 512
+       * Erik Andersen -- Make sure libpwd.a is linked _last_ so it 
+           overrides the system pwd/grp 
+       * Christophe Boyanique -- added an optional egrep alias for grep.
+       * Christophe Boyanique -- added optional 'rm -i' support.
+       * Kenneth Chalmers and Erik Andersen -- fixed ln so it
+           behaves when given no arguments (prints usage) and when
+           given just one arg (tries to make a link in the cwd).
+       * Magnus Damm -- added a tftp applet  
+       * Magnus Damm -- powerpc support for busybox insmod.
+       * David Douthitt -- fixed a build error in df.c when 
+           BB_FEATURE_HUMAN_READABLE was disabled
+       * John Beppu -- wrote autodocifier.pl, which will be used to auto-
+           generate the documentation from the source code, making life
+           much simpler for all.
+       * Magnus Damm <damm@opensource.se> -- Fixed an 'inner scope var
+           masking outer scope var with same name' bug that prevented 
+           the loopback device from being unmounted if mount() failed.
+       * Larry Doolittle -- rewrote ifconfig to make it smaller 
+       * Larry Doolittle and Erik Andersen -- cleanups to pristine source
+       * Larry Doolittle -- many bugfixes resulting from regression testing
+       * Gennady Feldman -- split syslogd.c into syslogd and klogd
+       * Gennady Feldman -- make syslogd single threaded -- no more forking
+       * Jeff Garzik -- getopt-ified rmmod.
+       * Jeff Garzik -- glibc 2.2 warning cleanups
+       * Jeff Garzik -- namespace pollution cleanup (staticified variables).
+       * Erik Gustavsson <cyrano@algonet.se> -- allow env variables set on the
+           kernel command line to be inherited into init and its children.
+       * Erik Habbinga -- fixed an uninitialized substitution delimiter in sed.
+       * Chris Jaeger -- Makefile cleanup to make option setting less error-prone
+       * Chris Jaeger <cjaeger@ensim.com> -- Carefully check NFS_MOUNT_VERSION
+           depending on what kernel is being used.
+       * Quinn Jensen <jensenq@lineo.com> -- MIPS support for busybox insmod.
+       * Evin Robertson -- new pivot_root applet 
+       * Kent Robotti -- usage message cleanups
+       * Kent Robotti -- reworked dos2unix/unix2dos
+       * Evin Robertson and Manuel Novoa III -- reworked how usage messages 
+           are stored to save several k of space.
+       * Matt Kraai -- Keep trying if an NFS mount fails 
+       * Matt Kraai -- fixed insmod so it won't try to insmod directories.
+       * Matt Kraai -- added nc listening support
+       * Matt Kraai and David Douthitt -- reworked fine to support -type, 
+           -perm, -mtime, and other improvements.
+       * Matt Kraai -- added find_applet_by_name and saved some memory thereby
+       * Matt Kraai -- added chomp to reduce redundant code elsewhere
+       * Matt Kraai -- Removed trailing \n chars from error_msg{,_and_die} messages. 
+       * John Lombardo -- fixed OOM in insmod.
+       * Glenn McGrath -- bypass /proc in mount, now uses sysfs. 
+       * Glenn McGrath -- several updates to dpkg and dpkg-deb. 
+       * Manuel Novoa III -- several size optimizations: parse_mode, 
+           process_escape_sequence, format, and get_kernel_revision. 
+       * Manuel Novoa III -- rewrote ifconfig again to make it smaller still 
+       * Manuel Novoa III -- added ifconfig -a, updated interface reporting
+       * Vladimir N. Oleynik -- Fixed a bug where init set PATH incorrectly 
+       * Vladimir N. Oleynik -- cleanups to route, cmdedit, mkdir, 
+           mkfs_minix, mkswap, chmod_chown_chgrp and utility.c
+       * Vladimir N. Oleynik -- many fixes to cmdedit. so tab completion
+           is now working and general editing is much improved, and to
+           improve complex prompt handling.
+       * Vladimir N. Oleynik -- added route status reporting.
+       * Vladimir N. Oleynik -- fixed wget to use xfopen
+       * Vladimir N. Oleynik -- new stty applet 
+       * Vladimir N. Oleynik -- fixed find, it used to stop on perm errors.
+       * Vladimir N. Oleynik -- locale forced to posix for scripts 
+       * Vladimir N. Oleynik -- saved 128 bytes by moving error checking 
+           for several my_* functions into utility.c
+       * Bjorn Wesen -- new ifconfig and route applet (taken from 
+           work done by Axis Communications).
+       * Mark Whitley -- Added a 'How to contribute to Busybox' doc
+           and updated the style guide.
+       * Mark Whitley -- implemented grep -A, -B, and -C
+       * Mark Whitley -- overhauled the test suite.
+
+
+        -Erik Andersen, 15 March 2001
+       
+0.49
+
+       * Matt Kraai -- new sort.c
+       * Matt Kraai -- new tail.c
+       * Glenn McGrath -- new 'dpkg-deb' applet
+       * Glenn McGrath -- new ar code
+       * spoon -- new watchdog applet
+       * Vladimir N. Oleynik <dzo@simtreas.ru> -- fixed cmdedit.c so now 
+           scrolling and tab completion in lash work properly.  Also several
+           byte saving optimizations.
+       * Erik Andersen -- disabled many less commonly used applets by default
+       * Mark Whitley -- more thrashing about to get clean perror_msg usage
+       * Matt Kraai -- new command line munging
+       * Larry Doolittle -- keep some locales from messing up busybox.sh
+       * Matt Kraai -- cleaned up dd and tail with new parse_number routine
+       * Mark Whitley -- remove debugging messages from deallocvt
+       * Matt Kraai and Mark Whitley -- new document "How to Add a New Applet 
+           to BusyBox"
+       * David Douthitt -- fixed "grep -qv" bug
+       * Larry Doolittle -- fixed insmod bug with old kernels
+       * Matt Kraai -- logger remixed to use getopt, selection of stdin made 
+           util-linux compatible
+       * Erik Andersen -- many more internal symbols classified static to 
+           avoid namespace pollution
+       * Matt Kraai -- nc listening support
+       * Erik Andersen -- made sed understand arbitrary regexp delimiters
+       * Matt Kraai et al. -- more tar improvements and bug fixes, now 
+           handles regexp file exclusion
+       * Larry Doolittle -- new script (multibuild.pl) to automate build rule
+           checking
+       * Matt Kraai -- update/cleanup of the docs on how to use init
+       * Erik Andersen -- renamed all sh.c symbols per the style guide, 
+           better if-then-else-fi handling
+       * Erik Andersen -- cleaner division of labor between cmdedit.c and sh.c
+       * Larry Doolittle -- shell data structure cleanup, fixed buglets
+           in read, exec, and piped builtins
+       * Erik Andersen -- md5sum was broken in 0.48.  Now fixed (and doesn't 
+           use getline, shrinking static compiles (since nothing else used it).
+       * ?? -- squashed memory leak in shell prompt handling
+       * Mark Whitley -- Updates to style guide
+       * Mark Whitley -- Big cleanup in utility.c: style guide compliance,
+           de-macro-ifying some variables and functions
+       * Erik Andersen -- ls now honors BB_FEATURE_AUTOWIDTH so it can find
+           the width and height of the console.
+       * Erik Andersen -- insmod now ignores -L and accepts the -o option.
+       * Erik Andersen -- updates so you can now select from the Makefile
+           whether or not to use the system's passwd and group functions.
+           Since most systems use GNU libc, this can save you from having to
+           install the /etc/nsswitch.conf configuration file and the required
+           libnss_* libraries.  Adds 1.5k.  You can now, also, disable this, 
+           causing busybox to use the system's pwd.h and grp.h functions.
+
+
+        -Erik Andersen, 27 January 2001
+
+0.48
+
+       * Glenn McGrath -- tar now supports uncompressing tar files,
+           define BB_FEATURE_TAR_GZIP to use the -z option.
+       * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now
+           return EXIT_SUCCESS or EXIT_FAILURE to the system.
+           Now TRUE and FALSE are set to the C standard where TRUE=1.
+       * me -- Fixed uname problem causing the kernel version to be
+           mis-detected (causing problems with poweroff, init,
+           and other things).  
+       * Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and 
+           Nicolas Ferre <nicolas.ferre@alcove.fr> -- insmod support on ARM 
+           and StrongArm, and suport for lsmod on older 2.0.x kernels.
+       * Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use 
+           an included shell script called unrpm as a front end to it.  There's
+           also a shell script called undeb included for debian packages.  
+       * Matt Kraai -- fix an infinite loop with ls -aR
+       * Larry Doolittle -- Shaved off about 100 bytes and 200 bytes heap 
+           from date.c.  Also document the "-d" option in the usage message.
+       * Gennady Feldman -- fixed dd to use blocksize when reading/writing, 
+           (it was reading the whole thing and then writing it out).  Also 
+           updated usage information (was missing conv=notrunc) and added 
+           conv=sync feature.
+       * Larry Doolittle (in collaboration with Matt Kraai) -- allow for a 
+           pristine source directory -- where all the .o files and such are 
+           not placed into the source tree.  Thanks Larry!
+       * Larry Doolittle -- use the applet definitions in applets.h 
+           to autogenerate the applet function and usage prototypes.
+       * Sebastien Huet, Arne Bernin, and Kent Robotti -- Add in tar -X and
+           fixed a bug breaking tar --exclude.  
+       * Jonas Holmberg -- echo option handling made GNU-echo compatible
+       * Aleksey Demidov <asd@ixcelerator.com> -- date option handling made 
+           GNU-date compatible
+       * me -- Progress meter (optional) in wget
+       * Doolittle/me -- programs invoked by full path name take
+           precedence over applets unless BB_FEATURE_SH_BUILTINS_ALWAYS_WIN
+       * Gaute B Strokkenes <gs234@cam.ac.uk> -- applets found using a
+           binary search instead of linear search.  Much faster!
+       * new applets: cmp readlink
+       * Mark Whitley -- Removed advertising clause of Berkeley license
+           according to decision by the Regents of the University of
+           California; included reference
+       * tail's confusing special treatment of single digit options removed;
+           people should use -n instead
+       * Larry Doolittle -- \r handled now in echo and tr
+       * Matt Kraai -- rewrite of uniq
+       * Mark Whitley -- remix of xargs
+       * Jim Gleason <jimg@lineo.com> -- fixed tar so it no longer breaks 
+           hard links.
+       * Matt Kraai -- logger now logs all arguments, not just the first
+       * Gennady Feldman -- syslogd no longer logs to localhost if compiled
+           for remote logging...
+       * Richard June <rjune@ims1.imagestream-is.com> -- support for 'gzip -d'
+       * various artists -- Other good stuff that I forgot to document.
+
+
+        -Erik Andersen, 13 December 2000
+
+0.47
+
+       * A bug in syslogd was fixed that allowed it to potentially fork-bomb
+           your system.  Anyone using 0.46 syslogd should upgrade.
+       * Renamed busybox.defs.h to the more sensible "Config.h"
+       * Improved portability between different libcs.
+       * Many apps ported to use getopt()
+       * Common handling of '--help'
+       * All usage messages centralized.
+       * Added a bunch of new commands:
+           * 'rdate' contributed by Sterling Huxley <sterling@europa.com>
+           * 'wget' contributed by Chip Rosenthal <chip@unicom.com>, 
+                   <crosenth@covad.com> and Covad Communications
+           * 'getopt' from "Alfred M. Szmidt" <ams@trillian.itslinux.org>
+           * dos2unix, unix2dos, reset, and unrpm.c (and lots of help
+               debugging) thanks to Kent Robotti <robotti@metconnect.com>.
+           * 'renice' command, thanks to Dave Cinege <dcinege@psychosis.com>
+           * 'xargs' (written by me)
+           * 'expr' contributed by Edward Betts <edward@debian.org>, based
+               on GNY expr
+       * lsmod now uses the query_module syscall, rather then /proc (me)
+       * syslogd can now log messages to remote hosts -- patch thanks
+           to Gyepi Sam <gyepi@praxis-sw.com>
+       * chroot can now call the builtin shell - Pavel Roskin <proski@gnu.org>
+       * 'make install' now creates relative symlinks, and added a new
+           'make install-hardlinks' target to (tada) install hardlinks.
+       * Rewrite of 'tail' to make it simpler, smaller, and more robust.  
+           It now weighs only 2.25k (3k when full featured).  The code is
+           cleaner too, thanks to Allen Soard <esp-software@mail.hypermart.net>
+       * Add optional ls file sorting, thanks to a patch from 
+           Sterling Huxley <sterling@europa.com>
+       * Fixed chmod option parsing so things like 'chmod -r /tmp/file'
+           now work (previously it thought -r was an option).  Doh!
+       * Fixed tar handling of stdin and stdout
+       * Renamed "internal.h" to the more sensible "busybox.h"
+       * Preliminary support for GNU HURD.
+       * Updated my devps and devmtab kernel patches for the latest 2.2.x
+           kernel, for those wanting to go proc-less.
+       * Tons of other bugfixes.
+
+
+        -Erik Andersen, 25 September 2000
+
+
+0.46
+
+       * Better portability.  Now should compile cleanly with libc5, 
+           GNU libc 2.0 and 2.1, and various Linux kernels including 
+           2.0.x, 2.2.x, and to 2.4.0-test*. (patch for 2.4.x kernels
+           to make /proc/mounts behave included in the kernel-patches dir). 
+       * Fixed a _horrible_ bug where 'tar -tvf' could unlink
+           local files that matched tarball contents!!!  Fix thanks 
+           to Marius Groeger <mgroeger@sysgo.de>
+       * Fixed a nasty bug in tar when could mess up saved symlinks.
+       * Fixed tar creation support when reading from stdin ('tar -cf - . ') 
+           thanks to Daniel Quinlan <quinlan@transmeta.com>
+       * Updates to handle Linux 2.4.0 kernels (kludged around the
+           "none" entries in /proc/mounts, added a hack to make sysinfo
+           work with both old and new kernels).
+       * Fixed insmod module option parsing for options lacking an '='.
+           Fix thanks to Marc Nijdam <marc_nijdam@hp.com>
+       * Fixed segfault with 'cut -f 1 -d:' and added 'cut -s' suport.
+           Fix thanks to Arne Bernin <arne@matrix.loopback.org>
+       * Several fixes from Marius Groeger <mag@sysgo.de>
+           - Added support for "sh -c command args..."
+           - Fixed globbing, i.e. 'echo * *' and 'echo "******"' now work.
+           - Added shell environment variable substitution 
+           - Added the "read" shell builtin.
+       * Fixed cursor editing in cmdedit.c. The following keyboard sequence 
+           used to create an infinite loop: ls, cursor up, left, down.
+       * Added support for being a login shell, so things like
+           '-su' or '-sh' (stuff where argv[0][0]=='-') will now always 
+           invoke the shell.  Now you can use BusyBox as a login shell.
+       * ls.c now ignores '-g', since some ftp clients like that sort 
+           of thing.  Patch thanks to David Vrabel <dvrabel@arcom.co.uk>
+       * Fix to init.c from Stuart Menefy <Stuart.Menefy@st.com> so that
+           it always sets the controlling terminal before running any programs
+       * Several fixes from Matt Kraai <kraai@alumni.carnegiemellon.edu>
+           - Fixed tr so it recognizes standard escape sequences.  
+               Merged common escape seq. code from tr and echo into utility.c.
+           - Major work in updating/cleaning up the docs, and getting the
+               new SGML based docs into shape.
+           - cleanup of ar.c
+           - BusyBox should now poweroff when asked to do so.
+           - Fixed 'ln -n' and 'ln -s' so they both work properly.
+       * Reorganized signal names in kill.c for better architecture support 
+           -- patch thanks to simon wood <simon@mungewell.uklinux.net>
+       * In 0.43, backspace and delete worked properly, but with 0.45, 
+           it just echoed a ^? for backspace, and ^H for control-h.  This
+           was due to a broken macro in init.c, that is now fixed.
+       * Removed sfdisk from BusyBox.  It was buggy, fat, and we really
+           couldn't maintain it very well, so including it was not really
+           very appropriate.  Those wanting an fdisk are invited to
+           grab a copy from util-linux.
+       * Added 'dumpkmap' to allow people to dump a binary keymap, which can 
+           then be loaded in by 'loadkmap' -- submitted by
+           Arne Bernin <arne@matrix.loopback.org>
+       * Fixed NFS so it supports 2.4.x kernels and NFSv3.
+       * Brand, new versions of grep and sed which use libc regex routines,
+           thanks to Mark Whitley <markw@codepoet.org>.  The hand-tooled 
+           "regexp.[ch]" files have been removed. Much help on these from 
+           Matt Kraai as well.
+
+
+        -Erik Andersen, 11 July 2000
+
+
+0.45
+       * Now compiles vs libc5 (which can save lots of space for 
+           embedded systems).
+       * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the
+           help messages (i.e --help).  Saves 17k over a full compile.
+       * Added cut and tr from minix, since due to the license change, 
+           we can now use minix code.  Minix tr saves 4k. 
+       * insmod now works.  It costs 29k, but imagine an initrd with a 
+           staticly linked busybox containing only insmod and sh, a few /dev 
+           entries, and a kernel module or two...  It doesn't get smaller
+           then this folks (I pity the fool that writes insmod in asm ;-).
+           Many kudos go to Ron Alder <alder@lineo.com> for finishing this off!
+       * Added a mini ar archive utility, especially written for BusyBox by 
+           Glenn McGrath <bug1@netconnect.com.au>
+       * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org>
+       * Added setkeycodes, for those that have weird keyboard buttons.
+       * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt 
+           <ams@trillian.itslinux.org> for contributing these.
+        * Added 'grep -v' option (inverted search) and updated 
+           docs accordingly.  -beppu
+       * Wrote which
+       * Replaced the telnet implementation with one written by 
+           Tomi Ollila <too@iki.fi> It works great and costs 3k.
+       * BusyBox sh (lash) now supports being used as a standalone shell.  When
+           BB_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may
+           be invoked as shell internals.  Best used when compiling staticly 
+           (i.e. DOSTATIC=true)
+       * BusyBox sh (lash) internals now behave as expected wrt pipes 
+           and redirects. 
+       * Fixed ping warnings -- fix from Sascha Ziemann <szi@aibon.ping.de>
+       * Fixed update segfault
+       * Fixed mknod -- minor number was always 0
+       * Fixed tar option parsing, so both "tar xvf foo.tar" and 
+           "tar -xvf foo.tar" now work (i.e. no "-" before options) 
+           (this was very broken in 0.43).
+       * Several contributions from Randolph Chung <tausq@debian.org>.
+           * cp/mv now accepts the -f flag
+           * tail can now accept -<num> commands (e.g. -10) for better 
+               compatibility with the standard tail command
+           * added a simple id implementation; doesn't support sup. groups yet
+       * logname used getlogin(3) which uses utmp.  Now it doesn't. 
+       * whoami used getpwuid(3) which uses libc NSS.  Now it behaves. 
+       * Add support for "noatime" and "nodiratime" mount flags to mount.
+       * Changed 'umount -f' to mean force, and actually use umount2.
+       * Changed 'umount -l' to mean "Do not free loop device".
+       * Fixed basename to support stripping of suffixes.  Patch thanks
+           to xiong jianxin <jxiong@uiuc.edu>
+       * cp -fa now works as expected for symlinks (it didn't before)
+       * zcat now works (wasn't working since option parsing was broken)
+       * Renamed "mnc" to the more correct "nc" (for netcat).
+       * Makefile intelligence updates
+       * Changed the way init parses /etc/inittab entries to avoid problems
+           with commands that contain colons in them.  Fix thanks to 
+           Pavel Roskin <proski@gnu.org>
+       * Fixed a warning in utility.c due to char being unsigned on Linux/PPC, 
+           Fix thanks to Pavel Roskin <proski@gnu.org>
+       * Made "killall" complain (not error and exit) about processes that it 
+           cannot find by name -- Pavel Roskin <proski@gnu.org> 
+       * Fixed more and ps to have sensible terminal width defaults, thanks 
+           to Pavel Roskin.
+       * Fixed all fatalError() calls lacking a "\n", thanks to Pavel Roskin.
+       * Fixed a segfault in yes when no args were given -- Pavel Roskin.
+       * Simplified freeramdisk and added argument checking -- Pavel Roskin. 
+       * Fixed segfault caused by "touch -c"
+       * Fixed segfault caused by "rm -f"
+       * Fixed segfault caused by "ln -s -s" and similar abuses. Further fixes
+           and "--" support from Pavel Roskin.
+       * Fixed segfault caused by "cp -a -a" and similar abuses.
+       * Implemented "rm -- <foo>". Implementation fixed by Pavel Roskin.
+       * "which" rewritten to use stat(). Fixes to improve its compatability
+           with traditional implementations -- Pavel Roskin.
+       * "mount" now reports errors from nfsmount() and assumes NFS mount
+           if ':' is present in the device name - Pavel Roskin
+       * Fixed exit status for killall - Pavel Roskin
+       * Fixed 'swapon -a' and 'swapoff -a', which were broken.
+       * Fixed 'mount -a' so it works as expected.
+       * Implemented 'ls -R' (enabled by enabling BB_FEATURE_LS_RECURSIVE)
+       * Implemented "ping -s", fixed error messages and argument parsing -
+           Pavel Roskin
+       * Syslogd will not go to background if "-n" is given. Better help
+           and argument checking -- Pavel Roskin
+       * Fixed a small bug that could cause tar to emit warning messages
+           and not extract the first file in a directory in some cases
+           of nested directories.  Thanks to Kevin Traas <kevin@netmaster.com>
+           for helping track this one down.
+       * More doc updates
+       * Fixed grep "Line too long" problem -- John Beppu
+       * Fixed 'grep -q -i B some_file' so it works
+       * math takes input from stdin if no args are given.  -- John Beppu
+       * math was renamed to dc.  Although it deviates from dc's behaviour,
+           this will probably be remedied in the future.  -- John Beppu
+
+
+        -Erik Andersen, June 21, 2000
+
+
+0.44
+       Previously, an erronous announcement of BusyBox 0.44 was made, so to 
+       avoid possible confusion, we are skipping straight to 0.45, and calling
+       it good.
+
+        -Erik Andersen
+
+
+0.43
+       * Major update to the provided documentation.
+       * Busybox now includes a shell!  It currently costs 7.5 k (plus an
+           additional 2.5 k if you compile in command line editing).  Handles
+           job control, has the usual set of builtins, and does everything
+           except for handling programming statements (if, while, etc...)
+       * Busybox can now work perfectly when /proc is disabled, thereby 
+           saving a bunch of memory (kernel /proc support is not thin).  This
+           is done by making use of some nice kernel patches I wrote up to
+           support the features that busybox requires and that /proc usually
+           provides.  To enable this, turn on BB_FEATURE_USE_DEVPS_PATCH and
+           patch your kernel with the devps patch in the kernel-patches/
+           directory. 
+       * Wrote basename, dirname, killall, and uptime.
+       * tar has been completely rewritten by me.  Both tar creation and 
+           extraction are now well behaved.  Costs 7.6k with all optional
+           tar features enabled, and 5k for just tar extraction support. 
+       * Added freeramdisk, which will free up all memory associated
+           with a ram disk.  Contributed by Emanuele Caratti <wiz@iol.it>
+           and then adjusted a bit by me.
+       * Added tr from John Lombardo <john@deltanet.com> 
+       * Added echo and test (from me).
+       * Added usleep contributed by Nicolas Pitre <nico@cam.org>
+       * BusyBox's bss size has been majorly reduced (was 384668, is now 28740).
+       * Several fixes from Pavel Roskin <proski@gnu.org>:
+           - When `tail' fails to open a file it now exits.
+           - When `syslogd' is given the `-n' option it should still use 
+               fork() for running klogd.
+       * nslookup types are now changed to u_int32_t (instead of uint32_t)
+           changed per a patch from Pascal Bellard <pascal.bellard@ascend.com>
+       * Fixed "du" so it gives the same answers as GNU "du" (busybox du used 
+           to count hard-linked files more then once).  Many thanks to 
+           Friedrich Vedder <fwv@myrtle.lahn.de> for the fix.
+       * Removed /proc dependancies for init and free (while maintaining 
+           exactly the same functionality).  /proc takes up 90k of kernel 
+           space, so it is nice to avoid using it at all costs.
+       * init no longer tries to mount /proc (unless there is less the 1 meg 
+           free).  Use of /proc (or not) is policy that should be set up in 
+           /etc/fstab (or in hardcoded scripts), not in init.
+       * Fixed rebooting when init runs as an initrd.
+       * Fixes and updates from Karl M. Hegbloom  <karlheg@debian.org>
+           - update.c rewritten to look more like update-2.11
+           - moveed the inode hash out of du.c and into utility.c to make 
+               it a common resource that can be used by other apps.
+           - cp_mv.c now checks inodes to see if a source and dest are
+               the same, and prints an error (instead of endlessly looping).
+           - mv now attempts to do a rename, and will fall back to doing
+               a copy only if the rename fails.
+           - Syslogd now supports multiple concurrent connections
+       * Several fixes from Pavel Roskin <proski@gnu.org>:
+           - Fixes to sort.  Removed "-g", fixed and added "-r"
+           - Fixes to the makefile for handling "strip"
+       * An initial telnet implementation was added by 
+           Randolph Chung <tausq@debian.org>.
+       * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e")
+       * ps now supports BB_FEATURE_AUTOWIDTH, and can adjust its width
+           to match the terminal (defaults to width=79 when this is off).
+       * ps now accepts (and ignores) all options except for "--help" (which
+               as would be expected displays help).
+       * Fixed mount'ing loop devices when the filesystem type was not 
+           specified.  It used to revert to non-loop after the first try.
+       * all mallocs now use xmalloc (and so are OOM error safe), and
+           the common error handling saves a few bytes.  Thanks to 
+           Bob Tinsley <bob@earthrise.demon.co.uk> for the patch.
+       * Fix "+" parsing bug in date, from "Merle F. McClelland" <mfm@cts.com>.
+       * Fix symlink following bug in chmod -R and friends.  
+       * Now allows SYSV style 'chown foo:bar' in addition to 'chown foo.bar'
+       * Fixed a bug in the busybox globbing routine such that 'find /dir -name [i]' 
+           no longer segfaults.
+
+
+       -Erik Andersen
+
+
+0.42
+
+        * Fairly massive restructuring of umount.c to deal with remounting 
+         busy devices read-only. Adds a -r option to control that; it is 
+         optionally compiled in with BB_FEATURE_REMOUNT
+       * Added a bunch of functions to mtab.c to interact with the
+         {get,set,end}mntent interface; as it turns out, those functions do
+         not appear to be re-entrant, and that causes a lot of problems with
+         the way umount was originally written.
+       * Makes init send TERM and KILL (instead of HUP and KILL) on reboot
+         to be more consistent with sysvinit
+       * Changes to init.c to use the new -r option to umount. Also increased
+         the sleep time between the time the TERM and KILL signals are sent
+
+        - Randolph Chung
+
+
+       * cp.c, mv.c: removed, replaced by cp_mv.c which has been
+           extensively rewritten from the original cp.c.
+       * Fixed cp and mv so if the source and destination are a the
+           same directory it will print an error and continue.
+       * Also added a warning message to the `mv' usage string saying that
+           this is not GNU mv, and it will break hard links. cp also breaks
+           hard links.
+       * ln.c: implemented `-n' switch, no-deref symlinks.
+       * include<sys/param.h>: and use PATH_MAX everywhere.  busybox: File
+       * name buffer overrun guards to prevent future crashes.
+           - Always check exit status.
+           - Purge all use of `creat()', replace with `open()'.
+       * utility.c 
+           - recursiveAction was overriding the value of followLinks thus
+             ignoring it.
+           - isDirectory now takes a followLinks boolean, updated all callers
+           - copyFile had the followLinks logic reversed.
+       * messages.c: New file. Put common error message strings all in
+           one place in an attempt to shrink the binary a little.
+
+       -Karl M. Hegbloom
+
+
+       * changed fsck_minix.c to reduce its .bss size significantly
+         -beppu -piptigger
+       * Made tar creation support in busybox tar optional.  You no longer
+       * _have_ to put a "-" in front of tar options.  Tar could inadvertently
+       * change permissions and ownership on
+           certain directories pointed to by symlinks.
+       * Made grep and grep -h do the right thing wrt printing
+           the file name (it failed to print files names in many cases).
+       * Fix a namespace aliasing problem wereby if du was built in, the 
+           symlink for both du and dutmp would be installed, or then rm was
+           built in, the symlinks for both rm and rmmod would be installed.
+       * Added a closelog() to init.c after loging -- fix thanks to 
+           Taketoshi Sano <kgh12351@nifty.ne.jp>
+       * Rewrote and simplified logger.  Added the "-t" option, and made it
+           behave itself a bit better.
+       * Optional support contributed by Ben Collins <bcollins@debian.org> 
+           for the kernel init chroot patch by Werner Almesberger, which
+           allows init to chroot to a new device, and umount the old one.
+       * Fixed bug that wouldn't let one chown a symlink -- it would
+           always dereference before.  -beppu
+       * Fixed a bug where init could have reference already freed memory.
+           Found and fixed by Taketoshi Sano <kgh12351@nifty.ne.jp>
+       * Several contributions from Friedrich Vedder <fwv@myrtle.lahn.de>
+       * Added (and documented) "-n" option for head
+       * Cleanup for a number of usage messages -- also 
+           contributed Friedrich Vedder <fwv@myrtle.lahn.de>
+       * Cosmetic fix to busybox.c (Don't print a comma at the
+           end of line if there are no more application names).
+       * Fixed a stupid bug in "head" option handling ("head -n" 
+           would segfault).
+       * Moved commonly used functions "xmalloc()" and "exit()"
+           to utility.c (with proper #ifdef's).
+       * Created a tiny tail implementation, removing -c, -q, -v, and making
+           tail -f work only with a single file.  This reduced tail from 6k to
+           2.4k.  The bigger/more featured tail can still be had by disabling
+           BB_FEATURE_SIMPLE_TAIL in busybox.defs.h
+       * Ping now falls back to doing the right thing if /etc/protocols
+           turns up missing.
+       * Fixed mount and umount.  Previously they could leak loop device 
+           allocations, causing the system to quickly run out.  Fix for umount
+           by Ben Collins <bcollins@debian.org>, and mount was fixed by me.
+       * ls formatting on eight charactor user names fixed by 
+           Randolph Chung <tausq@debian.org>.
+       * cp could, when copying symlinks, change permissions of the
+           files pointed to by the symlinks.
+       * Several fixes from Pavel Roskin <proski@gnu.org>:
+           - `chown' with 1 argument displayed the error incorrectly
+           - `fdflush', `length' and `printf' crashed if run without arguments
+           - `fdflush' tried to flush itself using *argv
+           - added "skip" and "seek" to dd.
+           - ls no longer messus up output when combining files and
+             directories on the command line 
+       * swapoff -a was not working.  Now it is.  
+       * init did not cleanly unmount filesystems on reboot.  Now it does.  
+       * "sed -ne s/foo/bar/" worked but "sed -n -e s/foo/bar/" didn't.
+           Now both work.
+       * Some architectures (PowerPc) assume chars are unsigned, so they could
+           not distinguish between EOF and '\0xFF' in sed.  Sed now uses ints.
+       * Began converting error handling to use some common routines
+           in utility.c
+       * syslogd now has better message handling and ignores SIGHUP.
+       * install.sh had a bug preventing installation to the specified
+           target directory.  Fix from Gilbert Coville <gilbert@mvista.com>
+       * You can now spefify alternative strip commands -- change 
+           also from Gilbert Coville.
+
+
+       -Erik Andersen
+
+0.41
+       * New Apps: wc, hostid, logname, tty, whoami, yes -- all contributed 
+           by Edward Betts <edward@debian.org>
+       * Fixed a bug in both cp and mv preventing 'cp foo/README bar'
+           type commands (file in a directory to another directory) from
+           working.
+       * Fixed a logger bug that caused garbage to be written to the syslog 
+           (unless you used busybox syslog, which hid the bug).  Thanks to
+           Alex Holden <alex@linuxhacker.org> for the fix.
+       * /bin/true and /bin/false were echoing a blank line when run.  
+           Now fixed.
+       * mkdir -p would print an error when asked to mkdir an existing dir
+           with no interveining subdirectories.
+       * Fixed "syslogd -O" so that it works.  Added -o loop option for mount,
+       * and support in umount for loop
+         devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins
+         <bcollins@debian.org>
+       * Several fixes from Marco Pantaleoni <panta@prosa.it> compile in
+       * fullWrite() not only if BB_TAR is defined, but also
+               if BB_CP or BB_MV are (fullWrite() is referenced by copyFile())
+           * add some compiler optimizations to further reduce executable size
+               (as a side note, on my machines the largest code is generated
+               by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with
+               -O2 -m386 ...)
+           * Compile now won't fail if busybox.def.h defines 
+               BB_FEATURE_LINUXRC but not BB_INIT.  (init_main used to be
+               referenced, but not compiled)
+       * Fixed a bug in setting TERM for serial console support.  TERM now
+           defaults to "ansi" for serial consoles.
+       * Fixed a bug in handling the CONSOLE env. variable for serial
+       * consoles.
+
+       -Erik Andersen, Jan 15, 2000
+
+0.40
+       * New Apps: sort, uniq. -beppu New Apps: lsmod, rmmod -erik New Apps:
+       * fbset contributed by Randolph Chung <tausq@debian.org>.  New App::
+       * loadacm contributed by Peter Novodvorsky <petya@logic.ru>
+           for loading application character maps for Unicode fonts.
+       * Major init re-work.  init now supports inittab (slightly different
+           but similar to sysvinit), allowing me to get all the policy out of
+           init and into the conf file.  It works just fine without inittab
+           being present, but if you dont like the default behavior you can
+           now do something about it.  Init is much cleaner as a result.
+       * Fixed an bug in syslogd causing it to stop after 20 minutes. -erik
+       * Fixed an embarrasing segfault in head -beppu Fixed the embarrasing
+       * failure of 'logger -p'. -erik Added the -s option to du -beppu
+       * Re-worked the source tree a bit so it will compile under glibc 2.0.7 
+           with the 2.0.x Linux kernel.
+       * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" 
+           <konst@voshod.com>.
+       * Grep -i previously failed on UPPER CASE patterns due to a silly 
+           regexp implementation bug that is now fixed.
+       * Fixed a bug where tar would set, and then clear SGID and SUID bits.
+       * Fixed a bug where tar would not set the user and group on device
+           special files.
+       * Fixed a bug where tar would not restore the time to files.  Fixed a
+       * major security problem with tar -- it changed ownership 
+           of any file pointed to by a symlink to 777 (like say libc....)
+           Ouch!!!
+       * cp and mv were very broken when moving directories.  I have rewritten 
+           them so they should now work as expected. 
+       * sed now supports addresses (numeric or regexp, with negation) and 
+           has an append command, thanks to Marco Pantaleoni <panta@prosa.it>
+       * Fixed dmesg.  It wasn't parsing its options (-n or -s) properly.
+       * Some cosmetic fixes to ls output formatting to make it behave more
+           like GNU ls.
+       * Fixed a stupid segfault in kill.  Several fixes from Friedrich Vedder
+       * <fwv@myrtle.lahn.de>:
+           - Added gunzip -t, removed gunzip.c dead code,
+           - fixed several typos
+           - Glibc 2.0.7 and libc5 compile fixes
+       * Fixed a bug where 'mknod --help' would segfault.
+           
+
+       -Erik Andersen, Jan 07, 2000
+
+0.39 
+       * New Apps: ping, hostname, and mkfifo contributed by Randolph Chung
+           <tausq@debian.org>.  3 items off the TODO list!
+       * I wrote free (just calls "cat /proc/meminfo").  Added tail, based on
+       * tail from GNU textutils-1.19, but adjusted
+           to suit my evil purposes.  Costs 6k.  I'll make it smaller
+           sometime.
+       * on reboot, init called 'umount -a -n', which caused errors
+           when BB_MTAB was not enabled.  Changed to 'umount -a', which does
+           the right thing.
+       * init will now try to run /sbin/getty if it is present (for easy
+           integration with the about-to-be-released tinylogin.)
+       * kill now behaves itself properly, added 'kill -l' to list signals 'ls
+       * -l' was failing on long directories, since my_getid was leaking 
+           one file descriptor per file.  Oops.
+       * Fixed rebooting from init.  I'd accidently left some debugging code
+       * in
+           which blocked reboots.
+       * Fixed reboot, halt (and added poweroff) such that they handle it when
+           init is not at PID 1 (like when running in an initrd).
+       * Added a prelinary du implementation.  Some parameter parsing
+           stuff still needs to be added. -beppu (John Beppu
+           <beppu@codepoet.org>)
+       * Implemented tee.  -beppu Implemented head. -beppu
+
+       -Erik Andersen, Dec 10, 1999
+
+0.38
+       * Fixed a segfault in 'umount -a' when a badly formed /etc/fstab
+           file existed.
+       * df will not exit on error, but will stat all mounted filesystems.
+       * Fixed tar so uid/gid/permissions on extracted tarballs will be 
+           correct.
+       * Fixed find -name so it properly uses shell wildcard patterns 
+           (i.e. `*', `?', and `[]') instead of regular expressions, which
+           was causing some confusing and unexpected behavior.
+       * Added klogd to syslogd, so now the log will contain both system and
+           kernel messages.
+       * syslogd now creates the /dev/log socket to make sure it is there, and
+           is actually a socket with the right permissions.
+       * I've taken a first step to making busybox not need the /proc 
+           filesystem.  Most apps don't need it.  Those that _require_ it, 
+           will complain if you enable them when you disable 
+           BB_FEATURE_USE_PROCFS.
+          
+       -Erik Andersen, Dec 5, 1999
+
+0.37
+       * Wrote a micro syslogd, and a logger util (to log things to the syslog
+           from the command line or scripts)  With both compiled in, costs 4k.
+       * Fixed 'make install' so symlinks are installed in their proper
+       * locations.  Changed the build system slightly so that features can
+       * now be enabled
+           or disabled from the busybox.defs.h header file, without trying to
+           compile in a source file named after that featue (unless that file
+           exists).
+       * Several options are now moved into busybox.defs.h Now 'rm -R' and 'rm
+       * -r' both work.  dd now properly handles input beyond 1 block from
+       * stdin.  Fixed a bug where tar unpacked everything a directories.
+       * Moved some code 
+           from createPath into mkdir where it belonged, thereby making tar
+           work properly.
+       * Fixed an off-by-one bug in cat.  Given a list of file it wouldn't cat
+       * out the
+           last file in the list.
+       * Fixed 'ls -ln' so numeric group/uid are presented properly, and fixed
+       * 'ls -l' 
+           so when uid/gid is not in /etc/{passwd,group} the numeric group/uid
+           are presented properly.  
+       * Also added a TODO.
+
+
+       -Erik Andersen, Nov 25, 1999
+
+0.36
+       * fixed dd so it properly defaults to stdin and stdout when no 
+           if= and of= are set (fix thanks to Eric Delaunay).
+       * Don't try to close the file descriptor of a pipein tar. (fix also
+       * from
+           Eric Delaunay).
+       * Made createPath be quiet (again thanks to Eric Delaunay).  If
+       * BB_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever
+           command you define it as will be run if the init script exits.
+       * Updated install.sh to make it more robust (thanks to Adam Di Carlo)
+       * NFS support added to mount by Eric Delaunay.  It costs 10k when
+       * compiled
+           in, but that is still a big win for those that use NFS.
+       * Made 'rm -f' be silent for non-existant files (thanks to Eric
+       * Delaunay).  changed zcat.c to gunzip.c.  It now obeys the principle
+       * of least surprise 
+           and acts as god intended gunzip and zcat to act.  They answer
+           --help and obey the '-c' flag.
+       * Fixed a bug in mv which caused it to not move files when the
+       * destination
+           was a directory.
+       * Fixed a decimal-instead-of-octal bug causing mkdir to make
+       * directories
+           with very wrong permissions.
+       * chmod would overwrite file permissions instead of modifying them.
+           Now it properly modifies permissions.
+       * Init now sends warnings destined for the console to /dev/console to
+       * ensure
+           they show up on whatever the active console it.  Otherwise
+           important messages (for example that the system is rebooting) were
+           not seen when switched to a different VT.
+
+       -Erik Andersen, Nov 17, 1999
+       
+0.35
+       * gzip now obeys the principle of least surprise and acts like god
+       * intended 
+           (i.e. it accepts a file name, answers --help, and obeys the '-c'
+           flag and only then outputs to stdout).
+       * Fixed more.c to compile autowidth on sparc and set initial winsize 
+           to 0,0 in case the TIOCGWINSZ ioctl fails.  Fix thanks to Eric
+           Delaunay.
+       * Fixed tar so it now works as expected (it had TRUE/FALSE backwards)
+       * tar now accepts --help chmod, chown, and chgrp usage now works
+       * General usage (i.e. --help) cleanups for most apps umount now parses
+       * options correctly tar can now unpack tarballs containing device
+       * special files, 
+           sockets, and fifos (though it can't pack them up) thanks to Matt
+           Porter.  Creating archives containing these is still left to the
+           interested student.
+       * fixed up the license in more.c to properly point to Bruce Perens.
+
+       -Erik Andersen, Nov  11, 1999
+
+0.34
+       * ls -l now displays link names outside the current directory,
+           Patch thanks to Eric Delaunay
+       * init now properly handles sparc serial consoles and does a
+           better job of finding the real console device rather than using
+           /dev/console which doesn't support job control. Patch also thanks
+           to Eric Delaunay.
+       * more started to read from stdin after the last file was finished, and 
+           options were not parsed correctly (fix thanks to Eric Delaunay).
+       * more will now use the terminal size if BB_FEATURE_AUTOWIDTH is on.
+       * rm wouldn't remove a symlink unless the symlink was valid.  This was
+           a side effect of the busybox 0.32 recursiveAction() fix.  Things
+           should now work correctly.
+       * grep wouldn't grep stdin.  Now it does.  sed wouldn't sed stdin.  Now
+       * it does.  sed was appending a \n to the end of lines with
+       * replacements.
+           Now it doesn't do that.
+       * ls -l now bypasses libc6 nss when displaying user/group names.
+           Now uses my_getpwuid and my_getgrgid.
+
+        -Erik Andersen, Nov  8, 1999
+
+0.33
+       * Fixed a bug where init could hang instead of rebooting.
+       * Removed some debugging noise from init.c
+       * Fixed ln so it works now (it was very broken).
+       * Fixed df so it won't segfault when there is no /etc/fstab,
+       * If BB_MTAB is not defined, df and mount will whine if /etc/fstab
+           is not installed (since they cannot fixup "/dev/root" to 
+           state the real root device name)
+       * merged some redundant code from mtab.c/df.c into utility.c
+
+        -Erik Andersen, Nov  5, 1999
+
+0.32
+       * More changes -- many thanks to Lineo for paying me to work on
+           busybox.  If you have any problems please let me know ASAP at
+           andersee@debian.org
+       * usage() now prints the BusyBox version.  This will help folks
+           realize that they are not in Kansas anymore.
+       * Fixed mkdir -m option so that it works.  kill segfaulted w/o any
+       * arguments.  Now it doesn't do that.  kill wasn't properly accepting
+       * signal names.  It does now.  Added new apps chvt and deallocvt (I
+       * should probably add open) Major rewrite of init.c.  Code is now
+       * readable by mere mortals IMHO.  Wrote sed -- weighs only 1.8k (5.8k
+       * with full regular expressions!).  Fixed a stupid seg-fault in sync
+       * Fixed mount -- mount -a failed to parse and apply mount options Fixed
+       * umount -n (patch thanks to Matthew Grant <grantma@anathoth.gen.nz>)
+       * umount -a no longer umounts /proc Added BB_MTAB, allowing (at the
+       * cost of ~1.5k and the need for a rw /etc)
+           folks to use a real /etc/mtab file instead of a symlink to
+           /proc/mounts.  mount, and umount will add/remove entries and df
+           will now use /etc/mtab if BB_MTAB is defined. 
+       * Fixed a nice bug in recursiveAction() which caused it to infinitely
+           hunt through /proc/../fd/* creating new file descriptors if it
+           followed the /dev/fd link over to /proc.  recursiveAction() now
+           lstat's the file when followLinks==FALSE so it won't follow links
+           as the name suggests.  Fix thanks to Matt Porter
+           <porter@debian.org>.
+
+
+        -Erik Andersen, Nov  4, 1999
+
+0.31
+       * I added a changelog for version 0.30.  adjusted find internals to
+       * make it smaller, and removed 
+           some redundancy.
+       * Fixed a segfault in ps when /etc/passwd or /etc/group 
+           are absent.  Now will warn you and carry on.
+       * Added in optional _real_ regular expression support (to be
+           the basis for a future sed utility).  When compiled in it adds
+           3.9k, but makes grep much more capable.
+       * Checked out using nftw(3) for recursive stuff, but unfortunatly
+           it wasn't supported before GNU libc 2.1, and some folks use glibc
+           2.0.7 since it is much smaller than that latest and greatest.
+
+        -Erik Andersen, Oct 21, 1999
+
+0.30
+       Major changes -- lots of stuff rewritten. Many thanks to Lineo for
+       paying me to make these updates. If you have any problems with busybox, 
+       or notice any bugs -- please let me know so I can fix it.  These 
+       changes include:
+
+       Core Changes:
+           * busybox can now invoke apps in two ways: via symlinks to the
+               busybox binary, and as 'busybox [function] [arguments]...'
+           * When invoked as busybox, the list of currently compiled in 
+               functions is printed out (no this is not bloat -- the list has
+               to be there anyway to map invocation name to function).
+           * busybox no longer parses command lines for apps or displays their
+               usage info.  Each app gets to handle (or not handle) this for
+               itself.
+           * Eliminated monadic, dyadic, descend, block_device, and 
+               postprocess.  It was cumbersome to have so many programs
+               cobbled together in this way.  Without them, the app is much
+               more granular.
+           * All shared code now lives in utility.c, and is properly
+               ifdef'ed to be only included for those apps requiring it.
+           * Eliminated struct FileInfo (the basis of monadic, dyadic, etc)
+               so now each app has the function prototype of (da-dum): extern
+               int foo_main(int argc, char** argv); which speeds integration
+               of new apps.
+           * Adjusted the Makefile to make it easier to 
+               {en|dis}able debugging.
+           * Changed default compiler optimization to -Os 
+               (optimize for smaller binaries).
+
+       App Changes:
+           * To cope with the new app function prototype and the removal of
+               monadic, dyadic, etc, the following apps were re-written:
+                   * cat - Works same as always.  chgrp, chmod, chown -
+                   * rewrite.  Combined into a single 
+                       source file.  Absorbed patches from Enrique Zanardi
+                       <ezanard@debian.org> that removes the dependency on
+                       libc6 libnss* libraries.
+                   * cp - Can now do 'cp -a' can can copy devices,
+                       pipes, symlinks, as well as recursive or non-recursive
+                       dir copies.
+                   * fdflush - adjusted to remove dependancy on struct
+                   * FileInfo.  find - Now includes some basic regexp matching 
+                       which will be the basic of a future mini-sed.
+                   * ln - Same functionality.  mkdir - Added -p flag to
+                   * feature set.  mv - rewrite.  rm - Added -f flag to
+                   * feature set.  rmdir - Same functionality.  swapon,
+                   * swapoff - Combined into a single binary. No longer
+                       uses /etc/swaps.  swap{on|off} -a uses /etc/fstab
+                       instead.
+                   * touch - Same functionality.  date - adjusted with a patch
+                   * from Matthew Grant <grantma@anathoth.gen.nz>
+               to accomodate glibc timezone support.  I then ripped out GNU
+               getopt.
+           * mkswap -- new version merged from util-linux.  Can now make 
+                       >128Meg swaps.  
+               * Replaced the old and star, unstar, and tarcat with the tar 
+                       implementation from sash.   Now tar behaves as god intended it
+                       to (i.e. tar -xvf <file> and tar -cf <file> <dir> work).
+           * dd -- rewritten.  Can with with files, stdin, stdout.  Added the
+           * following new apps: loadfont -- added from debian boot floppies
+           * chroot -- added based on a patch from Paolo Molaro
+           * <lupus@lettere.unipd.it> grep -- I just wrote it.  Only matches
+           * simple strings ps -- I just wrote it.  Has _no_ options at all,
+           * but works.  fsck_minix, mkfs_minix -- added from util-linux, but
+           * I ripped out
+                       internationalization and such to make them smaller.
+                   * sfdisk -- Added from util-linux (minus
+                   * internationalization and such).  Probably some other
+                   * changes that I forgot to document...
+
+        -Erik Andersen, Oct 20, 1999
+
+0.29   
+       This version was a messy pre-alpha.  stay away or it will bite you.
+        -Erik Andersen, Sep 24, 1999
+       
+0.28   
+       mini-netcat (mnc) rewritten.
+       
+0.27
+       Mount now supports -a, and -t auto.
+       Mount now updates mtab correctly for 'ro'.
+       More checks screen rows size, outputs bytes percentage.
+       Printf added as module.
+0.26
+       Touch now creates files. -c option for no create.
+       
diff --git a/Changelog.full b/Changelog.full
new file mode 100644 (file)
index 0000000..4902831
--- /dev/null
@@ -0,0 +1,138 @@
+2002-10-27  Erik Andersen  <andersen@dillweed>
+
+       * Makefile: Increment version number
+
+       * debian/control, debian/changelog: Update packaging info
+
+2002-10-26  Erik Andersen  <andersen@dillweed>
+
+       * debian/Config.h-udeb:
+       Don't support init being run as /linux in the debian installer
+        -Erik
+
+       * swaponoff.c: last_patch64 from vodz:
+
+           The following usage from original user:
+           $ ./busybox swapon -a
+           Have typo problem:
+           swapon: swapon: Operation not permitted
+
+           But regular version:
+           swapon: /dev/hda5: Operation not permitted
+
+           Patch attached, reduced 9 bytes and advanced
+           exit code also.
+
+       * vi.c:
+       A patch from Jouni Malinen to avoid some buffer overflows in vi,
+       closing bug #1270
+
+       * Makefile: Ivan Popov noticed that handling of PREFIX was bad.
+        -Erik
+
+2002-10-25  Erik Andersen  <andersen@dillweed>
+
+       * tftp.c: This patch from Magnus Damm fixed a long standing problem
+       with freeing memory.
+
+2002-10-23  Erik Andersen  <andersen@dillweed>
+
+       * top.c: Backport vodz' reworked top applet from unstable
+
+2002-10-22  Erik Andersen  <andersen@dillweed>
+
+       * ash.c, ifconfig.c: Fix warnings
+
+       * md5sum.c: Fix undefined operation (temp = temp = <stuff>) and remove
+       double definition.
+        -Erik
+
+       * init.c: I committed the fflush in the wrong spot.  I should go to bed
+       earlier so I don't screw up such easy stuff.
+        -Erik
+
+       * ash.c: Apply last_patch51_3 from vodz
+
+       * init.c: Be absurdly careful about flushing stdout.
+
+2002-10-18  Erik Andersen  <andersen@dillweed>
+
+       * tests/sh.testcases: Missed a spot
+
+       * tests/sh.testcases: disambiguate a test
+
+       * lsmod.c: Fixup some needless formatting differences vs modutils
+
+       * hostname.c:
+       Fixup slight difference in 'hostname -d' behavior vs GNU hostname
+
+2002-10-12  Erik Andersen  <andersen@dillweed>
+
+       * init.c:
+       After thinking about it, I think this patch from Matt Kraai is probably the
+       best way to go.  Sysvinit does not provide a controlling tty since it doesn't
+       even try to open ttys for apps.  We do.  We we should _try_ to provide a
+       controlling tty if possible, but we needn't freak out if it doesn't work.  So
+       we won't need to use openvt or similar, we'll just have init do the Right
+       Thing(tm).
+
+2002-10-08  Erik Andersen  <andersen@dillweed>
+
+       * docs/.cvsignore: oops
+
+       * docs/.cvsignore, Makefile: Remove docs/busybox.pod on 'make clean'
+
+       * init.c:
+       Patch from Ben Gamsa <ben@somanetworks.com> to handle it when orphaned
+       processes are created faster than busybox init reaps them.
+
+       * lsmod.c: Fix missing \n noticed by Robert Schwebel
+
+       * debian/Config.h-udeb: Enable pidof
+
+       * libbb/copy_file.c:
+       Doh!  It turns out I broke 'cp -a' symlink handling.  Oops.  This fix, from
+       Tollef Fog Heen <tollef@add.no> fixes my stupid thinko so that 'cp -a' once
+       again copies symlinks properly.
+
+2002-09-30  Erik Andersen  <andersen@dillweed>
+
+       * usage.h: Fix docs
+
+       * lash.c:
+       Use %m, not strerror (changing since strerror(err) was broken anyways)
+
+       * init.c: Set the close-on-exec flag, just to be safe
+
+       * time.c: Doh.  We divide microseconds by 60?
+
+2002-09-27  Erik Andersen  <andersen@dillweed>
+
+       * time.c: Bug fix from Nitin Gupta <gupta@equator.com>
+
+2002-09-26  Erik Andersen  <andersen@dillweed>
+
+       * lash.c: Avoid calling exit() from within fork/vfork'ed processes.
+        -Erik
+
+2002-09-25  Erik Andersen  <andersen@dillweed>
+
+       * init.c:
+       Ignoring SIGCHLD causes a race leading to the occasional hang of init
+       when init will wait() on itself in waitfor() when the child exits before
+       init is scheduled to run.  Letting init hang is very seriously bad.
+        -Erik
+
+2002-09-22  Erik Andersen  <andersen@dillweed>
+
+       * Makefile: Fixup largefile settings.
+        -Erik
+
+2002-09-20  Erik Andersen  <andersen@dillweed>
+
+       * gunzip.c: Doh!  As noted by K.-P. Kirchdörfer" <kapeka@epost.de>,
+       gunzip -c deletes the source source file!  This fixes it.
+        -Erik
+
+       * top.c: Don't leak FILEs
+
diff --git a/Config.h b/Config.h
new file mode 100644 (file)
index 0000000..c5ece59
--- /dev/null
+++ b/Config.h
@@ -0,0 +1,494 @@
+/* vi: set sw=4 ts=4: */
+// This file defines the feature set to be compiled into busybox.
+// When you turn things off here, they won't be compiled in at all.
+//
+//// This file is parsed by sed.  You MUST use single line comments.
+//   i.e.,  //#define BB_BLAH
+//
+//
+// BusyBox Applications
+//#define BB_ADJTIMEX
+//#define BB_AR
+#define BB_ASH
+#define BB_BASENAME
+#define BB_CAT
+#define BB_CHGRP
+#define BB_CHMOD
+#define BB_CHOWN
+#define BB_CHROOT
+#define BB_CHVT
+#define BB_CLEAR
+//#define BB_CMP
+#define BB_CP
+//#define BB_CPIO
+#define BB_CUT
+#define BB_DATE
+//#define BB_DC
+#define BB_DD
+//#define BB_DEALLOCVT
+#define BB_DF
+#define BB_DIRNAME
+#define BB_DMESG
+//#define BB_DOS2UNIX
+//#define BB_DPKG
+//#define BB_DPKG_DEB
+//#define BB_DUTMP
+#define BB_DU
+//#define BB_DUMPKMAP
+#define BB_ECHO
+#define BB_ENV
+//#define BB_EXPR
+//#define BB_FBSET
+//#define BB_FDFLUSH
+#define BB_FIND
+#define BB_FREE
+//#define BB_FREERAMDISK
+//#define BB_FSCK_MINIX
+//#define BB_GETOPT
+#define BB_GREP
+#define BB_GUNZIP
+#define BB_GZIP
+#define BB_HALT
+#define BB_HEAD
+//#define BB_HOSTID
+//#define BB_HOSTNAME
+//#define BB_HUSH
+#define BB_ID
+//#define BB_IFCONFIG
+#define BB_INIT
+//#define BB_INSMOD
+#define BB_KILL
+#define BB_KILLALL
+#define BB_KLOGD
+//#define BB_LASH
+//#define BB_LENGTH
+#define BB_LN
+//#define BB_LOADACM
+//#define BB_LOADFONT
+//#define BB_LOADKMAP
+#define BB_LOGGER
+//#define BB_LOGNAME
+//#define BB_LOSETUP
+#define BB_LS
+#define BB_LSMOD
+//#define BB_MAKEDEVS
+//#define BB_MD5SUM
+#define BB_MKDIR
+//#define BB_MKFIFO
+//#define BB_MKFS_MINIX
+#define BB_MKNOD
+#define BB_MKSWAP
+//#define BB_MKTEMP
+#define BB_MODPROBE
+#define BB_MORE
+#define BB_MOUNT
+//#define BB_MSH
+//#define BB_MT
+#define BB_MV
+//#define BB_NC
+//#define BB_NSLOOKUP
+#define BB_PIDOF
+//#define BB_PING
+//#define BB_PIVOT_ROOT
+#define BB_POWEROFF
+//#define BB_PRINTF
+#define BB_PS
+#define BB_PWD
+//#define BB_RDATE
+//#define BB_READLINK
+#define BB_REBOOT
+//#define BB_RENICE
+#define BB_RESET
+#define BB_RM
+#define BB_RMDIR
+//#define BB_RMMOD
+//#define BB_ROUTE
+//#define BB_RPM2CPIO
+#define BB_SED
+//#define BB_SETKEYCODES
+#define BB_SLEEP
+#define BB_SORT
+//#define BB_STTY
+#define BB_SWAPONOFF
+#define BB_SYNC
+#define BB_SYSLOGD
+#define BB_TAIL
+#define BB_TAR
+//#define BB_TEE
+//#define BB_TEST
+//#define BB_TELNET
+//#define BB_TFTP
+//#define BB_TIME
+//#define BB_TOP
+#define BB_TOUCH
+//#define BB_TR
+//#define BB_TRACEROUTE
+#define BB_TRUE_FALSE
+#define BB_TTY
+//#define BB_UNIX2DOS
+//#define BB_UUENCODE
+//#define BB_UUDECODE
+#define BB_UMOUNT
+#define BB_UNIQ
+#define BB_UNAME
+//#define BB_UPDATE
+#define BB_UPTIME
+//#define BB_USLEEP
+//#define BB_VI
+//#define BB_WATCHDOG
+#define BB_WC
+//#define BB_WGET
+#define BB_WHICH
+#define BB_WHOAMI
+#define BB_XARGS
+#define BB_YES
+// End of Applications List
+//
+//
+//
+// ---------------------------------------------------------
+// This is where feature definitions go.  Generally speaking,
+// turning this stuff off makes things a bit smaller (and less 
+// pretty/useful).
+//
+//
+// If you enabled one or more of the shells, you may select which one
+// should be run when sh is invoked:
+#define BB_FEATURE_SH_IS_ASH
+//#define BB_FEATURE_SH_IS_HUSH
+//#define BB_FEATURE_SH_IS_LASH
+//#define BB_FEATURE_SH_IS_MSH
+//
+// BusyBox will, by default, malloc space for its buffers.  This costs code
+// size for the call to xmalloc.  You can use the following feature to have
+// them put on the stack.  For some very small machines with limited stack
+// space, this can be deadly.  For most folks, this works just fine...
+//#define BB_FEATURE_BUFFERS_GO_ON_STACK
+// The third alternative for buffer allocation is to use BSS.  This works
+// beautifully for computers with a real MMU (and OS support), but wastes
+// runtime RAM for uCLinux.  This behavior was the only one available for
+// BusyBox versions 0.48 and earlier.
+//#define BB_FEATURE_BUFFERS_GO_IN_BSS
+//
+// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
+// thereby eliminating the need for the /proc filesystem and thereby saving
+// lots and lots memory for more important things.  NOTE:  If you enable this
+// feature, you _must_ have patched the kernel to include the devps patch that
+// is included in the busybox/kernel-patches directory.  You will also need to
+// create some device special files in /dev on your embedded system:
+//        mknod /dev/mtab c 10 22
+//        mknod /dev/ps c 10 21
+// I emailed Linus and this patch will not be going into the stock kernel.
+//#define BB_FEATURE_USE_DEVPS_PATCH
+//
+// show verbose usage messages
+#define BB_FEATURE_VERBOSE_USAGE
+//
+// Use termios to manipulate the screen ('more' is prettier with this on)
+//#define BB_FEATURE_USE_TERMIOS
+//
+// calculate terminal & column widths (for more, ls, and telnet)
+#define BB_FEATURE_AUTOWIDTH
+//
+// show username/groupnames for ls
+#define BB_FEATURE_LS_USERNAME
+//
+// show file timestamps in ls
+#define BB_FEATURE_LS_TIMESTAMPS
+//
+// enable ls -p and -F
+#define BB_FEATURE_LS_FILETYPES
+//
+// sort the file names
+#define BB_FEATURE_LS_SORTFILES
+//
+// enable ls -R
+#define BB_FEATURE_LS_RECURSIVE
+//
+// enable ls -L
+#define BB_FEATURE_LS_FOLLOWLINKS
+//
+// Use color to identify different file types
+#define BB_FEATURE_LS_COLOR
+//
+// Disable for a smaller (but less functional) ping
+#define BB_FEATURE_FANCY_PING
+//
+// Make init use a simplified /etc/inittab file (recommended).
+#define BB_FEATURE_USE_INITTAB
+//
+//Enable init being called as /linuxrc
+#define BB_FEATURE_LINUXRC
+//
+//Have init enable core dumping for child processes (for debugging only) 
+//#define BB_FEATURE_INIT_COREDUMPS
+//
+//Make sure nothing is printed to the console on boot
+//#define BB_FEATURE_EXTRA_QUIET
+//
+// enable syslogd -R remotehost
+#define BB_FEATURE_REMOTE_LOG
+//
+// enable syslogd -C
+//#define BB_FEATURE_IPC_SYSLOG
+//
+//Disable for a simple tail implementation (2.34k vs 3k for the full one).
+//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
+#define BB_FEATURE_FANCY_TAIL
+//
+// Enable support for loop devices in mount
+#define BB_FEATURE_MOUNT_LOOP
+//
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+//#define BB_FEATURE_MTAB_SUPPORT
+//
+// Enable support for mounting remote NFS volumes. 
+// You may need to mount with "-o nolock" if you are
+// not running a local portmapper daemon...
+//
+// If you are using uClibc, be sure that you've already compiled
+// uClibc with INCLUDE_RPC=true (contained in the Config file)
+//#define BB_FEATURE_NFSMOUNT
+//
+// Enable support forced filesystem unmounting 
+// (i.e., in case of an unreachable NFS system).
+#define BB_FEATURE_MOUNT_FORCE
+//
+// Enable support for creation of tar files.
+#define BB_FEATURE_TAR_CREATE
+//
+// Enable support for "--exclude" and "-X" for excluding files
+#define BB_FEATURE_TAR_EXCLUDE
+//
+// Enable support for tar -z option (currently only works for inflating)
+#define BB_FEATURE_TAR_GZIP 
+//
+// Enable reverse sort
+#define BB_FEATURE_SORT_REVERSE
+//
+// Enable uniqe sort
+#define BB_FEATURE_SORT_UNIQUE
+//
+// Enable command line editing in the shell.  
+// Only relevant if a shell is enabled. On by default.
+#define BB_FEATURE_COMMAND_EDITING
+//
+// Enable tab completion in the shell.  This is now working quite nicely.
+// This feature adds a bit over 4k. Only relevant if a shell is enabled.
+#define BB_FEATURE_COMMAND_TAB_COMPLETION
+//
+// Attempts to match usernames in a ~-prefixed path
+//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
+//
+//Allow the shell to invoke all the compiled in BusyBox applets as if they
+//were shell builtins.  Nice for staticly linking an emergency rescue shell,
+//among other things. Off by default.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_STANDALONE_SHELL
+//
+//When this is enabled, busybox shell applets can be called using full path
+//names.  This causes applets (i.e., most busybox commands) to override
+//real commands on the filesystem.  For example, if you run run /bin/cat, it
+//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
+//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
+//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
+// Only relevant if a shell is enabled. Off by default.
+//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+//
+// Uncomment this option for a fancy shell prompt that includes the
+// current username and hostname.  On systems that don't have usernames
+// or hostnames, this can look hideous.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_FANCY_PROMPT
+//
+// Uncomment this option to disable job control.  Job control lets you 
+// run jobs in the background (which completely useless for is all you 
+// are doing is running scripts).  Disabing this is bad for interactive
+// use, since when you hit ^C in an application, it will also kill the 
+// shell.  This adds about 2.5k on an x86 system.
+#define BB_FEATURE_ASH_JOB_CONTROL
+//
+//Turn on extra fbset options
+//#define BB_FEATURE_FBSET_FANCY
+//
+//Turn on fbset readmode support
+//#define BB_FEATURE_FBSET_READMODE
+//
+// Support insmod/lsmod/rmmod for post 2.1 kernels
+#define BB_FEATURE_NEW_MODULE_INTERFACE
+//
+// Support insmod/lsmod/rmmod for pre 2.1 kernels
+//#define BB_FEATURE_OLD_MODULE_INTERFACE
+//
+// Support module version checking
+//#define BB_FEATURE_INSMOD_VERSION_CHECKING
+//
+// Support for uClinux memory usage optimization, which will load the image
+// directly into the kernel memory.  This divides memory requrements by three.
+// If you are not running uClinux (i.e., your CPU has an MMU) leave this
+// disabled...
+//#define BB_FEATURE_INSMOD_LOADINKMEM
+//
+// Support for Minix filesystem, version 2
+//#define BB_FEATURE_MINIX2
+//
+// Enable ifconfig status reporting output -- this feature adds 7k.
+//#define BB_FEATURE_IFCONFIG_STATUS
+//
+// Enable ifconfig slip-specific options "keepalive" and "outfill"
+//#define BB_FEATURE_IFCONFIG_SLIP
+//
+// Enable ifconfig options "mem_start", "io_addr", and "irq".
+//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+//
+// Enable ifconfig option "hw".  Currently works for only with "ether".
+//#define BB_FEATURE_IFCONFIG_HW
+//
+// Allows "broadcast +" to set broadcast automatically based on hostaddr
+// and netmask, at a cost of about 100 bytes of code (i386).
+//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
+//
+// Enable busybox --install [-s]
+// to create links (or symlinks) for all the commands that are 
+// compiled into the binary.  (needs /proc filesystem)
+//#define BB_FEATURE_INSTALLER
+//
+// Enable a nifty progress meter in wget (adds just under 2k)
+#define BB_FEATURE_WGET_STATUSBAR
+//
+// Enable HTTP authentication in wget
+#define BB_FEATURE_WGET_AUTHENTICATION
+//
+// Clean up all memory before exiting -- usually not needed
+// as the OS can clean up...  Don't enable this unless you
+// have a really good reason for cleaning things up manually.
+//#define BB_FEATURE_CLEAN_UP
+//
+// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
+#define BB_FEATURE_HUMAN_READABLE
+//
+// Support for the find -type option.
+#define BB_FEATURE_FIND_TYPE
+//
+// Support for the find -perm option.
+#define BB_FEATURE_FIND_PERM
+//
+// Support for the find -mtime option.
+#define BB_FEATURE_FIND_MTIME
+//
+//// Support for the find -newer option.
+#define BB_FEATURE_FIND_NEWER
+//
+// Support for the -A -B and -C context flags in grep
+//#define BB_FEATURE_GREP_CONTEXT
+//
+// Support for the EGREP applet (alias to the grep applet)
+//#define BB_FEATURE_GREP_EGREP_ALIAS
+//
+// Tell tftp what commands that should be supported.
+#define BB_FEATURE_TFTP_PUT
+#define BB_FEATURE_TFTP_GET
+//
+// features for vi
+#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
+#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
+#define BB_FEATURE_VI_SEARCH           // search and replace cmds
+#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
+#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
+#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
+#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
+#define BB_FEATURE_VI_SET              // :set
+#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
+//
+// Enable a if you system have setuped locale
+//#define BB_LOCALE_SUPPORT
+//
+// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
+#define BB_FEATURE_TELNET_TTYPE
+//
+// Support for devfs.
+//#define BB_FEATURE_DEVFS
+//
+// End of Features List
+//
+//
+//
+//
+//
+//
+//---------------------------------------------------
+// Nothing beyond this point should ever be touched by 
+// mere mortals so leave this stuff alone.
+//
+#include <features.h>
+#if defined(__uClinux__)
+       #undef BB_ASH                   /* Not even a chance it will work */
+       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
+       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
+       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
+       #undef BB_UPDATE                /* Uses daemon() */
+#endif
+#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
+       #if defined BB_FEATURE_COMMAND_EDITING
+               #define BB_CMDEDIT
+       #else
+               #undef BB_FEATURE_COMMAND_EDITING
+               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
+               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               #undef BB_FEATURE_SH_FANCY_PROMPT
+       #endif
+#else
+       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       #undef BB_FEATURE_SH_STANDALONE_SHELL
+       #undef BB_FEATURE_SH_FANCY_PROMPT
+#endif
+//
+#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
+       #define BB_TEST
+#endif
+//
+#ifdef BB_KILLALL
+       #ifndef BB_KILL
+               #define BB_KILL
+       #endif
+#endif
+//
+#ifndef BB_INIT
+       #undef BB_FEATURE_LINUXRC
+#endif
+//
+#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
+       #define BB_NFSMOUNT
+#endif
+//
+#if defined BB_FEATURE_AUTOWIDTH
+       #ifndef BB_FEATURE_USE_TERMIOS
+               #define BB_FEATURE_USE_TERMIOS
+       #endif
+#endif
+//
+#if defined BB_INSMOD || defined BB_LSMOD
+       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
+               #define BB_FEATURE_NEW_MODULE_INTERFACE
+       #endif
+#endif
+//
+#ifdef BB_UNIX2DOS
+       #define BB_DOS2UNIX
+#endif 
+//
+#ifdef BB_SYSLOGD
+       #if defined BB_FEATURE_IPC_SYSLOG
+               #define BB_LOGREAD
+       #endif
+#endif
+//
+#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
+# define shell_main ash_main
+#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
+# define shell_main hush_main
+#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
+# define shell_main lash_main
+#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
+# define shell_main msh_main
+#endif
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..e17bd80
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,8 @@
+1) Check Config.h and adjust if you need a different functionality than
+   defined by default.
+
+2) Check the Makefile
+
+3) make
+
+4) make install
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..3f792d0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,377 @@
+Original release code (unless otherwise noted)
+Copyright 1995, 1996 Bruce Perens <bruce@pixar.com>
+
+mkswap
+Copyright 1991 Linus Torvalds
+
+tiny-ls(ls)
+Copyright 1996 Brian Candler <B.Candler@pobox.com>
+
+tarcat, loadkmap, various fixes, Debian maintenance
+Copyright 1998 Enrique Zanardi <ezanardi@ull.es>
+
+more(v2), makedevs, dutmp, modularization, auto links file, 
+various fixes, Linux Router Project maintenance
+Copyright 1998 Dave Cinege <dcinege@psychosis.com>     
+
+mini-gzip(gzip), mini-netcat(mnc)
+Copyright 1998 Charles P. Wright <cpwright@villagenet.com>
+
+Tons of new stuff as noted in header files 
+Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+
+
+Please feed suggestions, bug reports, insults, and bribes back to:
+       Erik Andersen 
+       <andersen@codepoet.org>
+       <andersee@debian.org>
+
+
+
+Busybox may be used and distributed under the GNU General Public License.
+
+---------------------------------------------------------------------------
+
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..3319293
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,487 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+PROG      := busybox
+VERSION   := 0.60.5
+BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z")
+export VERSION
+
+# With a modern GNU make(1) (highly recommended, that's what all the
+# developers use), all of the following configuration values can be
+# overridden at the command line.  For example:
+#   make CROSS=powerpc-linux- BB_SRC_DIR=$HOME/busybox PREFIX=/mnt/app
+
+# If you want to add some simple compiler switches (like -march=i686),
+# especially from the command line, use this instead of CFLAGS directly.
+# For optimization overrides, it's better still to set OPTIMIZATION.
+CFLAGS_EXTRA =
+# If you want a static binary, turn this on.
+DOSTATIC = false
+
+# Set the following to `true' to make a debuggable build.
+# Leave this set to `false' for production use.
+DODEBUG = false
+
+# If you enable this option, busybox will use the system's password
+# and group functions.  And if you are using the GNU C library
+# (glibc), you will then need to install the /etc/nsswitch.conf
+# configuration file and the required /lib/libnss_* libraries in
+# order for the password and group functions to work.  This generally
+# makes your embedded system quite a bit larger.
+# Disabling this option will cause busybox to directly access the
+# system's /etc/password, /etc/group files (and your system will be
+# smaller, and I will get fewer emails asking about how glibc NSS
+# works).  When this option is disabled, you will not be able to use
+# PAM to access remote LDAP password servers and whatnot.  And if you
+# want hostname resolution to work with glibc, you still need the
+# /lib/libnss_* libraries.
+# If you disable this option, it will add about 1.5k to busybox.
+USE_SYSTEM_PWD_GRP = true
+
+# This enables compiling with dmalloc ( http://dmalloc.com/ )
+# which is an excellent public domain mem leak and malloc problem
+# detector.  To enable dmalloc, before running busybox you will
+# want to first set up your environment.
+# eg: `export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile`
+# The debug= value is generated using the following command
+# dmalloc -p log-stats -p log-non-free -p log-bad-space -p log-elapsed-time \
+#      -p check-fence -p check-heap -p check-lists -p check-blank \
+#      -p check-funcs -p realloc-copy -p allow-free-null
+# Do not enable this for production builds...
+DODMALLOC = false
+
+# Electric-fence is another very useful malloc debugging library.
+# Do not enable this for production builds...
+DOEFENCE  = false
+
+# If you want large file summit support, turn this on.
+# This has no effect if you don't have a kernel with lfs
+# support, and a system with libc-2.1.3 or later.
+# Some of the programs that can benefit from lfs support
+# are dd, gzip, mount, tar, and mkfs_minix.
+# LFS allows you to use the above programs for files
+# larger than 2GB!
+DOLFS = false
+
+# If you have a "pristine" source directory, point BB_SRC_DIR to it.
+# Experimental and incomplete; tell the mailing list
+# <busybox@busybox.net> if you do or don't like it so far.
+BB_SRC_DIR =
+
+# If you are running a cross compiler, you may want to set this
+# to something more interesting, like "powerpc-linux-".
+CROSS =
+CC = $(CROSS)gcc
+AR = $(CROSS)ar
+STRIP = $(CROSS)strip
+
+# To compile vs uClibc, just use the compiler wrapper built by uClibc...
+# Everything should compile and work as expected these days...
+#CC=/usr/i386-linux-uclibc/bin/i386-uclibc-gcc
+
+# To compile vs some other alternative libc, you may need to use/adjust
+# the following lines to meet your needs...
+#
+# If you are using Red Hat 6.x with the compatible RPMs (for developing under
+# Red Hat 5.x and glibc 2.0) uncomment the following.  Be sure to read about
+# using the compatible RPMs (compat-*) at http://www.redhat.com !
+#LIBCDIR=/usr/i386-glibc20-linux
+#
+# The following is used for libc5 (if you install altgcc and libc5-altdev
+# on a Debian system).  
+#LIBCDIR=/usr/i486-linuxlibc1
+#
+# For other libraries, you are on your own...
+#LDFLAGS+=-nostdlib
+#LIBRARIES = $(LIBCDIR)/lib/libc.a -lgcc
+#CROSS_CFLAGS+=-nostdinc -I$(LIBCDIR)/include -I$(GCCINCDIR)
+#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
+
+WARNINGS = -Wall -Wshadow
+
+ARFLAGS = -r
+
+
+TARGET_ARCH:=${shell $(CC) -dumpmachine | sed -e s'/-.*//' \
+               -e 's/i.86/i386/' \
+               -e 's/sparc.*/sparc/' \
+               -e 's/arm.*/arm/g' \
+               -e 's/m68k.*/m68k/' \
+               -e 's/ppc/powerpc/g' \
+               -e 's/v850.*/v850/g' \
+               -e 's/sh[234]/sh/' \
+               -e 's/mips.*/mips/' \
+               }
+
+#--------------------------------------------------------
+# Arch specific compiler optimization stuff should go here.
+# Unless you want to override the defaults, do not set anything
+# for OPTIMIZATION...
+
+# use '-Os' optimization if available, else use -O2
+OPTIMIZATION := ${shell if $(CC) -Os -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \
+       then echo "-Os"; else echo "-O2" ; fi}
+
+# Some nice architecture specific optimizations
+ifeq ($(strip $(TARGET_ARCH)),arm)
+       OPTIMIZATION+=-fstrict-aliasing
+endif
+ifeq ($(strip $(TARGET_ARCH)),i386)
+       OPTIMIZATION+=-march=i386
+       OPTIMIZATION+=${shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc \
+               /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi}
+       OPTIMIZATION+=${shell if $(CC) -falign-functions=1 -falign-jumps=0 -falign-loops=0 \
+               -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo \
+               "-falign-functions=1 -falign-jumps=0 -falign-loops=0"; else \
+               if $(CC) -malign-functions=0 -malign-jumps=0 -S -o /dev/null -xc \
+               /dev/null >/dev/null 2>&1; then echo "-malign-functions=0 -malign-jumps=0"; fi; fi}
+endif
+OPTIMIZATIONS:=$(OPTIMIZATION) -fomit-frame-pointer
+
+
+#--------------------------------------------------------
+# If you're going to do a lot of builds with a non-vanilla configuration,
+# it makes sense to adjust parameters above, so you can type "make"
+# by itself, instead of following it by the same half-dozen overrides
+# every time.  The stuff below, on the other hand, is probably less
+# prone to casual user adjustment.
+# 
+ifeq ($(strip $(DOLFS)),true)
+    # For large file support
+    CFLAGS+=-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+ifeq ($(strip $(DODMALLOC)),true)
+    # For testing mem leaks with dmalloc
+    CFLAGS+=-DDMALLOC
+    LIBRARIES = -ldmalloc
+    # Force debug=true, since this is useless when not debugging...
+    DODEBUG = true
+else
+    ifeq ($(strip $(DOEFENCE)),true)
+       LIBRARIES = -lefence
+       # Force debug=true, since this is useless when not debugging...
+       DODEBUG = true
+    endif
+endif
+ifeq ($(strip $(DODEBUG)),true)
+    CFLAGS  += $(WARNINGS) -g -D_GNU_SOURCE
+    LDFLAGS += -Wl,-warn-common
+    STRIPCMD    = /bin/true -Since_we_are_debugging
+else
+    CFLAGS  += $(WARNINGS) $(OPTIMIZATIONS) -D_GNU_SOURCE
+    LDFLAGS += -s -Wl,-warn-common
+    STRIPCMD    = $(STRIP) -s --remove-section=.note --remove-section=.comment
+endif
+ifeq ($(strip $(DOSTATIC)),true)
+    LDFLAGS += --static
+    #
+    #use '-ffunction-sections -fdata-sections' and '--gc-sections' (if they 
+    # work) to try and strip out any unused junk.  Doesn't do much for me, 
+    # but you may want to give it a shot...
+    #
+    #ifeq ($(shell $(CC) -ffunction-sections -fdata-sections -S \
+    #  -o /dev/null -xc /dev/null 2>/dev/null && $(LD) \
+    #                  --gc-sections -v >/dev/null && echo 1),1)
+    #  CFLAGS += -ffunction-sections -fdata-sections
+    #  LDFLAGS += --gc-sections
+    #endif
+endif
+
+ifeq ($(strip $(PREFIX)),)
+    PREFIX = `pwd`/_install
+endif
+
+# Additional complications due to support for pristine source dir.
+# Include files in the build directory should take precedence over
+# the copy in BB_SRC_DIR, both during the compilation phase and the
+# shell script that finds the list of object files.
+# Work in progress by <ldoolitt@recycle.lbl.gov>.
+#
+ifneq ($(strip $(BB_SRC_DIR)),)
+    VPATH = $(BB_SRC_DIR)
+endif
+#ifneq ($(strip $(VPATH)),)
+#    CFLAGS += -I- -I. $(patsubst %,-I%,$(subst :, ,$(VPATH)))
+#endif
+
+# We need to set APPLET_SOURCES to something like
+#   $(shell busybox.sh Config.h)
+# but in a manner that works with VPATH and BB_SRC_DIR.
+# Possible ways to approach this:
+#
+#   1. Explicitly search through .:$(VPATH) for busybox.sh and config.h,
+#      then $(shell $(BUSYBOX_SH) $(CONFIG_H) $(BB_SRC_DIR))
+#
+#   2. Explicity search through .:$(VPATH) for slist.mk,
+#      then $(shell $(MAKE) -f $(SLIST_MK) VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR))
+#
+#   3. Create slist.mk in this directory, with commands embedded in
+#      a $(shell ...) command, and $(MAKE) it immediately.
+#
+#   4. Use a real rule within this makefile to create a file that sets 
+#      APPLET_SOURCE_LIST, then include that file.  Has complications
+#      with the first trip through the makefile (before processing the
+#      include) trying to do too much, and a spurious warning the first
+#      time make is run.
+#
+# This is option 3:
+#
+#APPLET_SOURCES = $(shell \
+#   echo -e 'all: busybox.sh Config.h\n\t@ $$(SHELL) $$^ $$(BB_SRC_DIR)' >slist.mk; \
+#   make -f slist.mk VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR) \
+#)
+# And option 4:
+-include applet_source_list
+
+OBJECTS   = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o
+CFLAGS    += $(CROSS_CFLAGS)
+CFLAGS    += -DBB_VER='"$(VERSION)"'
+CFLAGS    += -DBB_BT='"$(BUILDTIME)"'
+ifdef BB_INIT_SCRIPT
+    CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"'
+endif
+
+ifneq ($(strip $(USE_SYSTEM_PWD_GRP)),true)
+    PWD_GRP    = pwd_grp
+    PWD_GRP_DIR = $(BB_SRC_DIR:=/)$(PWD_GRP)
+    PWD_LIB     = libpwd.a
+    PWD_CSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c \
+           fgetpwent.c __getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c \
+           initgroups.c setgroups.c
+    PWD_OBJS=$(patsubst %.c,$(PWD_GRP)/%.o, $(PWD_CSRC))
+ifneq ($(strip $(BB_SRC_DIR)),)
+    PWD_CFLAGS = -I- -I.
+endif
+    PWD_CFLAGS += -I$(PWD_GRP_DIR)
+else
+    CFLAGS    += -DUSE_SYSTEM_PWD_GRP
+endif
+    
+LIBBB    = libbb
+LIBBB_LIB = libbb.a
+LIBBB_CSRC= ask_confirmation.c chomp.c concat_path_file.c copy_file.c \
+copy_file_chunk.c libc5.c device_open.c error_msg.c inode_hash.c \
+error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \
+find_root_device.c full_read.c full_write.c get_console.c \
+get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \
+isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \
+mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \
+my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \
+print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \
+safe_read.c safe_write.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \
+trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
+xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
+copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
+dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \
+simplify_path.c
+LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
+ifeq ($(strip $(BB_SRC_DIR)),)
+    LIBBB_CFLAGS += -I$(LIBBB)
+else
+    LIBBB_CFLAGS = -I- -I. -I./$(LIBBB) -I$(BB_SRC_DIR)/$(LIBBB) -I$(BB_SRC_DIR)
+endif
+
+LIBBB_MSRC=libbb/messages.c
+LIBBB_MESSAGES= full_version name_too_long omitting_directory not_a_directory \
+memory_exhausted invalid_date invalid_option io_error dash_dash_help \
+write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket
+LIBBB_MOBJ=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_MESSAGES))
+
+LIBBB_ARCSRC=libbb/unarchive.c
+LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \
+get_header_ar get_header_cpio get_header_tar deb_extract
+LIBBB_AROBJS=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_ARCOBJ))
+
+
+# Put user-supplied flags at the end, where they
+# have a chance of winning.
+CFLAGS += $(CFLAGS_EXTRA)
+
+.EXPORT_ALL_VARIABLES:
+
+all: applet_source_list busybox busybox.links doc
+
+applet_source_list: busybox.sh Config.h
+       (echo -n "APPLET_SOURCES := "; CC="$(CC)" BB_SRC_DIR="$(BB_SRC_DIR)" $(SHELL) $^) > $@
+
+doc: olddoc
+
+# Old Docs...
+olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html
+
+docs/busybox.pod : docs/busybox_header.pod usage.h docs/busybox_footer.pod
+       - ( cat docs/busybox_header.pod; \
+           docs/autodocifier.pl usage.h; \
+           cat docs/busybox_footer.pod ) > docs/busybox.pod
+
+docs/BusyBox.txt: docs/busybox.pod
+       @echo
+       @echo BusyBox Documentation
+       @echo
+       -mkdir -p docs
+       -pod2text $< > $@
+
+docs/BusyBox.1: docs/busybox.pod
+       - mkdir -p docs
+       - pod2man --center=BusyBox --release="version $(VERSION)" \
+               $< > $@
+
+docs/BusyBox.html: docs/busybox.pod
+       -@ mkdir -p docs
+       -  pod2html --noindex $< > docs/BusyBox.html
+       -@ rm -f pod2htm*
+
+
+# New docs based on DOCBOOK SGML
+newdoc: docs/busybox.txt docs/busybox.pdf docs/busybox/busyboxdocumentation.html
+
+docs/busybox.txt: docs/busybox.sgml
+       @echo
+       @echo BusyBox Documentation
+       @echo
+       - mkdir -p docs
+       (cd docs; sgmltools -b txt busybox.sgml)
+
+docs/busybox.dvi: docs/busybox.sgml
+       - mkdir -p docs
+       (cd docs; sgmltools -b dvi busybox.sgml)
+
+docs/busybox.ps: docs/busybox.sgml
+       - mkdir -p docs
+       (cd docs; sgmltools -b ps busybox.sgml)
+
+docs/busybox.pdf: docs/busybox.ps
+       - mkdir -p docs
+       (cd docs; ps2pdf busybox.ps)
+
+docs/busybox/busyboxdocumentation.html: docs/busybox.sgml
+       - mkdir -p docs
+       (cd docs; sgmltools -b html ../busybox.sgml)
+
+
+busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) 
+       $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES)
+       $(STRIPCMD) $(PROG)
+
+# Without VPATH, rule expands to "/bin/sh busybox.mkll Config.h applets.h"
+# but with VPATH, some or all of those file names are resolved to the
+# directories in which they live.
+busybox.links: busybox.mkll Config.h applets.h
+       - $(SHELL) $^ >$@
+
+nfsmount.o cmdedit.o: %.o: %.h
+ash.o hush.o lash.o msh.o: cmdedit.h
+$(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile
+ifeq ($(strip $(BB_SRC_DIR)),)
+       $(CC) $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
+else
+       $(CC) $(CFLAGS) -I- -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
+endif
+
+$(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile
+ifneq ($(strip $(BB_SRC_DIR)),)
+       -mkdir -p $(PWD_GRP)
+endif
+       $(CC) $(CFLAGS) $(PWD_CFLAGS) -c $< -o $*.o
+
+$(LIBBB_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile libbb/libbb.h
+ifneq ($(strip $(BB_SRC_DIR)),)
+       -mkdir -p $(LIBBB)
+endif
+       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o
+
+$(LIBBB_MOBJ): $(LIBBB_MSRC)
+ifneq ($(strip $(BB_SRC_DIR)),)
+       -mkdir -p $(LIBBB)
+endif
+       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o
+
+$(LIBBB_AROBJS): $(LIBBB_ARCSRC)
+ifneq ($(strip $(BB_SRC_DIR)),)
+       -mkdir -p $(LIBBB)
+endif
+       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o
+
+libpwd.a: $(PWD_OBJS)
+       $(AR) $(ARFLAGS) $@ $^
+
+libbb.a:  $(LIBBB_MOBJ) $(LIBBB_AROBJS) $(LIBBB_OBJS)
+       $(AR) $(ARFLAGS) $@ $^
+
+usage.o: usage.h
+
+libbb/loop.o: libbb/loop.h
+
+libbb/loop.h: mk_loop_h.sh
+       @ $(SHELL) $< > $@
+
+test tests:
+       # old way of doing it
+       #cd tests && $(MAKE) all
+       # new way of doing it
+       cd tests && ./tester.sh
+
+clean:
+       - cd tests && $(MAKE) clean
+       - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html docs/BusyBox.html
+       - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \
+           docs/busybox.pdf docs/busybox.html docs/busybox.pod
+       - rm -f multibuild.log Config.h.orig *.gdb *.elf
+       - rm -rf docs/busybox _install libpwd.a libbb.a pod2htm*
+       - rm -f busybox busybox.links libbb/loop.h *~ slist.mk core applet_source_list
+       - find . -name \*.o -exec rm -f {} \;
+
+distclean: clean
+       - cd tests && $(MAKE) distclean
+       - rm -f busybox applet_source_list
+
+install: install.sh busybox busybox.links
+       $(SHELL) $< $(PREFIX)
+
+uninstall: busybox busybox.links
+       for i in `cat busybox.links` ; do rm -f $$PREFIX$$i; done
+
+install-hardlinks: install.sh busybox busybox.links
+       $(SHELL) $< $(PREFIX) --hardlinks
+
+debug_pristine:
+       @ echo VPATH=\"$(VPATH)\"
+       @ echo OBJECTS=\"$(OBJECTS)\"
+
+dist release: distclean doc
+       cd ..;                                  \
+       rm -rf busybox-$(VERSION);              \
+       cp -a busybox busybox-$(VERSION);       \
+                                               \
+       find busybox-$(VERSION)/ -type d        \
+                                -name CVS      \
+                                -print         \
+               -exec rm -rf {} \; ;            \
+                                               \
+       find busybox-$(VERSION)/ -type f        \
+                                -name .\#*     \
+                                -print         \
+               -exec rm -f {} \;  ;            \
+                                               \
+       tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/;
+
+.PHONY: tags
+tags:
+       ctags -R .
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7e978b6
--- /dev/null
+++ b/README
@@ -0,0 +1,148 @@
+Please see the LICENSE file for copyright information.
+    
+BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides minimalist replacements for most of the utilities
+you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
+tar, etc. BusyBox provides a fairly complete POSIX environment for any small or
+embedded system. The utilities in BusyBox generally have fewer options than
+their full featured GNU cousins; however, the options that are included provide
+the expected functionality and behave very much like their GNU counterparts.
+
+BusyBox has been written with size-optimization and limited resources in mind.
+It is also extremely modular so you can easily include or exclude commands (or
+features) at compile time. This makes it easy to customize your embedded
+systems. To create a working system, just add /dev, /etc, and a kernel.
+
+BusyBox was originally written to support the Debian Rescue/Install disks, but
+it also makes an excellent environment for any small or embedded system.
+
+As of version 0.20 there is now a version number. : ) Also as of version 0.20,
+BusyBox is now modularized to easily allow you to build only the components you
+need, thereby reducing binary size. To turn off unwanted BusyBox components,
+simply edit the file "Config.h" and comment out the components you do not need
+using C++ style (//) comments.
+
+After the build is complete, a busybox.links file is generated.  This is
+used by 'make install' to create symlinks to the busybox binary for all
+compiled in functions.  By default, 'make install' will place the symlink
+forest into `pwd`/_install unless you have defined the PREFIX environment
+variable (i.e., 'make PREFIX=/tmp/foo install')
+
+----------------
+    
+Supported architectures:
+
+   Busybox in general will build on any architecture supported by gcc.  It has
+   a few specialized features added for __sparc__ and __alpha__.  insmod
+   functionality is currently limited to x86, ARM, SH3/4, powerpc, m68k, 
+   and MIPS.
+
+Supported libcs:
+
+   glibc-2.0.x, glibc-2.1.x, glibc-2.2.x, Linux-libc5, uClibc.  People
+   are looking at newlib and diet-libc, but consider them unsupported,
+   untested, or worse.
+
+Supported kernels:
+
+   Full functionality requires Linux 2.0.x, 2.2.x, or 2.4.x.  A large fraction
+   of the code should run on just about anything.
+
+----------------
+
+Shells:
+
+lash is the very smallest shell (adds just 10k) and it is quite usable as 
+a command prompt, but it is not suitable for any but the most trivial
+scripting (such as an initrd that calls insmod a few times) since it does
+not understand Bourne shell grammer.  It does handle pipes, redirects, and
+job control though.  Adding in command editing makes it a very nice
+lightweight command prompt.
+
+hush is also quite small (just 18k) and it has very complete Bourne shell
+grammer.  It handles if/then/else/fi just fine, but doesn't handle loops
+like for/do/done or case/esac and such.  It also currently has a problem
+with job control.  Using hush is not yet recommended.
+
+msh: The minix shell (adds just 30k) is quite complete and handles things
+like for/do/done, case/esac and all the things you expect a Bourne shell to
+do.  It is not always pedantically correct about Bourne shell grammer (try
+running the shell testscript "tests/sh.testcases" on it and compare vs bash)
+but for most things it works quite well.  It also uses only vfork, so it can
+be used on uClinux systems.  This was only recently added, so there is still
+room to shrink it further...
+
+ash: This adds about 60k in the default configuration and is the most
+complete and most pedantically correct shell included with busybox.  This
+shell was also recently added, and several people (mainly Vladimir and Erik)
+have been working on it.  There are a number of configurable things at the
+top of ash.c as well, so check those out if you want to tweak things.
+
+----------------
+
+Getting help:
+
+When you find you need help, you can check out the BusyBox mailing list
+archives at http://busybox.net/lists/busybox/ or even join
+the mailing list if you are interested.
+
+----------------
+
+Bugs:
+
+If you find bugs, please submit a bug report.  Full instructions on how to
+report a bug are found at http://bugs.busybox.net/Reporting.html.
+
+For the impatient: To submit a bug, simply send an email describing the problem
+to submit@bugs.busybox.net.  Bug reports should look something like this:
+
+    To: submit@bugs.busybox.net
+    From: diligent@testing.linux.org
+    Subject: /bin/true doesn't work
+
+    Package: busybox
+    Version: 0.51
+
+    When I invoke '/bin/true' it doesn't work.  I expected it to return 
+    a "0" but it returned a "1" instead.  Here is the transcript:
+       $ /bin/true ; echo $?
+       1
+    With GNU /bin/true, I get the following output:
+       $ /bin/true ; echo $?
+       0
+    I am using Debian 2.2r2, kernel version 2.2.18, and the latest
+    uClibc from CVS.  Thanks for the wonderful program!
+       -Diligent
+
+Note the careful description and use of examples showing not only what BusyBox
+does, but also a counter example showing what an equivalent GNU app does.  Bug
+reports lacking such detail may take a _long_ time to be fixed...  Thanks for
+understanding.
+
+----------------
+
+FTP:
+
+Source for the latest released version can always be downloaded from 
+    http://busybox.net/downloads/
+
+----------------
+
+CVS:
+
+BusyBox now has its own publicly browsable CVS tree at:
+    http://busybox.net/cgi-bin/cvsweb/busybox/
+
+Anonymous CVS access is available.  For instructions, check out:
+    http://busybox.net/cvs_anon.html
+
+For those that are actively contributing there is even CVS write access:
+    http://busybox.net/cvs_write.html
+
+----------------
+
+Please feed suggestions, bug reports, insults, and bribes back to:
+       Erik Andersen 
+       <andersen@codepoet.org>
+       <andersee@debian.org>
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..1e63885
--- /dev/null
+++ b/TODO
@@ -0,0 +1,52 @@
+TODO list for busybox in no particular order. Just because something
+is listed here doesn't mean that it is going to be added to busybox,
+or that doing so is even a good idea. It just means that I _might_ get
+around to it some time. If you have any good ideas, please let me know.
+
+* login/sulogin/passwd/getty/etc are part of tinylogin, and so are not
+    needed or wanted in busybox (or else I'd have to link to libcrypt).
+
+* We _were_ going to split networking apps into a new package called 
+    netkit-tiny.  Per discussions on the mailing list, this isn't going
+    to happen.  False alarm.  Sorry about the confusion.  
+
+
+ -Erik
+
+-----------
+
+Possible apps to include some time:
+
+* hwclock
+* group/commonize strings, remove dups (for i18n, l10n)
+
+-----------
+
+With sysvinit, reboot, poweroff and halt all used a named pipe, 
+/dev/initctl, to communicate with the init process.  Busybox
+currently uses signals to communicate with init.  This makes
+busybox incompatible with sysvinit.  We should probably use
+a named pipe as well so we can be compatible.
+
+-----------------------
+
+Run the following:
+
+    rm -f busybox && make LDFLAGS+=-nostdlib 2>&1 | \
+       sed -ne 's/.*undefined reference to `\(.*\)..*/\1/gp' | sort | uniq
+
+reveals the list of all external (i.e., libc) things that BusyBox depends on.
+It would be a very nice thing to reduce this list to an absolute minimum, to
+reduce the footprint of busybox, especially when staticly linking with
+libraries such as uClibc.
+
+-----------------------
+
+Compile with debugging on, run 'nm --size-sort ./busybox'
+and then start with the biggest things and make them smaller...
+
+-----------------------
+
+xargs could use a -l option
+
+------------------------------------------------------------------
diff --git a/adjtimex.c b/adjtimex.c
new file mode 100644 (file)
index 0000000..e3c160d
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables.
+ *
+ * Originally written: October 1997
+ * Last hack: March 2001
+ * Copyright 1997, 2000, 2001 Larry Doolittle <LRDoolittle@lbl.gov>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License (Version 2,
+ *  June 1991) as published by the Free Software Foundation.  At the
+ *  time of writing, that license was published by the FSF with the URL
+ *  http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
+ *  reference.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ * This adjtimex(1) is very similar in intent to adjtimex(8) by Steven
+ * Dick <ssd@nevets.oau.org> and Jim Van Zandt <jrv@vanzandt.mv.com>
+ * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*).
+ * That version predates this one, and is _much_ bigger and more
+ * featureful.  My independently written version was very similar to
+ * Steven's from the start, because they both follow the kernel timex
+ * structure.  I further tweaked this version to be equivalent to Steven's
+ * where possible, but I don't like getopt_long, so the actual usage
+ * syntax is incompatible.
+ *
+ * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes)
+ * don't actually give a prototype for adjtimex(2), so building
+ * this code (with -Wall) gives a warning.  Later versions of
+ * glibc fix this issue.
+ *
+ * This program is too simple for a Makefile, just build with:
+ *  gcc -Wall -O adjtimex.c -o adjtimex
+ *
+ * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
+ * It will autosense if it is built in a busybox environment, based
+ * on the BB_VER preprocessor macro.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if __GNU_LIBRARY__ < 5
+#include <sys/timex.h>
+extern int adjtimex(struct timex *buf);
+#else
+#include <sys/timex.h>
+#endif
+
+#ifdef BB_VER
+#include "busybox.h"
+#endif
+
+static struct {int bit; char *name;} statlist[] = {
+       { STA_PLL,       "PLL"       },
+       { STA_PPSFREQ,   "PPSFREQ"   },
+       { STA_PPSTIME,   "PPSTIME"   },
+       { STA_FLL,       "FFL"       },
+       { STA_INS,       "INS"       },
+       { STA_DEL,       "DEL"       },
+       { STA_UNSYNC,    "UNSYNC"    },
+       { STA_FREQHOLD,  "FREQHOLD"  },
+       { STA_PPSSIGNAL, "PPSSIGNAL" },
+       { STA_PPSJITTER, "PPSJITTER" },
+       { STA_PPSWANDER, "PPSWANDER" },
+       { STA_PPSERROR,  "PPSERROR"  },
+       { STA_CLOCKERR,  "CLOCKERR"  },
+       { 0, NULL } };
+
+static char *ret_code_descript[] = {
+       "clock synchronized",
+       "insert leap second",
+       "delete leap second",
+       "leap second in progress",
+       "leap second has occurred",
+       "clock not synchronized" };
+
+#ifdef BB_VER
+#define main adjtimex_main
+#else
+void usage(char *prog)
+{
+       fprintf(stderr, 
+               "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n",
+               prog);
+}
+#define show_usage() usage(argv[0])
+#endif
+
+int main(int argc, char ** argv)
+{
+       struct timex txc;
+       int quiet=0;
+       int c, i, ret, sep;
+       char *descript;
+       txc.modes=0;
+       for (;;) {
+               c = getopt( argc, argv, "qo:f:p:t:");
+               if (c == EOF) break;
+               switch (c) {
+                       case 'q':
+                               quiet=1;
+                               break;
+                       case 'o':
+                               txc.offset = atoi(optarg);
+                               txc.modes |= ADJ_OFFSET_SINGLESHOT;
+                               break;
+                       case 'f':
+                               txc.freq = atoi(optarg);
+                               txc.modes |= ADJ_FREQUENCY;
+                               break;
+                       case 'p':
+                               txc.constant = atoi(optarg);
+                               txc.modes |= ADJ_TIMECONST;
+                               break;
+                       case 't':
+                               txc.tick = atoi(optarg);
+                               txc.modes |= ADJ_TICK;
+                               break;
+                       default:
+                               show_usage();
+                               exit(1);
+               }
+       }
+       if (argc != optind) { /* no valid non-option parameters */
+               show_usage();
+               exit(1);
+       }
+
+       ret = adjtimex(&txc);
+
+       if (ret < 0) perror("adjtimex");
+       
+       if (!quiet && ret>=0) {
+               printf(
+                       "    mode:         %d\n"
+                       "-o  offset:       %ld\n"
+                       "-f  frequency:    %ld\n"
+                       "    maxerror:     %ld\n"
+                       "    esterror:     %ld\n"
+                       "    status:       %d ( ",
+               txc.modes, txc.offset, txc.freq, txc.maxerror,
+               txc.esterror, txc.status);
+
+               /* representative output of next code fragment:
+                  "PLL | PPSTIME" */
+               sep=0;
+               for (i=0; statlist[i].name; i++) {
+                       if (txc.status & statlist[i].bit) {
+                               if (sep) fputs(" | ",stdout);
+                               fputs(statlist[i].name,stdout);
+                               sep=1;
+                       }
+               }
+
+               descript = "error";
+               if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret];
+               printf(" )\n"
+                       "-p  timeconstant: %ld\n"
+                       "    precision:    %ld\n"
+                       "    tolerance:    %ld\n"
+                       "-t  tick:         %ld\n"
+                       "    time.tv_sec:  %ld\n"
+                       "    time.tv_usec: %ld\n"
+                       "    return value: %d (%s)\n",
+               txc.constant,
+               txc.precision, txc.tolerance, txc.tick,
+               (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
+       }
+       return (ret<0);
+}
diff --git a/applets.c b/applets.c
new file mode 100644 (file)
index 0000000..f3e56a9
--- /dev/null
+++ b/applets.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) tons of folks.  Tracking down who wrote what
+ * isn't something I'm going to worry about...  If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "busybox.h"
+
+#undef APPLET
+#undef APPLET_NOUSAGE
+#undef PROTOTYPES
+#include "applets.h"
+
+struct BB_applet *applet_using;
+
+/* The -1 arises because of the {0,NULL,0,-1} entry above. */
+const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
+
+extern void show_usage(void)
+{
+       const char *format_string;
+       const char *usage_string = usage_messages;
+       int i;
+
+       for (i = applet_using - applets; i > 0; ) {
+               if (!*usage_string++) {
+                       --i;
+               }
+       }
+       format_string = "%s\n\nUsage: %s %s\n\n";
+       if(*usage_string == 0)
+               format_string = "%s\n\nNo help available.\n\n";
+       fprintf(stderr, format_string,
+                       full_version, applet_using->name, usage_string);
+       exit(EXIT_FAILURE);
+}
+
+static int applet_name_compare(const void *x, const void *y)
+{
+       const char *name = x;
+       const struct BB_applet *applet = y;
+
+       return strcmp(name, applet->name);
+}
+
+extern const size_t NUM_APPLETS;
+
+struct BB_applet *find_applet_by_name(const char *name)
+{
+       return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
+                       applet_name_compare);
+}
+
+void run_applet_by_name(const char *name, int argc, char **argv)
+{
+       static int recurse_level = 0;
+       extern int been_there_done_that; /* From busybox.c */
+
+       recurse_level++;
+       /* Do a binary search to find the applet entry given the name. */
+       if ((applet_using = find_applet_by_name(name)) != NULL) {
+               applet_name = applet_using->name;
+               if (argv[1] && strcmp(argv[1], "--help") == 0) {
+                       if (strcmp(applet_using->name, "busybox")==0) {
+                               if(argv[2])
+                                 applet_using = find_applet_by_name(argv[2]);
+                                else
+                                 applet_using = NULL;
+                       }
+                       if(applet_using)
+                               show_usage();
+                       been_there_done_that=1;
+                       busybox_main(0, NULL);
+               }
+               exit((*(applet_using->main)) (argc, argv));
+       }
+       /* Just in case they have renamed busybox - Check argv[1] */
+       if (recurse_level == 1) {
+               run_applet_by_name("busybox", argc, argv);
+       }
+       recurse_level--;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/applets.h b/applets.h
new file mode 100644 (file)
index 0000000..403c06e
--- /dev/null
+++ b/applets.h
@@ -0,0 +1,487 @@
+/*
+ * applets.h - a listing of all busybox applets.
+ *
+ * If you write a new applet, you need to add an entry to this list to make
+ * busybox aware of it.
+ *
+ * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary
+ * search lookup contributed by Gaute B Strokkenes stops working. If you value
+ * your kneecaps, you'll be sure to *make sure* that any changes made to this
+ * file result in the listing remaining in ascii order. You have been warned.
+ */
+
+#undef APPLET
+#undef APPLET_ODDNAME
+#undef APPLET_NOUSAGE
+
+
+#if defined(PROTOTYPES)
+  #define APPLET(a,b,c) extern int b(int argc, char **argv);
+  #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv);
+  #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv);
+  extern const char usage_messages[];
+#elif defined(MAKE_USAGE)
+  #ifdef BB_FEATURE_VERBOSE_USAGE
+    #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0"
+    #define APPLET_NOUSAGE(a,b,c) "\0"
+    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0"
+  #else
+    #define APPLET(a,b,c) a##_trivial_usage "\0"
+    #define APPLET_NOUSAGE(a,b,c) "\0"
+    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0"
+  #endif
+#elif defined(MAKE_LINKS)
+#  define APPLET(a,b,c) LINK c a
+#  define APPLET_NOUSAGE(a,b,c) LINK c a
+#  define APPLET_ODDNAME(a,b,c,d) LINK c a
+#else
+  const struct BB_applet applets[] = {
+  #define APPLET(a,b,c) {#a,b,c},
+  #define APPLET_NOUSAGE(a,b,c) {a,b,c},
+  #define APPLET_ODDNAME(a,b,c,d) {a,b,c},
+#endif
+
+
+
+#ifdef BB_TEST
+       APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_ADJTIMEX
+       APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_AR
+       APPLET(ar, ar_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_ASH
+       APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_BASENAME
+       APPLET(basename, basename_main, _BB_DIR_USR_BIN)
+#endif
+       APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN)
+#ifdef BB_CAT
+       APPLET(cat, cat_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CHGRP
+       APPLET(chgrp, chgrp_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CHMOD
+       APPLET(chmod, chmod_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CHOWN
+       APPLET(chown, chown_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CHROOT
+       APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN)
+#endif
+#ifdef BB_CHVT
+       APPLET(chvt, chvt_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_CLEAR
+       APPLET(clear, clear_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_CMP
+       APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_CP
+       APPLET(cp, cp_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CPIO
+       APPLET(cpio, cpio_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_CUT
+       APPLET(cut, cut_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DATE
+       APPLET(date, date_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_DC
+       APPLET(dc, dc_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DD
+       APPLET(dd, dd_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_DEALLOCVT
+       APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DF
+       APPLET(df, df_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_DIRNAME
+       APPLET(dirname, dirname_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DMESG
+       APPLET(dmesg, dmesg_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_DOS2UNIX
+       APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DPKG
+       APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DPKG_DEB
+       APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb)
+#endif
+#ifdef BB_DU
+       APPLET(du, du_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_DUMPKMAP
+       APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_DUTMP
+       APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN)
+#endif
+#ifdef BB_ECHO
+       APPLET(echo, echo_main, _BB_DIR_BIN)
+#endif
+#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP)
+       APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_ENV
+       APPLET(env, env_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_EXPR
+       APPLET(expr, expr_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TRUE_FALSE
+       APPLET(false, false_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_FBSET
+       APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN)
+#endif
+#ifdef BB_FDFLUSH
+       APPLET(fdflush, fdflush_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_FIND
+       APPLET(find, find_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_FREE
+       APPLET(free, free_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_FREERAMDISK
+       APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_FSCK_MINIX
+       APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix)
+#endif
+#ifdef BB_GETOPT
+       APPLET(getopt, getopt_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_GREP
+       APPLET(grep, grep_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_GUNZIP
+       APPLET(gunzip, gunzip_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_GZIP
+       APPLET(gzip, gzip_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_HALT
+       APPLET(halt, halt_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_HEAD
+       APPLET(head, head_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_HOSTID
+       APPLET(hostid, hostid_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_HOSTNAME
+       APPLET(hostname, hostname_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_HUSH
+       APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_ID
+       APPLET(id, id_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_IFCONFIG
+       APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_INIT
+       APPLET(init, init_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_INSMOD
+       APPLET(insmod, insmod_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_KILL
+       APPLET(kill, kill_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_KILLALL
+       APPLET(killall, kill_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_KLOGD
+       APPLET(klogd, klogd_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_LASH
+       APPLET(lash, lash_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_LENGTH
+       APPLET(length, length_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_FEATURE_LINUXRC
+       APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT)
+#endif
+#ifdef BB_LN
+       APPLET(ln, ln_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_LOADACM
+       APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_LOADFONT
+       APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_LOADKMAP
+       APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_LOGGER
+       APPLET(logger, logger_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_LOGNAME
+       APPLET(logname, logname_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_LOGREAD
+       APPLET(logread, logread_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_LOSETUP
+       APPLET(losetup, losetup_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_LS
+       APPLET(ls, ls_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_LSMOD
+       APPLET(lsmod, lsmod_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_MAKEDEVS
+       APPLET(makedevs, makedevs_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_MD5SUM
+       APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_MKDIR
+       APPLET(mkdir, mkdir_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MKFIFO
+       APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_MKFS_MINIX
+       APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix)
+#endif
+#ifdef BB_MKNOD
+       APPLET(mknod, mknod_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MKSWAP
+       APPLET(mkswap, mkswap_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_MKTEMP
+       APPLET(mktemp, mktemp_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MODPROBE
+       APPLET(modprobe, modprobe_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_MORE
+       APPLET(more, more_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MOUNT
+       APPLET(mount, mount_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MSH
+       APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MT
+       APPLET(mt, mt_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_MV
+       APPLET(mv, mv_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_NC
+       APPLET(nc, nc_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_NSLOOKUP
+       APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_PIDOF
+       APPLET(pidof, pidof_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_PING
+       APPLET(ping, ping_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_PIVOT_ROOT
+       APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_POWEROFF
+       APPLET(poweroff, poweroff_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_PRINTF
+       APPLET(printf, printf_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_PS
+       APPLET(ps, ps_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_PWD
+       APPLET(pwd, pwd_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_RDATE
+       APPLET(rdate, rdate_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_READLINK
+       APPLET(readlink, readlink_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_REBOOT
+       APPLET(reboot, reboot_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_RENICE
+       APPLET(renice, renice_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_RESET
+       APPLET(reset, reset_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_RM
+       APPLET(rm, rm_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_RMDIR
+       APPLET(rmdir, rmdir_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_RMMOD
+       APPLET(rmmod, rmmod_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_ROUTE
+       APPLET(route, route_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_RPM2CPIO
+       APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_SED
+       APPLET(sed, sed_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_SETKEYCODES
+       APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN)
+#endif
+#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH)
+       APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN)
+#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH)
+       APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN)
+#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH)
+       APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN)
+#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH)
+       APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_SLEEP
+       APPLET(sleep, sleep_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_SORT
+       APPLET(sort, sort_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_STTY
+       APPLET(stty, stty_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_SWAPONOFF
+       APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_SWAPONOFF
+       APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_SYNC
+       APPLET(sync, sync_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_SYSLOGD
+       APPLET(syslogd, syslogd_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_TAIL
+       APPLET(tail, tail_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TAR
+       APPLET(tar, tar_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_TEE
+       APPLET(tee, tee_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TELNET
+       APPLET(telnet, telnet_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TEST
+       APPLET(test, test_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TFTP
+       APPLET(tftp, tftp_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TIME
+       APPLET(time, time_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TOP
+       APPLET(top, top_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TOUCH
+       APPLET(touch, touch_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_TR
+       APPLET(tr, tr_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TRACEROUTE
+       APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_TRUE_FALSE
+       APPLET(true, true_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_TTY
+       APPLET(tty, tty_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_UMOUNT
+       APPLET(umount, umount_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_UNAME
+       APPLET(uname, uname_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_UNIQ
+       APPLET(uniq, uniq_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_UNIX2DOS
+       APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_UPDATE
+       APPLET(update, update_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_UPTIME
+       APPLET(uptime, uptime_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_USLEEP
+       APPLET(usleep, usleep_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_UUDECODE
+       APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_UUENCODE
+       APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_VI
+       APPLET(vi, vi_main, _BB_DIR_BIN)
+#endif
+#ifdef BB_WATCHDOG
+       APPLET(watchdog, watchdog_main, _BB_DIR_SBIN)
+#endif
+#ifdef BB_WC
+       APPLET(wc, wc_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_WGET
+       APPLET(wget, wget_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_WHICH
+       APPLET(which, which_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_WHOAMI
+       APPLET(whoami, whoami_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_XARGS
+       APPLET(xargs, xargs_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_YES
+       APPLET(yes, yes_main, _BB_DIR_USR_BIN)
+#endif
+#ifdef BB_GUNZIP
+       APPLET(zcat, gunzip_main, _BB_DIR_BIN)
+#endif
+
+#if !defined(PROTOTYPES) && !defined(MAKE_USAGE)
+       { 0,NULL,0 }
+};
+
+#endif
diff --git a/ar.c b/ar.c
new file mode 100644 (file)
index 0000000..7f3396c
--- /dev/null
+++ b/ar.c
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ar implementation for busybox 
+ *
+ * Copyright (C) 2000 by Glenn McGrath
+ * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000
+ *             
+ * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int ar_main(int argc, char **argv)
+{
+       FILE *src_stream = NULL;
+       char **extract_names = NULL;
+       char ar_magic[8];
+       int extract_function =  extract_unconditional;
+       int opt;
+       int num_of_entries = 0;
+       extern off_t archive_offset;
+
+       while ((opt = getopt(argc, argv, "ovtpx")) != -1) {
+               switch (opt) {
+               case 'o':
+                       extract_function |= extract_preserve_date;
+                       break;
+               case 'v':
+                       extract_function |= extract_verbose_list;
+                       break;
+               case 't':
+                       extract_function |= extract_list;
+                       break;
+               case 'p':
+                       extract_function |= extract_to_stdout;
+                       break;
+               case 'x':
+                       extract_function |= extract_all_to_fs;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+       /* check the src filename was specified */
+       if (optind == argc) {
+               show_usage();
+       }
+
+       src_stream = xfopen(argv[optind++], "r");
+
+       /* check ar magic */
+       fread(ar_magic, 1, 8, src_stream);
+       archive_offset = 8;
+       if (strncmp(ar_magic,"!<arch>",7) != 0) {
+               error_msg_and_die("invalid magic");
+       }
+
+       /* Create a list of files to extract */
+       while (optind < argc) {
+               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
+               extract_names[num_of_entries] = xstrdup(argv[optind]);
+               num_of_entries++;
+               extract_names[num_of_entries] = NULL;
+               optind++;
+       }
+
+       unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names);
+       return EXIT_SUCCESS;
+}
diff --git a/ash.c b/ash.c
new file mode 100644 (file)
index 0000000..6db0c88
--- /dev/null
+++ b/ash.c
@@ -0,0 +1,13528 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ash shell port for busybox
+ *
+ * Copyright (c) 1989, 1991, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
+ * was re-ported from NetBSD and debianized.
+ *
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original BSD copyright notice is retained at the end of this file.
+ */
+
+/*
+ * rewrite arith.y to micro stack based cryptic algorithm by
+ * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
+ *
+ * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
+ * used in busybox and size optimizations,
+ * support locale, rewrited arith (see notes to this)
+ *
+ */
+
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ *      define SYSV if you are running under System V.
+ *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
+ *      define DEBUG=2 to compile in and turn on debugging.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+/* This enables alias support in ash.  If you want to support things
+ * like "alias ls='ls -l'" with ash, enable this.  This is only useful
+ * when ash is used as an intractive shell.   This adds about 1.5k */
+#define BB_ASH_ALIAS
+
+/* If you need ash to act as a full Posix shell, with full math
+ * support, enable this.   This adds a bit over 2k an x86 system. */
+#define BB_ASH_MATH_SUPPORT
+
+/* Getopts is used by shell procedures to parse positional parameters.
+ * You probably want to leave this disabled, and use the busybox getopt
+ * applet if you want to do this sort of thing.  There are some scripts
+ * out there that use it, so if you need it, enable it.  Most people will
+ * leave this disabled.  This adds 1k on an x86 system. */
+#undef BB_ASH_GETOPTS
+
+/* This allows you to override shell builtins and use whatever is on
+ * the filesystem.  This is most useful when ash is acting as a
+ * standalone shell.   Adds about 272 bytes. */
+#undef BB_ASH_CMDCMD
+
+/* Check for mail */
+#undef BB_ASH_MAIL
+
+/* Optimize size vs speed as size */
+#define BB_ASH_OPTIMIZE_FOR_SIZE
+
+/* Enable this to compile in extra debugging noise.  When debugging is
+ * on, debugging info will be written to $HOME/trace and a quit signal
+ * will generate a core dump. */
+#undef DEBUG
+
+
+
+#define IFS_BROKEN
+
+#define PROFILE 0
+
+#ifdef DEBUG
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sysexits.h>
+
+#include <fnmatch.h>
+
+
+#include "busybox.h"
+#include "pwd_grp/pwd.h"
+
+#ifdef BB_ASH_JOB_CONTROL
+#define JOBS 1
+#else
+#undef JOBS
+#endif
+
+#if JOBS
+#include <termios.h>
+#endif
+
+#include "cmdedit.h"
+
+#ifdef __GLIBC__
+/* glibc sucks */
+static int *dash_errno;
+#undef errno
+#define errno (*dash_errno)
+#endif
+
+#if defined(__uClinux__)
+#error "Do not even bother, ash will not run on uClinux"
+#endif
+
+#ifdef DEBUG
+#define _DIAGASSERT(assert_expr) assert(assert_expr)
+#else
+#define _DIAGASSERT(assert_expr)
+#endif
+
+
+#ifdef BB_ASH_ALIAS
+/*      $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $       */
+
+#define ALIASINUSE      1
+#define ALIASDEAD       2
+
+struct alias {
+       struct alias *next;
+       char *name;
+       char *val;
+       int flag;
+};
+
+static struct alias *lookupalias(const char *, int);
+static int aliascmd(int, char **);
+static int unaliascmd(int, char **);
+static void rmaliases(void);
+static int unalias(const char *);
+static void printalias(const struct alias *);
+#endif
+
+/*      $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $  */
+
+
+static void    setpwd(const char *, int);
+
+/*      $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $      */
+
+
+/*
+ * Types of operations (passed to the errmsg routine).
+ */
+
+
+static const char not_found_msg[] = "%s: not found";
+
+
+#define E_OPEN  "No such file"          /* opening a file */
+#define E_CREAT "Directory nonexistent" /* creating a file */
+#define E_EXEC  not_found_msg+4         /* executing a program */
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations.  The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exeception.  To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+struct jmploc {
+       jmp_buf loc;
+};
+
+static struct jmploc *handler;
+static int exception;
+static volatile int suppressint;
+static volatile sig_atomic_t intpending;
+
+static int exerrno;            /* Last exec error, error for EXEXEC */
+
+/* exceptions */
+#define EXINT 0         /* SIGINT received */
+#define EXERROR 1       /* a generic error */
+#define EXSHELLPROC 2   /* execute a shell procedure */
+#define EXEXEC 3        /* command execution failed */
+#define EXEXIT 4        /* exit the shell */
+#define EXSIG 5         /* trapped signal in wait(1) */
+
+
+/* do we generate EXSIG events */
+static int exsig;
+/* last pending signal */
+static volatile sig_atomic_t pendingsigs;
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time.  This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable.  (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define INTOFF \
+       ({ \
+               suppressint++; \
+               barrier(); \
+               0; \
+       })
+#define SAVEINT(v) ((v) = suppressint)
+#define RESTOREINT(v) \
+       ({ \
+               barrier(); \
+               if ((suppressint = (v)) == 0 && intpending) onint(); \
+               0; \
+       })
+#define EXSIGON() \
+       ({ \
+               exsig++; \
+               barrier(); \
+               if (pendingsigs) \
+                       exraise(EXSIG); \
+               0; \
+       })
+/* EXSIG is turned off by evalbltin(). */
+
+
+static void exraise(int) __attribute__((__noreturn__));
+static void onint(void) __attribute__((__noreturn__));
+
+static void error(const char *, ...) __attribute__((__noreturn__));
+static void exerror(int, const char *, ...) __attribute__((__noreturn__));
+
+static void sh_warnx(const char *, ...);
+
+#ifdef BB_ASH_OPTIMIZE_FOR_SIZE
+static void
+inton(void) {
+       if (--suppressint == 0 && intpending) {
+               onint();
+       }
+}
+#define INTON inton()
+static void forceinton(void)
+{
+       suppressint = 0;
+       if (intpending)
+               onint();
+}
+#define FORCEINTON forceinton()
+#else
+#define INTON \
+       ({ \
+               barrier(); \
+               if (--suppressint == 0 && intpending) onint(); \
+               0; \
+       })
+#define FORCEINTON \
+       ({ \
+               barrier(); \
+               suppressint = 0; \
+               if (intpending) onint(); \
+               0; \
+       })
+#endif /* BB_ASH_OPTIMIZE_FOR_SIZE */
+
+/*
+ * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
+ * so we use _setjmp instead.
+ */
+
+#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
+#define setjmp(jmploc)  _setjmp(jmploc)
+#define longjmp(jmploc, val)    _longjmp(jmploc, val)
+#endif
+
+/*      $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $     */
+
+struct strlist {
+       struct strlist *next;
+       char *text;
+};
+
+
+struct arglist {
+       struct strlist *list;
+       struct strlist **lastp;
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_FULL        0x1     /* perform word splitting & file globbing */
+#define EXP_TILDE       0x2     /* do normal tilde expansion */
+#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
+#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
+#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
+#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
+#define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
+#define EXP_WORD        0x80    /* expand word in parameter expansion */
+#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
+
+
+union node;
+static void expandarg(union node *, struct arglist *, int);
+#define rmescapes(p) _rmescapes((p), 0)
+static char *_rmescapes(char *, int);
+static int casematch(union node *, char *);
+
+#ifdef BB_ASH_MATH_SUPPORT
+static void expari(int);
+#endif
+
+/*      $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $       */
+
+static char *commandname;              /* currently executing command */
+static struct strlist *cmdenviron;     /* environment for builtin command */
+static int exitstatus;                 /* exit status of last command */
+static int back_exitstatus;            /* exit status of backquoted command */
+
+
+struct backcmd {                /* result of evalbackcmd */
+       int fd;                 /* file descriptor to read from */
+       char *buf;              /* buffer */
+       int nleft;              /* number of chars in buffer */
+       struct job *jp;         /* job structure for command */
+};
+
+/*
+ * This file was generated by the mknodes program.
+ */
+
+#define NCMD 0
+#define NPIPE 1
+#define NREDIR 2
+#define NBACKGND 3
+#define NSUBSHELL 4
+#define NAND 5
+#define NOR 6
+#define NSEMI 7
+#define NIF 8
+#define NWHILE 9
+#define NUNTIL 10
+#define NFOR 11
+#define NCASE 12
+#define NCLIST 13
+#define NDEFUN 14
+#define NARG 15
+#define NTO 16
+#define NCLOBBER 17
+#define NFROM 18
+#define NFROMTO 19
+#define NAPPEND 20
+#define NTOFD 21
+#define NFROMFD 22
+#define NHERE 23
+#define NXHERE 24
+#define NNOT 25
+
+
+
+struct ncmd {
+      int type;
+      union node *assign;
+      union node *args;
+      union node *redirect;
+};
+
+
+struct npipe {
+      int type;
+      int backgnd;
+      struct nodelist *cmdlist;
+};
+
+
+struct nredir {
+      int type;
+      union node *n;
+      union node *redirect;
+};
+
+
+struct nbinary {
+      int type;
+      union node *ch1;
+      union node *ch2;
+};
+
+
+struct nif {
+      int type;
+      union node *test;
+      union node *ifpart;
+      union node *elsepart;
+};
+
+
+struct nfor {
+      int type;
+      union node *args;
+      union node *body;
+      char *var;
+};
+
+
+struct ncase {
+      int type;
+      union node *expr;
+      union node *cases;
+};
+
+
+struct nclist {
+      int type;
+      union node *next;
+      union node *pattern;
+      union node *body;
+};
+
+
+struct narg {
+      int type;
+      union node *next;
+      char *text;
+      struct nodelist *backquote;
+};
+
+
+struct nfile {
+      int type;
+      union node *next;
+      int fd;
+      union node *fname;
+      char *expfname;
+};
+
+
+struct ndup {
+      int type;
+      union node *next;
+      int fd;
+      int dupfd;
+      union node *vname;
+};
+
+
+struct nhere {
+      int type;
+      union node *next;
+      int fd;
+      union node *doc;
+};
+
+
+struct nnot {
+      int type;
+      union node *com;
+};
+
+
+union node {
+      int type;
+      struct ncmd ncmd;
+      struct npipe npipe;
+      struct nredir nredir;
+      struct nbinary nbinary;
+      struct nif nif;
+      struct nfor nfor;
+      struct ncase ncase;
+      struct nclist nclist;
+      struct narg narg;
+      struct nfile nfile;
+      struct ndup ndup;
+      struct nhere nhere;
+      struct nnot nnot;
+};
+
+
+struct nodelist {
+       struct nodelist *next;
+       union node *n;
+};
+
+
+struct funcnode {
+       int count;
+       union node n;
+};
+
+
+static void freefunc(struct funcnode *);
+/*      $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $     */
+
+/* control characters in argument strings */
+#define CTL_FIRST '\201'        /* first 'special' character */
+#define CTLESC '\201'           /* escape next character */
+#define CTLVAR '\202'           /* variable defn */
+#define CTLENDVAR '\203'
+#define CTLBACKQ '\204'
+#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
+/*      CTLBACKQ | CTLQUOTE == '\205' */
+#define CTLARI  '\206'          /* arithmetic expression */
+#define CTLENDARI '\207'
+#define CTLQUOTEMARK '\210'
+#define CTL_LAST '\210'         /* last 'special' character */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE  0x0f            /* type of variable substitution */
+#define VSNUL   0x10            /* colon--treat the empty string as unset */
+#define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
+
+/* values of VSTYPE field */
+#define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
+#define VSMINUS         0x2             /* ${var-text} */
+#define VSPLUS          0x3             /* ${var+text} */
+#define VSQUESTION      0x4             /* ${var?message} */
+#define VSASSIGN        0x5             /* ${var=text} */
+#define VSTRIMRIGHT     0x6             /* ${var%pattern} */
+#define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
+#define VSTRIMLEFT      0x8             /* ${var#pattern} */
+#define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
+#define VSLENGTH        0xa             /* ${#var} */
+
+/* values of checkkwd variable */
+#define CHKALIAS        0x1
+#define CHKKWD          0x2
+#define CHKNL           0x4
+
+#define IBUFSIZ (BUFSIZ + 1)
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file.  It
+ * must be distinct from NULL, so we use the address of a variable that
+ * happens to be handy.
+ */
+static int plinno = 1;                  /* input line number */
+
+/* number of characters left in input buffer */
+static int parsenleft;                  /* copy of parsefile->nleft */
+static int parselleft;                  /* copy of parsefile->lleft */
+
+/* next character in input buffer */
+static char *parsenextc;                /* copy of parsefile->nextc */
+
+struct strpush {
+       struct strpush *prev;   /* preceding string on stack */
+       char *prevstring;
+       int prevnleft;
+#ifdef BB_ASH_ALIAS
+       struct alias *ap;       /* if push was associated with an alias */
+#endif
+       char *string;           /* remember the string since it may change */
+};
+
+struct parsefile {
+       struct parsefile *prev; /* preceding file on stack */
+       int linno;              /* current line */
+       int fd;                 /* file descriptor (or -1 if string) */
+       int nleft;              /* number of chars left in this line */
+       int lleft;              /* number of chars left in this buffer */
+       char *nextc;            /* next char in buffer */
+       char *buf;              /* input buffer */
+       struct strpush *strpush; /* for pushing strings at this level */
+       struct strpush basestrpush; /* so pushing one is fast */
+};
+
+static struct parsefile basepf;         /* top level input file */
+static char basebuf[IBUFSIZ];           /* buffer for top level input file */
+static struct parsefile *parsefile = &basepf;  /* current input file */
+
+
+static int tokpushback;                 /* last token pushed back */
+#define NEOF ((union node *)&tokpushback)
+static int parsebackquote;             /* nonzero if we are inside backquotes */
+static int doprompt;                   /* if set, prompt the user */
+static int needprompt;                 /* true if interactive and at start of line */
+static int lasttoken;                  /* last token read */
+static char *wordtext;                 /* text of last word returned by readtoken */
+static int checkkwd;
+static struct nodelist *backquotelist;
+static union node *redirnode;
+static struct heredoc *heredoc;
+static int quoteflag;                  /* set if (part of) last token was quoted */
+static int startlinno;                 /* line # where last token started */
+
+static union node *parsecmd(int);
+static void fixredir(union node *, const char *, int);
+static const char *const *findkwd(const char *);
+static char *endofname(const char *);
+
+/*      $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $   */
+
+typedef void *pointer;
+
+static char nullstr[1];                /* zero length string */
+static const char spcstr[] = " ";
+static const char snlfmt[] = "%s\n";
+static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
+static const char illnum[] = "Illegal number: %s";
+static const char homestr[] = "HOME";
+
+#ifdef DEBUG
+#define TRACE(param)    trace param
+#define TRACEV(param)   tracev param
+#else
+#define TRACE(param)
+#define TRACEV(param)
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x)       __builtin_expect((x),1)
+
+
+#define TEOF 0
+#define TNL 1
+#define TREDIR 2
+#define TWORD 3
+#define TSEMI 4
+#define TBACKGND 5
+#define TAND 6
+#define TOR 7
+#define TPIPE 8
+#define TLP 9
+#define TRP 10
+#define TENDCASE 11
+#define TENDBQUOTE 12
+#define TNOT 13
+#define TCASE 14
+#define TDO 15
+#define TDONE 16
+#define TELIF 17
+#define TELSE 18
+#define TESAC 19
+#define TFI 20
+#define TFOR 21
+#define TIF 22
+#define TIN 23
+#define TTHEN 24
+#define TUNTIL 25
+#define TWHILE 26
+#define TBEGIN 27
+#define TEND 28
+
+/* first char is indicating which tokens mark the end of a list */
+static const char *const tokname_array[] = {
+       "\1end of file",
+       "\0newline",
+       "\0redirection",
+       "\0word",
+       "\0;",
+       "\0&",
+       "\0&&",
+       "\0||",
+       "\0|",
+       "\0(",
+       "\1)",
+       "\1;;",
+       "\1`",
+#define KWDOFFSET 13
+       /* the following are keywords */
+       "\0!",
+       "\0case",
+       "\1do",
+       "\1done",
+       "\1elif",
+       "\1else",
+       "\1esac",
+       "\1fi",
+       "\0for",
+       "\0if",
+       "\0in",
+       "\1then",
+       "\0until",
+       "\0while",
+       "\0{",
+       "\1}",
+};
+
+static const char *tokname(int tok)
+{
+       static char buf[16];
+
+       if (tok >= TSEMI)
+               buf[0] = '"';
+       sprintf(buf + (tok >= TSEMI), "%s%c",
+                       tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
+       return buf;
+}
+
+/*      $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $    */
+
+/*
+ * Most machines require the value returned from malloc to be aligned
+ * in some way.  The following macro will get this right on many machines.
+ */
+
+#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
+/*
+ * It appears that grabstackstr() will barf with such alignments
+ * because stalloc() will return a string allocated in a new stackblock.
+ */
+#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
+
+/*
+ * This file was generated by the mksyntax program.
+ */
+
+
+/* Syntax classes */
+#define CWORD 0                 /* character is nothing special */
+#define CNL 1                   /* newline character */
+#define CBACK 2                 /* a backslash character */
+#define CSQUOTE 3               /* single quote */
+#define CDQUOTE 4               /* double quote */
+#define CENDQUOTE 5             /* a terminating quote */
+#define CBQUOTE 6               /* backwards single quote */
+#define CVAR 7                  /* a dollar sign */
+#define CENDVAR 8               /* a '}' character */
+#define CLP 9                   /* a left paren in arithmetic */
+#define CRP 10                  /* a right paren in arithmetic */
+#define CENDFILE 11             /* end of file */
+#define CCTL 12                 /* like CWORD, except it must be escaped */
+#define CSPCL 13                /* these terminate a word */
+#define CIGN 14                 /* character should be ignored */
+
+#ifdef BB_ASH_ALIAS
+#define SYNBASE 130
+#define PEOF -130
+#define PEOA -129
+#define PEOA_OR_PEOF PEOA
+#else
+#define SYNBASE 129
+#define PEOF -129
+#define PEOA_OR_PEOF PEOF
+#endif
+
+#define is_digit(c)     ((unsigned)((c) - '0') <= 9)
+#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
+#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
+
+/*
+ * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
+ * (assuming ascii char codes, as the original implementation did)
+ */
+#define is_special(c) \
+    ( (((unsigned int)c) - 33 < 32) \
+                        && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
+
+#define digit_val(c)    ((c) - '0')
+
+/*
+ * This file was generated by the mksyntax program.
+ */
+
+#ifdef BB_ASH_OPTIMIZE_FOR_SIZE
+#define USE_SIT_FUNCTION
+#endif
+
+/* number syntax index */
+#define  BASESYNTAX  0  /* not in quotes */
+#define  DQSYNTAX    1  /* in double quotes */
+#define  SQSYNTAX    2  /* in single quotes */
+#define  ARISYNTAX   3  /* in arithmetic */
+
+#ifdef BB_ASH_MATH_SUPPORT
+static const char S_I_T[][4] = {
+#ifdef BB_ASH_ALIAS
+       {CSPCL, CIGN, CIGN, CIGN},              /* 0, PEOA */
+#endif
+       {CSPCL, CWORD, CWORD, CWORD},           /* 1, ' ' */
+       {CNL, CNL, CNL, CNL},                   /* 2, \n */
+       {CWORD, CCTL, CCTL, CWORD},             /* 3, !*-/:=?[]~ */
+       {CDQUOTE, CENDQUOTE, CWORD, CWORD},     /* 4, '"' */
+       {CVAR, CVAR, CWORD, CVAR},              /* 5, $ */
+       {CSQUOTE, CWORD, CENDQUOTE, CWORD},     /* 6, "'" */
+       {CSPCL, CWORD, CWORD, CLP},             /* 7, ( */
+       {CSPCL, CWORD, CWORD, CRP},             /* 8, ) */
+       {CBACK, CBACK, CCTL, CBACK},            /* 9, \ */
+       {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},     /* 10, ` */
+       {CENDVAR, CENDVAR, CWORD, CENDVAR},     /* 11, } */
+#ifndef USE_SIT_FUNCTION
+       {CENDFILE, CENDFILE, CENDFILE, CENDFILE},       /* 12, PEOF */
+       {CWORD, CWORD, CWORD, CWORD},           /* 13, 0-9A-Za-z */
+       {CCTL, CCTL, CCTL, CCTL}                /* 14, CTLESC ... */
+#endif
+};
+#else
+static const char S_I_T[][3] = {
+#ifdef BB_ASH_ALIAS
+       {CSPCL, CIGN, CIGN},                    /* 0, PEOA */
+#endif
+       {CSPCL, CWORD, CWORD},                  /* 1, ' ' */
+       {CNL, CNL, CNL},                        /* 2, \n */
+       {CWORD, CCTL, CCTL},                    /* 3, !*-/:=?[]~ */
+       {CDQUOTE, CENDQUOTE, CWORD},            /* 4, '"' */
+       {CVAR, CVAR, CWORD},                    /* 5, $ */
+       {CSQUOTE, CWORD, CENDQUOTE},            /* 6, "'" */
+       {CSPCL, CWORD, CWORD},                  /* 7, ( */
+       {CSPCL, CWORD, CWORD},                  /* 8, ) */
+       {CBACK, CBACK, CCTL},                   /* 9, \ */
+       {CBQUOTE, CBQUOTE, CWORD},              /* 10, ` */
+       {CENDVAR, CENDVAR, CWORD},              /* 11, } */
+#ifndef USE_SIT_FUNCTION
+       {CENDFILE, CENDFILE, CENDFILE},         /* 12, PEOF */
+       {CWORD, CWORD, CWORD},                  /* 13, 0-9A-Za-z */
+       {CCTL, CCTL, CCTL}                      /* 14, CTLESC ... */
+#endif
+};
+#endif /* BB_ASH_MATH_SUPPORT */
+
+#ifdef USE_SIT_FUNCTION
+
+#define U_C(c) ((unsigned char)(c))
+
+static int SIT(int c, int syntax)
+{
+       static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
+#ifdef BB_ASH_ALIAS
+       static const char syntax_index_table[] = {
+               1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
+               7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
+               3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
+               11, 3                           /* "}~" */
+       };
+#else
+       static const char syntax_index_table[] = {
+               0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
+               6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
+               2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
+               10, 2                           /* "}~" */
+       };
+#endif
+       const char *s;
+       int indx;
+
+       if (c == PEOF)          /* 2^8+2 */
+               return CENDFILE;
+#ifdef BB_ASH_ALIAS
+       if (c == PEOA)          /* 2^8+1 */
+               indx = 0;
+       else
+#endif
+               if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
+                       return CCTL;
+       else {
+               s = strchr(spec_symbls, c);
+               if (s == 0 || *s == 0)
+                       return CWORD;
+               indx = syntax_index_table[(s - spec_symbls)];
+       }
+       return S_I_T[indx][syntax];
+}
+
+#else                                                   /* USE_SIT_FUNCTION */
+
+#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
+
+#ifdef BB_ASH_ALIAS
+#define CSPCL_CIGN_CIGN_CIGN                           0
+#define CSPCL_CWORD_CWORD_CWORD                        1
+#define CNL_CNL_CNL_CNL                                2
+#define CWORD_CCTL_CCTL_CWORD                          3
+#define CDQUOTE_CENDQUOTE_CWORD_CWORD                  4
+#define CVAR_CVAR_CWORD_CVAR                           5
+#define CSQUOTE_CWORD_CENDQUOTE_CWORD                  6
+#define CSPCL_CWORD_CWORD_CLP                          7
+#define CSPCL_CWORD_CWORD_CRP                          8
+#define CBACK_CBACK_CCTL_CBACK                         9
+#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                 10
+#define CENDVAR_CENDVAR_CWORD_CENDVAR                 11
+#define CENDFILE_CENDFILE_CENDFILE_CENDFILE           12
+#define CWORD_CWORD_CWORD_CWORD                       13
+#define CCTL_CCTL_CCTL_CCTL                           14
+#else
+#define CSPCL_CWORD_CWORD_CWORD                        0
+#define CNL_CNL_CNL_CNL                                1
+#define CWORD_CCTL_CCTL_CWORD                          2
+#define CDQUOTE_CENDQUOTE_CWORD_CWORD                  3
+#define CVAR_CVAR_CWORD_CVAR                           4
+#define CSQUOTE_CWORD_CENDQUOTE_CWORD                  5
+#define CSPCL_CWORD_CWORD_CLP                          6
+#define CSPCL_CWORD_CWORD_CRP                          7
+#define CBACK_CBACK_CCTL_CBACK                         8
+#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                  9
+#define CENDVAR_CENDVAR_CWORD_CENDVAR                 10
+#define CENDFILE_CENDFILE_CENDFILE_CENDFILE           11
+#define CWORD_CWORD_CWORD_CWORD                       12
+#define CCTL_CCTL_CCTL_CCTL                           13
+#endif
+
+static const char syntax_index_table[258] = {
+       /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
+       /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,
+#ifdef BB_ASH_ALIAS
+       /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,
+#endif
+       /*   2  -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
+       /*   3  -127 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
+       /*   4  -126 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
+       /*   5  -125 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
+       /*   6  -124 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
+       /*   7  -123 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
+       /*   8  -122 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
+       /*   9  -121 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
+       /*  10  -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
+       /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,
+       /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,
+       /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,
+       /*  14  -116      */ CWORD_CWORD_CWORD_CWORD,
+       /*  15  -115      */ CWORD_CWORD_CWORD_CWORD,
+       /*  16  -114      */ CWORD_CWORD_CWORD_CWORD,
+       /*  17  -113      */ CWORD_CWORD_CWORD_CWORD,
+       /*  18  -112      */ CWORD_CWORD_CWORD_CWORD,
+       /*  19  -111      */ CWORD_CWORD_CWORD_CWORD,
+       /*  20  -110      */ CWORD_CWORD_CWORD_CWORD,
+       /*  21  -109      */ CWORD_CWORD_CWORD_CWORD,
+       /*  22  -108      */ CWORD_CWORD_CWORD_CWORD,
+       /*  23  -107      */ CWORD_CWORD_CWORD_CWORD,
+       /*  24  -106      */ CWORD_CWORD_CWORD_CWORD,
+       /*  25  -105      */ CWORD_CWORD_CWORD_CWORD,
+       /*  26  -104      */ CWORD_CWORD_CWORD_CWORD,
+       /*  27  -103      */ CWORD_CWORD_CWORD_CWORD,
+       /*  28  -102      */ CWORD_CWORD_CWORD_CWORD,
+       /*  29  -101      */ CWORD_CWORD_CWORD_CWORD,
+       /*  30  -100      */ CWORD_CWORD_CWORD_CWORD,
+       /*  31   -99      */ CWORD_CWORD_CWORD_CWORD,
+       /*  32   -98      */ CWORD_CWORD_CWORD_CWORD,
+       /*  33   -97      */ CWORD_CWORD_CWORD_CWORD,
+       /*  34   -96      */ CWORD_CWORD_CWORD_CWORD,
+       /*  35   -95      */ CWORD_CWORD_CWORD_CWORD,
+       /*  36   -94      */ CWORD_CWORD_CWORD_CWORD,
+       /*  37   -93      */ CWORD_CWORD_CWORD_CWORD,
+       /*  38   -92      */ CWORD_CWORD_CWORD_CWORD,
+       /*  39   -91      */ CWORD_CWORD_CWORD_CWORD,
+       /*  40   -90      */ CWORD_CWORD_CWORD_CWORD,
+       /*  41   -89      */ CWORD_CWORD_CWORD_CWORD,
+       /*  42   -88      */ CWORD_CWORD_CWORD_CWORD,
+       /*  43   -87      */ CWORD_CWORD_CWORD_CWORD,
+       /*  44   -86      */ CWORD_CWORD_CWORD_CWORD,
+       /*  45   -85      */ CWORD_CWORD_CWORD_CWORD,
+       /*  46   -84      */ CWORD_CWORD_CWORD_CWORD,
+       /*  47   -83      */ CWORD_CWORD_CWORD_CWORD,
+       /*  48   -82      */ CWORD_CWORD_CWORD_CWORD,
+       /*  49   -81      */ CWORD_CWORD_CWORD_CWORD,
+       /*  50   -80      */ CWORD_CWORD_CWORD_CWORD,
+       /*  51   -79      */ CWORD_CWORD_CWORD_CWORD,
+       /*  52   -78      */ CWORD_CWORD_CWORD_CWORD,
+       /*  53   -77      */ CWORD_CWORD_CWORD_CWORD,
+       /*  54   -76      */ CWORD_CWORD_CWORD_CWORD,
+       /*  55   -75      */ CWORD_CWORD_CWORD_CWORD,
+       /*  56   -74      */ CWORD_CWORD_CWORD_CWORD,
+       /*  57   -73      */ CWORD_CWORD_CWORD_CWORD,
+       /*  58   -72      */ CWORD_CWORD_CWORD_CWORD,
+       /*  59   -71      */ CWORD_CWORD_CWORD_CWORD,
+       /*  60   -70      */ CWORD_CWORD_CWORD_CWORD,
+       /*  61   -69      */ CWORD_CWORD_CWORD_CWORD,
+       /*  62   -68      */ CWORD_CWORD_CWORD_CWORD,
+       /*  63   -67      */ CWORD_CWORD_CWORD_CWORD,
+       /*  64   -66      */ CWORD_CWORD_CWORD_CWORD,
+       /*  65   -65      */ CWORD_CWORD_CWORD_CWORD,
+       /*  66   -64      */ CWORD_CWORD_CWORD_CWORD,
+       /*  67   -63      */ CWORD_CWORD_CWORD_CWORD,
+       /*  68   -62      */ CWORD_CWORD_CWORD_CWORD,
+       /*  69   -61      */ CWORD_CWORD_CWORD_CWORD,
+       /*  70   -60      */ CWORD_CWORD_CWORD_CWORD,
+       /*  71   -59      */ CWORD_CWORD_CWORD_CWORD,
+       /*  72   -58      */ CWORD_CWORD_CWORD_CWORD,
+       /*  73   -57      */ CWORD_CWORD_CWORD_CWORD,
+       /*  74   -56      */ CWORD_CWORD_CWORD_CWORD,
+       /*  75   -55      */ CWORD_CWORD_CWORD_CWORD,
+       /*  76   -54      */ CWORD_CWORD_CWORD_CWORD,
+       /*  77   -53      */ CWORD_CWORD_CWORD_CWORD,
+       /*  78   -52      */ CWORD_CWORD_CWORD_CWORD,
+       /*  79   -51      */ CWORD_CWORD_CWORD_CWORD,
+       /*  80   -50      */ CWORD_CWORD_CWORD_CWORD,
+       /*  81   -49      */ CWORD_CWORD_CWORD_CWORD,
+       /*  82   -48      */ CWORD_CWORD_CWORD_CWORD,
+       /*  83   -47      */ CWORD_CWORD_CWORD_CWORD,
+       /*  84   -46      */ CWORD_CWORD_CWORD_CWORD,
+       /*  85   -45      */ CWORD_CWORD_CWORD_CWORD,
+       /*  86   -44      */ CWORD_CWORD_CWORD_CWORD,
+       /*  87   -43      */ CWORD_CWORD_CWORD_CWORD,
+       /*  88   -42      */ CWORD_CWORD_CWORD_CWORD,
+       /*  89   -41      */ CWORD_CWORD_CWORD_CWORD,
+       /*  90   -40      */ CWORD_CWORD_CWORD_CWORD,
+       /*  91   -39      */ CWORD_CWORD_CWORD_CWORD,
+       /*  92   -38      */ CWORD_CWORD_CWORD_CWORD,
+       /*  93   -37      */ CWORD_CWORD_CWORD_CWORD,
+       /*  94   -36      */ CWORD_CWORD_CWORD_CWORD,
+       /*  95   -35      */ CWORD_CWORD_CWORD_CWORD,
+       /*  96   -34      */ CWORD_CWORD_CWORD_CWORD,
+       /*  97   -33      */ CWORD_CWORD_CWORD_CWORD,
+       /*  98   -32      */ CWORD_CWORD_CWORD_CWORD,
+       /*  99   -31      */ CWORD_CWORD_CWORD_CWORD,
+       /* 100   -30      */ CWORD_CWORD_CWORD_CWORD,
+       /* 101   -29      */ CWORD_CWORD_CWORD_CWORD,
+       /* 102   -28      */ CWORD_CWORD_CWORD_CWORD,
+       /* 103   -27      */ CWORD_CWORD_CWORD_CWORD,
+       /* 104   -26      */ CWORD_CWORD_CWORD_CWORD,
+       /* 105   -25      */ CWORD_CWORD_CWORD_CWORD,
+       /* 106   -24      */ CWORD_CWORD_CWORD_CWORD,
+       /* 107   -23      */ CWORD_CWORD_CWORD_CWORD,
+       /* 108   -22      */ CWORD_CWORD_CWORD_CWORD,
+       /* 109   -21      */ CWORD_CWORD_CWORD_CWORD,
+       /* 110   -20      */ CWORD_CWORD_CWORD_CWORD,
+       /* 111   -19      */ CWORD_CWORD_CWORD_CWORD,
+       /* 112   -18      */ CWORD_CWORD_CWORD_CWORD,
+       /* 113   -17      */ CWORD_CWORD_CWORD_CWORD,
+       /* 114   -16      */ CWORD_CWORD_CWORD_CWORD,
+       /* 115   -15      */ CWORD_CWORD_CWORD_CWORD,
+       /* 116   -14      */ CWORD_CWORD_CWORD_CWORD,
+       /* 117   -13      */ CWORD_CWORD_CWORD_CWORD,
+       /* 118   -12      */ CWORD_CWORD_CWORD_CWORD,
+       /* 119   -11      */ CWORD_CWORD_CWORD_CWORD,
+       /* 120   -10      */ CWORD_CWORD_CWORD_CWORD,
+       /* 121    -9      */ CWORD_CWORD_CWORD_CWORD,
+       /* 122    -8      */ CWORD_CWORD_CWORD_CWORD,
+       /* 123    -7      */ CWORD_CWORD_CWORD_CWORD,
+       /* 124    -6      */ CWORD_CWORD_CWORD_CWORD,
+       /* 125    -5      */ CWORD_CWORD_CWORD_CWORD,
+       /* 126    -4      */ CWORD_CWORD_CWORD_CWORD,
+       /* 127    -3      */ CWORD_CWORD_CWORD_CWORD,
+       /* 128    -2      */ CWORD_CWORD_CWORD_CWORD,
+       /* 129    -1      */ CWORD_CWORD_CWORD_CWORD,
+       /* 130     0      */ CWORD_CWORD_CWORD_CWORD,
+       /* 131     1      */ CWORD_CWORD_CWORD_CWORD,
+       /* 132     2      */ CWORD_CWORD_CWORD_CWORD,
+       /* 133     3      */ CWORD_CWORD_CWORD_CWORD,
+       /* 134     4      */ CWORD_CWORD_CWORD_CWORD,
+       /* 135     5      */ CWORD_CWORD_CWORD_CWORD,
+       /* 136     6      */ CWORD_CWORD_CWORD_CWORD,
+       /* 137     7      */ CWORD_CWORD_CWORD_CWORD,
+       /* 138     8      */ CWORD_CWORD_CWORD_CWORD,
+       /* 139     9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 140    10 "\n" */ CNL_CNL_CNL_CNL,
+       /* 141    11      */ CWORD_CWORD_CWORD_CWORD,
+       /* 142    12      */ CWORD_CWORD_CWORD_CWORD,
+       /* 143    13      */ CWORD_CWORD_CWORD_CWORD,
+       /* 144    14      */ CWORD_CWORD_CWORD_CWORD,
+       /* 145    15      */ CWORD_CWORD_CWORD_CWORD,
+       /* 146    16      */ CWORD_CWORD_CWORD_CWORD,
+       /* 147    17      */ CWORD_CWORD_CWORD_CWORD,
+       /* 148    18      */ CWORD_CWORD_CWORD_CWORD,
+       /* 149    19      */ CWORD_CWORD_CWORD_CWORD,
+       /* 150    20      */ CWORD_CWORD_CWORD_CWORD,
+       /* 151    21      */ CWORD_CWORD_CWORD_CWORD,
+       /* 152    22      */ CWORD_CWORD_CWORD_CWORD,
+       /* 153    23      */ CWORD_CWORD_CWORD_CWORD,
+       /* 154    24      */ CWORD_CWORD_CWORD_CWORD,
+       /* 155    25      */ CWORD_CWORD_CWORD_CWORD,
+       /* 156    26      */ CWORD_CWORD_CWORD_CWORD,
+       /* 157    27      */ CWORD_CWORD_CWORD_CWORD,
+       /* 158    28      */ CWORD_CWORD_CWORD_CWORD,
+       /* 159    29      */ CWORD_CWORD_CWORD_CWORD,
+       /* 160    30      */ CWORD_CWORD_CWORD_CWORD,
+       /* 161    31      */ CWORD_CWORD_CWORD_CWORD,
+       /* 162    32  " " */ CSPCL_CWORD_CWORD_CWORD,
+       /* 163    33  "!" */ CWORD_CCTL_CCTL_CWORD,
+       /* 164    34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
+       /* 165    35  "#" */ CWORD_CWORD_CWORD_CWORD,
+       /* 166    36  "$" */ CVAR_CVAR_CWORD_CVAR,
+       /* 167    37  "%" */ CWORD_CWORD_CWORD_CWORD,
+       /* 168    38  "&" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 169    39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
+       /* 170    40  "(" */ CSPCL_CWORD_CWORD_CLP,
+       /* 171    41  ")" */ CSPCL_CWORD_CWORD_CRP,
+       /* 172    42  "*" */ CWORD_CCTL_CCTL_CWORD,
+       /* 173    43  "+" */ CWORD_CWORD_CWORD_CWORD,
+       /* 174    44  "," */ CWORD_CWORD_CWORD_CWORD,
+       /* 175    45  "-" */ CWORD_CCTL_CCTL_CWORD,
+       /* 176    46  "." */ CWORD_CWORD_CWORD_CWORD,
+       /* 177    47  "/" */ CWORD_CCTL_CCTL_CWORD,
+       /* 178    48  "0" */ CWORD_CWORD_CWORD_CWORD,
+       /* 179    49  "1" */ CWORD_CWORD_CWORD_CWORD,
+       /* 180    50  "2" */ CWORD_CWORD_CWORD_CWORD,
+       /* 181    51  "3" */ CWORD_CWORD_CWORD_CWORD,
+       /* 182    52  "4" */ CWORD_CWORD_CWORD_CWORD,
+       /* 183    53  "5" */ CWORD_CWORD_CWORD_CWORD,
+       /* 184    54  "6" */ CWORD_CWORD_CWORD_CWORD,
+       /* 185    55  "7" */ CWORD_CWORD_CWORD_CWORD,
+       /* 186    56  "8" */ CWORD_CWORD_CWORD_CWORD,
+       /* 187    57  "9" */ CWORD_CWORD_CWORD_CWORD,
+       /* 188    58  ":" */ CWORD_CCTL_CCTL_CWORD,
+       /* 189    59  ";" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 190    60  "<" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 191    61  "=" */ CWORD_CCTL_CCTL_CWORD,
+       /* 192    62  ">" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 193    63  "?" */ CWORD_CCTL_CCTL_CWORD,
+       /* 194    64  "@" */ CWORD_CWORD_CWORD_CWORD,
+       /* 195    65  "A" */ CWORD_CWORD_CWORD_CWORD,
+       /* 196    66  "B" */ CWORD_CWORD_CWORD_CWORD,
+       /* 197    67  "C" */ CWORD_CWORD_CWORD_CWORD,
+       /* 198    68  "D" */ CWORD_CWORD_CWORD_CWORD,
+       /* 199    69  "E" */ CWORD_CWORD_CWORD_CWORD,
+       /* 200    70  "F" */ CWORD_CWORD_CWORD_CWORD,
+       /* 201    71  "G" */ CWORD_CWORD_CWORD_CWORD,
+       /* 202    72  "H" */ CWORD_CWORD_CWORD_CWORD,
+       /* 203    73  "I" */ CWORD_CWORD_CWORD_CWORD,
+       /* 204    74  "J" */ CWORD_CWORD_CWORD_CWORD,
+       /* 205    75  "K" */ CWORD_CWORD_CWORD_CWORD,
+       /* 206    76  "L" */ CWORD_CWORD_CWORD_CWORD,
+       /* 207    77  "M" */ CWORD_CWORD_CWORD_CWORD,
+       /* 208    78  "N" */ CWORD_CWORD_CWORD_CWORD,
+       /* 209    79  "O" */ CWORD_CWORD_CWORD_CWORD,
+       /* 210    80  "P" */ CWORD_CWORD_CWORD_CWORD,
+       /* 211    81  "Q" */ CWORD_CWORD_CWORD_CWORD,
+       /* 212    82  "R" */ CWORD_CWORD_CWORD_CWORD,
+       /* 213    83  "S" */ CWORD_CWORD_CWORD_CWORD,
+       /* 214    84  "T" */ CWORD_CWORD_CWORD_CWORD,
+       /* 215    85  "U" */ CWORD_CWORD_CWORD_CWORD,
+       /* 216    86  "V" */ CWORD_CWORD_CWORD_CWORD,
+       /* 217    87  "W" */ CWORD_CWORD_CWORD_CWORD,
+       /* 218    88  "X" */ CWORD_CWORD_CWORD_CWORD,
+       /* 219    89  "Y" */ CWORD_CWORD_CWORD_CWORD,
+       /* 220    90  "Z" */ CWORD_CWORD_CWORD_CWORD,
+       /* 221    91  "[" */ CWORD_CCTL_CCTL_CWORD,
+       /* 222    92  "\" */ CBACK_CBACK_CCTL_CBACK,
+       /* 223    93  "]" */ CWORD_CCTL_CCTL_CWORD,
+       /* 224    94  "^" */ CWORD_CWORD_CWORD_CWORD,
+       /* 225    95  "_" */ CWORD_CWORD_CWORD_CWORD,
+       /* 226    96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
+       /* 227    97  "a" */ CWORD_CWORD_CWORD_CWORD,
+       /* 228    98  "b" */ CWORD_CWORD_CWORD_CWORD,
+       /* 229    99  "c" */ CWORD_CWORD_CWORD_CWORD,
+       /* 230   100  "d" */ CWORD_CWORD_CWORD_CWORD,
+       /* 231   101  "e" */ CWORD_CWORD_CWORD_CWORD,
+       /* 232   102  "f" */ CWORD_CWORD_CWORD_CWORD,
+       /* 233   103  "g" */ CWORD_CWORD_CWORD_CWORD,
+       /* 234   104  "h" */ CWORD_CWORD_CWORD_CWORD,
+       /* 235   105  "i" */ CWORD_CWORD_CWORD_CWORD,
+       /* 236   106  "j" */ CWORD_CWORD_CWORD_CWORD,
+       /* 237   107  "k" */ CWORD_CWORD_CWORD_CWORD,
+       /* 238   108  "l" */ CWORD_CWORD_CWORD_CWORD,
+       /* 239   109  "m" */ CWORD_CWORD_CWORD_CWORD,
+       /* 240   110  "n" */ CWORD_CWORD_CWORD_CWORD,
+       /* 241   111  "o" */ CWORD_CWORD_CWORD_CWORD,
+       /* 242   112  "p" */ CWORD_CWORD_CWORD_CWORD,
+       /* 243   113  "q" */ CWORD_CWORD_CWORD_CWORD,
+       /* 244   114  "r" */ CWORD_CWORD_CWORD_CWORD,
+       /* 245   115  "s" */ CWORD_CWORD_CWORD_CWORD,
+       /* 246   116  "t" */ CWORD_CWORD_CWORD_CWORD,
+       /* 247   117  "u" */ CWORD_CWORD_CWORD_CWORD,
+       /* 248   118  "v" */ CWORD_CWORD_CWORD_CWORD,
+       /* 249   119  "w" */ CWORD_CWORD_CWORD_CWORD,
+       /* 250   120  "x" */ CWORD_CWORD_CWORD_CWORD,
+       /* 251   121  "y" */ CWORD_CWORD_CWORD_CWORD,
+       /* 252   122  "z" */ CWORD_CWORD_CWORD_CWORD,
+       /* 253   123  "{" */ CWORD_CWORD_CWORD_CWORD,
+       /* 254   124  "|" */ CSPCL_CWORD_CWORD_CWORD,
+       /* 255   125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
+       /* 256   126  "~" */ CWORD_CCTL_CCTL_CWORD,
+       /* 257   127      */ CWORD_CWORD_CWORD_CWORD,
+};
+
+#endif                                                  /* USE_SIT_FUNCTION */
+
+/*      $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $      */
+
+
+#define ATABSIZE 39
+
+static int     funcblocksize;          /* size of structures in function */
+static int     funcstringsize;         /* size of strings in node */
+static pointer funcblock;              /* block to allocate function from */
+static char   *funcstring;             /* block to allocate strings from */
+
+static const short nodesize[26] = {
+      SHELL_ALIGN(sizeof (struct ncmd)),
+      SHELL_ALIGN(sizeof (struct npipe)),
+      SHELL_ALIGN(sizeof (struct nredir)),
+      SHELL_ALIGN(sizeof (struct nredir)),
+      SHELL_ALIGN(sizeof (struct nredir)),
+      SHELL_ALIGN(sizeof (struct nbinary)),
+      SHELL_ALIGN(sizeof (struct nbinary)),
+      SHELL_ALIGN(sizeof (struct nbinary)),
+      SHELL_ALIGN(sizeof (struct nif)),
+      SHELL_ALIGN(sizeof (struct nbinary)),
+      SHELL_ALIGN(sizeof (struct nbinary)),
+      SHELL_ALIGN(sizeof (struct nfor)),
+      SHELL_ALIGN(sizeof (struct ncase)),
+      SHELL_ALIGN(sizeof (struct nclist)),
+      SHELL_ALIGN(sizeof (struct narg)),
+      SHELL_ALIGN(sizeof (struct narg)),
+      SHELL_ALIGN(sizeof (struct nfile)),
+      SHELL_ALIGN(sizeof (struct nfile)),
+      SHELL_ALIGN(sizeof (struct nfile)),
+      SHELL_ALIGN(sizeof (struct nfile)),
+      SHELL_ALIGN(sizeof (struct nfile)),
+      SHELL_ALIGN(sizeof (struct ndup)),
+      SHELL_ALIGN(sizeof (struct ndup)),
+      SHELL_ALIGN(sizeof (struct nhere)),
+      SHELL_ALIGN(sizeof (struct nhere)),
+      SHELL_ALIGN(sizeof (struct nnot)),
+};
+
+
+static void calcsize(union node *);
+static void sizenodelist(struct nodelist *);
+static union node *copynode(union node *);
+static struct nodelist *copynodelist(struct nodelist *);
+static char *nodesavestr(char *);
+
+
+
+static void evalstring(char *, int);
+union node;     /* BLETCH for ansi C */
+static void evaltree(union node *, int);
+static void evalbackcmd(union node *, struct backcmd *);
+
+/* in_function returns nonzero if we are currently evaluating a function */
+#define in_function()   funcnest
+static int evalskip;                   /* set if we are skipping commands */
+static int skipcount;           /* number of levels to skip */
+static int funcnest;                   /* depth of function calls */
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK       1
+#define SKIPCONT        2
+#define SKIPFUNC        3
+#define SKIPFILE        4
+
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#ifdef JOBS
+static int bgcmd(int, char **);
+#endif
+static int breakcmd(int, char **);
+static int cdcmd(int, char **);
+#ifdef BB_ASH_CMDCMD
+static int commandcmd(int, char **);
+#endif
+static int dotcmd(int, char **);
+static int evalcmd(int, char **);
+static int execcmd(int, char **);
+static int exitcmd(int, char **);
+static int exportcmd(int, char **);
+static int falsecmd(int, char **);
+#ifdef JOBS
+static int fgcmd(int, char **);
+#endif
+#ifdef BB_ASH_GETOPTS
+static int getoptscmd(int, char **);
+#endif
+static int hashcmd(int, char **);
+#ifndef BB_FEATURE_SH_EXTRA_QUIET
+static int helpcmd(int argc, char **argv);
+#endif
+#ifdef JOBS
+static int jobscmd(int, char **);
+#endif
+#ifdef BB_ASH_MATH_SUPPORT
+static int letcmd(int, char **);
+#endif
+static int localcmd(int, char **);
+static int pwdcmd(int, char **);
+static int readcmd(int, char **);
+static int returncmd(int, char **);
+static int setcmd(int, char **);
+static int shiftcmd(int, char **);
+static int timescmd(int, char **);
+static int trapcmd(int, char **);
+static int truecmd(int, char **);
+static int typecmd(int, char **);
+static int umaskcmd(int, char **);
+static int unsetcmd(int, char **);
+static int waitcmd(int, char **);
+static int ulimitcmd(int, char **);
+#ifdef JOBS
+static int killcmd(int, char **);
+#endif
+
+/*      $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
+
+#ifdef BB_ASH_MAIL
+static void chkmail(void);
+static void changemail(const char *);
+#endif
+
+/*      $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $    */
+
+/* values of cmdtype */
+#define CMDUNKNOWN      -1      /* no entry in table for command */
+#define CMDNORMAL       0       /* command is an executable program */
+#define CMDFUNCTION     1       /* command is a shell function */
+#define CMDBUILTIN      2       /* command is a shell builtin */
+
+struct builtincmd {
+       const char *name;
+       int (*builtin)(int, char **);
+       /* unsigned flags; */
+};
+
+#ifdef BB_ASH_CMDCMD
+# ifdef JOBS
+#  ifdef BB_ASH_ALIAS
+#    define COMMANDCMD (builtincmd + 7)
+#    define EXECCMD (builtincmd + 10)
+#  else
+#    define COMMANDCMD (builtincmd + 6)
+#    define EXECCMD (builtincmd + 9)
+#  endif
+# else /* ! JOBS */
+#  ifdef BB_ASH_ALIAS
+#    define COMMANDCMD (builtincmd + 6)
+#    define EXECCMD (builtincmd + 9)
+#  else
+#    define COMMANDCMD (builtincmd + 5)
+#    define EXECCMD (builtincmd + 8)
+#  endif
+# endif /* JOBS */
+#else   /* ! BB_ASH_CMDCMD */
+# ifdef JOBS
+#  ifdef BB_ASH_ALIAS
+#    define EXECCMD (builtincmd + 9)
+#  else
+#    define EXECCMD (builtincmd + 8)
+#  endif
+# else /* ! JOBS */
+#  ifdef BB_ASH_ALIAS
+#    define EXECCMD (builtincmd + 8)
+#  else
+#    define EXECCMD (builtincmd + 7)
+#  endif
+# endif /* JOBS */
+#endif /* BB_ASH_CMDCMD */
+
+#define BUILTIN_NOSPEC  "0"
+#define BUILTIN_SPECIAL "1"
+#define BUILTIN_REGULAR "2"
+#define BUILTIN_SPEC_REG "3"
+#define BUILTIN_ASSIGN  "4"
+#define BUILTIN_SPEC_ASSG  "5"
+#define BUILTIN_REG_ASSG   "6"
+#define BUILTIN_SPEC_REG_ASSG   "7"
+
+#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
+#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
+
+static const struct builtincmd builtincmd[] = {
+       { BUILTIN_SPEC_REG      ".", dotcmd },
+       { BUILTIN_SPEC_REG      ":", truecmd },
+#ifdef BB_ASH_ALIAS
+       { BUILTIN_REG_ASSG      "alias", aliascmd },
+#endif
+#ifdef JOBS
+       { BUILTIN_REGULAR       "bg", bgcmd },
+#endif
+       { BUILTIN_SPEC_REG      "break", breakcmd },
+       { BUILTIN_REGULAR       "cd", cdcmd },
+       { BUILTIN_NOSPEC        "chdir", cdcmd },
+#ifdef BB_ASH_CMDCMD
+       { BUILTIN_REGULAR       "command", commandcmd },
+#endif
+       { BUILTIN_SPEC_REG      "continue", breakcmd },
+       { BUILTIN_SPEC_REG      "eval", evalcmd },
+       { BUILTIN_SPEC_REG      "exec", execcmd },
+       { BUILTIN_SPEC_REG      "exit", exitcmd },
+       { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
+       { BUILTIN_REGULAR       "false", falsecmd },
+#ifdef JOBS
+       { BUILTIN_REGULAR       "fg", fgcmd },
+#endif
+#ifdef BB_ASH_GETOPTS
+       { BUILTIN_REGULAR       "getopts", getoptscmd },
+#endif
+       { BUILTIN_NOSPEC        "hash", hashcmd },
+#ifndef BB_FEATURE_SH_EXTRA_QUIET
+       { BUILTIN_NOSPEC        "help", helpcmd },
+#endif
+#ifdef JOBS
+       { BUILTIN_REGULAR       "jobs", jobscmd },
+       { BUILTIN_REGULAR       "kill", killcmd },
+#endif
+#ifdef BB_ASH_MATH_SUPPORT
+       { BUILTIN_NOSPEC        "let", letcmd },
+#endif
+       { BUILTIN_ASSIGN        "local", localcmd },
+       { BUILTIN_NOSPEC        "pwd", pwdcmd },
+       { BUILTIN_REGULAR       "read", readcmd },
+       { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
+       { BUILTIN_SPEC_REG      "return", returncmd },
+       { BUILTIN_SPEC_REG      "set", setcmd },
+       { BUILTIN_SPEC_REG      "shift", shiftcmd },
+       { BUILTIN_SPEC_REG      "times", timescmd },
+       { BUILTIN_SPEC_REG      "trap", trapcmd },
+       { BUILTIN_REGULAR       "true", truecmd },
+       { BUILTIN_NOSPEC        "type", typecmd },
+       { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
+       { BUILTIN_REGULAR       "umask", umaskcmd },
+#ifdef BB_ASH_ALIAS
+       { BUILTIN_REGULAR       "unalias", unaliascmd },
+#endif
+       { BUILTIN_SPEC_REG      "unset", unsetcmd },
+       { BUILTIN_REGULAR       "wait", waitcmd },
+};
+
+#define NUMBUILTINS  (sizeof (builtincmd) / sizeof (struct builtincmd) )
+
+
+
+struct cmdentry {
+       int cmdtype;
+       union param {
+               int index;
+               const struct builtincmd *cmd;
+               struct funcnode *func;
+       } u;
+};
+
+
+/* action to find_command() */
+#define DO_ERR          0x01    /* prints errors */
+#define DO_ABS          0x02    /* checks absolute paths */
+#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
+#define DO_ALTPATH      0x08    /* using alternate path */
+#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
+
+static const char *pathopt;     /* set by padvance */
+
+static void shellexec(char **, const char *, int)
+    __attribute__((__noreturn__));
+static char *padvance(const char **, const char *);
+static void find_command(char *, struct cmdentry *, int, const char *);
+static struct builtincmd *find_builtin(const char *);
+static void hashcd(void);
+static void changepath(const char *);
+static void defun(char *, union node *);
+static void unsetfunc(const char *);
+
+#ifdef BB_ASH_MATH_SUPPORT
+static int dash_arith(const char *);
+#endif
+
+/*      $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
+
+static void reset(void);
+
+/*      $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $     */
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT         0x01    /* variable is exported */
+#define VREADONLY       0x02    /* variable cannot be modified */
+#define VSTRFIXED       0x04    /* variable struct is statically allocated */
+#define VTEXTFIXED      0x08    /* text is statically allocated */
+#define VSTACK          0x10    /* text is allocated on the stack */
+#define VUNSET          0x20    /* the variable is not set */
+#define VNOFUNC         0x40    /* don't call the callback function */
+#define VNOSET          0x80    /* do not set variable - just readonly test */
+#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
+
+
+struct var {
+       struct var *next;               /* next entry in hash list */
+       int flags;                      /* flags are defined above */
+       const char *text;               /* name=value */
+       void (*func)(const char *);
+                                       /* function to be called when  */
+                                       /* the variable gets set/unset */
+};
+
+struct localvar {
+       struct localvar *next;          /* next local variable in list */
+       struct var *vp;                 /* the variable that was made local */
+       int flags;                      /* saved flags */
+       const char *text;               /* saved text */
+};
+
+
+static struct localvar *localvars;
+
+/*
+ * Shell variables.
+ */
+
+#ifdef BB_ASH_GETOPTS
+static void getoptsreset(const char *);
+#endif
+
+#ifdef BB_LOCALE_SUPPORT
+#include <locale.h>
+static void change_lc_all(const char *value);
+static void change_lc_ctype(const char *value);
+#endif
+
+#define VTABSIZE 39
+
+static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
+#ifdef IFS_BROKEN
+static const char defifsvar[] = "IFS= \t\n";
+#define defifs (defifsvar + 4)
+#else
+static const char defifs[] = " \t\n";
+#endif
+
+
+static struct var varinit[] = {
+#ifdef IFS_BROKEN
+       { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
+#else
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
+#endif
+
+#ifdef BB_ASH_MAIL
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
+       { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
+#endif
+
+       { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0 },
+#ifdef BB_ASH_GETOPTS
+       { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
+#endif
+#ifdef BB_LOCALE_SUPPORT
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
+#endif
+#ifdef BB_FEATURE_COMMAND_SAVEHISTORY
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
+#endif
+};
+
+#define vifs varinit[0]
+#ifdef BB_ASH_MAIL
+#define vmail (&vifs)[1]
+#define vmpath (&vmail)[1]
+#else
+#define vmpath vifs
+#endif
+#define vpath (&vmpath)[1]
+#define vps1 (&vpath)[1]
+#define vps2 (&vps1)[1]
+#define vps4 (&vps2)[1]
+#define voptind (&vps4)[1]
+
+#define defpath (defpathvar + 5)
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name.  They return the null string
+ * for unset variables.
+ */
+
+#define ifsval()        (vifs.text + 4)
+#define ifsset()        ((vifs.flags & VUNSET) == 0)
+#define mailval()       (vmail.text + 5)
+#define mpathval()      (vmpath.text + 9)
+#define pathval()       (vpath.text + 5)
+#define ps1val()        (vps1.text + 4)
+#define ps2val()        (vps2.text + 4)
+#define ps4val()        (vps4.text + 4)
+#define optindval()     (voptind.text + 7)
+
+#define mpathset()      ((vmpath.flags & VUNSET) == 0)
+
+static void setvar(const char *, const char *, int);
+static void setvareq(char *, int);
+static void listsetvar(struct strlist *, int);
+static char *lookupvar(const char *);
+static char *bltinlookup(const char *);
+static char **listvars(int, int, char ***);
+#define environment() listvars(VEXPORT, VUNSET, 0)
+static int showvars(const char *, int, int);
+static void poplocalvars(void);
+static int unsetvar(const char *);
+#ifdef BB_ASH_GETOPTS
+static int setvarsafe(const char *, const char *, int);
+#endif
+static int varcmp(const char *, const char *);
+static struct var **hashvar(const char *);
+
+
+static inline int varequal(const char *a, const char *b) {
+       return !varcmp(a, b);
+}
+
+
+static int loopnest;            /* current loop nesting level */
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+
+struct redirtab {
+       struct redirtab *next;
+       int renamed[10];
+       int nullredirs;
+};
+
+static struct redirtab *redirlist;
+static int nullredirs;
+
+extern char **environ;
+
+/*      $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $     */
+
+
+static void outstr(const char *, FILE *);
+static void outcslow(int, FILE *);
+static void flushall(void);
+static void flushout(FILE *);
+static int  out1fmt(const char *, ...)
+    __attribute__((__format__(__printf__,1,2)));
+static int fmtstr(char *, size_t, const char *, ...)
+    __attribute__((__format__(__printf__,3,4)));
+static void xwrite(int, const void *, size_t);
+
+static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
+
+
+static void out1str(const char *p)
+{
+       outstr(p, stdout);
+}
+
+static void out2str(const char *p)
+{
+       outstr(p, stderr);
+       flushout(stderr);
+}
+
+/*
+ * Initialization code.
+ */
+
+/*
+ * This routine initializes the builtin variables.
+ */
+
+static inline void
+initvar(void)
+{
+       struct var *vp;
+       struct var *end;
+       struct var **vpp;
+
+       /*
+        * PS1 depends on uid
+        */
+#if defined(BB_FEATURE_COMMAND_EDITING) && defined(BB_FEATURE_SH_FANCY_PROMPT)
+       vps1.text = "PS1=\\w \\$ ";
+#else
+       if (!geteuid())
+               vps1.text = "PS1=# ";
+#endif
+       vp = varinit;
+       end = vp + sizeof(varinit) / sizeof(varinit[0]);
+       do {
+               vpp = hashvar(vp->text);
+               vp->next = *vpp;
+               *vpp = vp;
+       } while (++vp < end);
+}
+
+static inline void
+init(void)
+{
+
+      /* from input.c: */
+      {
+             basepf.nextc = basepf.buf = basebuf;
+      }
+
+      /* from trap.c: */
+      {
+             signal(SIGCHLD, SIG_DFL);
+      }
+
+      /* from var.c: */
+      {
+             char **envp;
+             char ppid[32];
+
+             initvar();
+             for (envp = environ ; *envp ; envp++) {
+                     if (strchr(*envp, '=')) {
+                             setvareq(*envp, VEXPORT|VTEXTFIXED);
+                     }
+             }
+
+             snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
+             setvar("PPID", ppid, 0);
+             setpwd(0, 0);
+      }
+}
+
+/* PEOF (the end of file marker) */
+
+/*
+ * The input line number.  Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped.  The user of this
+ * package must set its value.
+ */
+
+static int pgetc(void);
+static int pgetc2(void);
+static int preadbuffer(void);
+static void pungetc(void);
+static void pushstring(char *, void *);
+static void popstring(void);
+static void setinputfile(const char *, int);
+static void setinputfd(int, int);
+static void setinputstring(char *);
+static void popfile(void);
+static void popallfiles(void);
+static void closescript(void);
+
+
+/*      $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $    */
+
+
+/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+/* mode flags for showjob(s) */
+#define SHOW_PGID       0x01    /* only show pgid - for jobs -p */
+#define SHOW_PID        0x04    /* include process pid */
+#define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
+
+
+/*
+ * A job structure contains information about a job.  A job is either a
+ * single process or a set of processes contained in a pipeline.  In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+       pid_t   pid;            /* process id */
+       int     status;         /* last process status from wait() */
+       char    *cmd;           /* text of command being run */
+};
+
+struct job {
+       struct procstat ps0;    /* status of process */
+       struct procstat *ps;    /* status or processes when more than one */
+#if JOBS
+       int stopstatus;         /* status of a stopped job */
+#endif
+       uint32_t
+               nprocs: 16,     /* number of processes */
+               state: 8,
+#define JOBRUNNING      0       /* at least one proc running */
+#define JOBSTOPPED      1       /* all procs are stopped */
+#define JOBDONE         2       /* all procs are completed */
+#if JOBS
+               sigint: 1,      /* job was killed by SIGINT */
+               jobctl: 1,      /* job running under job control */
+#endif
+               waited: 1,      /* true if this entry has been waited for */
+               used: 1,        /* true if this entry is in used */
+               changed: 1;     /* true if status has changed */
+       struct job *prev_job;   /* previous job */
+};
+
+static pid_t backgndpid;        /* pid of last background process */
+static int job_warning;         /* user was warned about stopped jobs */
+#if JOBS
+static int jobctl;              /* true if doing job control */
+#endif
+
+static struct job *makejob(union node *, int);
+static int forkshell(struct job *, union node *, int);
+static int waitforjob(struct job *);
+static int stoppedjobs(void);
+
+#if ! JOBS
+#define setjobctl(on)   /* do nothing */
+#else
+static void setjobctl(int);
+static void showjobs(FILE *, int);
+#endif
+
+/*      $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $        */
+
+
+/* pid of main shell */
+static int rootpid;
+/* true if we aren't a child of the main shell */
+static int rootshell;
+
+static void readcmdfile(char *);
+static void cmdloop(int);
+
+/*      $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $        */
+
+
+struct stackmark {
+       struct stack_block *stackp;
+       char *stacknxt;
+       size_t stacknleft;
+       struct stackmark *marknext;
+};
+
+/* minimum size of a block */
+#define MINSIZE SHELL_ALIGN(504)
+
+struct stack_block {
+       struct stack_block *prev;
+       char space[MINSIZE];
+};
+
+static struct stack_block stackbase;
+static struct stack_block *stackp = &stackbase;
+static struct stackmark *markp;
+static char *stacknxt = stackbase.space;
+static size_t stacknleft = MINSIZE;
+static char *sstrend = stackbase.space + MINSIZE;
+static int herefd = -1;
+
+
+static pointer ckmalloc(size_t);
+static pointer ckrealloc(pointer, size_t);
+static char *savestr(const char *);
+static pointer stalloc(size_t);
+static void stunalloc(pointer);
+static void setstackmark(struct stackmark *);
+static void popstackmark(struct stackmark *);
+static void growstackblock(void);
+static void *growstackstr(void);
+static char *makestrspace(size_t, char *);
+static char *stnputs(const char *, size_t, char *);
+static char *stputs(const char *, char *);
+
+
+static inline char *_STPUTC(char c, char *p) {
+       if (p == sstrend)
+               p = growstackstr();
+       *p++ = c;
+       return p;
+}
+
+#define stackblock() ((void *)stacknxt)
+#define stackblocksize() stacknleft
+#define STARTSTACKSTR(p) ((p) = stackblock())
+#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
+#define CHECKSTRSPACE(n, p) \
+       ({ \
+               char *q = (p); \
+               size_t l = (n); \
+               size_t m = sstrend - q; \
+               if (l > m) \
+                       (p) = makestrspace(l, q); \
+               0; \
+       })
+#define USTPUTC(c, p)   (*p++ = (c))
+#define STACKSTRNUL(p)  ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p)     (--p)
+#define STTOPC(p)       p[-1]
+#define STADJUST(amount, p)     (p += (amount))
+
+#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define stackstrend() ((void *)sstrend)
+
+#define ckfree(p)       free((pointer)(p))
+
+/*      $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $   */
+
+
+#define DOLATSTRLEN 4
+
+static char *prefix(const char *, const char *);
+static int number(const char *);
+static int is_number(const char *);
+static char *single_quote(const char *);
+static char *sstrdup(const char *);
+
+#define equal(s1, s2)   (strcmp(s1, s2) == 0)
+#define scopy(s1, s2)   ((void)strcpy(s2, s1))
+
+/*      $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
+
+struct shparam {
+       int nparam;             /* # of positional parameters (without $0) */
+       unsigned char malloc;   /* if parameter list dynamically allocated */
+       char **p;               /* parameter list */
+#ifdef BB_ASH_GETOPTS
+       int optind;             /* next parameter to be processed by getopts */
+       int optoff;             /* used by getopts */
+#endif
+};
+
+
+#define eflag optlist[0]
+#define fflag optlist[1]
+#define Iflag optlist[2]
+#define iflag optlist[3]
+#define mflag optlist[4]
+#define nflag optlist[5]
+#define sflag optlist[6]
+#define xflag optlist[7]
+#define vflag optlist[8]
+#define Cflag optlist[9]
+#define aflag optlist[10]
+#define bflag optlist[11]
+#define uflag optlist[12]
+#define qflag optlist[13]
+
+#ifdef DEBUG
+#define nolog optlist[14]
+#define debug optlist[15]
+#define NOPTS   16
+#else
+#define NOPTS   14
+#endif
+
+/*      $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
+
+
+static const char *const optletters_optnames[NOPTS] = {
+       "e"   "errexit",
+       "f"   "noglob",
+       "I"   "ignoreeof",
+       "i"   "interactive",
+       "m"   "monitor",
+       "n"   "noexec",
+       "s"   "stdin",
+       "x"   "xtrace",
+       "v"   "verbose",
+       "C"   "noclobber",
+       "a"   "allexport",
+       "b"   "notify",
+       "u"   "nounset",
+       "q"   "quietprofile",
+#ifdef DEBUG
+       "\0"  "nolog",
+       "\0"  "debug",
+#endif
+};
+
+#define optletters(n) optletters_optnames[(n)][0]
+#define optnames(n) (&optletters_optnames[(n)][1])
+
+
+static char optlist[NOPTS];
+
+
+static char *arg0;                     /* value of $0 */
+static struct shparam shellparam;      /* $@ current positional parameters */
+static char **argptr;                  /* argument list for builtin commands */
+static char *optionarg;                /* set by nextopt (like getopt) */
+static char *optptr;                   /* used by nextopt */
+
+static char *minusc;                   /* argument to -c option */
+
+
+static void procargs(int, char **);
+static void optschanged(void);
+static void setparam(char **);
+static void freeparam(volatile struct shparam *);
+static int shiftcmd(int, char **);
+static int setcmd(int, char **);
+static int nextopt(const char *);
+
+/*      $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $      */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01           /* save previous values of file descriptors */
+#define REDIR_SAVEFD2 03       /* set preverrout */
+
+union node;
+static void redirect(union node *, int);
+static void popredir(int);
+static void clearredir(int);
+static int ash_copyfd(int, int);
+static int redirectsafe(union node *, int);
+
+/*      $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $     */
+
+
+#ifdef DEBUG
+static void showtree(union node *);
+static void trace(const char *, ...);
+static void tracev(const char *, va_list);
+static void trargs(char **);
+static void trputc(int);
+static void trputs(const char *);
+static void opentrace(void);
+#endif
+
+/*      $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $       */
+
+
+/* trap handler commands */
+static char *trap[NSIG];
+/* current value of signal */
+static char sigmode[NSIG - 1];
+/* indicates specified signal received */
+static char gotsig[NSIG - 1];
+
+static void clear_traps(void);
+static void setsignal(int);
+static void ignoresig(int);
+static void onsig(int);
+static void dotrap(void);
+static void setinteractive(int);
+static void exitshell(void) __attribute__((__noreturn__));
+static int decode_signal(const char *, int);
+
+/*
+ * This routine is called when an error or an interrupt occurs in an
+ * interactive shell and control is returned to the main command loop.
+ */
+
+static void
+reset(void)
+{
+      /* from eval.c: */
+      {
+             evalskip = 0;
+             loopnest = 0;
+             funcnest = 0;
+      }
+
+      /* from input.c: */
+      {
+             parselleft = parsenleft = 0;      /* clear input buffer */
+             popallfiles();
+      }
+
+      /* from parser.c: */
+      {
+             tokpushback = 0;
+             checkkwd = 0;
+      }
+
+      /* from redir.c: */
+      {
+             clearredir(0);
+      }
+
+}
+
+#ifdef BB_ASH_ALIAS
+static struct alias *atab[ATABSIZE];
+
+static void setalias(const char *, const char *);
+static struct alias *freealias(struct alias *);
+static struct alias **__lookupalias(const char *);
+
+static void
+setalias(const char *name, const char *val)
+{
+       struct alias *ap, **app;
+
+       app = __lookupalias(name);
+       ap = *app;
+       INTOFF;
+       if (ap) {
+               if (!(ap->flag & ALIASINUSE)) {
+                       ckfree(ap->val);
+               }
+               ap->val = savestr(val);
+               ap->flag &= ~ALIASDEAD;
+       } else {
+               /* not found */
+               ap = ckmalloc(sizeof (struct alias));
+               ap->name = savestr(name);
+               ap->val = savestr(val);
+               ap->flag = 0;
+               ap->next = 0;
+               *app = ap;
+       }
+       INTON;
+}
+
+static int
+unalias(const char *name)
+{
+       struct alias **app;
+
+       app = __lookupalias(name);
+
+       if (*app) {
+               INTOFF;
+               *app = freealias(*app);
+               INTON;
+               return (0);
+       }
+
+       return (1);
+}
+
+static void
+rmaliases(void)
+{
+       struct alias *ap, **app;
+       int i;
+
+       INTOFF;
+       for (i = 0; i < ATABSIZE; i++) {
+               app = &atab[i];
+               for (ap = *app; ap; ap = *app) {
+                       *app = freealias(*app);
+                       if (ap == *app) {
+                               app = &ap->next;
+                       }
+               }
+       }
+       INTON;
+}
+
+static struct alias *
+lookupalias(const char *name, int check)
+{
+       struct alias *ap = *__lookupalias(name);
+
+       if (check && ap && (ap->flag & ALIASINUSE))
+               return (NULL);
+       return (ap);
+}
+
+/*
+ * TODO - sort output
+ */
+static int
+aliascmd(int argc, char **argv)
+{
+       char *n, *v;
+       int ret = 0;
+       struct alias *ap;
+
+       if (argc == 1) {
+               int i;
+
+               for (i = 0; i < ATABSIZE; i++)
+                       for (ap = atab[i]; ap; ap = ap->next) {
+                               printalias(ap);
+                       }
+               return (0);
+       }
+       while ((n = *++argv) != NULL) {
+               if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
+                       if ((ap = *__lookupalias(n)) == NULL) {
+                               fprintf(stderr, "%s: %s not found\n", "alias", n);
+                               ret = 1;
+                       } else
+                               printalias(ap);
+               } else {
+                       *v++ = '\0';
+                       setalias(n, v);
+               }
+       }
+
+       return (ret);
+}
+
+static int
+unaliascmd(int argc, char **argv)
+{
+       int i;
+
+       while ((i = nextopt("a")) != '\0') {
+               if (i == 'a') {
+                       rmaliases();
+                       return (0);
+               }
+       }
+       for (i = 0; *argptr; argptr++) {
+               if (unalias(*argptr)) {
+                       fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
+                       i = 1;
+               }
+       }
+
+       return (i);
+}
+
+static struct alias *
+freealias(struct alias *ap) {
+       struct alias *next;
+
+       if (ap->flag & ALIASINUSE) {
+               ap->flag |= ALIASDEAD;
+               return ap;
+       }
+
+       next = ap->next;
+       ckfree(ap->name);
+       ckfree(ap->val);
+       ckfree(ap);
+       return next;
+}
+
+static void
+printalias(const struct alias *ap) {
+       out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
+}
+
+static struct alias **
+__lookupalias(const char *name) {
+       unsigned int hashval;
+       struct alias **app;
+       const char *p;
+       unsigned int ch;
+
+       p = name;
+
+       ch = (unsigned char)*p;
+       hashval = ch << 4;
+       while (ch) {
+               hashval += ch;
+               ch = (unsigned char)*++p;
+       }
+       app = &atab[hashval % ATABSIZE];
+
+       for (; *app; app = &(*app)->next) {
+               if (equal(name, (*app)->name)) {
+                       break;
+               }
+       }
+
+       return app;
+}
+#endif /* BB_ASH_ALIAS */
+
+
+/*      $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $      */
+
+/*
+ * The cd and pwd commands.
+ */
+
+#define CD_PHYSICAL 1
+#define CD_PRINT 2
+
+static int docd(const char *, int);
+static int cdopt(void);
+
+static char *curdir = nullstr;          /* current working directory */
+static char *physdir = nullstr;         /* physical working directory */
+
+static int
+cdopt(void)
+{
+       int flags = 0;
+       int i, j;
+
+       j = 'L';
+       while ((i = nextopt("LP"))) {
+               if (i != j) {
+                       flags ^= CD_PHYSICAL;
+                       j = i;
+               }
+       }
+
+       return flags;
+}
+
+static int
+cdcmd(int argc, char **argv)
+{
+       const char *dest;
+       const char *path;
+       const char *p;
+       char c;
+       struct stat statb;
+       int flags;
+
+       flags = cdopt();
+       dest = *argptr;
+       if (!dest)
+               dest = bltinlookup(homestr);
+       else if (dest[0] == '-' && dest[1] == '\0') {
+               dest = bltinlookup("OLDPWD");
+               flags |= CD_PRINT;
+               goto step7;
+       }
+       if (!dest)
+               dest = nullstr;
+       if (*dest == '/')
+               goto step7;
+       if (*dest == '.') {
+               c = dest[1];
+dotdot:
+               switch (c) {
+               case '\0':
+               case '/':
+                       goto step6;
+               case '.':
+                       c = dest[2];
+                       if (c != '.')
+                               goto dotdot;
+               }
+       }
+       if (!*dest)
+               dest = ".";
+       if (!(path = bltinlookup("CDPATH"))) {
+step6:
+step7:
+               p = dest;
+               goto docd;
+       }
+       do {
+               c = *path;
+               p = padvance(&path, dest);
+               if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
+                       if (c && c != ':')
+                               flags |= CD_PRINT;
+docd:
+                       if (!docd(p, flags))
+                               goto out;
+                       break;
+               }
+       } while (path);
+       error("can't cd to %s", dest);
+       /* NOTREACHED */
+out:
+       if (flags & CD_PRINT)
+               out1fmt(snlfmt, curdir);
+       return 0;
+}
+
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.
+ */
+
+static inline const char *
+updatepwd(const char *dir)
+{
+       char *new;
+       char *p;
+       char *cdcomppath;
+       const char *lim;
+
+       cdcomppath = sstrdup(dir);
+       STARTSTACKSTR(new);
+       if (*dir != '/') {
+               if (curdir == nullstr)
+                       return 0;
+               new = stputs(curdir, new);
+       }
+       new = makestrspace(strlen(dir) + 2, new);
+       lim = stackblock() + 1;
+       if (*dir != '/') {
+               if (new[-1] != '/')
+                       USTPUTC('/', new);
+               if (new > lim && *lim == '/')
+                       lim++;
+       } else {
+               USTPUTC('/', new);
+               cdcomppath++;
+               if (dir[1] == '/' && dir[2] != '/') {
+                       USTPUTC('/', new);
+                       cdcomppath++;
+                       lim++;
+               }
+       }
+       p = strtok(cdcomppath, "/");
+       while (p) {
+               switch(*p) {
+               case '.':
+                       if (p[1] == '.' && p[2] == '\0') {
+                               while (new > lim) {
+                                       STUNPUTC(new);
+                                       if (new[-1] == '/')
+                                               break;
+                               }
+                               break;
+                       } else if (p[1] == '\0')
+                               break;
+                       /* fall through */
+               default:
+                       new = stputs(p, new);
+                       USTPUTC('/', new);
+               }
+               p = strtok(0, "/");
+       }
+       if (new > lim)
+               STUNPUTC(new);
+       *new = 0;
+       return stackblock();
+}
+
+/*
+ * Actually do the chdir.  We also call hashcd to let the routines in exec.c
+ * know that the current directory has changed.
+ */
+
+static int
+docd(const char *dest, int flags)
+{
+       const char *dir = 0;
+       int err;
+
+       TRACE(("docd(\"%s\", %d) called\n", dest, flags));
+
+       INTOFF;
+       if (!(flags & CD_PHYSICAL)) {
+               dir = updatepwd(dest);
+               if (dir)
+                       dest = dir;
+       }
+       err = chdir(dest);
+       if (err)
+               goto out;
+       setpwd(dir, 1);
+       hashcd();
+out:
+       INTON;
+       return err;
+}
+
+/*
+ * Find out what the current directory is. If we already know the current
+ * directory, this routine returns immediately.
+ */
+static inline char *
+getpwd(void)
+{
+       char *dir = getcwd(0, 0);
+       return dir ? dir : nullstr;
+}
+
+static int
+pwdcmd(int argc, char **argv)
+{
+       int flags;
+       const char *dir = curdir;
+
+       flags = cdopt();
+       if (flags) {
+               if (physdir == nullstr)
+                       setpwd(dir, 0);
+               dir = physdir;
+       }
+       out1fmt(snlfmt, dir);
+       return 0;
+}
+
+static void
+setpwd(const char *val, int setold)
+{
+       char *oldcur, *dir;
+
+       oldcur = dir = curdir;
+
+       if (setold) {
+               setvar("OLDPWD", oldcur, VEXPORT);
+       }
+       INTOFF;
+       if (physdir != nullstr) {
+               if (physdir != oldcur)
+                       free(physdir);
+               physdir = nullstr;
+       }
+       if (oldcur == val || !val) {
+               char *s = getpwd();
+               physdir = s;
+               if (!val)
+                       dir = s;
+       } else
+               dir = savestr(val);
+       if (oldcur != dir && oldcur != nullstr) {
+               free(oldcur);
+       }
+       curdir = dir;
+       INTON;
+       setvar("PWD", dir, VEXPORT);
+}
+
+/*      $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $   */
+
+/*
+ * Errors and exceptions.
+ */
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+
+
+static void exverror(int, const char *, va_list)
+    __attribute__((__noreturn__));
+
+/*
+ * Called to raise an exception.  Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler.  The type of exception is
+ * stored in the global variable "exception".
+ */
+
+static void
+exraise(int e)
+{
+#ifdef DEBUG
+       if (handler == NULL)
+               abort();
+#endif
+       INTOFF;
+
+       exception = e;
+       longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received.  (If the user specifies
+ * that SIGINT is to be trapped or ignored using the trap builtin, then
+ * this routine is not called.)  Suppressint is nonzero when interrupts
+ * are held using the INTOFF macro.  (The test for iflag is just
+ * defensive programming.)
+ */
+
+static void
+onint(void) {
+       int i;
+
+       intpending = 0;
+       sigsetmask(0);
+       i = EXSIG;
+       if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
+               if (!(rootshell && iflag)) {
+                       signal(SIGINT, SIG_DFL);
+                       raise(SIGINT);
+               }
+               i = EXINT;
+       }
+       exraise(i);
+       /* NOTREACHED */
+}
+
+static void
+exvwarning(const char *msg, va_list ap)
+{
+       FILE *errs;
+       const char *name;
+       const char *fmt;
+
+       errs = stderr;
+       name = arg0;
+       fmt = "%s: ";
+       if (commandname) {
+               name = commandname;
+               fmt = "%s: %d: ";
+       }
+       fprintf(errs, fmt, name, startlinno);
+       vfprintf(errs, msg, ap);
+       outcslow('\n', errs);
+}
+
+/*
+ * Exverror is called to raise the error exception.  If the second argument
+ * is not NULL then error prints an error message using printf style
+ * formatting.  It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+#ifdef DEBUG
+       if (msg) {
+               TRACE(("exverror(%d, \"", cond));
+               TRACEV((msg, ap));
+               TRACE(("\") pid=%d\n", getpid()));
+       } else
+               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+       if (msg)
+#endif
+               exvwarning(msg, ap);
+
+       flushall();
+       exraise(cond);
+       /* NOTREACHED */
+}
+
+
+static void
+error(const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       exverror(EXERROR, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+
+static void
+exerror(int cond, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       exverror(cond, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+/*
+ * error/warning routines for external builtins
+ */
+
+static void
+sh_warnx(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(fmt, ap);
+       va_end(ap);
+}
+
+
+/*
+ * Return a string describing an error.  The returned string may be a
+ * pointer to a static buffer that will be overwritten on the next call.
+ * Action describes the operation that got the error.
+ */
+
+static const char *
+errmsg(int e, const char *em)
+{
+       if(e == ENOENT || e == ENOTDIR) {
+
+               return em;
+       }
+       return strerror(e);
+}
+
+
+/*      $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $  */
+
+/*
+ * Evaluate a command.
+ */
+
+/* flags in argument to evaltree */
+#define EV_EXIT 01              /* exit after evaluating tree */
+#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04           /* command executing within back quotes */
+
+
+static void evalloop(union node *, int);
+static void evalfor(union node *, int);
+static void evalcase(union node *, int);
+static void evalsubshell(union node *, int);
+static void expredir(union node *);
+static void evalpipe(union node *, int);
+static void evalcommand(union node *, int);
+static int evalbltin(const struct builtincmd *, int, char **);
+static int evalfun(struct funcnode *, int, char **, int);
+static void prehash(union node *);
+static int bltincmd(int, char **);
+
+
+static const struct builtincmd bltin = {
+       "\0\0", bltincmd
+};
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+/*
+ * The eval commmand.
+ */
+
+static int
+evalcmd(int argc, char **argv)
+{
+       char *p;
+       char *concat;
+       char **ap;
+
+       if (argc > 1) {
+               p = argv[1];
+               if (argc > 2) {
+                       STARTSTACKSTR(concat);
+                       ap = argv + 2;
+                       for (;;) {
+                               concat = stputs(p, concat);
+                               if ((p = *ap++) == NULL)
+                                       break;
+                               STPUTC(' ', concat);
+                       }
+                       STPUTC('\0', concat);
+                       p = grabstackstr(concat);
+               }
+               evalstring(p, EV_TESTED);
+       }
+       return exitstatus;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+static void
+evalstring(char *s, int flag)
+{
+       union node *n;
+       struct stackmark smark;
+
+       setstackmark(&smark);
+       setinputstring(s);
+
+       while ((n = parsecmd(0)) != NEOF) {
+               evaltree(n, flag);
+               popstackmark(&smark);
+               if (evalskip)
+                       break;
+       }
+       popfile();
+       popstackmark(&smark);
+}
+
+
+
+/*
+ * Evaluate a parse tree.  The value is left in the global variable
+ * exitstatus.
+ */
+
+static void
+evaltree(union node *n, int flags)
+{
+       int checkexit = 0;
+       void (*evalfn)(union node *, int);
+       unsigned isor;
+       int status;
+       if (n == NULL) {
+               TRACE(("evaltree(NULL) called\n"));
+               goto out;
+       }
+       TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
+           getpid(), n, n->type, flags));
+       switch (n->type) {
+       default:
+#ifdef DEBUG
+               out1fmt("Node type = %d\n", n->type);
+               fflush(stdout);
+               break;
+#endif
+       case NNOT:
+               evaltree(n->nnot.com, EV_TESTED);
+               status = !exitstatus;
+               goto setstatus;
+       case NREDIR:
+               expredir(n->nredir.redirect);
+               status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
+               if (!status) {
+                       evaltree(n->nredir.n, flags & EV_TESTED);
+                       status = exitstatus;
+               }
+               popredir(0);
+               goto setstatus;
+       case NCMD:
+               evalfn = evalcommand;
+checkexit:
+               if (eflag && !(flags & EV_TESTED))
+                       checkexit = ~0;
+               goto calleval;
+       case NFOR:
+               evalfn = evalfor;
+               goto calleval;
+       case NWHILE:
+       case NUNTIL:
+               evalfn = evalloop;
+               goto calleval;
+       case NSUBSHELL:
+       case NBACKGND:
+               evalfn = evalsubshell;
+               goto calleval;
+       case NPIPE:
+               evalfn = evalpipe;
+               goto checkexit;
+       case NCASE:
+               evalfn = evalcase;
+               goto calleval;
+       case NAND:
+       case NOR:
+       case NSEMI:
+#if NAND + 1 != NOR
+#error NAND + 1 != NOR
+#endif
+#if NOR + 1 != NSEMI
+#error NOR + 1 != NSEMI
+#endif
+               isor = n->type - NAND;
+               evaltree(
+                       n->nbinary.ch1,
+                       (flags | ((isor >> 1) - 1)) & EV_TESTED
+               );
+               if (!exitstatus == isor)
+                       break;
+               if (!evalskip) {
+                       n = n->nbinary.ch2;
+evaln:
+                       evalfn = evaltree;
+calleval:
+                       evalfn(n, flags);
+                       break;
+               }
+               break;
+       case NIF:
+               evaltree(n->nif.test, EV_TESTED);
+               if (evalskip)
+                       break;
+               if (exitstatus == 0) {
+                       n = n->nif.ifpart;
+                       goto evaln;
+               } else if (n->nif.elsepart) {
+                       n = n->nif.elsepart;
+                       goto evaln;
+               }
+               goto success;
+       case NDEFUN:
+               defun(n->narg.text, n->narg.next);
+success:
+               status = 0;
+setstatus:
+               exitstatus = status;
+               break;
+       }
+out:
+       if (pendingsigs)
+               dotrap();
+       if (flags & EV_EXIT || checkexit & exitstatus)
+               exraise(EXEXIT);
+}
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+static
+#endif
+void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
+
+
+static void
+evalloop(union node *n, int flags)
+{
+       int status;
+
+       loopnest++;
+       status = 0;
+       flags &= EV_TESTED;
+       for (;;) {
+               int i;
+
+               evaltree(n->nbinary.ch1, EV_TESTED);
+               if (evalskip) {
+skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
+                               evalskip = 0;
+                               continue;
+                       }
+                       if (evalskip == SKIPBREAK && --skipcount <= 0)
+                               evalskip = 0;
+                       break;
+               }
+               i = exitstatus;
+               if (n->type != NWHILE)
+                       i = !i;
+               if (i != 0)
+                       break;
+               evaltree(n->nbinary.ch2, flags);
+               status = exitstatus;
+               if (evalskip)
+                       goto skipping;
+       }
+       loopnest--;
+       exitstatus = status;
+}
+
+
+
+static void
+evalfor(union node *n, int flags)
+{
+       struct arglist arglist;
+       union node *argp;
+       struct strlist *sp;
+       struct stackmark smark;
+
+       setstackmark(&smark);
+       arglist.lastp = &arglist.list;
+       for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
+               /* XXX */
+               if (evalskip)
+                       goto out;
+       }
+       *arglist.lastp = NULL;
+
+       exitstatus = 0;
+       loopnest++;
+       flags &= EV_TESTED;
+       for (sp = arglist.list ; sp ; sp = sp->next) {
+               setvar(n->nfor.var, sp->text, 0);
+               evaltree(n->nfor.body, flags);
+               if (evalskip) {
+                       if (evalskip == SKIPCONT && --skipcount <= 0) {
+                               evalskip = 0;
+                               continue;
+                       }
+                       if (evalskip == SKIPBREAK && --skipcount <= 0)
+                               evalskip = 0;
+                       break;
+               }
+       }
+       loopnest--;
+out:
+       popstackmark(&smark);
+}
+
+
+
+static void
+evalcase(union node *n, int flags)
+{
+       union node *cp;
+       union node *patp;
+       struct arglist arglist;
+       struct stackmark smark;
+
+       setstackmark(&smark);
+       arglist.lastp = &arglist.list;
+       expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+       exitstatus = 0;
+       for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
+               for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+                       if (casematch(patp, arglist.list->text)) {
+                               if (evalskip == 0) {
+                                       evaltree(cp->nclist.body, flags);
+                               }
+                               goto out;
+                       }
+               }
+       }
+out:
+       popstackmark(&smark);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+static void
+evalsubshell(union node *n, int flags)
+{
+       struct job *jp;
+       int backgnd = (n->type == NBACKGND);
+       int status;
+
+       expredir(n->nredir.redirect);
+       if (!backgnd && flags & EV_EXIT && !trap[0])
+               goto nofork;
+       INTOFF;
+       jp = makejob(n, 1);
+       if (forkshell(jp, n, backgnd) == 0) {
+               INTON;
+               flags |= EV_EXIT;
+               if (backgnd)
+                       flags &=~ EV_TESTED;
+nofork:
+               redirect(n->nredir.redirect, 0);
+               evaltreenr(n->nredir.n, flags);
+               /* never returns */
+       }
+       status = 0;
+       if (! backgnd)
+               status = waitforjob(jp);
+       exitstatus = status;
+       INTON;
+}
+
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+static void
+expredir(union node *n)
+{
+       union node *redir;
+
+       for (redir = n ; redir ; redir = redir->nfile.next) {
+               struct arglist fn;
+               fn.lastp = &fn.list;
+               switch (redir->type) {
+               case NFROMTO:
+               case NFROM:
+               case NTO:
+               case NCLOBBER:
+               case NAPPEND:
+                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+                       redir->nfile.expfname = fn.list->text;
+                       break;
+               case NFROMFD:
+               case NTOFD:
+                       if (redir->ndup.vname) {
+                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+                               fixredir(redir, fn.list->text, 1);
+                       }
+                       break;
+               }
+       }
+}
+
+
+
+/*
+ * Evaluate a pipeline.  All the processes in the pipeline are children
+ * of the process creating the pipeline.  (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+static void
+evalpipe(union node *n, int flags)
+{
+       struct job *jp;
+       struct nodelist *lp;
+       int pipelen;
+       int prevfd;
+       int pip[2];
+
+       TRACE(("evalpipe(0x%lx) called\n", (long)n));
+       pipelen = 0;
+       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+               pipelen++;
+       flags |= EV_EXIT;
+       INTOFF;
+       jp = makejob(n, pipelen);
+       prevfd = -1;
+       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+               prehash(lp->n);
+               pip[1] = -1;
+               if (lp->next) {
+                       if (pipe(pip) < 0) {
+                               close(prevfd);
+                               error("Pipe call failed");
+                       }
+               }
+               if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+                       INTON;
+                       if (pip[1] >= 0) {
+                               close(pip[0]);
+                       }
+                       if (prevfd > 0) {
+                               dup2(prevfd, 0);
+                               close(prevfd);
+                       }
+                       if (pip[1] > 1) {
+                               dup2(pip[1], 1);
+                               close(pip[1]);
+                       }
+                       evaltreenr(lp->n, flags);
+                       /* never returns */
+               }
+               if (prevfd >= 0)
+                       close(prevfd);
+               prevfd = pip[0];
+               close(pip[1]);
+       }
+       if (n->npipe.backgnd == 0) {
+               exitstatus = waitforjob(jp);
+               TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
+       }
+       INTON;
+}
+
+
+
+/*
+ * Execute a command inside back quotes.  If it's a builtin command, we
+ * want to save its output in a block obtained from malloc.  Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+static void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+       int saveherefd;
+
+       result->fd = -1;
+       result->buf = NULL;
+       result->nleft = 0;
+       result->jp = NULL;
+       if (n == NULL) {
+               goto out;
+       }
+
+       saveherefd = herefd;
+       herefd = -1;
+
+       {
+               int pip[2];
+               struct job *jp;
+
+               if (pipe(pip) < 0)
+                       error("Pipe call failed");
+               jp = makejob(n, 1);
+               if (forkshell(jp, n, FORK_NOJOB) == 0) {
+                       FORCEINTON;
+                       close(pip[0]);
+                       if (pip[1] != 1) {
+                               close(1);
+                               ash_copyfd(pip[1], 1);
+                               close(pip[1]);
+                       }
+                       eflag = 0;
+                       evaltreenr(n, EV_EXIT);
+                       /* NOTREACHED */
+               }
+               close(pip[1]);
+               result->fd = pip[0];
+               result->jp = jp;
+       }
+       herefd = saveherefd;
+out:
+       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
+               result->fd, result->buf, result->nleft, result->jp));
+}
+
+#ifdef BB_ASH_CMDCMD
+static inline char **
+parse_command_args(char **argv, const char **path)
+{
+       char *cp, c;
+
+       for (;;) {
+               cp = *++argv;
+               if (!cp)
+                       return 0;
+               if (*cp++ != '-')
+                       break;
+               if (!(c = *cp++))
+                       break;
+               if (c == '-' && !*cp) {
+                       argv++;
+                       break;
+               }
+               do {
+                       switch (c) {
+                       case 'p':
+                               *path = defpath;
+                               break;
+                       default:
+                               /* run 'typecmd' for other options */
+                               return 0;
+                       }
+               } while ((c = *cp++));
+       }
+       return argv;
+}
+#endif
+
+
+
+/*
+ * Execute a simple command.
+ */
+
+static void
+evalcommand(union node *cmd, int flags)
+{
+       struct stackmark smark;
+       union node *argp;
+       struct arglist arglist;
+       struct arglist varlist;
+       char **argv;
+       int argc;
+       const struct strlist *sp;
+       struct cmdentry cmdentry;
+       struct job *jp;
+       char *lastarg;
+       const char *path;
+       int spclbltin;
+       int cmd_is_exec;
+       int status;
+       char **nargv;
+
+       /* First expand the arguments. */
+       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
+       setstackmark(&smark);
+       back_exitstatus = 0;
+
+       cmdentry.cmdtype = CMDBUILTIN;
+       cmdentry.u.cmd = &bltin;
+       varlist.lastp = &varlist.list;
+       *varlist.lastp = NULL;
+       arglist.lastp = &arglist.list;
+       *arglist.lastp = NULL;
+
+       argc = 0;
+       for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
+               struct strlist **spp;
+
+               spp = arglist.lastp;
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+               for (sp = *spp; sp; sp = sp->next)
+                       argc++;
+       }
+
+       argv = nargv = stalloc(sizeof (char *) * (argc + 1));
+       for (sp = arglist.list ; sp ; sp = sp->next) {
+               TRACE(("evalcommand arg: %s\n", sp->text));
+               *nargv++ = sp->text;
+       }
+       *nargv = NULL;
+
+       lastarg = NULL;
+       if (iflag && funcnest == 0 && argc > 0)
+               lastarg = nargv[-1];
+
+       preverrout_fd = 2;
+       expredir(cmd->ncmd.redirect);
+       status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
+
+       path = vpath.text;
+       for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
+               struct strlist **spp;
+               char *p;
+
+               spp = varlist.lastp;
+               expandarg(argp, &varlist, EXP_VARTILDE);
+
+               /*
+                * Modify the command lookup path, if a PATH= assignment
+                * is present
+                */
+               p = (*spp)->text;
+               if (varequal(p, path))
+                       path = p;
+       }
+
+       /* Print the command if xflag is set. */
+       if (xflag) {
+               int n;
+               const char *p = " %s";
+
+               p++;
+               dprintf(preverrout_fd, p, ps4val());
+
+               sp = varlist.list;
+               for(n = 0; n < 2; n++) {
+                       while (sp) {
+                               dprintf(preverrout_fd, p, sp->text);
+                               sp = sp->next;
+                               if(*p == '%') {
+                                       p--;
+                               }
+                       }
+                       sp = arglist.list;
+               }
+               xwrite(preverrout_fd, "\n", 1);
+       }
+
+       cmd_is_exec = 0;
+       spclbltin = -1;
+
+       /* Now locate the command. */
+       if (argc) {
+               const char *oldpath;
+               int cmd_flag = DO_ERR;
+
+               path += 5;
+               oldpath = path;
+               for (;;) {
+                       find_command(argv[0], &cmdentry, cmd_flag, path);
+                       if (cmdentry.cmdtype == CMDUNKNOWN) {
+                               status = 127;
+                               flushout(stderr);
+                               goto bail;
+                       }
+
+                       /* implement bltin and command here */
+                       if (cmdentry.cmdtype != CMDBUILTIN)
+                               break;
+                       if (spclbltin < 0)
+                               spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
+                       if (cmdentry.u.cmd == EXECCMD)
+                               cmd_is_exec++;
+#ifdef BB_ASH_CMDCMD
+                       if (cmdentry.u.cmd == COMMANDCMD) {
+
+                               path = oldpath;
+                               nargv = parse_command_args(argv, &path);
+                               if (!nargv)
+                                       break;
+                               argc -= nargv - argv;
+                               argv = nargv;
+                               cmd_flag |= DO_NOFUNC;
+                       } else
+#endif
+                               break;
+               }
+       }
+
+       if (status) {
+               /* We have a redirection error. */
+               if (spclbltin > 0)
+                       exraise(EXERROR);
+bail:
+               exitstatus = status;
+               goto out;
+       }
+
+       /* Execute the command. */
+       switch (cmdentry.cmdtype) {
+       default:
+               /* Fork off a child process if necessary. */
+               if (!(flags & EV_EXIT) || trap[0]) {
+                       INTOFF;
+                       jp = makejob(cmd, 1);
+                       if (forkshell(jp, cmd, FORK_FG) != 0) {
+                               exitstatus = waitforjob(jp);
+                               INTON;
+                               break;
+                       }
+                       FORCEINTON;
+               }
+               listsetvar(varlist.list, VEXPORT|VSTACK);
+               shellexec(argv, path, cmdentry.u.index);
+               /* NOTREACHED */
+
+       case CMDBUILTIN:
+               cmdenviron = varlist.list;
+               if (cmdenviron) {
+                       struct strlist *list = cmdenviron;
+                       int i = VNOSET;
+                       if (spclbltin > 0 || argc == 0) {
+                               i = 0;
+                               if (cmd_is_exec && argc > 1)
+                                       i = VEXPORT;
+                       }
+                       listsetvar(list, i);
+               }
+               if (evalbltin(cmdentry.u.cmd, argc, argv)) {
+                       int exit_status;
+                       int i, j;
+
+                       i = exception;
+                       if (i == EXEXIT)
+                               goto raise;
+
+                       exit_status = 2;
+                       j = 0;
+                       if (i == EXINT)
+                               j = SIGINT;
+                       if (i == EXSIG)
+                               j = pendingsigs;
+                       if (j)
+                               exit_status = j + 128;
+                       exitstatus = exit_status;
+
+                       if (i == EXINT || spclbltin > 0) {
+raise:
+                               longjmp(handler->loc, 1);
+                       }
+                       FORCEINTON;
+               }
+               break;
+
+       case CMDFUNCTION:
+               listsetvar(varlist.list, 0);
+               if (evalfun(cmdentry.u.func, argc, argv, flags))
+                       goto raise;
+               break;
+       }
+
+out:
+       popredir(cmd_is_exec);
+       if (lastarg)
+               /* dsl: I think this is intended to be used to support
+                * '_' in 'vi' command mode during line editing...
+                * However I implemented that within libedit itself.
+                */
+               setvar("_", lastarg, 0);
+       popstackmark(&smark);
+}
+
+static int
+evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
+       char *volatile savecmdname;
+       struct jmploc *volatile savehandler;
+       struct jmploc jmploc;
+       int i;
+
+       savecmdname = commandname;
+       if ((i = setjmp(jmploc.loc)))
+               goto cmddone;
+       savehandler = handler;
+       handler = &jmploc;
+       commandname = argv[0];
+       argptr = argv + 1;
+       optptr = NULL;                  /* initialize nextopt */
+       exitstatus = (*cmd->builtin)(argc, argv);
+       flushall();
+cmddone:
+       exitstatus |= ferror(stdout);
+       commandname = savecmdname;
+       exsig = 0;
+       handler = savehandler;
+
+       return i;
+}
+
+static int
+evalfun(struct funcnode *func, int argc, char **argv, int flags)
+{
+       volatile struct shparam saveparam;
+       struct localvar *volatile savelocalvars;
+       struct jmploc *volatile savehandler;
+       struct jmploc jmploc;
+       int e;
+
+       saveparam = shellparam;
+       savelocalvars = localvars;
+       if ((e = setjmp(jmploc.loc))) {
+               goto funcdone;
+       }
+       INTOFF;
+       savehandler = handler;
+       handler = &jmploc;
+       localvars = NULL;
+       shellparam.malloc = 0;
+       func->count++;
+       INTON;
+       shellparam.nparam = argc - 1;
+       shellparam.p = argv + 1;
+#ifdef BB_ASH_GETOPTS
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+#endif
+       funcnest++;
+       evaltree(&func->n, flags & EV_TESTED);
+       funcnest--;
+funcdone:
+       INTOFF;
+       freefunc(func);
+       poplocalvars();
+       localvars = savelocalvars;
+       freeparam(&shellparam);
+       shellparam = saveparam;
+       handler = savehandler;
+       INTON;
+       if (evalskip == SKIPFUNC) {
+               evalskip = 0;
+               skipcount = 0;
+       }
+       return e;
+}
+
+
+/*
+ * Search for a command.  This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child.
+ */
+
+static void
+prehash(union node *n)
+{
+       struct cmdentry entry;
+
+       if (n->type == NCMD && n->ncmd.args)
+               find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
+}
+
+
+
+/*
+ * Builtin commands.  Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given.
+ */
+
+static int
+bltincmd(int argc, char **argv)
+{
+       /*
+        * Preserve exitstatus of a previous possible redirection
+        * as POSIX mandates
+        */
+       return back_exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands.  Break, continue, and return are
+ * all handled by setting the evalskip flag.  The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them.  The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return.  (The latter is always 1.)  It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+static int
+breakcmd(int argc, char **argv)
+{
+       int n = argc > 1 ? number(argv[1]) : 1;
+
+       if (n <= 0)
+               error(illnum, argv[1]);
+       if (n > loopnest)
+               n = loopnest;
+       if (n > 0) {
+               evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+               skipcount = n;
+       }
+       return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+static int
+returncmd(int argc, char **argv)
+{
+       int ret = argc > 1 ? number(argv[1]) : exitstatus;
+
+       if (funcnest) {
+               evalskip = SKIPFUNC;
+               skipcount = 1;
+               return ret;
+       }
+       else {
+               /* Do what ksh does; skip the rest of the file */
+               evalskip = SKIPFILE;
+               skipcount = 1;
+               return ret;
+       }
+}
+
+
+static int
+falsecmd(int argc, char **argv)
+{
+       return 1;
+}
+
+
+static int
+truecmd(int argc, char **argv)
+{
+       return 0;
+}
+
+
+static int
+execcmd(int argc, char **argv)
+{
+       if (argc > 1) {
+               iflag = 0;              /* exit on error */
+               mflag = 0;
+               optschanged();
+               shellexec(argv + 1, pathval(), 0);
+       }
+       return 0;
+}
+
+
+/*      $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $    */
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#define CMDTABLESIZE 31         /* should be prime */
+#define ARB 1                   /* actual size determined at run time */
+
+
+
+struct tblentry {
+       struct tblentry *next;  /* next entry in hash chain */
+       union param param;      /* definition of builtin function */
+       short cmdtype;          /* index identifying command */
+       char rehash;            /* if set, cd done since entry created */
+       char cmdname[ARB];      /* name of command */
+};
+
+
+static struct tblentry *cmdtable[CMDTABLESIZE];
+static int builtinloc = -1;             /* index in path of %builtin, or -1 */
+
+
+static void tryexec(char *, char **, char **);
+static void clearcmdentry(int);
+static struct tblentry *cmdlookup(const char *, int);
+static void delete_cmd_entry(void);
+
+
+/*
+ * Exec a program.  Never returns.  If you change this routine, you may
+ * have to change the find_command routine as well.
+ */
+
+static void
+shellexec(char **argv, const char *path, int idx)
+{
+       char *cmdname;
+       int e;
+       char **envp;
+
+       clearredir(1);
+       envp = environment();
+       if (strchr(argv[0], '/') != NULL
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+               || find_applet_by_name(argv[0])
+#endif
+                                               ) {
+               tryexec(argv[0], argv, envp);
+               e = errno;
+       } else {
+               e = ENOENT;
+               while ((cmdname = padvance(&path, argv[0])) != NULL) {
+                       if (--idx < 0 && pathopt == NULL) {
+                               tryexec(cmdname, argv, envp);
+                               if (errno != ENOENT && errno != ENOTDIR)
+                                       e = errno;
+                       }
+                       stunalloc(cmdname);
+               }
+       }
+
+       /* Map to POSIX errors */
+       switch (e) {
+       case EACCES:
+               exerrno = 126;
+               break;
+       case ENOENT:
+               exerrno = 127;
+               break;
+       default:
+               exerrno = 2;
+               break;
+       }
+       TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
+               argv[0], e, suppressint ));
+       exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
+       /* NOTREACHED */
+}
+
+
+static void
+tryexec(char *cmd, char **argv, char **envp)
+{
+       int repeated = 0;
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       int flg_bb = 0;
+       char *name = cmd;
+
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       name = bb_get_last_path_component(name);
+       if(find_applet_by_name(name) != NULL)
+               flg_bb = 1;
+#else
+       if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
+               flg_bb = 1;
+       }
+#endif
+       if(flg_bb) {
+               char **ap;
+               char **new;
+
+               *argv = name;
+               if(strcmp(name, "busybox")) {
+                       for (ap = argv; *ap; ap++);
+                       ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
+                       *ap++ = cmd = "/bin/busybox";
+                       while ((*ap++ = *argv++));
+                       argv = new;
+                       repeated++;
+               } else {
+                       cmd = "/bin/busybox";
+               }
+       }
+#endif
+
+repeat:
+#ifdef SYSV
+       do {
+               execve(cmd, argv, envp);
+       } while (errno == EINTR);
+#else
+       execve(cmd, argv, envp);
+#endif
+       if (repeated++) {
+               ckfree(argv);
+       } else if (errno == ENOEXEC) {
+               char **ap;
+               char **new;
+
+               for (ap = argv; *ap; ap++)
+                       ;
+               ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
+               ap[1] = cmd;
+               *ap = cmd = (char *)"/bin/sh";
+               ap += 2;
+               argv++;
+               while ((*ap++ = *argv++))
+                       ;
+               argv = new;
+               goto repeat;
+       }
+}
+
+
+
+/*
+ * Do a path search.  The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds.  Successive calls to padvance will return
+ * the possible path expansions in sequence.  If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+static char *
+padvance(const char **path, const char *name)
+{
+       const char *p;
+       char *q;
+       const char *start;
+       size_t len;
+
+       if (*path == NULL)
+               return NULL;
+       start = *path;
+       for (p = start ; *p && *p != ':' && *p != '%' ; p++);
+       len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
+       while (stackblocksize() < len)
+               growstackblock();
+       q = stackblock();
+       if (p != start) {
+               memcpy(q, start, p - start);
+               q += p - start;
+               *q++ = '/';
+       }
+       strcpy(q, name);
+       pathopt = NULL;
+       if (*p == '%') {
+               pathopt = ++p;
+               while (*p && *p != ':')  p++;
+       }
+       if (*p == ':')
+               *path = p + 1;
+       else
+               *path = NULL;
+       return stalloc(len);
+}
+
+
+/*** Command hashing code ***/
+
+static void
+printentry(struct tblentry *cmdp)
+{
+       int idx;
+       const char *path;
+       char *name;
+
+       idx = cmdp->param.index;
+       path = pathval();
+       do {
+               name = padvance(&path, cmdp->cmdname);
+               stunalloc(name);
+       } while (--idx >= 0);
+       out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
+}
+
+
+static int
+hashcmd(int argc, char **argv)
+{
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+       int c;
+       struct cmdentry entry;
+       char *name;
+
+       while ((c = nextopt("r")) != '\0') {
+               clearcmdentry(0);
+               return 0;
+       }
+       if (*argptr == NULL) {
+               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+                               if (cmdp->cmdtype == CMDNORMAL)
+                                       printentry(cmdp);
+                       }
+               }
+               return 0;
+       }
+       c = 0;
+       while ((name = *argptr) != NULL) {
+               if ((cmdp = cmdlookup(name, 0)) != NULL
+                && (cmdp->cmdtype == CMDNORMAL
+                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
+                       delete_cmd_entry();
+               find_command(name, &entry, DO_ERR, pathval());
+               if (entry.cmdtype == CMDUNKNOWN)
+                       c = 1;
+               argptr++;
+       }
+       return c;
+}
+
+
+/*
+ * Resolve a command name.  If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+static void
+find_command(char *name, struct cmdentry *entry, int act, const char *path)
+{
+       struct tblentry *cmdp;
+       int idx;
+       int prev;
+       char *fullname;
+       struct stat statb;
+       int e;
+       int updatetbl;
+       struct builtincmd *bcmd;
+
+       /* If name contains a slash, don't use PATH or hash table */
+       if (strchr(name, '/') != NULL) {
+               entry->u.index = -1;
+               if (act & DO_ABS) {
+                       while (stat(name, &statb) < 0) {
+#ifdef SYSV
+                               if (errno == EINTR)
+                                       continue;
+#endif
+                               entry->cmdtype = CMDUNKNOWN;
+                               return;
+                       }
+               }
+               entry->cmdtype = CMDNORMAL;
+               return;
+       }
+
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       if (find_applet_by_name(name)) {
+               entry->cmdtype = CMDNORMAL;
+               entry->u.index = -1;
+               return;
+       }
+#endif
+
+       updatetbl = (path == pathval());
+       if (!updatetbl) {
+               act |= DO_ALTPATH;
+               if (strstr(path, "%builtin") != NULL)
+                       act |= DO_ALTBLTIN;
+       }
+
+       /* If name is in the table, check answer will be ok */
+       if ((cmdp = cmdlookup(name, 0)) != NULL) {
+               int bit;
+
+               switch (cmdp->cmdtype) {
+               default:
+#if DEBUG
+                       abort();
+#endif
+               case CMDNORMAL:
+                       bit = DO_ALTPATH;
+                       break;
+               case CMDFUNCTION:
+                       bit = DO_NOFUNC;
+                       break;
+               case CMDBUILTIN:
+                       bit = DO_ALTBLTIN;
+                       break;
+               }
+               if (act & bit) {
+                       updatetbl = 0;
+                       cmdp = NULL;
+               } else if (cmdp->rehash == 0)
+                       /* if not invalidated by cd, we're done */
+                       goto success;
+       }
+
+       /* If %builtin not in path, check for builtin next */
+       bcmd = find_builtin(name);
+       if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
+               act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
+       )))
+               goto builtin_success;
+
+       /* We have to search path. */
+       prev = -1;              /* where to start */
+       if (cmdp && cmdp->rehash) {     /* doing a rehash */
+               if (cmdp->cmdtype == CMDBUILTIN)
+                       prev = builtinloc;
+               else
+                       prev = cmdp->param.index;
+       }
+
+       e = ENOENT;
+       idx = -1;
+loop:
+       while ((fullname = padvance(&path, name)) != NULL) {
+               stunalloc(fullname);
+               idx++;
+               if (pathopt) {
+                       if (prefix(pathopt, "builtin")) {
+                               if (bcmd)
+                                       goto builtin_success;
+                               continue;
+                       } else if (!(act & DO_NOFUNC) &&
+                                  prefix(pathopt, "func")) {
+                               /* handled below */
+                       } else {
+                               /* ignore unimplemented options */
+                               continue;
+                       }
+               }
+               /* if rehash, don't redo absolute path names */
+               if (fullname[0] == '/' && idx <= prev) {
+                       if (idx < prev)
+                               continue;
+                       TRACE(("searchexec \"%s\": no change\n", name));
+                       goto success;
+               }
+               while (stat(fullname, &statb) < 0) {
+#ifdef SYSV
+                       if (errno == EINTR)
+                               continue;
+#endif
+                       if (errno != ENOENT && errno != ENOTDIR)
+                               e = errno;
+                       goto loop;
+               }
+               e = EACCES;     /* if we fail, this will be the error */
+               if (!S_ISREG(statb.st_mode))
+                       continue;
+               if (pathopt) {          /* this is a %func directory */
+                       stalloc(strlen(fullname) + 1);
+                       readcmdfile(fullname);
+                       if ((cmdp = cmdlookup(name, 0)) == NULL ||
+                           cmdp->cmdtype != CMDFUNCTION)
+                               error("%s not defined in %s", name, fullname);
+                       stunalloc(fullname);
+                       goto success;
+               }
+               TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+               if (!updatetbl) {
+                       entry->cmdtype = CMDNORMAL;
+                       entry->u.index = idx;
+                       return;
+               }
+               INTOFF;
+               cmdp = cmdlookup(name, 1);
+               cmdp->cmdtype = CMDNORMAL;
+               cmdp->param.index = idx;
+               INTON;
+               goto success;
+       }
+
+       /* We failed.  If there was an entry for this command, delete it */
+       if (cmdp && updatetbl)
+               delete_cmd_entry();
+       if (act & DO_ERR)
+               sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
+       entry->cmdtype = CMDUNKNOWN;
+       return;
+
+builtin_success:
+       if (!updatetbl) {
+               entry->cmdtype = CMDBUILTIN;
+               entry->u.cmd = bcmd;
+               return;
+       }
+       INTOFF;
+       cmdp = cmdlookup(name, 1);
+       cmdp->cmdtype = CMDBUILTIN;
+       cmdp->param.cmd = bcmd;
+       INTON;
+success:
+       cmdp->rehash = 0;
+       entry->cmdtype = cmdp->cmdtype;
+       entry->u = cmdp->param;
+}
+
+
+/*
+ * Wrapper around strcmp for qsort/bsearch/...
+ */
+static int pstrcmp(const void *a, const void *b)
+{
+       return strcmp((const char *) a, (*(const char *const *) b) + 1);
+}
+
+/*
+ * Search the table of builtin commands.
+ */
+
+static struct builtincmd *
+find_builtin(const char *name)
+{
+       struct builtincmd *bp;
+
+       bp = bsearch(
+               name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
+               pstrcmp
+       );
+       return bp;
+}
+
+
+
+/*
+ * Called when a cd is done.  Marks all commands so the next time they
+ * are executed they will be rehashed.
+ */
+
+static void
+hashcd(void)
+{
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+
+       for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+               for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+                       if (cmdp->cmdtype == CMDNORMAL || (
+                               cmdp->cmdtype == CMDBUILTIN &&
+                               !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
+                               builtinloc > 0
+                       ))
+                               cmdp->rehash = 1;
+               }
+       }
+}
+
+
+
+/*
+ * Fix command hash table when PATH changed.
+ * Called before PATH is changed.  The argument is the new value of PATH;
+ * pathval() still returns the old value at this point.
+ * Called with interrupts off.
+ */
+
+static void
+changepath(const char *newval)
+{
+       const char *old, *new;
+       int idx;
+       int firstchange;
+       int idx_bltin;
+
+       old = pathval();
+       new = newval;
+       firstchange = 9999;     /* assume no change */
+       idx = 0;
+       idx_bltin = -1;
+       for (;;) {
+               if (*old != *new) {
+                       firstchange = idx;
+                       if ((*old == '\0' && *new == ':')
+                        || (*old == ':' && *new == '\0'))
+                               firstchange++;
+                       old = new;      /* ignore subsequent differences */
+               }
+               if (*new == '\0')
+                       break;
+               if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
+                       idx_bltin = idx;
+               if (*new == ':') {
+                       idx++;
+               }
+               new++, old++;
+       }
+       if (builtinloc < 0 && idx_bltin >= 0)
+               builtinloc = idx_bltin;             /* zap builtins */
+       if (builtinloc >= 0 && idx_bltin < 0)
+               firstchange = 0;
+       clearcmdentry(firstchange);
+       builtinloc = idx_bltin;
+}
+
+
+/*
+ * Clear out command entries.  The argument specifies the first entry in
+ * PATH which has changed.
+ */
+
+static void
+clearcmdentry(int firstchange)
+{
+       struct tblentry **tblp;
+       struct tblentry **pp;
+       struct tblentry *cmdp;
+
+       INTOFF;
+       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+               pp = tblp;
+               while ((cmdp = *pp) != NULL) {
+                       if ((cmdp->cmdtype == CMDNORMAL &&
+                            cmdp->param.index >= firstchange)
+                        || (cmdp->cmdtype == CMDBUILTIN &&
+                            builtinloc >= firstchange)) {
+                               *pp = cmdp->next;
+                               ckfree(cmdp);
+                       } else {
+                               pp = &cmdp->next;
+                       }
+               }
+       }
+       INTON;
+}
+
+
+
+/*
+ * Locate a command in the command hash table.  If "add" is nonzero,
+ * add the command to the table if it is not already present.  The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ *
+ * Interrupts must be off if called with add != 0.
+ */
+
+static struct tblentry **lastcmdentry;
+
+
+static struct tblentry *
+cmdlookup(const char *name, int add)
+{
+       unsigned int hashval;
+       const char *p;
+       struct tblentry *cmdp;
+       struct tblentry **pp;
+
+       p = name;
+       hashval = (unsigned char)*p << 4;
+       while (*p)
+               hashval += (unsigned char)*p++;
+       hashval &= 0x7FFF;
+       pp = &cmdtable[hashval % CMDTABLESIZE];
+       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+               if (equal(cmdp->cmdname, name))
+                       break;
+               pp = &cmdp->next;
+       }
+       if (add && cmdp == NULL) {
+               cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+                                       + strlen(name) + 1);
+               cmdp->next = NULL;
+               cmdp->cmdtype = CMDUNKNOWN;
+               strcpy(cmdp->cmdname, name);
+       }
+       lastcmdentry = pp;
+       return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+static void
+delete_cmd_entry(void)
+{
+       struct tblentry *cmdp;
+
+       INTOFF;
+       cmdp = *lastcmdentry;
+       *lastcmdentry = cmdp->next;
+       if (cmdp->cmdtype == CMDFUNCTION)
+               freefunc(cmdp->param.func);
+       ckfree(cmdp);
+       INTON;
+}
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name - except special builtins.
+ */
+
+static inline void
+addcmdentry(char *name, struct cmdentry *entry)
+{
+       struct tblentry *cmdp;
+
+       cmdp = cmdlookup(name, 1);
+       if (cmdp->cmdtype == CMDFUNCTION) {
+               freefunc(cmdp->param.func);
+       }
+       cmdp->cmdtype = entry->cmdtype;
+       cmdp->param = entry->u;
+       cmdp->rehash = 0;
+}
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+static inline struct funcnode *
+copyfunc(union node *n)
+{
+       struct funcnode *f;
+       size_t blocksize;
+
+       funcblocksize = offsetof(struct funcnode, n);
+       funcstringsize = 0;
+       calcsize(n);
+       blocksize = funcblocksize;
+       f = ckmalloc(blocksize + funcstringsize);
+       funcblock = (char *) f + offsetof(struct funcnode, n);
+       funcstring = (char *) f + blocksize;
+       copynode(n);
+       f->count = 0;
+       return f;
+}
+
+/*
+ * Define a shell function.
+ */
+
+static void
+defun(char *name, union node *func)
+{
+       struct cmdentry entry;
+
+       INTOFF;
+       entry.cmdtype = CMDFUNCTION;
+       entry.u.func = copyfunc(func);
+       addcmdentry(name, &entry);
+       INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ */
+
+static void
+unsetfunc(const char *name)
+{
+       struct tblentry *cmdp;
+
+       if ((cmdp = cmdlookup(name, 0)) != NULL &&
+           cmdp->cmdtype == CMDFUNCTION)
+               delete_cmd_entry();
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+
+#ifdef BB_ASH_CMDCMD
+static int
+describe_command(char *command, int describe_command_verbose)
+#else
+#define describe_command_verbose 1
+static int
+describe_command(char *command)
+#endif
+{
+       struct cmdentry entry;
+       struct tblentry *cmdp;
+#ifdef BB_ASH_ALIAS
+       const struct alias *ap;
+#endif
+       const char *path = pathval();
+
+       if (describe_command_verbose) {
+               out1str(command);
+       }
+
+       /* First look at the keywords */
+       if (findkwd(command)) {
+               out1str(describe_command_verbose ? " is a shell keyword" : command);
+               goto out;
+       }
+
+#ifdef BB_ASH_ALIAS
+       /* Then look at the aliases */
+       if ((ap = lookupalias(command, 0)) != NULL) {
+               if (describe_command_verbose) {
+                       out1fmt(" is an alias for %s", ap->val);
+               } else {
+                       out1str("alias ");
+                       printalias(ap);
+                       return 0;
+               }
+               goto out;
+       }
+#endif
+       /* Then check if it is a tracked alias */
+       if ((cmdp = cmdlookup(command, 0)) != NULL) {
+               entry.cmdtype = cmdp->cmdtype;
+               entry.u = cmdp->param;
+       } else {
+               /* Finally use brute force */
+               find_command(command, &entry, DO_ABS, path);
+       }
+
+       switch (entry.cmdtype) {
+       case CMDNORMAL: {
+               int j = entry.u.index;
+               char *p;
+               if (j == -1) {
+                       p = command;
+               } else {
+                       do {
+                               p = padvance(&path, command);
+                               stunalloc(p);
+                       } while (--j >= 0);
+               }
+               if (describe_command_verbose) {
+                       out1fmt(" is%s %s",
+                               (cmdp ? " a tracked alias for" : nullstr), p
+                       );
+               } else {
+                       out1str(p);
+               }
+               break;
+       }
+
+       case CMDFUNCTION:
+               if (describe_command_verbose) {
+                       out1str(" is a shell function");
+               } else {
+                       out1str(command);
+               }
+               break;
+
+       case CMDBUILTIN:
+               if (describe_command_verbose) {
+                       out1fmt(" is a %sshell builtin",
+                               IS_BUILTIN_SPECIAL(entry.u.cmd) ?
+                                       "special " : nullstr
+                       );
+               } else {
+                       out1str(command);
+               }
+               break;
+
+       default:
+               if (describe_command_verbose) {
+                       out1str(": not found\n");
+               }
+               return 127;
+       }
+
+out:
+       outstr("\n", stdout);
+       return 0;
+}
+
+static int
+typecmd(int argc, char **argv)
+{
+       int i;
+       int err = 0;
+
+       for (i = 1; i < argc; i++) {
+#ifdef BB_ASH_CMDCMD
+               err |= describe_command(argv[i], 1);
+#else
+               err |= describe_command(argv[i]);
+#endif
+       }
+       return err;
+}
+
+#ifdef BB_ASH_CMDCMD
+static int
+commandcmd(int argc, char **argv)
+{
+       int c;
+       int default_path = 0;
+       int verify_only = 0;
+       int verbose_verify_only = 0;
+
+       while ((c = nextopt("pvV")) != '\0')
+               switch (c) {
+               default:
+#ifdef DEBUG
+                       fprintf(stderr,
+"command: nextopt returned character code 0%o\n", c);
+                       return EX_SOFTWARE;
+#endif
+               case 'p':
+                       default_path = 1;
+                       break;
+               case 'v':
+                       verify_only = 1;
+                       break;
+               case 'V':
+                       verbose_verify_only = 1;
+                       break;
+               }
+
+       if (default_path + verify_only + verbose_verify_only > 1 ||
+           !*argptr) {
+                       fprintf(stderr,
+                               "command [-p] command [arg ...]\n"
+                               "command {-v|-V} command\n");
+                       return EX_USAGE;
+       }
+
+       if (verify_only || verbose_verify_only) {
+               return describe_command(*argptr, verbose_verify_only);
+       }
+
+       return 0;
+}
+#endif
+
+/*      $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $     */
+
+/*
+ * Routines to expand arguments to commands.  We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+/*
+ * _rmescape() flags
+ */
+#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
+#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
+#define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
+#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
+#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
+
+/*
+ * Structure specifying which parts of the string should be searched
+ * for IFS characters.
+ */
+
+struct ifsregion {
+       struct ifsregion *next; /* next region in list */
+       int begoff;             /* offset of start of region */
+       int endoff;             /* offset of end of region */
+       int nulonly;            /* search for nul bytes only */
+};
+
+/* output of current string */
+static char *expdest;
+/* list of back quote expressions */
+static struct nodelist *argbackq;
+/* first struct in list of ifs regions */
+static struct ifsregion ifsfirst;
+/* last struct in list */
+static struct ifsregion *ifslastp;
+/* holds expanded arg list */
+static struct arglist exparg;
+
+static void argstr(char *, int);
+static char *exptilde(char *, char *, int);
+static void expbackq(union node *, int, int);
+static const char *subevalvar(char *, char *, int, int, int, int, int);
+static char *evalvar(char *, int);
+static int varisset(char *, int);
+static void strtodest(const char *, int, int);
+static void memtodest(const char *p, size_t len, int syntax, int quotes);
+static void varvalue(char *, int, int);
+static void recordregion(int, int, int);
+static void removerecordregions(int);
+static void ifsbreakup(char *, struct arglist *);
+static void ifsfree(void);
+static void expandmeta(struct strlist *, int);
+static int patmatch(char *, const char *);
+
+static int cvtnum(long);
+static size_t esclen(const char *, const char *);
+static char *scanleft(char *, char *, char *, char *, int, int);
+static char *scanright(char *, char *, char *, char *, int, int);
+static void varunset(const char *, const char *, const char *, int)
+       __attribute__((__noreturn__));
+
+
+#define pmatch(a, b) !fnmatch((a), (b), 0)
+/*
+ * Prepare a pattern for a expmeta (internal glob(3)) call.
+ *
+ * Returns an stalloced string.
+ */
+
+static inline char *
+preglob(const char *pattern, int quoted, int flag) {
+       flag |= RMESCAPE_GLOB;
+       if (quoted) {
+               flag |= RMESCAPE_QUOTED;
+       }
+       return _rmescapes((char *)pattern, flag);
+}
+
+
+static size_t
+esclen(const char *start, const char *p) {
+       size_t esc = 0;
+
+       while (p > start && *--p == CTLESC) {
+               esc++;
+       }
+       return esc;
+}
+
+
+/*
+ * Expand shell variables and backquotes inside a here document.
+ */
+
+static inline void
+expandhere(union node *arg, int fd)
+{
+       herefd = fd;
+       expandarg(arg, (struct arglist *)NULL, 0);
+       xwrite(fd, stackblock(), expdest - (char *)stackblock());
+}
+
+
+/*
+ * Perform variable substitution and command substitution on an argument,
+ * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
+ * perform splitting and file name expansion.  When arglist is NULL, perform
+ * here document expansion.
+ */
+
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+       struct strlist *sp;
+       char *p;
+
+       argbackq = arg->narg.backquote;
+       STARTSTACKSTR(expdest);
+       ifsfirst.next = NULL;
+       ifslastp = NULL;
+       argstr(arg->narg.text, flag);
+       if (arglist == NULL) {
+               return;                 /* here document expanded */
+       }
+       STPUTC('\0', expdest);
+       p = grabstackstr(expdest);
+       exparg.lastp = &exparg.list;
+       /*
+        * TODO - EXP_REDIR
+        */
+       if (flag & EXP_FULL) {
+               ifsbreakup(p, &exparg);
+               *exparg.lastp = NULL;
+               exparg.lastp = &exparg.list;
+               expandmeta(exparg.list, flag);
+       } else {
+               if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
+                       rmescapes(p);
+               sp = (struct strlist *)stalloc(sizeof (struct strlist));
+               sp->text = p;
+               *exparg.lastp = sp;
+               exparg.lastp = &sp->next;
+       }
+       if (ifsfirst.next)
+               ifsfree();
+       *exparg.lastp = NULL;
+       if (exparg.list) {
+               *arglist->lastp = exparg.list;
+               arglist->lastp = exparg.lastp;
+       }
+}
+
+
+/*
+ * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing.  Otherwise treat
+ * $@ like $* since no splitting will be performed.
+ */
+
+static void
+argstr(char *p, int flag)
+{
+       static const char spclchars[] = {
+               '=',
+               ':',
+               CTLQUOTEMARK,
+               CTLENDVAR,
+               CTLESC,
+               CTLVAR,
+               CTLBACKQ,
+               CTLBACKQ | CTLQUOTE,
+#ifdef BB_ASH_MATH_SUPPORT
+               CTLENDARI,
+#endif
+               0
+       };
+       const char *reject = spclchars;
+       int c;
+       int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
+       int breakall = flag & EXP_WORD;
+       int inquotes;
+       size_t length;
+       int startloc;
+
+       if (!(flag & EXP_VARTILDE)) {
+               reject += 2;
+       } else if (flag & EXP_VARTILDE2) {
+               reject++;
+       }
+       inquotes = 0;
+       length = 0;
+       if (flag & EXP_TILDE) {
+               char *q;
+
+               flag &= ~EXP_TILDE;
+tilde:
+               q = p;
+               if (*q == CTLESC && (flag & EXP_QWORD))
+                       q++;
+               if (*q == '~')
+                       p = exptilde(p, q, flag);
+       }
+start:
+       startloc = expdest - (char *)stackblock();
+       for (;;) {
+               length += strcspn(p + length, reject);
+               c = p[length];
+               if (c && (!(c & 0x80)
+#ifdef BB_ASH_MATH_SUPPORT
+                                       || c == CTLENDARI
+#endif
+                  )) {
+                       /* c == '=' || c == ':' || c == CTLENDARI */
+                       length++;
+               }
+               if (length > 0) {
+                       int newloc;
+                       expdest = stnputs(p, length, expdest);
+                       newloc = expdest - (char *)stackblock();
+                       if (breakall && !inquotes && newloc > startloc) {
+                               recordregion(startloc, newloc, 0);
+                       }
+                       startloc = newloc;
+               }
+               p += length + 1;
+               length = 0;
+
+               switch (c) {
+               case '\0':
+                       goto breakloop;
+               case '=':
+                       if (flag & EXP_VARTILDE2) {
+                               p--;
+                               continue;
+                       }
+                       flag |= EXP_VARTILDE2;
+                       reject++;
+                       /* fall through */
+               case ':':
+                       /*
+                        * sort of a hack - expand tildes in variable
+                        * assignments (after the first '=' and after ':'s).
+                        */
+                       if (*--p == '~') {
+                               goto tilde;
+                       }
+                       continue;
+               }
+
+               switch (c) {
+               case CTLENDVAR: /* ??? */
+                       goto breakloop;
+               case CTLQUOTEMARK:
+                       /* "$@" syntax adherence hack */
+                       if (
+                               !inquotes &&
+                               !memcmp(p, dolatstr, DOLATSTRLEN) &&
+                               (p[4] == CTLQUOTEMARK || (
+                                       p[4] == CTLENDVAR &&
+                                       p[5] == CTLQUOTEMARK
+                               ))
+                       ) {
+                               p = evalvar(p + 1, flag) + 1;
+                               goto start;
+                       }
+                       inquotes = !inquotes;
+addquote:
+                       if (quotes) {
+                               p--;
+                               length++;
+                               startloc++;
+                       }
+                       break;
+               case CTLESC:
+                       startloc++;
+                       length++;
+                       goto addquote;
+               case CTLVAR:
+                       p = evalvar(p, flag);
+                       goto start;
+               case CTLBACKQ:
+                       c = 0;
+               case CTLBACKQ|CTLQUOTE:
+                       expbackq(argbackq->n, c, quotes);
+                       argbackq = argbackq->next;
+                       goto start;
+#ifdef BB_ASH_MATH_SUPPORT
+               case CTLENDARI:
+                       p--;
+                       expari(quotes);
+                       goto start;
+#endif
+               }
+       }
+breakloop:
+       ;
+}
+
+static char *
+exptilde(char *startp, char *p, int flag)
+{
+       char c;
+       char *name;
+       struct passwd *pw;
+       const char *home;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
+       int startloc;
+
+       name = p + 1;
+
+       while ((c = *++p) != '\0') {
+               switch(c) {
+               case CTLESC:
+                       return (startp);
+               case CTLQUOTEMARK:
+                       return (startp);
+               case ':':
+                       if (flag & EXP_VARTILDE)
+                               goto done;
+                       break;
+               case '/':
+               case CTLENDVAR:
+                       goto done;
+               }
+       }
+done:
+       *p = '\0';
+       if (*name == '\0') {
+               if ((home = lookupvar(homestr)) == NULL)
+                       goto lose;
+       } else {
+               if ((pw = getpwnam(name)) == NULL)
+                       goto lose;
+               home = pw->pw_dir;
+       }
+       if (*home == '\0')
+               goto lose;
+       *p = c;
+       startloc = expdest - (char *)stackblock();
+       strtodest(home, SQSYNTAX, quotes);
+       recordregion(startloc, expdest - (char *)stackblock(), 0);
+       return (p);
+lose:
+       *p = c;
+       return (startp);
+}
+
+
+static void
+removerecordregions(int endoff)
+{
+       if (ifslastp == NULL)
+               return;
+
+       if (ifsfirst.endoff > endoff) {
+               while (ifsfirst.next != NULL) {
+                       struct ifsregion *ifsp;
+                       INTOFF;
+                       ifsp = ifsfirst.next->next;
+                       ckfree(ifsfirst.next);
+                       ifsfirst.next = ifsp;
+                       INTON;
+               }
+               if (ifsfirst.begoff > endoff)
+                       ifslastp = NULL;
+               else {
+                       ifslastp = &ifsfirst;
+                       ifsfirst.endoff = endoff;
+               }
+               return;
+       }
+
+       ifslastp = &ifsfirst;
+       while (ifslastp->next && ifslastp->next->begoff < endoff)
+               ifslastp=ifslastp->next;
+       while (ifslastp->next != NULL) {
+               struct ifsregion *ifsp;
+               INTOFF;
+               ifsp = ifslastp->next->next;
+               ckfree(ifslastp->next);
+               ifslastp->next = ifsp;
+               INTON;
+       }
+       if (ifslastp->endoff > endoff)
+               ifslastp->endoff = endoff;
+}
+
+
+#ifdef BB_ASH_MATH_SUPPORT
+/*
+ * Expand arithmetic expression.  Backup to start of expression,
+ * evaluate, place result in (backed up) result, adjust string position.
+ */
+void
+expari(int quotes)
+{
+       char *p, *start;
+       int begoff;
+       int flag;
+       int len;
+
+       /*      ifsfree(); */
+
+       /*
+        * This routine is slightly over-complicated for
+        * efficiency.  Next we scan backwards looking for the
+        * start of arithmetic.
+        */
+       start = stackblock();
+       p = expdest - 1;
+       *p = '\0';
+       p--;
+       do {
+               int esc;
+
+               while (*p != CTLARI) {
+                       p--;
+#ifdef DEBUG
+                       if (p < start) {
+                               error("missing CTLARI (shouldn't happen)");
+                       }
+#endif
+               }
+
+               esc = esclen(start, p);
+               if (!(esc % 2)) {
+                       break;
+               }
+
+               p -= esc + 1;
+       } while (1);
+
+       begoff = p - start;
+
+       removerecordregions(begoff);
+
+       flag = p[1];
+
+       expdest = p;
+
+       if (quotes)
+               rmescapes(p + 2);
+
+       len = cvtnum(dash_arith(p + 2));
+
+       if (flag != '"')
+               recordregion(begoff, begoff + len, 0);
+}
+#endif
+
+/*
+ * Expand stuff in backwards quotes.
+ */
+
+static void
+expbackq(union node *cmd, int quoted, int quotes)
+{
+       struct backcmd in;
+       int i;
+       char buf[128];
+       char *p;
+       char *dest;
+       int startloc;
+       int syntax = quoted? DQSYNTAX : BASESYNTAX;
+       struct stackmark smark;
+
+       INTOFF;
+       setstackmark(&smark);
+       dest = expdest;
+       startloc = dest - (char *)stackblock();
+       grabstackstr(dest);
+       evalbackcmd(cmd, (struct backcmd *) &in);
+       popstackmark(&smark);
+
+       p = in.buf;
+       i = in.nleft;
+       if (i == 0)
+               goto read;
+       for (;;) {
+               memtodest(p, i, syntax, quotes);
+read:
+               if (in.fd < 0)
+                       break;
+               i = safe_read(in.fd, buf, sizeof buf);
+               TRACE(("expbackq: read returns %d\n", i));
+               if (i <= 0)
+                       break;
+               p = buf;
+       }
+
+       if (in.buf)
+               ckfree(in.buf);
+       if (in.fd >= 0) {
+               close(in.fd);
+               back_exitstatus = waitforjob(in.jp);
+       }
+       INTON;
+
+       /* Eat all trailing newlines */
+       dest = expdest;
+       for (; dest > (char *)stackblock() && dest[-1] == '\n';)
+               STUNPUTC(dest);
+       expdest = dest;
+
+       if (quoted == 0)
+               recordregion(startloc, dest - (char *)stackblock(), 0);
+       TRACE(("evalbackq: size=%d: \"%.*s\"\n",
+               (dest - (char *)stackblock()) - startloc,
+               (dest - (char *)stackblock()) - startloc,
+               stackblock() + startloc));
+}
+
+
+static char *
+scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+       int zero)
+{
+       char *loc;
+       char *loc2;
+       char c;
+
+       loc = startp;
+       loc2 = rmesc;
+       do {
+               int match;
+               const char *s = loc2;
+               c = *loc2;
+               if (zero) {
+                       *loc2 = '\0';
+                       s = rmesc;
+               }
+               match = pmatch(str, s);
+               *loc2 = c;
+               if (match)
+                       return loc;
+               if (quotes && *loc == CTLESC)
+                       loc++;
+               loc++;
+               loc2++;
+       } while (c);
+       return 0;
+}
+
+
+static char *
+scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+       int zero)
+{
+       int esc = 0;
+       char *loc;
+       char *loc2;
+
+       for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
+               int match;
+               char c = *loc2;
+               const char *s = loc2;
+               if (zero) {
+                       *loc2 = '\0';
+                       s = rmesc;
+               }
+               match = pmatch(str, s);
+               *loc2 = c;
+               if (match)
+                       return loc;
+               loc--;
+               if (quotes) {
+                       if (--esc < 0) {
+                               esc = esclen(startp, loc);
+                       }
+                       if (esc % 2) {
+                               esc--;
+                               loc--;
+                       }
+               }
+       }
+       return 0;
+}
+
+static const char *
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
+{
+       char *startp;
+       char *loc;
+       int saveherefd = herefd;
+       struct nodelist *saveargbackq = argbackq;
+       int amount;
+       char *rmesc, *rmescend;
+       int zero;
+       char *(*scan)(char *, char *, char *, char *, int , int);
+
+       herefd = -1;
+       argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
+       STPUTC('\0', expdest);
+       herefd = saveherefd;
+       argbackq = saveargbackq;
+       startp = stackblock() + startloc;
+
+       switch (subtype) {
+       case VSASSIGN:
+               setvar(str, startp, 0);
+               amount = startp - expdest;
+               STADJUST(amount, expdest);
+               return startp;
+
+       case VSQUESTION:
+               varunset(p, str, startp, varflags);
+               /* NOTREACHED */
+       }
+
+       subtype -= VSTRIMRIGHT;
+#ifdef DEBUG
+       if (subtype < 0 || subtype > 3)
+               abort();
+#endif
+
+       rmesc = startp;
+       rmescend = stackblock() + strloc;
+       if (quotes) {
+               rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+               if (rmesc != startp) {
+                       rmescend = expdest;
+                       startp = stackblock() + startloc;
+               }
+       }
+       rmescend--;
+       str = stackblock() + strloc;
+       preglob(str, varflags & VSQUOTE, 0);
+
+       /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
+       zero = subtype >> 1;
+       /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
+       scan = (subtype & 1) ^ zero ? scanleft : scanright;
+
+       loc = scan(startp, rmesc, rmescend, str, quotes, zero);
+       if (loc) {
+               if (zero) {
+                       memmove(startp, loc, str - loc);
+                       loc = startp + (str - loc) - 1;
+               }
+               *loc = '\0';
+               amount = loc - expdest;
+               STADJUST(amount, expdest);
+       }
+       return loc;
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+static char *
+evalvar(char *p, int flag)
+{
+       int subtype;
+       int varflags;
+       char *var;
+       int patloc;
+       int c;
+       int set;
+       int startloc;
+       size_t varlen;
+       int easy;
+       int quotes;
+       int quoted;
+
+       quotes = flag & (EXP_FULL | EXP_CASE);
+       varflags = *p++;
+       subtype = varflags & VSTYPE;
+       quoted = varflags & VSQUOTE;
+       var = p;
+       easy = (!quoted || (*var == '@' && shellparam.nparam));
+       varlen = 0;
+       startloc = expdest - (char *)stackblock();
+       p = strchr(p, '=') + 1;
+
+       if (!is_name(*var)) {
+               set = varisset(var, varflags & VSNUL);
+               set--;
+               if (subtype == VSPLUS)
+                       goto vsplus;
+               if (++set) {
+                       varvalue(var, quoted, flag);
+                       if (subtype == VSLENGTH) {
+                               varlen =
+                                       expdest - (char *)stackblock() -
+                                       startloc;
+                               STADJUST(-varlen, expdest);
+                               goto vslen;
+                       }
+               }
+       } else {
+               const char *val;
+again:
+               /* jump here after setting a variable with ${var=text} */
+               val = lookupvar(var);
+               set = !val || ((varflags & VSNUL) && !*val);
+               if (subtype == VSPLUS)
+                       goto vsplus;
+               if (--set) {
+                       varlen = strlen(val);
+                       if (subtype == VSLENGTH)
+                               goto vslen;
+                       memtodest(
+                               val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
+                               quotes
+                       );
+               }
+       }
+
+
+       if (subtype == VSMINUS) {
+vsplus:
+               if (!set) {
+                       argstr(
+                               p, flag | EXP_TILDE |
+                                       (quoted ?  EXP_QWORD : EXP_WORD)
+                       );
+                       goto end;
+               }
+               if (easy)
+                       goto record;
+               goto end;
+       }
+
+       if (subtype == VSASSIGN || subtype == VSQUESTION) {
+               if (!set) {
+                       if (subevalvar(p, var, 0, subtype, startloc,
+                                      varflags, 0)) {
+                               varflags &= ~VSNUL;
+                               /*
+                                * Remove any recorded regions beyond
+                                * start of variable
+                                */
+                               removerecordregions(startloc);
+                               goto again;
+                       }
+                       goto end;
+               }
+               if (easy)
+                       goto record;
+               goto end;
+       }
+
+       if (!set && uflag)
+               varunset(p, var, 0, 0);
+
+       if (subtype == VSLENGTH) {
+vslen:
+               cvtnum(varlen);
+               goto record;
+       }
+
+       if (subtype == VSNORMAL) {
+               if (!easy)
+                       goto end;
+record:
+               recordregion(startloc, expdest - (char *)stackblock(), quoted);
+               goto end;
+       }
+
+#ifdef DEBUG
+       switch (subtype) {
+       case VSTRIMLEFT:
+       case VSTRIMLEFTMAX:
+       case VSTRIMRIGHT:
+       case VSTRIMRIGHTMAX:
+               break;
+       default:
+               abort();
+       }
+#endif
+
+       if (set) {
+               /*
+                * Terminate the string and start recording the pattern
+                * right after it
+                */
+               STPUTC('\0', expdest);
+               patloc = expdest - (char *)stackblock();
+               if (subevalvar(p, NULL, patloc, subtype,
+                              startloc, varflags, quotes) == 0) {
+                       int amount = expdest - (
+                               (char *)stackblock() + patloc - 1
+                       );
+                       STADJUST(-amount, expdest);
+               }
+               /* Remove any recorded regions beyond start of variable */
+               removerecordregions(startloc);
+               goto record;
+       }
+
+end:
+       if (subtype != VSNORMAL) {      /* skip to end of alternative */
+               int nesting = 1;
+               for (;;) {
+                       if ((c = *p++) == CTLESC)
+                               p++;
+                       else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
+                               if (set)
+                                       argbackq = argbackq->next;
+                       } else if (c == CTLVAR) {
+                               if ((*p++ & VSTYPE) != VSNORMAL)
+                                       nesting++;
+                       } else if (c == CTLENDVAR) {
+                               if (--nesting == 0)
+                                       break;
+                       }
+               }
+       }
+       return p;
+}
+
+
+
+/*
+ * Test whether a specialized variable is set.
+ */
+
+static int
+varisset(char *name, int nulok)
+{
+       if (*name == '!')
+               return backgndpid != 0;
+       else if (*name == '@' || *name == '*') {
+               if (*shellparam.p == NULL)
+                       return 0;
+
+               if (nulok) {
+                       char **av;
+
+                       for (av = shellparam.p; *av; av++)
+                               if (**av != '\0')
+                                       return 1;
+                       return 0;
+               }
+       } else if (is_digit(*name)) {
+               char *ap;
+               int num = atoi(name);
+
+               if (num > shellparam.nparam)
+                       return 0;
+
+               if (num == 0)
+                       ap = arg0;
+               else
+                       ap = shellparam.p[num - 1];
+
+               if (nulok && (ap == NULL || *ap == '\0'))
+                       return 0;
+       }
+       return 1;
+}
+
+
+/*
+ * Put a string on the stack.
+ */
+
+static void
+memtodest(const char *p, size_t len, int syntax, int quotes) {
+       char *q = expdest;
+
+       q = makestrspace(len * 2, q);
+
+       while (len--) {
+               int c = *p++;
+               if (!c)
+                       continue;
+               if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
+                       USTPUTC(CTLESC, q);
+               USTPUTC(c, q);
+       }
+
+       expdest = q;
+}
+
+
+static void
+strtodest(const char *p, int syntax, int quotes)
+{
+       memtodest(p, strlen(p), syntax, quotes);
+}
+
+
+/*
+ * Add the value of a specialized variable to the stack string.
+ */
+
+static void
+varvalue(char *name, int quoted, int flags)
+{
+       int num;
+       char *p;
+       int i;
+       int sep;
+       int sepq = 0;
+       char **ap;
+       int syntax;
+       int allow_split = flags & EXP_FULL;
+       int quotes = flags & (EXP_FULL | EXP_CASE);
+
+       syntax = quoted ? DQSYNTAX : BASESYNTAX;
+       switch (*name) {
+       case '$':
+               num = rootpid;
+               goto numvar;
+       case '?':
+               num = exitstatus;
+               goto numvar;
+       case '#':
+               num = shellparam.nparam;
+               goto numvar;
+       case '!':
+               num = backgndpid;
+numvar:
+               cvtnum(num);
+               break;
+       case '-':
+               for (i = 0 ; i < NOPTS ; i++) {
+                       if (optlist[i])
+                               STPUTC(optletters(i), expdest);
+               }
+               break;
+       case '@':
+               if (allow_split && quoted) {
+                       sep = 1 << CHAR_BIT;
+                       goto param;
+               }
+               /* fall through */
+       case '*':
+               sep = ifsset() ? ifsval()[0] : ' ';
+               if (quotes) {
+                       sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
+               }
+param:
+               for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+                       strtodest(p, syntax, quotes);
+                       if (*ap && sep) {
+                               p = expdest;
+                               if (sepq)
+                                       STPUTC(CTLESC, p);
+                               STPUTC(sep, p);
+                               expdest = p;
+                       }
+               }
+               break;
+       case '0':
+               strtodest(arg0, syntax, quotes);
+               break;
+       default:
+               num = atoi(name);
+               if (num > 0 && num <= shellparam.nparam) {
+                       strtodest(shellparam.p[num - 1], syntax, quotes);
+               }
+               break;
+       }
+}
+
+
+/*
+ * Record the fact that we have to scan this region of the
+ * string for IFS characters.
+ */
+
+static void
+recordregion(int start, int end, int nulonly)
+{
+       struct ifsregion *ifsp;
+
+       if (ifslastp == NULL) {
+               ifsp = &ifsfirst;
+       } else {
+               INTOFF;
+               ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
+               ifsp->next = NULL;
+               ifslastp->next = ifsp;
+               INTON;
+       }
+       ifslastp = ifsp;
+       ifslastp->begoff = start;
+       ifslastp->endoff = end;
+       ifslastp->nulonly = nulonly;
+}
+
+
+/*
+ * Break the argument string into pieces based upon IFS and add the
+ * strings to the argument list.  The regions of the string to be
+ * searched for IFS characters have been stored by recordregion.
+ */
+static void
+ifsbreakup(char *string, struct arglist *arglist)
+{
+       struct ifsregion *ifsp;
+       struct strlist *sp;
+       char *start;
+       char *p;
+       char *q;
+       const char *ifs, *realifs;
+       int ifsspc;
+       int nulonly;
+
+
+       start = string;
+       if (ifslastp != NULL) {
+               ifsspc = 0;
+               nulonly = 0;
+               realifs = ifsset() ? ifsval() : defifs;
+               ifsp = &ifsfirst;
+               do {
+                       p = string + ifsp->begoff;
+                       nulonly = ifsp->nulonly;
+                       ifs = nulonly ? nullstr : realifs;
+                       ifsspc = 0;
+                       while (p < string + ifsp->endoff) {
+                               q = p;
+                               if (*p == CTLESC)
+                                       p++;
+                               if (strchr(ifs, *p)) {
+                                       if (!nulonly)
+                                               ifsspc = (strchr(defifs, *p) != NULL);
+                                       /* Ignore IFS whitespace at start */
+                                       if (q == start && ifsspc) {
+                                               p++;
+                                               start = p;
+                                               continue;
+                                       }
+                                       *q = '\0';
+                                       sp = (struct strlist *)stalloc(sizeof *sp);
+                                       sp->text = start;
+                                       *arglist->lastp = sp;
+                                       arglist->lastp = &sp->next;
+                                       p++;
+                                       if (!nulonly) {
+                                               for (;;) {
+                                                       if (p >= string + ifsp->endoff) {
+                                                               break;
+                                                       }
+                                                       q = p;
+                                                       if (*p == CTLESC)
+                                                               p++;
+                                                       if (strchr(ifs, *p) == NULL ) {
+                                                               p = q;
+                                                               break;
+                                                       } else if (strchr(defifs, *p) == NULL) {
+                                                               if (ifsspc) {
+                                                                       p++;
+                                                                       ifsspc = 0;
+                                                               } else {
+                                                                       p = q;
+                                                                       break;
+                                                               }
+                                                       } else
+                                                               p++;
+                                               }
+                                       }
+                                       start = p;
+                               } else
+                                       p++;
+                       }
+               } while ((ifsp = ifsp->next) != NULL);
+               if (nulonly)
+                       goto add;
+       }
+
+       if (!*start)
+               return;
+
+add:
+       sp = (struct strlist *)stalloc(sizeof *sp);
+       sp->text = start;
+       *arglist->lastp = sp;
+       arglist->lastp = &sp->next;
+}
+
+static void
+ifsfree(void)
+{
+       struct ifsregion *p;
+
+       INTOFF;
+       p = ifsfirst.next;
+       do {
+               struct ifsregion *ifsp;
+               ifsp = p->next;
+               ckfree(p);
+               p = ifsp;
+       } while (p);
+       ifslastp = NULL;
+       ifsfirst.next = NULL;
+       INTON;
+}
+
+static void expmeta(char *, char *);
+static struct strlist *expsort(struct strlist *);
+static struct strlist *msort(struct strlist *, int);
+
+static char *expdir;
+
+
+static void
+expandmeta(struct strlist *str, int flag)
+{
+       static const char metachars[] = {
+               '*', '?', '[', 0
+       };
+       /* TODO - EXP_REDIR */
+
+       while (str) {
+               struct strlist **savelastp;
+               struct strlist *sp;
+               char *p;
+
+               if (fflag)
+                       goto nometa;
+               if (!strpbrk(str->text, metachars))
+                       goto nometa;
+               savelastp = exparg.lastp;
+
+               INTOFF;
+               p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+               {
+                       int i = strlen(str->text);
+                       expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
+               }
+
+               expmeta(expdir, p);
+               ckfree(expdir);
+               if (p != str->text)
+                       ckfree(p);
+               INTON;
+               if (exparg.lastp == savelastp) {
+                       /*
+                        * no matches
+                        */
+nometa:
+                       *exparg.lastp = str;
+                       rmescapes(str->text);
+                       exparg.lastp = &str->next;
+               } else {
+                       *exparg.lastp = NULL;
+                       *savelastp = sp = expsort(*savelastp);
+                       while (sp->next != NULL)
+                               sp = sp->next;
+                       exparg.lastp = &sp->next;
+               }
+               str = str->next;
+       }
+}
+
+/*
+ * Add a file name to the list.
+ */
+
+static void
+addfname(const char *name)
+{
+       struct strlist *sp;
+
+       sp = (struct strlist *)stalloc(sizeof *sp);
+       sp->text = sstrdup(name);
+       *exparg.lastp = sp;
+       exparg.lastp = &sp->next;
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+static void
+expmeta(char *enddir, char *name)
+{
+       char *p;
+       const char *cp;
+       char *start;
+       char *endname;
+       int metaflag;
+       struct stat statb;
+       DIR *dirp;
+       struct dirent *dp;
+       int atend;
+       int matchdot;
+
+       metaflag = 0;
+       start = name;
+       for (p = name; *p; p++) {
+               if (*p == '*' || *p == '?')
+                       metaflag = 1;
+               else if (*p == '[') {
+                       char *q = p + 1;
+                       if (*q == '!')
+                               q++;
+                       for (;;) {
+                               if (*q == '\\')
+                                       q++;
+                               if (*q == '/' || *q == '\0')
+                                       break;
+                               if (*++q == ']') {
+                                       metaflag = 1;
+                                       break;
+                               }
+                       }
+               } else if (*p == '\\')
+                       p++;
+               else if (*p == '/') {
+                       if (metaflag)
+                               goto out;
+                       start = p + 1;
+               }
+       }
+out:
+       if (metaflag == 0) {    /* we've reached the end of the file name */
+               if (enddir != expdir)
+                       metaflag++;
+               p = name;
+               do {
+                       if (*p == '\\')
+                               p++;
+                       *enddir++ = *p;
+               } while (*p++);
+               if (metaflag == 0 || lstat(expdir, &statb) >= 0)
+                       addfname(expdir);
+               return;
+       }
+       endname = p;
+       if (name < start) {
+               p = name;
+               do {
+                       if (*p == '\\')
+                               p++;
+                       *enddir++ = *p++;
+               } while (p < start);
+       }
+       if (enddir == expdir) {
+               cp = ".";
+       } else if (enddir == expdir + 1 && *expdir == '/') {
+               cp = "/";
+       } else {
+               cp = expdir;
+               enddir[-1] = '\0';
+       }
+       if ((dirp = opendir(cp)) == NULL)
+               return;
+       if (enddir != expdir)
+               enddir[-1] = '/';
+       if (*endname == 0) {
+               atend = 1;
+       } else {
+               atend = 0;
+               *endname++ = '\0';
+       }
+       matchdot = 0;
+       p = start;
+       if (*p == '\\')
+               p++;
+       if (*p == '.')
+               matchdot++;
+       while (! intpending && (dp = readdir(dirp)) != NULL) {
+               if (dp->d_name[0] == '.' && ! matchdot)
+                       continue;
+               if (pmatch(start, dp->d_name)) {
+                       if (atend) {
+                               scopy(dp->d_name, enddir);
+                               addfname(expdir);
+                       } else {
+                               for (p = enddir, cp = dp->d_name;
+                                    (*p++ = *cp++) != '\0';)
+                                       continue;
+                               p[-1] = '/';
+                               expmeta(p, endname);
+                       }
+               }
+       }
+       closedir(dirp);
+       if (! atend)
+               endname[-1] = '/';
+}
+
+/*
+ * Sort the results of file name expansion.  It calculates the number of
+ * strings to sort and then calls msort (short for merge sort) to do the
+ * work.
+ */
+
+static struct strlist *
+expsort(struct strlist *str)
+{
+       int len;
+       struct strlist *sp;
+
+       len = 0;
+       for (sp = str ; sp ; sp = sp->next)
+               len++;
+       return msort(str, len);
+}
+
+
+static struct strlist *
+msort(struct strlist *list, int len)
+{
+       struct strlist *p, *q = NULL;
+       struct strlist **lpp;
+       int half;
+       int n;
+
+       if (len <= 1)
+               return list;
+       half = len >> 1;
+       p = list;
+       for (n = half ; --n >= 0 ; ) {
+               q = p;
+               p = p->next;
+       }
+       q->next = NULL;                 /* terminate first half of list */
+       q = msort(list, half);          /* sort first half of list */
+       p = msort(p, len - half);               /* sort second half */
+       lpp = &list;
+       for (;;) {
+#ifdef BB_LOCALE_SUPPORT
+               if (strcoll(p->text, q->text) < 0)
+#else
+               if (strcmp(p->text, q->text) < 0)
+#endif
+                                               {
+                       *lpp = p;
+                       lpp = &p->next;
+                       if ((p = *lpp) == NULL) {
+                               *lpp = q;
+                               break;
+                       }
+               } else {
+                       *lpp = q;
+                       lpp = &q->next;
+                       if ((q = *lpp) == NULL) {
+                               *lpp = p;
+                               break;
+                       }
+               }
+       }
+       return list;
+}
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+static inline int
+patmatch(char *pattern, const char *string)
+{
+       return pmatch(preglob(pattern, 0, 0), string);
+}
+
+
+/*
+ * Remove any CTLESC characters from a string.
+ */
+
+static char *
+_rmescapes(char *str, int flag)
+{
+       char *p, *q, *r;
+       static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
+       unsigned inquotes;
+       int notescaped;
+       int globbing;
+
+       p = strpbrk(str, qchars);
+       if (!p) {
+               return str;
+       }
+       q = p;
+       r = str;
+       if (flag & RMESCAPE_ALLOC) {
+               size_t len = p - str;
+               size_t fulllen = len + strlen(p) + 1;
+
+               if (flag & RMESCAPE_GROW) {
+                       r = makestrspace(fulllen, expdest);
+               } else if (flag & RMESCAPE_HEAP) {
+                       r = ckmalloc(fulllen);
+               } else {
+                       r = stalloc(fulllen);
+               }
+               q = r;
+               if (len > 0) {
+                       q = mempcpy(q, str, len);
+               }
+       }
+       inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
+       globbing = flag & RMESCAPE_GLOB;
+       notescaped = globbing;
+       while (*p) {
+               if (*p == CTLQUOTEMARK) {
+                       inquotes = ~inquotes;
+                       p++;
+                       notescaped = globbing;
+                       continue;
+               }
+               if (*p == '\\') {
+                       /* naked back slash */
+                       notescaped = 0;
+                       goto copy;
+               }
+               if (*p == CTLESC) {
+                       p++;
+                       if (notescaped && inquotes && *p != '/') {
+                               *q++ = '\\';
+                       }
+               }
+               notescaped = globbing;
+copy:
+               *q++ = *p++;
+       }
+       *q = '\0';
+       if (flag & RMESCAPE_GROW) {
+               expdest = r;
+               STADJUST(q - r + 1, expdest);
+       }
+       return r;
+}
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, char *val)
+{
+       struct stackmark smark;
+       int result;
+
+       setstackmark(&smark);
+       argbackq = pattern->narg.backquote;
+       STARTSTACKSTR(expdest);
+       ifslastp = NULL;
+       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
+       STACKSTRNUL(expdest);
+       result = patmatch(stackblock(), val);
+       popstackmark(&smark);
+       return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+static int
+cvtnum(long num)
+{
+       int len;
+
+       expdest = makestrspace(32, expdest);
+       len = fmtstr(expdest, 32, "%ld", num);
+       STADJUST(len, expdest);
+       return len;
+}
+
+static void
+varunset(const char *end, const char *var, const char *umsg, int varflags)
+{
+       const char *msg;
+       const char *tail;
+
+       tail = nullstr;
+       msg = "parameter not set";
+       if (umsg) {
+               if (*end == CTLENDVAR) {
+                       if (varflags & VSNUL)
+                               tail = " or null";
+               } else
+                       msg = umsg;
+       }
+       error("%.*s: %s%s", end - var - 1, var, msg, tail);
+}
+
+
+/*      $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $      */
+
+/*
+ * This implements the input routines used by the parser.
+ */
+
+#define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
+#define IBUFSIZ (BUFSIZ + 1)
+
+static void pushfile(void);
+
+/*
+ * Read a line from the script.
+ */
+
+static inline char *
+pfgets(char *line, int len)
+{
+       char *p = line;
+       int nleft = len;
+       int c;
+
+       while (--nleft > 0) {
+               c = pgetc2();
+               if (c == PEOF) {
+                       if (p == line)
+                               return NULL;
+                       break;
+               }
+               *p++ = c;
+               if (c == '\n')
+                       break;
+       }
+       *p = '\0';
+       return line;
+}
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+#define pgetc_as_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
+
+#ifdef BB_ASH_OPTIMIZE_FOR_SIZE
+#define pgetc_macro() pgetc()
+static int
+pgetc(void)
+{
+       return pgetc_as_macro();
+}
+#else
+#define pgetc_macro()   pgetc_as_macro()
+static int
+pgetc(void)
+{
+       return pgetc_macro();
+}
+#endif
+
+
+/*
+ * Same as pgetc(), but ignores PEOA.
+ */
+#ifdef BB_ASH_ALIAS
+static int pgetc2(void)
+{
+       int c;
+
+       do {
+               c = pgetc_macro();
+       } while (c == PEOA);
+       return c;
+}
+#else
+static inline int pgetc2(void)
+{
+       return pgetc_macro();
+}
+#endif
+
+
+#ifdef BB_FEATURE_COMMAND_EDITING
+static const char *cmdedit_prompt;
+static inline void putprompt(const char *s)
+{
+       cmdedit_prompt = s;
+}
+#else
+static inline void putprompt(const char *s)
+{
+       out2str(s);
+}
+#endif
+
+static inline int
+preadfd(void)
+{
+       int nr;
+       char *buf =  parsefile->buf;
+       parsenextc = buf;
+
+retry:
+#ifdef BB_FEATURE_COMMAND_EDITING
+       if (!iflag || parsefile->fd)
+               nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
+       else {
+               nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
+               if(nr == 0) {
+                       /* Ctrl+C presend */
+                       raise(SIGINT);
+                       goto retry;
+               }
+               if(nr < 0) {
+                       /* Ctrl+D presend */
+                       nr = 0;
+               }
+       }
+#else
+       nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
+#endif
+
+       if (nr < 0) {
+               if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+                       int flags = fcntl(0, F_GETFL, 0);
+                       if (flags >= 0 && flags & O_NONBLOCK) {
+                               flags &=~ O_NONBLOCK;
+                               if (fcntl(0, F_SETFL, flags) >= 0) {
+                                       out2str("sh: turning off NDELAY mode\n");
+                                       goto retry;
+                               }
+                       }
+               }
+       }
+       return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ *    from a string so we can't refill the buffer, return EOF.
+ * 3) If the is more stuff in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+       char *p, *q;
+       int more;
+       char savec;
+
+       while (parsefile->strpush) {
+#ifdef BB_ASH_ALIAS
+               if (parsenleft == -1 && parsefile->strpush->ap &&
+                       parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
+                       return PEOA;
+               }
+#endif
+               popstring();
+               if (--parsenleft >= 0)
+                       return (*parsenextc++);
+       }
+       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+               return PEOF;
+       flushall();
+
+again:
+       if (parselleft <= 0) {
+               if ((parselleft = preadfd()) <= 0) {
+                       parselleft = parsenleft = EOF_NLEFT;
+                       return PEOF;
+               }
+       }
+
+       q = p = parsenextc;
+
+       /* delete nul characters */
+       for (more = 1; more;) {
+               switch (*p) {
+               case '\0':
+                       p++;    /* Skip nul */
+                       goto check;
+
+               case '\n':
+                       parsenleft = q - parsenextc;
+                       more = 0; /* Stop processing here */
+                       break;
+
+               }
+
+               *q++ = *p++;
+check:
+               if (--parselleft <= 0 && more) {
+                       parsenleft = q - parsenextc - 1;
+                       if (parsenleft < 0)
+                               goto again;
+                       more = 0;
+               }
+       }
+
+       savec = *q;
+       *q = '\0';
+
+       if (vflag) {
+               out2str(parsenextc);
+       }
+
+       *q = savec;
+
+       return *parsenextc++;
+}
+
+/*
+ * Undo the last call to pgetc.  Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+       parsenleft++;
+       parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(char *s, void *ap)
+{
+       struct strpush *sp;
+       size_t len;
+
+       len = strlen(s);
+       INTOFF;
+/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
+       if (parsefile->strpush) {
+               sp = ckmalloc(sizeof (struct strpush));
+               sp->prev = parsefile->strpush;
+               parsefile->strpush = sp;
+       } else
+               sp = parsefile->strpush = &(parsefile->basestrpush);
+       sp->prevstring = parsenextc;
+       sp->prevnleft = parsenleft;
+#ifdef BB_ASH_ALIAS
+       sp->ap = (struct alias *)ap;
+       if (ap) {
+               ((struct alias *)ap)->flag |= ALIASINUSE;
+               sp->string = s;
+       }
+#endif
+       parsenextc = s;
+       parsenleft = len;
+       INTON;
+}
+
+void
+popstring(void)
+{
+       struct strpush *sp = parsefile->strpush;
+
+       INTOFF;
+#ifdef BB_ASH_ALIAS
+       if (sp->ap) {
+               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+                       checkkwd |= CHKALIAS;
+               }
+               if (sp->string != sp->ap->val) {
+                       ckfree(sp->string);
+               }
+               sp->ap->flag &= ~ALIASINUSE;
+               if (sp->ap->flag & ALIASDEAD) {
+                       unalias(sp->ap->name);
+               }
+       }
+#endif
+       parsenextc = sp->prevstring;
+       parsenleft = sp->prevnleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+       parsefile->strpush = sp->prev;
+       if (sp != &(parsefile->basestrpush))
+               ckfree(sp);
+       INTON;
+}
+
+/*
+ * Set the input to take input from a file.  If push is set, push the
+ * old input onto the stack first.
+ */
+
+void
+setinputfile(const char *fname, int push)
+{
+       int fd;
+       int fd2;
+
+       INTOFF;
+       if ((fd = open(fname, O_RDONLY)) < 0)
+               error("Can't open %s", fname);
+       if (fd < 10) {
+               fd2 = ash_copyfd(fd, 10);
+               close(fd);
+               if (fd2 < 0)
+                       error("Out of file descriptors");
+               fd = fd2;
+       }
+       setinputfd(fd, push);
+       INTON;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor.  Call this with
+ * interrupts off.
+ */
+
+static void
+setinputfd(int fd, int push)
+{
+       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+       if (push) {
+               pushfile();
+               parsefile->buf = 0;
+       }
+       parsefile->fd = fd;
+       if (parsefile->buf == NULL)
+               parsefile->buf = ckmalloc(IBUFSIZ);
+       parselleft = parsenleft = 0;
+       plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+static void
+setinputstring(char *string)
+{
+       INTOFF;
+       pushfile();
+       parsenextc = string;
+       parsenleft = strlen(string);
+       parsefile->buf = NULL;
+       plinno = 1;
+       INTON;
+}
+
+
+/*
+ * To handle the "." command, a stack of input files is used.  Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+static void
+pushfile(void)
+{
+       struct parsefile *pf;
+
+       parsefile->nleft = parsenleft;
+       parsefile->lleft = parselleft;
+       parsefile->nextc = parsenextc;
+       parsefile->linno = plinno;
+       pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+       pf->prev = parsefile;
+       pf->fd = -1;
+       pf->strpush = NULL;
+       pf->basestrpush.prev = NULL;
+       parsefile = pf;
+}
+
+
+static void
+popfile(void)
+{
+       struct parsefile *pf = parsefile;
+
+       INTOFF;
+       if (pf->fd >= 0)
+               close(pf->fd);
+       if (pf->buf)
+               ckfree(pf->buf);
+       while (pf->strpush)
+               popstring();
+       parsefile = pf->prev;
+       ckfree(pf);
+       parsenleft = parsefile->nleft;
+       parselleft = parsefile->lleft;
+       parsenextc = parsefile->nextc;
+       plinno = parsefile->linno;
+       INTON;
+}
+
+
+/*
+ * Return to top level.
+ */
+
+static void
+popallfiles(void)
+{
+       while (parsefile != &basepf)
+               popfile();
+}
+
+
+/*
+ * Close the file(s) that the shell is reading commands from.  Called
+ * after a fork is done.
+ */
+
+static void
+closescript(void)
+{
+       popallfiles();
+       if (parsefile->fd > 0) {
+               close(parsefile->fd);
+               parsefile->fd = 0;
+       }
+}
+
+/*      $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $    */
+
+/* mode flags for set_curjob */
+#define CUR_DELETE 2
+#define CUR_RUNNING 1
+#define CUR_STOPPED 0
+
+/* mode flags for dowait */
+#define DOWAIT_NORMAL 0
+#define DOWAIT_BLOCK 1
+
+/* array of jobs */
+static struct job *jobtab;
+/* size of array */
+static unsigned njobs;
+#if JOBS
+/* pgrp of shell on invocation */
+static int initialpgrp;
+static int ttyfd = -1;
+#endif
+/* current job */
+static struct job *curjob;
+/* number of presumed living untracked jobs */
+static int jobless;
+
+static void set_curjob(struct job *, unsigned);
+#if JOBS
+static int restartjob(struct job *, int);
+static void xtcsetpgrp(int, pid_t);
+static char *commandtext(union node *);
+static void cmdlist(union node *, int);
+static void cmdtxt(union node *);
+static void cmdputs(const char *);
+static void showpipe(struct job *, FILE *);
+#endif
+static int sprint_status(char *, int, int);
+static void freejob(struct job *);
+static struct job *getjob(const char *, int);
+static struct job *growjobtab(void);
+static void forkchild(struct job *, union node *, int);
+static void forkparent(struct job *, union node *, int, pid_t);
+static int dowait(int, struct job *);
+static int getstatus(struct job *);
+
+static void
+set_curjob(struct job *jp, unsigned mode)
+{
+       struct job *jp1;
+       struct job **jpp, **curp;
+
+       /* first remove from list */
+       jpp = curp = &curjob;
+       do {
+               jp1 = *jpp;
+               if (jp1 == jp)
+                       break;
+               jpp = &jp1->prev_job;
+       } while (1);
+       *jpp = jp1->prev_job;
+
+       /* Then re-insert in correct position */
+       jpp = curp;
+       switch (mode) {
+       default:
+#ifdef DEBUG
+               abort();
+#endif
+       case CUR_DELETE:
+               /* job being deleted */
+               break;
+       case CUR_RUNNING:
+               /* newly created job or backgrounded job,
+                  put after all stopped jobs. */
+               do {
+                       jp1 = *jpp;
+#ifdef JOBS
+                       if (!jp1 || jp1->state != JOBSTOPPED)
+#endif
+                               break;
+                       jpp = &jp1->prev_job;
+               } while (1);
+               /* FALLTHROUGH */
+#ifdef JOBS
+       case CUR_STOPPED:
+#endif
+               /* newly stopped job - becomes curjob */
+               jp->prev_job = *jpp;
+               *jpp = jp;
+               break;
+       }
+}
+
+#if JOBS
+/*
+ * Turn job control on and off.
+ *
+ * Note:  This code assumes that the third arg to ioctl is a character
+ * pointer, which is true on Berkeley systems but not System V.  Since
+ * System V doesn't have job control yet, this isn't a problem now.
+ *
+ * Called with interrupts off.
+ */
+
+void
+setjobctl(int on)
+{
+       int fd;
+       int pgrp;
+
+       if (on == jobctl || rootshell == 0)
+               return;
+       if (on) {
+               int ofd;
+               ofd = fd = open(_PATH_TTY, O_RDWR);
+               if (fd < 0) {
+                       fd += 3;
+                       while (!isatty(fd) && --fd >= 0)
+                               ;
+               }
+               fd = fcntl(fd, F_DUPFD, 10);
+               close(ofd);
+               if (fd < 0)
+                       goto out;
+               fcntl(fd, F_SETFD, FD_CLOEXEC);
+               do { /* while we are in the background */
+                       if ((pgrp = tcgetpgrp(fd)) < 0) {
+out:
+                               sh_warnx("can't access tty; job control turned off");
+                               mflag = on = 0;
+                               goto close;
+                       }
+                       if (pgrp == getpgrp())
+                               break;
+                       killpg(0, SIGTTIN);
+               } while (1);
+               initialpgrp = pgrp;
+
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+               setsignal(SIGTTIN);
+               pgrp = rootpid;
+               setpgid(0, pgrp);
+               xtcsetpgrp(fd, pgrp);
+       } else {
+               /* turning job control off */
+               fd = ttyfd;
+               pgrp = initialpgrp;
+               xtcsetpgrp(fd, pgrp);
+               setpgid(0, pgrp);
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+               setsignal(SIGTTIN);
+close:
+               close(fd);
+               fd = -1;
+       }
+       ttyfd = fd;
+       jobctl = on;
+}
+
+static int
+killcmd(int argc, char **argv)
+{
+       int signo = -1;
+       int list = 0;
+       int i;
+       pid_t pid;
+       struct job *jp;
+
+       if (argc <= 1) {
+usage:
+               error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+               );
+       }
+
+       if (**++argv == '-') {
+               signo = decode_signal(*argv + 1, 1);
+               if (signo < 0) {
+                       int c;
+
+                       while ((c = nextopt("ls:")) != '\0')
+                               switch (c) {
+                               default:
+#ifdef DEBUG
+                                       abort();
+#endif
+                               case 'l':
+                                       list = 1;
+                                       break;
+                               case 's':
+                                       signo = decode_signal(optionarg, 1);
+                                       if (signo < 0) {
+                                               error(
+                                                       "invalid signal number or name: %s",
+                                                       optionarg
+                                               );
+                                       }
+                                       break;
+                               }
+                       argv = argptr;
+               } else
+                       argv++;
+       }
+
+       if (!list && signo < 0)
+               signo = SIGTERM;
+
+       if ((signo < 0 || !*argv) ^ list) {
+               goto usage;
+       }
+
+       if (list) {
+               const char *name;
+
+               if (!*argv) {
+                       for (i = 1; i < NSIG; i++) {
+                               name = u_signal_names(0, &i, 1);
+                               if (name)
+                                       out1fmt(snlfmt, name);
+                       }
+                       return 0;
+               }
+               name = u_signal_names(*argptr, &signo, -1);
+               if (name)
+                       out1fmt(snlfmt, name);
+               else
+                       error("invalid signal number or exit status: %s", *argptr);
+               return 0;
+       }
+
+       i = 0;
+       do {
+               if (**argv == '%') {
+                       jp = getjob(*argv, 0);
+                       pid = -jp->ps[0].pid;
+               } else
+                       pid = number(*argv);
+               if (kill(pid, signo) != 0) {
+                       sh_warnx("%m\n");
+                       i = 1;
+               }
+       } while (*++argv);
+
+       return i;
+}
+#endif /* JOBS */
+
+#if defined(JOBS) || defined(DEBUG)
+static int
+jobno(const struct job *jp)
+{
+       return jp - jobtab + 1;
+}
+#endif
+
+#ifdef JOBS
+static int
+fgcmd(int argc, char **argv)
+{
+       struct job *jp;
+       FILE *out;
+       int mode;
+       int retval;
+
+       mode = (**argv == 'f') ? FORK_FG : FORK_BG;
+       nextopt(nullstr);
+       argv = argptr;
+       out = stdout;
+       do {
+               jp = getjob(*argv, 1);
+               if (mode == FORK_BG) {
+                       set_curjob(jp, CUR_RUNNING);
+                       fprintf(out, "[%d] ", jobno(jp));
+               }
+               outstr(jp->ps->cmd, out);
+               showpipe(jp, out);
+               retval = restartjob(jp, mode);
+       } while (*argv && *++argv);
+       return retval;
+}
+
+static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
+
+
+static int
+restartjob(struct job *jp, int mode)
+{
+       struct procstat *ps;
+       int i;
+       int status;
+       pid_t pgid;
+
+       INTOFF;
+       if (jp->state == JOBDONE)
+               goto out;
+       jp->state = JOBRUNNING;
+       pgid = jp->ps->pid;
+       if (mode == FORK_FG)
+               xtcsetpgrp(ttyfd, pgid);
+       killpg(pgid, SIGCONT);
+       ps = jp->ps;
+       i = jp->nprocs;
+       do {
+               if (WIFSTOPPED(ps->status)) {
+                       ps->status = -1;
+               }
+       } while (ps++, --i);
+out:
+       status = (mode == FORK_FG) ? waitforjob(jp) : 0;
+       INTON;
+       return status;
+}
+#endif
+
+static int
+sprint_status(char *s, int status, int sigonly)
+{
+       int col;
+       int st;
+
+       col = 0;
+       if (!WIFEXITED(status)) {
+#if JOBS
+               if (WIFSTOPPED(status))
+                       st = WSTOPSIG(status);
+               else
+#endif
+                       st = WTERMSIG(status);
+               if (sigonly) {
+                       if (st == SIGINT || st == SIGPIPE)
+                               goto out;
+#if JOBS
+                       if (WIFSTOPPED(status))
+                               goto out;
+#endif
+               }
+               st &= 0x7f;
+               col = fmtstr(s, 32, strsignal(st));
+               if (WCOREDUMP(status)) {
+                       col += fmtstr(s + col, 16, " (core dumped)");
+               }
+       } else if (!sigonly) {
+               st = WEXITSTATUS(status);
+               if (st)
+                       col = fmtstr(s, 16, "Done(%d)", st);
+               else
+                       col = fmtstr(s, 16, "Done");
+       }
+
+out:
+       return col;
+}
+
+#if JOBS
+static void
+showjob(FILE *out, struct job *jp, int mode)
+{
+       struct procstat *ps;
+       struct procstat *psend;
+       int col;
+       int indent;
+       char s[80];
+
+       ps = jp->ps;
+
+       if (mode & SHOW_PGID) {
+               /* just output process (group) id of pipeline */
+               fprintf(out, "%d\n", ps->pid);
+               return;
+       }
+
+       col = fmtstr(s, 16, "[%d]   ", jobno(jp));
+       indent = col;
+
+       if (jp == curjob)
+               s[col - 2] = '+';
+       else if (curjob && jp == curjob->prev_job)
+               s[col - 2] = '-';
+
+       if (mode & SHOW_PID)
+               col += fmtstr(s + col, 16, "%d ", ps->pid);
+
+       psend = ps + jp->nprocs;
+
+       if (jp->state == JOBRUNNING) {
+               scopy("Running", s + col);
+               col += strlen("Running");
+       } else {
+               int status = psend[-1].status;
+#if JOBS
+               if (jp->state == JOBSTOPPED)
+                       status = jp->stopstatus;
+#endif
+               col += sprint_status(s + col, status, 0);
+       }
+
+       goto start;
+
+       do {
+               /* for each process */
+               col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
+
+start:
+               fprintf(out, "%s%*c%s",
+                       s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
+               );
+               if (!(mode & SHOW_PID)) {
+                       showpipe(jp, out);
+                       break;
+               }
+               if (++ps == psend) {
+                       outcslow('\n', out);
+                       break;
+               }
+       } while (1);
+
+       jp->changed = 0;
+
+       if (jp->state == JOBDONE) {
+               TRACE(("showjob: freeing job %d\n", jobno(jp)));
+               freejob(jp);
+       }
+}
+
+
+static int
+jobscmd(int argc, char **argv)
+{
+       int mode, m;
+       FILE *out;
+
+       mode = 0;
+       while ((m = nextopt("lp")))
+               if (m == 'l')
+                       mode = SHOW_PID;
+               else
+                       mode = SHOW_PGID;
+
+       out = stdout;
+       argv = argptr;
+       if (*argv)
+               do
+                       showjob(out, getjob(*argv,0), mode);
+               while (*++argv);
+       else
+               showjobs(out, mode);
+
+       return 0;
+}
+
+
+/*
+ * Print a list of jobs.  If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ */
+
+static void
+showjobs(FILE *out, int mode)
+{
+       struct job *jp;
+
+       TRACE(("showjobs(%x) called\n", mode));
+
+       /* If not even one one job changed, there is nothing to do */
+       while (dowait(DOWAIT_NORMAL, NULL) > 0)
+               continue;
+
+       for (jp = curjob; jp; jp = jp->prev_job) {
+               if (!(mode & SHOW_CHANGED) || jp->changed)
+                       showjob(out, jp, mode);
+       }
+}
+#endif /* JOBS */
+
+/*
+ * Mark a job structure as unused.
+ */
+
+static void
+freejob(struct job *jp)
+{
+       struct procstat *ps;
+       int i;
+
+       INTOFF;
+       for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+               if (ps->cmd != nullstr)
+                       ckfree(ps->cmd);
+       }
+       if (jp->ps != &jp->ps0)
+               ckfree(jp->ps);
+       jp->used = 0;
+       set_curjob(jp, CUR_DELETE);
+       INTON;
+}
+
+
+static int
+waitcmd(int argc, char **argv)
+{
+       struct job *job;
+       int retval;
+       struct job *jp;
+
+       EXSIGON();
+
+       nextopt(nullstr);
+       retval = 0;
+
+       argv = argptr;
+       if (!*argv) {
+               /* wait for all jobs */
+               for (;;) {
+                       jp = curjob;
+                       while (1) {
+                               if (!jp) {
+                                       /* no running procs */
+                                       goto out;
+                               }
+                               if (jp->state == JOBRUNNING)
+                                       break;
+                               jp->waited = 1;
+                               jp = jp->prev_job;
+                       }
+                       dowait(DOWAIT_BLOCK, 0);
+               }
+       }
+
+       retval = 127;
+       do {
+               if (**argv != '%') {
+                       pid_t pid = number(*argv);
+                       job = curjob;
+                       goto start;
+                       do {
+                               if (job->ps[job->nprocs - 1].pid == pid)
+                                       break;
+                               job = job->prev_job;
+start:
+                               if (!job)
+                                       goto repeat;
+                       } while (1);
+               } else
+                       job = getjob(*argv, 0);
+               /* loop until process terminated or stopped */
+               while (job->state == JOBRUNNING)
+                       dowait(DOWAIT_BLOCK, 0);
+               job->waited = 1;
+               retval = getstatus(job);
+repeat:
+               ;
+       } while (*++argv);
+
+out:
+       return retval;
+}
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+static struct job *
+getjob(const char *name, int getctl)
+{
+       struct job *jp;
+       struct job *found;
+       const char *err_msg = "No such job: %s";
+       unsigned num;
+       int c;
+       const char *p;
+       char *(*match)(const char *, const char *);
+
+       jp = curjob;
+       p = name;
+       if (!p)
+               goto currentjob;
+
+       if (*p != '%')
+               goto err;
+
+       c = *++p;
+       if (!c)
+               goto currentjob;
+
+       if (!p[1]) {
+               if (c == '+' || c == '%') {
+currentjob:
+                       err_msg = "No current job";
+                       goto check;
+               } else if (c == '-') {
+                       if (jp)
+                               jp = jp->prev_job;
+                       err_msg = "No previous job";
+check:
+                       if (!jp)
+                               goto err;
+                       goto gotit;
+               }
+       }
+
+       if (is_number(p)) {
+               num = atoi(p);
+               if (num < njobs) {
+                       jp = jobtab + num - 1;
+                       if (jp->used)
+                               goto gotit;
+                       goto err;
+               }
+       }
+
+       match = prefix;
+       if (*p == '?') {
+               match = strstr;
+               p++;
+       }
+
+       found = 0;
+       while (1) {
+               if (!jp)
+                       goto err;
+               if (match(jp->ps[0].cmd, p)) {
+                       if (found)
+                               goto err;
+                       found = jp;
+                       err_msg = "%s: ambiguous";
+               }
+               jp = jp->prev_job;
+       }
+
+gotit:
+#if JOBS
+       err_msg = "job %s not created under job control";
+       if (getctl && jp->jobctl == 0)
+               goto err;
+#endif
+       return jp;
+err:
+       error(err_msg, name);
+}
+
+
+/*
+ * Return a new job structure.
+ * Called with interrupts off.
+ */
+
+static struct job *
+makejob(union node *node, int nprocs)
+{
+       int i;
+       struct job *jp;
+
+       for (i = njobs, jp = jobtab ; ; jp++) {
+               if (--i < 0) {
+                       jp = growjobtab();
+                       break;
+               }
+               if (jp->used == 0)
+                       break;
+               if (jp->state != JOBDONE || !jp->waited)
+                       continue;
+#if JOBS
+               if (jobctl)
+                       continue;
+#endif
+               freejob(jp);
+               break;
+       }
+       memset(jp, 0, sizeof(*jp));
+#if JOBS
+       if (jobctl)
+               jp->jobctl = 1;
+#endif
+       jp->prev_job = curjob;
+       curjob = jp;
+       jp->used = 1;
+       jp->ps = &jp->ps0;
+       if (nprocs > 1) {
+               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+       }
+       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+           jobno(jp)));
+       return jp;
+}
+
+static struct job *
+growjobtab(void)
+{
+       size_t len;
+       ptrdiff_t offset;
+       struct job *jp, *jq;
+
+       len = njobs * sizeof(*jp);
+       jq = jobtab;
+       jp = ckrealloc(jq, len + 4 * sizeof(*jp));
+
+       offset = (char *)jp - (char *)jq;
+       if (offset) {
+               /* Relocate pointers */
+               size_t l = len;
+
+               jq = (struct job *)((char *)jq + l);
+               while (l) {
+                       l -= sizeof(*jp);
+                       jq--;
+#define joff(p) ((struct job *)((char *)(p) + l))
+#define jmove(p) (p) = (void *)((char *)(p) + offset)
+                       if (likely(joff(jp)->ps == &jq->ps0))
+                               jmove(joff(jp)->ps);
+                       if (joff(jp)->prev_job)
+                               jmove(joff(jp)->prev_job);
+               }
+               if (curjob)
+                       jmove(curjob);
+#undef joff
+#undef jmove
+       }
+
+       njobs += 4;
+       jobtab = jp;
+       jp = (struct job *)((char *)jp + len);
+       jq = jp + 3;
+       do {
+               jq->used = 0;
+       } while (--jq >= jp);
+       return jp;
+}
+
+
+/*
+ * Fork off a subshell.  If we are doing job control, give the subshell its
+ * own process group.  Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child.  Both jp and n may
+ * be NULL.  The mode parameter can be one of the following:
+ *      FORK_FG - Fork off a foreground process.
+ *      FORK_BG - Fork off a background process.
+ *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ *                   process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ *
+ * Called with interrupts off.
+ */
+
+static inline void
+forkchild(struct job *jp, union node *n, int mode)
+{
+       int wasroot;
+
+       TRACE(("Child shell %d\n", getpid()));
+       wasroot = rootshell;
+       rootshell = 0;
+
+       closescript();
+       clear_traps();
+#if JOBS
+       /* do job control only in root shell */
+       jobctl = 0;
+       if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
+               pid_t pgrp;
+
+               if (jp->nprocs == 0)
+                       pgrp = getpid();
+               else
+                       pgrp = jp->ps[0].pid;
+               /* This can fail because we are doing it in the parent also */
+               (void)setpgid(0, pgrp);
+               if (mode == FORK_FG)
+                       xtcsetpgrp(ttyfd, pgrp);
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+       } else
+#endif
+       if (mode == FORK_BG) {
+               ignoresig(SIGINT);
+               ignoresig(SIGQUIT);
+               if (jp->nprocs == 0) {
+                       close(0);
+                       if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+                               error("Can't open %s", _PATH_DEVNULL);
+               }
+       }
+       if (wasroot && iflag) {
+               setsignal(SIGINT);
+               setsignal(SIGQUIT);
+               setsignal(SIGTERM);
+       }
+       for (jp = curjob; jp; jp = jp->prev_job)
+               freejob(jp);
+       jobless = 0;
+}
+
+static inline void
+forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+{
+       TRACE(("In parent shell:  child = %d\n", pid));
+       if (!jp) {
+               while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
+               jobless++;
+               return;
+       }
+#if JOBS
+       if (mode != FORK_NOJOB && jp->jobctl) {
+               int pgrp;
+
+               if (jp->nprocs == 0)
+                       pgrp = pid;
+               else
+                       pgrp = jp->ps[0].pid;
+               /* This can fail because we are doing it in the child also */
+               (void)setpgid(pid, pgrp);
+       }
+#endif
+       if (mode == FORK_BG) {
+               backgndpid = pid;               /* set $! */
+               set_curjob(jp, CUR_RUNNING);
+       }
+       if (jp) {
+               struct procstat *ps = &jp->ps[jp->nprocs++];
+               ps->pid = pid;
+               ps->status = -1;
+               ps->cmd = nullstr;
+#if JOBS
+               if (jobctl && n)
+                       ps->cmd = commandtext(n);
+#endif
+       }
+}
+
+static int
+forkshell(struct job *jp, union node *n, int mode)
+{
+       int pid;
+
+       TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
+       pid = fork();
+       if (pid < 0) {
+               TRACE(("Fork failed, errno=%d", errno));
+               if (jp)
+                       freejob(jp);
+               error("Cannot fork");
+       }
+       if (pid == 0)
+               forkchild(jp, n, mode);
+       else
+               forkparent(jp, n, mode, pid);
+       return pid;
+}
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell.  This means that an infinite loop started by an inter-
+ * active user may be hard to kill.  With job control turned off, an
+ * interactive user may place an interactive program inside a loop.  If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop.  The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * forground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ *
+ * Called with interrupts off.
+ */
+
+int
+waitforjob(struct job *jp)
+{
+       int st;
+
+       TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
+       while (jp->state == JOBRUNNING) {
+               dowait(DOWAIT_BLOCK, jp);
+       }
+       st = getstatus(jp);
+#if JOBS
+       if (jp->jobctl) {
+               xtcsetpgrp(ttyfd, rootpid);
+               /*
+                * This is truly gross.
+                * If we're doing job control, then we did a TIOCSPGRP which
+                * caused us (the shell) to no longer be in the controlling
+                * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
+                * intuit from the subprocess exit status whether a SIGINT
+                * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
+                */
+               if (jp->sigint)
+                       raise(SIGINT);
+       }
+       if (jp->state == JOBDONE)
+#endif
+               freejob(jp);
+       return st;
+}
+
+
+/*
+ * Do a wait system call.  If job control is compiled in, we accept
+ * stopped processes.  If block is zero, we return a value of zero
+ * rather than blocking.
+ *
+ * System V doesn't have a non-blocking wait system call.  It does
+ * have a SIGCLD signal that is sent to a process when one of it's
+ * children dies.  The obvious way to use SIGCLD would be to install
+ * a handler for SIGCLD which simply bumped a counter when a SIGCLD
+ * was received, and have waitproc bump another counter when it got
+ * the status of a process.  Waitproc would then know that a wait
+ * system call would not block if the two counters were different.
+ * This approach doesn't work because if a process has children that
+ * have not been waited for, System V will send it a SIGCLD when it
+ * installs a signal handler for SIGCLD.  What this means is that when
+ * a child exits, the shell will be sent SIGCLD signals continuously
+ * until is runs out of stack space, unless it does a wait call before
+ * restoring the signal handler.  The code below takes advantage of
+ * this (mis)feature by installing a signal handler for SIGCLD and
+ * then checking to see whether it was called.  If there are any
+ * children to be waited for, it will be.
+ *
+ * If neither SYSV nor BSD is defined, we don't implement nonblocking
+ * waits at all.  In this case, the user will not be informed when
+ * a background process until the next time she runs a real program
+ * (as opposed to running a builtin command or just typing return),
+ * and the jobs command may give out of date information.
+ */
+
+static inline int
+waitproc(int block, int *status)
+{
+       int flags = 0;
+
+#if JOBS
+       if (jobctl)
+               flags |= WUNTRACED;
+#endif
+       if (block == 0)
+               flags |= WNOHANG;
+       return wait3(status, flags, (struct rusage *)NULL);
+}
+
+/*
+ * Wait for a process to terminate.
+ */
+
+static int
+dowait(int block, struct job *job)
+{
+       int pid;
+       int status;
+       struct job *jp;
+       struct job *thisjob;
+       int state;
+
+       TRACE(("dowait(%d) called\n", block));
+       pid = waitproc(block, &status);
+       TRACE(("wait returns pid %d, status=%d\n", pid, status));
+       if (pid <= 0)
+               return pid;
+       INTOFF;
+       thisjob = NULL;
+       for (jp = curjob; jp; jp = jp->prev_job) {
+               struct procstat *sp;
+               struct procstat *spend;
+               if (jp->state == JOBDONE)
+                       continue;
+               state = JOBDONE;
+               spend = jp->ps + jp->nprocs;
+               sp = jp->ps;
+               do {
+                       if (sp->pid == pid) {
+                               TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
+                               sp->status = status;
+                               thisjob = jp;
+                       }
+                       if (sp->status == -1)
+                               state = JOBRUNNING;
+#ifdef JOBS
+                       if (state == JOBRUNNING)
+                               continue;
+                       if (WIFSTOPPED(sp->status)) {
+                               jp->stopstatus = sp->status;
+                               state = JOBSTOPPED;
+                       }
+#endif
+               } while (++sp < spend);
+               if (thisjob)
+                       goto gotjob;
+       }
+#ifdef JOBS
+       if (!WIFSTOPPED(status))
+#endif
+
+               jobless--;
+       goto out;
+
+gotjob:
+       if (state != JOBRUNNING) {
+               thisjob->changed = 1;
+
+               if (thisjob->state != state) {
+                       TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
+                       thisjob->state = state;
+#ifdef JOBS
+                       if (state == JOBSTOPPED) {
+                               set_curjob(thisjob, CUR_STOPPED);
+                       }
+#endif
+               }
+       }
+
+out:
+       INTON;
+
+       if (thisjob && thisjob == job) {
+               char s[48 + 1];
+               int len;
+
+               len = sprint_status(s, status, 1);
+               if (len) {
+                       s[len] = '\n';
+                       s[len + 1] = 0;
+                       out2str(s);
+               }
+       }
+       return pid;
+}
+
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+
+int
+stoppedjobs(void)
+{
+       struct job *jp;
+       int retval;
+
+       retval = 0;
+       if (job_warning)
+               goto out;
+       jp = curjob;
+       if (jp && jp->state == JOBSTOPPED) {
+               out2str("You have stopped jobs.\n");
+               job_warning = 2;
+               retval++;
+       }
+
+out:
+       return retval;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command).
+ */
+
+#if JOBS
+static char *cmdnextc;
+
+static char *
+commandtext(union node *n)
+{
+       char *name;
+
+       STARTSTACKSTR(cmdnextc);
+       cmdtxt(n);
+       name = stackblock();
+       TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
+               name, cmdnextc, cmdnextc));
+       return savestr(name);
+}
+
+static void
+cmdtxt(union node *n)
+{
+       union node *np;
+       struct nodelist *lp;
+       const char *p;
+       char s[2];
+
+       switch (n->type) {
+       default:
+#if DEBUG
+               abort();
+#endif
+       case NPIPE:
+               lp = n->npipe.cmdlist;
+               for (;;) {
+                       cmdtxt(lp->n);
+                       lp = lp->next;
+                       if (!lp)
+                               break;
+                       cmdputs(" | ");
+               }
+               break;
+       case NSEMI:
+               p = "; ";
+               goto binop;
+       case NAND:
+               p = " && ";
+               goto binop;
+       case NOR:
+               p = " || ";
+binop:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs(p);
+               n = n->nbinary.ch2;
+               goto donode;
+       case NREDIR:
+       case NBACKGND:
+               n = n->nredir.n;
+               goto donode;
+       case NNOT:
+               cmdputs("!");
+               n = n->nnot.com;
+donode:
+               cmdtxt(n);
+               break;
+       case NIF:
+               cmdputs("if ");
+               cmdtxt(n->nif.test);
+               cmdputs("; then ");
+               n = n->nif.ifpart;
+               if (n->nif.elsepart) {
+                       cmdtxt(n);
+                       cmdputs("; else ");
+                       n = n->nif.elsepart;
+               }
+               p = "; fi";
+               goto dotail;
+       case NSUBSHELL:
+               cmdputs("(");
+               n = n->nredir.n;
+               p = ")";
+               goto dotail;
+       case NWHILE:
+               p = "while ";
+               goto until;
+       case NUNTIL:
+               p = "until ";
+until:
+               cmdputs(p);
+               cmdtxt(n->nbinary.ch1);
+               n = n->nbinary.ch2;
+               p = "; done";
+dodo:
+               cmdputs("; do ");
+dotail:
+               cmdtxt(n);
+               goto dotail2;
+       case NFOR:
+               cmdputs("for ");
+               cmdputs(n->nfor.var);
+               cmdputs(" in ");
+               cmdlist(n->nfor.args, 1);
+               n = n->nfor.body;
+               p = "; done";
+               goto dodo;
+       case NDEFUN:
+               cmdputs(n->narg.text);
+               p = "() { ... }";
+               goto dotail2;
+       case NCMD:
+               cmdlist(n->ncmd.args, 1);
+               cmdlist(n->ncmd.redirect, 0);
+               break;
+       case NARG:
+               p = n->narg.text;
+dotail2:
+               cmdputs(p);
+               break;
+       case NHERE:
+       case NXHERE:
+               p = "<<...";
+               goto dotail2;
+       case NCASE:
+               cmdputs("case ");
+               cmdputs(n->ncase.expr->narg.text);
+               cmdputs(" in ");
+               for (np = n->ncase.cases; np; np = np->nclist.next) {
+                       cmdtxt(np->nclist.pattern);
+                       cmdputs(") ");
+                       cmdtxt(np->nclist.body);
+                       cmdputs(";; ");
+               }
+               p = "esac";
+               goto dotail2;
+       case NTO:
+               p = ">";
+               goto redir;
+       case NCLOBBER:
+               p = ">|";
+               goto redir;
+       case NAPPEND:
+               p = ">>";
+               goto redir;
+       case NTOFD:
+               p = ">&";
+               goto redir;
+       case NFROM:
+               p = "<";
+               goto redir;
+       case NFROMFD:
+               p = "<&";
+               goto redir;
+       case NFROMTO:
+               p = "<>";
+redir:
+               s[0] = n->nfile.fd + '0';
+               s[1] = '\0';
+               cmdputs(s);
+               cmdputs(p);
+               if (n->type == NTOFD || n->type == NFROMFD) {
+                       s[0] = n->ndup.dupfd + '0';
+                       p = s;
+                       goto dotail2;
+               } else {
+                       n = n->nfile.fname;
+                       goto donode;
+               }
+       }
+}
+
+static void
+cmdlist(union node *np, int sep)
+{
+       for (; np; np = np->narg.next) {
+               if (!sep)
+                       cmdputs(spcstr);
+               cmdtxt(np);
+               if (sep && np->narg.next)
+                       cmdputs(spcstr);
+       }
+}
+
+static void
+cmdputs(const char *s)
+{
+       const char *p, *str;
+       char c, cc[2] = " ";
+       char *nextc;
+       int subtype = 0;
+       int quoted = 0;
+       static const char *const vstype[16] = {
+               nullstr, "}", "-", "+", "?", "=",
+               "#", "##", "%", "%%"
+       };
+
+       nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
+       p = s;
+       while ((c = *p++) != 0) {
+               str = 0;
+               switch (c) {
+               case CTLESC:
+                       c = *p++;
+                       break;
+               case CTLVAR:
+                       subtype = *p++;
+                       if ((subtype & VSTYPE) == VSLENGTH)
+                               str = "${#";
+                       else
+                               str = "${";
+                       if (!(subtype & VSQUOTE) != !(quoted & 1)) {
+                               quoted ^= 1;
+                               c = '"';
+                       } else
+                               goto dostr;
+                       break;
+               case CTLENDVAR:
+                       quoted >>= 1;
+                       subtype = 0;
+                       if (quoted & 1) {
+                               str = "\"}";
+                               goto dostr;
+                       }
+                       c = '}';
+                       break;
+               case CTLBACKQ:
+                       str = "$(...)";
+                       goto dostr;
+               case CTLBACKQ+CTLQUOTE:
+                       str = "\"$(...)\"";
+                       goto dostr;
+#ifdef BB_ASH_MATH_SUPPORT
+               case CTLARI:
+                       str = "$((";
+                       goto dostr;
+               case CTLENDARI:
+                       str = "))";
+                       goto dostr;
+#endif
+               case CTLQUOTEMARK:
+                       quoted ^= 1;
+                       c = '"';
+                       break;
+               case '=':
+                       if (subtype == 0)
+                               break;
+                       str = vstype[subtype & VSTYPE];
+                       if (subtype & VSNUL)
+                               c = ':';
+                       else
+                               c = *str++;
+                       if (c != '}')
+                               quoted <<= 1;
+                       break;
+               case '\'':
+               case '\\':
+               case '"':
+               case '$':
+                       /* These can only happen inside quotes */
+                       cc[0] = c;
+                       str = cc;
+                       c = '\\';
+                       break;
+               default:
+                       break;
+               }
+               USTPUTC(c, nextc);
+               if (!str)
+                       continue;
+dostr:
+               while ((c = *str++)) {
+                       USTPUTC(c, nextc);
+               }
+       }
+       if (quoted & 1) {
+               USTPUTC('"', nextc);
+       }
+       *nextc = 0;
+       cmdnextc = nextc;
+}
+
+
+static void
+showpipe(struct job *jp, FILE *out)
+{
+       struct procstat *sp;
+       struct procstat *spend;
+
+       spend = jp->ps + jp->nprocs;
+       for (sp = jp->ps + 1; sp < spend; sp++)
+               fprintf(out, " | %s", sp->cmd);
+       outcslow('\n', out);
+       flushall();
+}
+
+static void
+xtcsetpgrp(int fd, pid_t pgrp)
+{
+       if (tcsetpgrp(fd, pgrp))
+               error("Cannot set tty process group (%m)");
+}
+#endif /* JOBS */
+
+static int
+getstatus(struct job *job) {
+       int status;
+       int retval;
+
+       status = job->ps[job->nprocs - 1].status;
+       retval = WEXITSTATUS(status);
+       if (!WIFEXITED(status)) {
+#if JOBS
+               retval = WSTOPSIG(status);
+               if (!WIFSTOPPED(status))
+#endif
+               {
+                       /* XXX: limits number of signals */
+                       retval = WTERMSIG(status);
+#if JOBS
+                       if (retval == SIGINT)
+                               job->sigint = 1;
+#endif
+               }
+               retval += 128;
+       }
+       TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
+               jobno(job), job->nprocs, status, retval));
+       return retval;
+}
+
+#ifdef BB_ASH_MAIL
+/*      $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $       */
+
+/*
+ * Routines to check for mail.  (Perhaps make part of main.c?)
+ */
+
+#define MAXMBOXES 10
+
+/* times of mailboxes */
+static time_t mailtime[MAXMBOXES];
+/* Set if MAIL or MAILPATH is changed. */
+static int mail_var_path_changed;
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived.
+ * If mail_var_path_changed is set,
+ * then the value of MAIL has mail_var_path_changed,
+ * so we just update the values.
+ */
+
+static void
+chkmail(void)
+{
+       const char *mpath;
+       char *p;
+       char *q;
+       time_t *mtp;
+       struct stackmark smark;
+       struct stat statb;
+
+       setstackmark(&smark);
+       mpath = mpathset() ? mpathval() : mailval();
+       for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
+               p = padvance(&mpath, nullstr);
+               if (p == NULL)
+                       break;
+               if (*p == '\0')
+                       continue;
+               for (q = p ; *q ; q++);
+#ifdef DEBUG
+               if (q[-1] != '/')
+                       abort();
+#endif
+               q[-1] = '\0';                   /* delete trailing '/' */
+               if (stat(p, &statb) < 0) {
+                       *mtp = 0;
+                       continue;
+               }
+               if (!mail_var_path_changed && statb.st_mtime != *mtp) {
+                       fprintf(
+                               stderr, snlfmt,
+                               pathopt ? pathopt : "you have mail"
+                       );
+               }
+               *mtp = statb.st_mtime;
+       }
+       mail_var_path_changed = 0;
+       popstackmark(&smark);
+}
+
+
+static void
+changemail(const char *val)
+{
+       mail_var_path_changed++;
+}
+
+#endif /* BB_ASH_MAIL */
+
+/*      $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $       */
+
+
+#if PROFILE
+static short profile_buf[16384];
+extern int etext();
+#endif
+
+static int isloginsh;
+
+static void read_profile(const char *);
+
+/*
+ * Main routine.  We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands.  The setjmp call sets up the location to jump to when an
+ * exception occurs.  When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+ash_main(int argc, char **argv)
+{
+       char *shinit;
+       volatile int state;
+       struct jmploc jmploc;
+       struct stackmark smark;
+
+#ifdef __GLIBC__
+       dash_errno = __errno_location();
+#endif
+
+#if PROFILE
+       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+#endif
+       state = 0;
+       if (setjmp(jmploc.loc)) {
+               int status;
+               int e;
+
+               reset();
+
+               e = exception;
+               switch (exception) {
+               case EXEXEC:
+                       status = exerrno;
+                       break;
+
+               case EXERROR:
+                       status = 2;
+                       break;
+
+               default:
+                       status = exitstatus;
+                       break;
+               }
+               exitstatus = status;
+
+               if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
+                       exitshell();
+
+               if (e == EXINT) {
+                       outcslow('\n', stderr);
+               }
+               popstackmark(&smark);
+               FORCEINTON;                             /* enable interrupts */
+               if (state == 1)
+                       goto state1;
+               else if (state == 2)
+                       goto state2;
+               else if (state == 3)
+                       goto state3;
+               else
+                       goto state4;
+       }
+       handler = &jmploc;
+#ifdef DEBUG
+       opentrace();
+       trputs("Shell args:  ");  trargs(argv);
+#endif
+       rootpid = getpid();
+       rootshell = 1;
+       init();
+       setstackmark(&smark);
+       procargs(argc, argv);
+#ifdef BB_FEATURE_COMMAND_SAVEHISTORY
+       if ( iflag ) {
+               const char *hp = lookupvar("HISTFILE");
+
+               if(hp == NULL ) {
+                       hp = lookupvar("HOME");
+                       if(hp != NULL) {
+                               char *defhp = concat_path_file(hp, ".ash_history");
+                               setvar("HISTFILE", defhp, 0);
+                               free(defhp);
+                       }
+               }
+       }
+#endif
+       if (argv[0] && argv[0][0] == '-')
+               isloginsh = 1;
+       if (isloginsh) {
+               state = 1;
+               read_profile("/etc/profile");
+state1:
+               state = 2;
+               read_profile(".profile");
+       }
+state2:
+       state = 3;
+       if (
+#ifndef linux
+               getuid() == geteuid() && getgid() == getegid() &&
+#endif
+               iflag
+       ) {
+               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+                       read_profile(shinit);
+               }
+       }
+state3:
+       state = 4;
+       if (minusc)
+               evalstring(minusc, 0);
+
+       if (sflag || minusc == NULL) {
+#ifdef BB_FEATURE_COMMAND_SAVEHISTORY
+           if ( iflag ) {
+               const char *hp = lookupvar("HISTFILE");
+
+               if(hp != NULL )
+                       load_history ( hp );
+           }
+#endif
+state4: /* XXX ??? - why isn't this before the "if" statement */
+               cmdloop(1);
+       }
+#if PROFILE
+       monitor(0);
+#endif
+#if GPROF
+       {
+               extern void _mcleanup(void);
+               _mcleanup();
+       }
+#endif
+       exitshell();
+       /* NOTREACHED */
+}
+
+
+/*
+ * Read and execute commands.  "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static void
+cmdloop(int top)
+{
+       union node *n;
+       struct stackmark smark;
+       int inter;
+       int numeof = 0;
+
+       TRACE(("cmdloop(%d) called\n", top));
+       setstackmark(&smark);
+       for (;;) {
+               if (pendingsigs)
+                       dotrap();
+#if JOBS
+               if (jobctl)
+                       showjobs(stderr, SHOW_CHANGED);
+#endif
+               inter = 0;
+               if (iflag && top) {
+                       inter++;
+#ifdef BB_ASH_MAIL
+                       chkmail();
+#endif
+               }
+               n = parsecmd(inter);
+               /* showtree(n); DEBUG */
+               if (n == NEOF) {
+                       if (!top || numeof >= 50)
+                               break;
+                       if (!stoppedjobs()) {
+                               if (!Iflag)
+                                       break;
+                               out2str("\nUse \"exit\" to leave shell.\n");
+                       }
+                       numeof++;
+               } else if (n != NULL && nflag == 0) {
+                       job_warning = (job_warning == 2) ? 1 : 0;
+                       numeof = 0;
+                       evaltree(n, 0);
+               }
+               popstackmark(&smark);
+               setstackmark(&smark);
+               if (evalskip == SKIPFILE) {
+                       evalskip = 0;
+                       break;
+               }
+       }
+       popstackmark(&smark);
+}
+
+
+/*
+ * Read /etc/profile or .profile.  Return on error.
+ */
+
+static void
+read_profile(const char *name)
+{
+       int fd;
+       int xflag_set = 0;
+       int vflag_set = 0;
+
+       INTOFF;
+       if ((fd = open(name, O_RDONLY)) >= 0)
+               setinputfd(fd, 1);
+       INTON;
+       if (fd < 0)
+               return;
+       /* -q turns off -x and -v just when executing init files */
+       if (qflag)  {
+           if (xflag)
+                   xflag = 0, xflag_set = 1;
+           if (vflag)
+                   vflag = 0, vflag_set = 1;
+       }
+       cmdloop(0);
+       if (qflag)  {
+           if (xflag_set)
+                   xflag = 1;
+           if (vflag_set)
+                   vflag = 1;
+       }
+       popfile();
+}
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+static void
+readcmdfile(char *name)
+{
+       int fd;
+
+       INTOFF;
+       if ((fd = open(name, O_RDONLY)) >= 0)
+               setinputfd(fd, 1);
+       else
+               error("Can't open %s", name);
+       INTON;
+       cmdloop(0);
+       popfile();
+}
+
+
+/*
+ * Take commands from a file.  To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+static inline char *
+find_dot_file(char *name)
+{
+       char *fullname;
+       const char *path = pathval();
+       struct stat statb;
+
+       /* don't try this for absolute or relative paths */
+       if (strchr(name, '/'))
+               return name;
+
+       while ((fullname = padvance(&path, name)) != NULL) {
+               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+                       /*
+                        * Don't bother freeing here, since it will
+                        * be freed by the caller.
+                        */
+                       return fullname;
+               }
+               stunalloc(fullname);
+       }
+
+       /* not found in the PATH */
+       error(not_found_msg, name);
+       /* NOTREACHED */
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+       exitstatus = 0;
+
+       if (argc >= 2) {                /* That's what SVR2 does */
+               char *fullname;
+               struct stackmark smark;
+
+               setstackmark(&smark);
+               fullname = find_dot_file(argv[1]);
+               setinputfile(fullname, 1);
+               commandname = fullname;
+               cmdloop(0);
+               popfile();
+               popstackmark(&smark);
+       }
+       return exitstatus;
+}
+
+
+static int
+exitcmd(int argc, char **argv)
+{
+       if (stoppedjobs())
+               return 0;
+       if (argc > 1)
+               exitstatus = number(argv[1]);
+       exraise(EXEXIT);
+       /* NOTREACHED */
+}
+
+/*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
+
+/*
+ * Same for malloc, realloc, but returns an error when out of space.
+ */
+
+static pointer
+ckrealloc(pointer p, size_t nbytes)
+{
+       p = realloc(p, nbytes);
+       if (p == NULL)
+               error(memory_exhausted);
+       return p;
+}
+
+static pointer
+ckmalloc(size_t nbytes)
+{
+       return ckrealloc(NULL, nbytes);
+}
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+static char *
+savestr(const char *s)
+{
+       char *p = strdup(s);
+       if (!p)
+               error(memory_exhausted);
+       return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 504 was chosen because the Ultrix malloc handles that size
+ * well.
+ */
+
+
+static pointer
+stalloc(size_t nbytes)
+{
+       char *p;
+       size_t aligned;
+
+       aligned = SHELL_ALIGN(nbytes);
+       if (aligned > stacknleft) {
+               size_t len;
+               size_t blocksize;
+               struct stack_block *sp;
+
+               blocksize = aligned;
+               if (blocksize < MINSIZE)
+                       blocksize = MINSIZE;
+               len = sizeof(struct stack_block) - MINSIZE + blocksize;
+               if (len < blocksize)
+                       error(memory_exhausted);
+               INTOFF;
+               sp = ckmalloc(len);
+               sp->prev = stackp;
+               stacknxt = sp->space;
+               stacknleft = blocksize;
+               sstrend = stacknxt + blocksize;
+               stackp = sp;
+               INTON;
+       }
+       p = stacknxt;
+       stacknxt += aligned;
+       stacknleft -= aligned;
+       return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+#ifdef DEBUG
+       if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
+               write(2, "stunalloc\n", 10);
+               abort();
+       }
+#endif
+       stacknleft += stacknxt - (char *)p;
+       stacknxt = p;
+}
+
+
+void
+setstackmark(struct stackmark *mark)
+{
+       mark->stackp = stackp;
+       mark->stacknxt = stacknxt;
+       mark->stacknleft = stacknleft;
+       mark->marknext = markp;
+       markp = mark;
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+       struct stack_block *sp;
+
+       INTOFF;
+       markp = mark->marknext;
+       while (stackp != mark->stackp) {
+               sp = stackp;
+               stackp = sp->prev;
+               ckfree(sp);
+       }
+       stacknxt = mark->stacknxt;
+       stacknleft = mark->stacknleft;
+       sstrend = mark->stacknxt + mark->stacknleft;
+       INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is.  Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block.  Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc).  Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+void
+growstackblock(void)
+{
+       size_t newlen;
+
+       newlen = stacknleft * 2;
+       if (newlen < stacknleft)
+               error(memory_exhausted);
+       if (newlen < 128)
+               newlen += 128;
+
+       if (stacknxt == stackp->space && stackp != &stackbase) {
+               struct stack_block *oldstackp;
+               struct stackmark *xmark;
+               struct stack_block *sp;
+               struct stack_block *prevstackp;
+               size_t grosslen;
+
+               INTOFF;
+               oldstackp = stackp;
+               sp = stackp;
+               prevstackp = sp->prev;
+               grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
+               sp = ckrealloc((pointer)sp, grosslen);
+               sp->prev = prevstackp;
+               stackp = sp;
+               stacknxt = sp->space;
+               stacknleft = newlen;
+               sstrend = sp->space + newlen;
+
+               /*
+                * Stack marks pointing to the start of the old block
+                * must be relocated to point to the new block
+                */
+               xmark = markp;
+               while (xmark != NULL && xmark->stackp == oldstackp) {
+                       xmark->stackp = stackp;
+                       xmark->stacknxt = stacknxt;
+                       xmark->stacknleft = stacknleft;
+                       xmark = xmark->marknext;
+               }
+               INTON;
+       } else {
+               char *oldspace = stacknxt;
+               int oldlen = stacknleft;
+               char *p = stalloc(newlen);
+
+               /* free the space we just allocated */
+               stacknxt = memcpy(p, oldspace, oldlen);
+               stacknleft += newlen;
+       }
+}
+
+static inline void
+grabstackblock(size_t len)
+{
+       len = SHELL_ALIGN(len);
+       stacknxt += len;
+       stacknleft -= len;
+}
+
+/*
+ * The following routines are somewhat easier to use than the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register.  The macro STARTSTACKSTR initializes things.  Then
+ * the user uses the macro STPUTC to add characters to the string.  In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary.  When the user is done, she can just leave the
+ * string there and refer to it using stackblock().  Or she can allocate
+ * the space for it using grabstackstr().  If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+void *
+growstackstr(void)
+{
+       size_t len = stackblocksize();
+       if (herefd >= 0 && len >= 1024) {
+               xwrite(herefd, stackblock(), len);
+               return stackblock();
+       }
+       growstackblock();
+       return stackblock() + len;
+}
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(size_t newlen, char *p)
+{
+       size_t len = p - stacknxt;
+       size_t size = stackblocksize();
+
+       for (;;) {
+               size_t nleft;
+
+               size = stackblocksize();
+               nleft = size - len;
+               if (nleft >= newlen)
+                       break;
+               growstackblock();
+       }
+       return stackblock() + len;
+}
+
+char *
+stnputs(const char *s, size_t n, char *p)
+{
+       p = makestrspace(n, p);
+       p = mempcpy(p, s, n);
+       return p;
+}
+
+char *
+stputs(const char *s, char *p)
+{
+       return stnputs(s, strlen(s), p);
+}
+
+/*      $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $   */
+
+/*
+ * String functions.
+ *
+ *      number(s)               Convert a string of digits to an integer.
+ *      is_number(s)            Return true if s is a string of digits.
+ */
+
+/*
+ * prefix -- see if pfx is a prefix of string.
+ */
+
+char *
+prefix(const char *string, const char *pfx)
+{
+       while (*pfx) {
+               if (*pfx++ != *string++)
+                       return 0;
+       }
+       return (char *) string;
+}
+
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+
+       if (! is_number(s))
+               error(illnum, s);
+       return atoi(s);
+}
+
+
+/*
+ * Check for a valid number.  This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+       do {
+               if (! is_digit(*p))
+                       return 0;
+       } while (*++p != '\0');
+       return 1;
+}
+
+
+/*
+ * Produce a possibly single quoted string suitable as input to the shell.
+ * The return string is allocated on the stack.
+ */
+
+char *
+single_quote(const char *s) {
+       char *p;
+
+       STARTSTACKSTR(p);
+
+       do {
+               char *q;
+               size_t len;
+
+               len = strchrnul(s, '\'') - s;
+
+               q = p = makestrspace(len + 3, p);
+
+               *q++ = '\'';
+               q = mempcpy(q, s, len);
+               *q++ = '\'';
+               s += len;
+
+               STADJUST(q - p, p);
+
+               len = strspn(s, "'");
+               if (!len)
+                       break;
+
+               q = p = makestrspace(len + 3, p);
+
+               *q++ = '"';
+               q = mempcpy(q, s, len);
+               *q++ = '"';
+               s += len;
+
+               STADJUST(q - p, p);
+       } while (*s);
+
+       USTPUTC(0, p);
+
+       return stackblock();
+}
+
+/*
+ * Like strdup but works with the ash stack.
+ */
+
+char *
+sstrdup(const char *p)
+{
+       size_t len = strlen(p) + 1;
+       return memcpy(stalloc(len), p, len);
+}
+
+
+static void
+calcsize(union node *n)
+{
+      if (n == NULL)
+           return;
+      funcblocksize += nodesize[n->type];
+      switch (n->type) {
+      case NCMD:
+           calcsize(n->ncmd.redirect);
+           calcsize(n->ncmd.args);
+           calcsize(n->ncmd.assign);
+           break;
+      case NPIPE:
+           sizenodelist(n->npipe.cmdlist);
+           break;
+      case NREDIR:
+      case NBACKGND:
+      case NSUBSHELL:
+           calcsize(n->nredir.redirect);
+           calcsize(n->nredir.n);
+           break;
+      case NAND:
+      case NOR:
+      case NSEMI:
+      case NWHILE:
+      case NUNTIL:
+           calcsize(n->nbinary.ch2);
+           calcsize(n->nbinary.ch1);
+           break;
+      case NIF:
+           calcsize(n->nif.elsepart);
+           calcsize(n->nif.ifpart);
+           calcsize(n->nif.test);
+           break;
+      case NFOR:
+           funcstringsize += strlen(n->nfor.var) + 1;
+           calcsize(n->nfor.body);
+           calcsize(n->nfor.args);
+           break;
+      case NCASE:
+           calcsize(n->ncase.cases);
+           calcsize(n->ncase.expr);
+           break;
+      case NCLIST:
+           calcsize(n->nclist.body);
+           calcsize(n->nclist.pattern);
+           calcsize(n->nclist.next);
+           break;
+      case NDEFUN:
+      case NARG:
+           sizenodelist(n->narg.backquote);
+           funcstringsize += strlen(n->narg.text) + 1;
+           calcsize(n->narg.next);
+           break;
+      case NTO:
+      case NCLOBBER:
+      case NFROM:
+      case NFROMTO:
+      case NAPPEND:
+           calcsize(n->nfile.fname);
+           calcsize(n->nfile.next);
+           break;
+      case NTOFD:
+      case NFROMFD:
+           calcsize(n->ndup.vname);
+           calcsize(n->ndup.next);
+           break;
+      case NHERE:
+      case NXHERE:
+           calcsize(n->nhere.doc);
+           calcsize(n->nhere.next);
+           break;
+      case NNOT:
+           calcsize(n->nnot.com);
+           break;
+      };
+}
+
+
+static void
+sizenodelist(struct nodelist *lp)
+{
+       while (lp) {
+               funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
+               calcsize(lp->n);
+               lp = lp->next;
+       }
+}
+
+
+static union node *
+copynode(union node *n)
+{
+      union node *new;
+
+      if (n == NULL)
+           return NULL;
+      new = funcblock;
+      funcblock = (char *) funcblock + nodesize[n->type];
+      switch (n->type) {
+      case NCMD:
+           new->ncmd.redirect = copynode(n->ncmd.redirect);
+           new->ncmd.args = copynode(n->ncmd.args);
+           new->ncmd.assign = copynode(n->ncmd.assign);
+           break;
+      case NPIPE:
+           new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
+           new->npipe.backgnd = n->npipe.backgnd;
+           break;
+      case NREDIR:
+      case NBACKGND:
+      case NSUBSHELL:
+           new->nredir.redirect = copynode(n->nredir.redirect);
+           new->nredir.n = copynode(n->nredir.n);
+           break;
+      case NAND:
+      case NOR:
+      case NSEMI:
+      case NWHILE:
+      case NUNTIL:
+           new->nbinary.ch2 = copynode(n->nbinary.ch2);
+           new->nbinary.ch1 = copynode(n->nbinary.ch1);
+           break;
+      case NIF:
+           new->nif.elsepart = copynode(n->nif.elsepart);
+           new->nif.ifpart = copynode(n->nif.ifpart);
+           new->nif.test = copynode(n->nif.test);
+           break;
+      case NFOR:
+           new->nfor.var = nodesavestr(n->nfor.var);
+           new->nfor.body = copynode(n->nfor.body);
+           new->nfor.args = copynode(n->nfor.args);
+           break;
+      case NCASE:
+           new->ncase.cases = copynode(n->ncase.cases);
+           new->ncase.expr = copynode(n->ncase.expr);
+           break;
+      case NCLIST:
+           new->nclist.body = copynode(n->nclist.body);
+           new->nclist.pattern = copynode(n->nclist.pattern);
+           new->nclist.next = copynode(n->nclist.next);
+           break;
+      case NDEFUN:
+      case NARG:
+           new->narg.backquote = copynodelist(n->narg.backquote);
+           new->narg.text = nodesavestr(n->narg.text);
+           new->narg.next = copynode(n->narg.next);
+           break;
+      case NTO:
+      case NCLOBBER:
+      case NFROM:
+      case NFROMTO:
+      case NAPPEND:
+           new->nfile.fname = copynode(n->nfile.fname);
+           new->nfile.fd = n->nfile.fd;
+           new->nfile.next = copynode(n->nfile.next);
+           break;
+      case NTOFD:
+      case NFROMFD:
+           new->ndup.vname = copynode(n->ndup.vname);
+           new->ndup.dupfd = n->ndup.dupfd;
+           new->ndup.fd = n->ndup.fd;
+           new->ndup.next = copynode(n->ndup.next);
+           break;
+      case NHERE:
+      case NXHERE:
+           new->nhere.doc = copynode(n->nhere.doc);
+           new->nhere.fd = n->nhere.fd;
+           new->nhere.next = copynode(n->nhere.next);
+           break;
+      case NNOT:
+           new->nnot.com = copynode(n->nnot.com);
+           break;
+      };
+      new->type = n->type;
+       return new;
+}
+
+
+static struct nodelist *
+copynodelist(struct nodelist *lp)
+{
+       struct nodelist *start;
+       struct nodelist **lpp;
+
+       lpp = &start;
+       while (lp) {
+               *lpp = funcblock;
+               funcblock = (char *) funcblock +
+                   SHELL_ALIGN(sizeof(struct nodelist));
+               (*lpp)->n = copynode(lp->n);
+               lp = lp->next;
+               lpp = &(*lpp)->next;
+       }
+       *lpp = NULL;
+       return start;
+}
+
+
+static char *
+nodesavestr(char   *s)
+{
+       char   *rtn = funcstring;
+
+       funcstring = stpcpy(funcstring, s) + 1;
+       return rtn;
+}
+
+
+/*
+ * Free a parse tree.
+ */
+
+static void
+freefunc(struct funcnode *f)
+{
+       if (f && --f->count < 0)
+               ckfree(f);
+}
+
+
+static void options(int);
+static void setoption(int, int);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+void
+procargs(int argc, char **argv)
+{
+       int i;
+       const char *xminusc;
+       char **xargv;
+
+       xargv = argv;
+       arg0 = xargv[0];
+       if (argc > 0)
+               xargv++;
+       for (i = 0; i < NOPTS; i++)
+               optlist[i] = 2;
+       argptr = xargv;
+       options(1);
+       xargv = argptr;
+       xminusc = minusc;
+       if (*xargv == NULL) {
+               if (xminusc)
+                       error("-c requires an argument");
+               sflag = 1;
+       }
+       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
+               iflag = 1;
+       if (mflag == 2)
+               mflag = iflag;
+       for (i = 0; i < NOPTS; i++)
+               if (optlist[i] == 2)
+                       optlist[i] = 0;
+#if DEBUG == 2
+       debug = 1;
+#endif
+       /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+       if (xminusc) {
+               minusc = *xargv++;
+               if (*xargv)
+                       goto setarg0;
+       } else if (!sflag) {
+               setinputfile(*xargv, 0);
+setarg0:
+               arg0 = *xargv++;
+               commandname = arg0;
+       }
+
+       shellparam.p = xargv;
+#ifdef BB_ASH_GETOPTS
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+#endif
+       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+       while (*xargv) {
+               shellparam.nparam++;
+               xargv++;
+       }
+       optschanged();
+}
+
+
+void
+optschanged(void)
+{
+#ifdef DEBUG
+       opentrace();
+#endif
+       setinteractive(iflag);
+       setjobctl(mflag);
+}
+
+static inline void
+minus_o(char *name, int val)
+{
+       int i;
+
+       if (name == NULL) {
+               out1str("Current option settings\n");
+               for (i = 0; i < NOPTS; i++)
+                       out1fmt("%-16s%s\n", optnames(i),
+                               optlist[i] ? "on" : "off");
+       } else {
+               for (i = 0; i < NOPTS; i++)
+                       if (equal(name, optnames(i))) {
+                               optlist[i] = val;
+                               return;
+                       }
+               error("Illegal option -o %s", name);
+       }
+}
+
+/*
+ * Process shell options.  The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ */
+
+static void
+options(int cmdline)
+{
+       char *p;
+       int val;
+       int c;
+
+       if (cmdline)
+               minusc = NULL;
+       while ((p = *argptr) != NULL) {
+               argptr++;
+               if ((c = *p++) == '-') {
+                       val = 1;
+                       if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+                               if (!cmdline) {
+                                       /* "-" means turn off -x and -v */
+                                       if (p[0] == '\0')
+                                               xflag = vflag = 0;
+                                       /* "--" means reset params */
+                                       else if (*argptr == NULL)
+                                               setparam(argptr);
+                               }
+                               break;    /* "-" or  "--" terminates options */
+                       }
+               } else if (c == '+') {
+                       val = 0;
+               } else {
+                       argptr--;
+                       break;
+               }
+               while ((c = *p++) != '\0') {
+                       if (c == 'c' && cmdline) {
+                               minusc = p;     /* command is after shell args*/
+                       } else if (c == 'o') {
+                               minus_o(*argptr, val);
+                               if (*argptr)
+                                       argptr++;
+                       } else if (cmdline && (c == '-')) {     // long options
+                               if (strcmp(p, "login") == 0)
+                                       isloginsh = 1;
+                               break;
+                       } else {
+                               setoption(c, val);
+                       }
+               }
+       }
+}
+
+
+static void
+setoption(int flag, int val)
+{
+       int i;
+
+       for (i = 0; i < NOPTS; i++)
+               if (optletters(i) == flag) {
+                       optlist[i] = val;
+                       return;
+               }
+       error("Illegal option -%c", flag);
+       /* NOTREACHED */
+}
+
+
+
+/*
+ * Set the shell parameters.
+ */
+
+void
+setparam(char **argv)
+{
+       char **newparam;
+       char **ap;
+       int nparam;
+
+       for (nparam = 0 ; argv[nparam] ; nparam++);
+       ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
+       while (*argv) {
+               *ap++ = savestr(*argv++);
+       }
+       *ap = NULL;
+       freeparam(&shellparam);
+       shellparam.malloc = 1;
+       shellparam.nparam = nparam;
+       shellparam.p = newparam;
+#ifdef BB_ASH_GETOPTS
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+#endif
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(volatile struct shparam *param)
+{
+       char **ap;
+
+       if (param->malloc) {
+               for (ap = param->p ; *ap ; ap++)
+                       ckfree(*ap);
+               ckfree(param->p);
+       }
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+       int n;
+       char **ap1, **ap2;
+
+       n = 1;
+       if (argc > 1)
+               n = number(argv[1]);
+       if (n > shellparam.nparam)
+               error("can't shift that many");
+       INTOFF;
+       shellparam.nparam -= n;
+       for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
+               if (shellparam.malloc)
+                       ckfree(*ap1);
+       }
+       ap2 = shellparam.p;
+       while ((*ap2++ = *ap1++) != NULL);
+#ifdef BB_ASH_GETOPTS
+       shellparam.optind = 1;
+       shellparam.optoff = -1;
+#endif
+       INTON;
+       return 0;
+}
+
+
+
+/*
+ * The set command builtin.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+       if (argc == 1)
+               return showvars(nullstr, 0, VUNSET);
+       INTOFF;
+       options(0);
+       optschanged();
+       if (*argptr != NULL) {
+               setparam(argptr);
+       }
+       INTON;
+       return 0;
+}
+
+
+#ifdef BB_ASH_GETOPTS
+static void
+getoptsreset(value)
+       const char *value;
+{
+       shellparam.optind = number(value);
+       shellparam.optoff = -1;
+}
+#endif
+
+#ifdef BB_LOCALE_SUPPORT
+static void change_lc_all(const char *value)
+{
+       if (value != 0 && *value != 0)
+               setlocale(LC_ALL, value);
+}
+
+static void change_lc_ctype(const char *value)
+{
+       if (value != 0 && *value != 0)
+               setlocale(LC_CTYPE, value);
+}
+
+#endif
+
+#ifdef BB_ASH_GETOPTS
+static int
+getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
+{
+       char *p, *q;
+       char c = '?';
+       int done = 0;
+       int err = 0;
+       char s[12];
+       char **optnext;
+
+       if(*param_optind < 1)
+               return 1;
+       optnext = optfirst + *param_optind - 1;
+
+       if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
+               p = NULL;
+       else
+               p = optnext[-1] + *optoff;
+       if (p == NULL || *p == '\0') {
+               /* Current word is done, advance */
+               p = *optnext;
+               if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+                       p = NULL;
+                       done = 1;
+                       goto out;
+               }
+               optnext++;
+               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
+                       goto atend;
+       }
+
+       c = *p++;
+       for (q = optstr; *q != c; ) {
+               if (*q == '\0') {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               err |= setvarsafe("OPTARG", s, 0);
+                       } else {
+                               fprintf(stderr, "Illegal option -%c\n", c);
+                               (void) unsetvar("OPTARG");
+                       }
+                       c = '?';
+                       goto out;
+               }
+               if (*++q == ':')
+                       q++;
+       }
+
+       if (*++q == ':') {
+               if (*p == '\0' && (p = *optnext) == NULL) {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+                               err |= setvarsafe("OPTARG", s, 0);
+                               c = ':';
+                       } else {
+                               fprintf(stderr, "No arg for -%c option\n", c);
+                               (void) unsetvar("OPTARG");
+                               c = '?';
+                       }
+                       goto out;
+               }
+
+               if (p == *optnext)
+                       optnext++;
+               err |= setvarsafe("OPTARG", p, 0);
+               p = NULL;
+       } else
+               err |= setvarsafe("OPTARG", nullstr, 0);
+
+out:
+       *optoff = p ? p - *(optnext - 1) : -1;
+       *param_optind = optnext - optfirst + 1;
+       fmtstr(s, sizeof(s), "%d", *param_optind);
+       err |= setvarsafe("OPTIND", s, VNOFUNC);
+       s[0] = c;
+       s[1] = '\0';
+       err |= setvarsafe(optvar, s, 0);
+       if (err) {
+               *param_optind = 1;
+               *optoff = -1;
+               flushall();
+               exraise(EXERROR);
+       }
+       return done;
+}
+
+/*
+ * The getopts builtin.  Shellparam.optnext points to the next argument
+ * to be processed.  Shellparam.optptr points to the next character to
+ * be processed in the current argument.  If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+       char **optbase;
+
+       if (argc < 3)
+               error("Usage: getopts optstring var [arg]");
+       else if (argc == 3) {
+               optbase = shellparam.p;
+               if (shellparam.optind > shellparam.nparam + 1) {
+                       shellparam.optind = 1;
+                       shellparam.optoff = -1;
+               }
+       }
+       else {
+               optbase = &argv[3];
+               if (shellparam.optind > argc - 2) {
+                       shellparam.optind = 1;
+                       shellparam.optoff = -1;
+               }
+       }
+
+       return getopts(argv[1], argv[2], optbase, &shellparam.optind,
+                      &shellparam.optoff);
+}
+#endif /* BB_ASH_GETOPTS */
+
+/*
+ * XXX - should get rid of.  have all builtins use getopt(3).  the
+ * library getopt must have the BSD extension static variable "optreset"
+ * otherwise it can't be used within the shell safely.
+ *
+ * Standard option processing (a la getopt) for builtin routines.  The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary.  It return the character, or '\0' on
+ * end of input.
+ */
+
+static int
+nextopt(const char *optstring)
+{
+       char *p;
+       const char *q;
+       char c;
+
+       if ((p = optptr) == NULL || *p == '\0') {
+               p = *argptr;
+               if (p == NULL || *p != '-' || *++p == '\0')
+                       return '\0';
+               argptr++;
+               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
+                       return '\0';
+       }
+       c = *p++;
+       for (q = optstring ; *q != c ; ) {
+               if (*q == '\0')
+                       error("Illegal option -%c", c);
+               if (*++q == ':')
+                       q++;
+       }
+       if (*++q == ':') {
+               if (*p == '\0' && (p = *argptr++) == NULL)
+                       error("No arg for -%c option", c);
+               optionarg = p;
+               p = NULL;
+       }
+       optptr = p;
+       return c;
+}
+
+
+/*      $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $     */
+
+void
+outstr(const char *p, FILE *file)
+{
+       INTOFF;
+       fputs(p, file);
+       INTON;
+}
+
+void
+flushall(void)
+{
+       INTOFF;
+       fflush(stdout);
+       fflush(stderr);
+       INTON;
+}
+
+void
+flushout(FILE *dest)
+{
+       INTOFF;
+       fflush(dest);
+       INTON;
+}
+
+static void
+outcslow(int c, FILE *dest)
+{
+       INTOFF;
+       putc(c, dest);
+       fflush(dest);
+       INTON;
+}
+
+
+static int
+out1fmt(const char *fmt, ...)
+{
+       va_list ap;
+       int r;
+
+       INTOFF;
+       va_start(ap, fmt);
+       r = vprintf(fmt, ap);
+       va_end(ap);
+       INTON;
+       return r;
+}
+
+
+int
+fmtstr(char *outbuf, size_t length, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       INTOFF;
+       ret = vsnprintf(outbuf, length, fmt, ap);
+       va_end(ap);
+       INTON;
+       return ret;
+}
+
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+static void
+xwrite(int fd, const void *p, size_t n)
+{
+       ssize_t i;
+
+       do {
+               i = full_write(fd, p, n);
+       } while (i < 0 && errno == EINTR);
+}
+
+
+/*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
+
+
+/*
+ * Shell command parser.
+ */
+
+#define EOFMARKLEN 79
+
+
+struct heredoc {
+       struct heredoc *next;   /* next here document in list */
+       union node *here;               /* redirection node */
+       char *eofmark;          /* string indicating end of input */
+       int striptabs;          /* if set, strip leading tabs */
+};
+
+
+
+static struct heredoc *heredoclist;    /* list of here documents to read */
+
+
+static union node *list(int);
+static union node *andor(void);
+static union node *pipeline(void);
+static union node *command(void);
+static union node *simplecmd(void);
+static union node *makename(void);
+static void parsefname(void);
+static void parseheredoc(void);
+static char peektoken(void);
+static int readtoken(void);
+static int xxreadtoken(void);
+static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
+static int noexpand(char *);
+static void synexpect(int) __attribute__((__noreturn__));
+static void synerror(const char *) __attribute__((__noreturn__));
+static void setprompt(int);
+
+
+static inline int
+goodname(const char *p)
+{
+       return !*endofname(p);
+}
+
+static inline int
+isassignment(const char *p)
+{
+       const char *q = endofname(p);
+       if (p == q)
+               return 0;
+       return *q == '=';
+}
+
+
+/*
+ * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+       int t;
+
+       tokpushback = 0;
+       doprompt = interact;
+       if (doprompt)
+               setprompt(doprompt);
+       needprompt = 0;
+       t = readtoken();
+       if (t == TEOF)
+               return NEOF;
+       if (t == TNL)
+               return NULL;
+       tokpushback++;
+       return list(1);
+}
+
+
+static union node *
+list(int nlflag)
+{
+       union node *n1, *n2, *n3;
+       int tok;
+
+       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+       if (nlflag == 2 && peektoken())
+               return NULL;
+       n1 = NULL;
+       for (;;) {
+               n2 = andor();
+               tok = readtoken();
+               if (tok == TBACKGND) {
+                       if (n2->type == NPIPE) {
+                               n2->npipe.backgnd = 1;
+                       } else {
+                               if (n2->type != NREDIR) {
+                                       n3 = stalloc(sizeof(struct nredir));
+                                       n3->nredir.n = n2;
+                                       n3->nredir.redirect = NULL;
+                                       n2 = n3;
+                               }
+                               n2->type = NBACKGND;
+                       }
+               }
+               if (n1 == NULL) {
+                       n1 = n2;
+               }
+               else {
+                       n3 = (union node *)stalloc(sizeof (struct nbinary));
+                       n3->type = NSEMI;
+                       n3->nbinary.ch1 = n1;
+                       n3->nbinary.ch2 = n2;
+                       n1 = n3;
+               }
+               switch (tok) {
+               case TBACKGND:
+               case TSEMI:
+                       tok = readtoken();
+                       /* fall through */
+               case TNL:
+                       if (tok == TNL) {
+                               parseheredoc();
+                               if (nlflag == 1)
+                                       return n1;
+                       } else {
+                               tokpushback++;
+                       }
+                       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                       if (peektoken())
+                               return n1;
+                       break;
+               case TEOF:
+                       if (heredoclist)
+                               parseheredoc();
+                       else
+                               pungetc();              /* push back EOF on input */
+                       return n1;
+               default:
+                       if (nlflag == 1)
+                               synexpect(-1);
+                       tokpushback++;
+                       return n1;
+               }
+       }
+}
+
+
+
+static union node *
+andor(void)
+{
+       union node *n1, *n2, *n3;
+       int t;
+
+       n1 = pipeline();
+       for (;;) {
+               if ((t = readtoken()) == TAND) {
+                       t = NAND;
+               } else if (t == TOR) {
+                       t = NOR;
+               } else {
+                       tokpushback++;
+                       return n1;
+               }
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               n2 = pipeline();
+               n3 = (union node *)stalloc(sizeof (struct nbinary));
+               n3->type = t;
+               n3->nbinary.ch1 = n1;
+               n3->nbinary.ch2 = n2;
+               n1 = n3;
+       }
+}
+
+
+
+static union node *
+pipeline(void)
+{
+       union node *n1, *n2, *pipenode;
+       struct nodelist *lp, *prev;
+       int negate;
+
+       negate = 0;
+       TRACE(("pipeline: entered\n"));
+       if (readtoken() == TNOT) {
+               negate = !negate;
+               checkkwd = CHKKWD | CHKALIAS;
+       } else
+               tokpushback++;
+       n1 = command();
+       if (readtoken() == TPIPE) {
+               pipenode = (union node *)stalloc(sizeof (struct npipe));
+               pipenode->type = NPIPE;
+               pipenode->npipe.backgnd = 0;
+               lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+               pipenode->npipe.cmdlist = lp;
+               lp->n = n1;
+               do {
+                       prev = lp;
+                       lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+                       checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                       lp->n = command();
+                       prev->next = lp;
+               } while (readtoken() == TPIPE);
+               lp->next = NULL;
+               n1 = pipenode;
+       }
+       tokpushback++;
+       if (negate) {
+               n2 = (union node *)stalloc(sizeof (struct nnot));
+               n2->type = NNOT;
+               n2->nnot.com = n1;
+               return n2;
+       } else
+               return n1;
+}
+
+
+
+static union node *
+command(void)
+{
+       union node *n1, *n2;
+       union node *ap, **app;
+       union node *cp, **cpp;
+       union node *redir, **rpp;
+       union node **rpp2;
+       int t;
+
+       redir = NULL;
+       rpp2 = &redir;
+
+       switch (readtoken()) {
+       default:
+               synexpect(-1);
+               /* NOTREACHED */
+       case TIF:
+               n1 = (union node *)stalloc(sizeof (struct nif));
+               n1->type = NIF;
+               n1->nif.test = list(0);
+               if (readtoken() != TTHEN)
+                       synexpect(TTHEN);
+               n1->nif.ifpart = list(0);
+               n2 = n1;
+               while (readtoken() == TELIF) {
+                       n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+                       n2 = n2->nif.elsepart;
+                       n2->type = NIF;
+                       n2->nif.test = list(0);
+                       if (readtoken() != TTHEN)
+                               synexpect(TTHEN);
+                       n2->nif.ifpart = list(0);
+               }
+               if (lasttoken == TELSE)
+                       n2->nif.elsepart = list(0);
+               else {
+                       n2->nif.elsepart = NULL;
+                       tokpushback++;
+               }
+               t = TFI;
+               break;
+       case TWHILE:
+       case TUNTIL: {
+               int got;
+               n1 = (union node *)stalloc(sizeof (struct nbinary));
+               n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
+               n1->nbinary.ch1 = list(0);
+               if ((got=readtoken()) != TDO) {
+TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
+                       synexpect(TDO);
+               }
+               n1->nbinary.ch2 = list(0);
+               t = TDONE;
+               break;
+       }
+       case TFOR:
+               if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+                       synerror("Bad for loop variable");
+               n1 = (union node *)stalloc(sizeof (struct nfor));
+               n1->type = NFOR;
+               n1->nfor.var = wordtext;
+               checkkwd = CHKKWD | CHKALIAS;
+               if (readtoken() == TIN) {
+                       app = &ap;
+                       while (readtoken() == TWORD) {
+                               n2 = (union node *)stalloc(sizeof (struct narg));
+                               n2->type = NARG;
+                               n2->narg.text = wordtext;
+                               n2->narg.backquote = backquotelist;
+                               *app = n2;
+                               app = &n2->narg.next;
+                       }
+                       *app = NULL;
+                       n1->nfor.args = ap;
+                       if (lasttoken != TNL && lasttoken != TSEMI)
+                               synexpect(-1);
+               } else {
+                       n2 = (union node *)stalloc(sizeof (struct narg));
+                       n2->type = NARG;
+                       n2->narg.text = (char *)dolatstr;
+                       n2->narg.backquote = NULL;
+                       n2->narg.next = NULL;
+                       n1->nfor.args = n2;
+                       /*
+                        * Newline or semicolon here is optional (but note
+                        * that the original Bourne shell only allowed NL).
+                        */
+                       if (lasttoken != TNL && lasttoken != TSEMI)
+                               tokpushback++;
+               }
+               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+               if (readtoken() != TDO)
+                       synexpect(TDO);
+               n1->nfor.body = list(0);
+               t = TDONE;
+               break;
+       case TCASE:
+               n1 = (union node *)stalloc(sizeof (struct ncase));
+               n1->type = NCASE;
+               if (readtoken() != TWORD)
+                       synexpect(TWORD);
+               n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
+               n2->type = NARG;
+               n2->narg.text = wordtext;
+               n2->narg.backquote = backquotelist;
+               n2->narg.next = NULL;
+               do {
+                       checkkwd = CHKKWD | CHKALIAS;
+               } while (readtoken() == TNL);
+               if (lasttoken != TIN)
+                       synexpect(TIN);
+               cpp = &n1->ncase.cases;
+next_case:
+               checkkwd = CHKNL | CHKKWD;
+               t = readtoken();
+               while(t != TESAC) {
+                       if (lasttoken == TLP)
+                               readtoken();
+                       *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+                       cp->type = NCLIST;
+                       app = &cp->nclist.pattern;
+                       for (;;) {
+                               *app = ap = (union node *)stalloc(sizeof (struct narg));
+                               ap->type = NARG;
+                               ap->narg.text = wordtext;
+                               ap->narg.backquote = backquotelist;
+                               if (readtoken() != TPIPE)
+                                       break;
+                               app = &ap->narg.next;
+                               readtoken();
+                       }
+                       ap->narg.next = NULL;
+                       if (lasttoken != TRP)
+                               synexpect(TRP);
+                       cp->nclist.body = list(2);
+
+                       cpp = &cp->nclist.next;
+
+                       checkkwd = CHKNL | CHKKWD;
+                       if ((t = readtoken()) != TESAC) {
+                               if (t != TENDCASE)
+                                       synexpect(TENDCASE);
+                               else
+                                       goto next_case;
+                       }
+               }
+               *cpp = NULL;
+               goto redir;
+       case TLP:
+               n1 = (union node *)stalloc(sizeof (struct nredir));
+               n1->type = NSUBSHELL;
+               n1->nredir.n = list(0);
+               n1->nredir.redirect = NULL;
+               t = TRP;
+               break;
+       case TBEGIN:
+               n1 = list(0);
+               t = TEND;
+               break;
+       case TWORD:
+       case TREDIR:
+               tokpushback++;
+               return simplecmd();
+       }
+
+       if (readtoken() != t)
+               synexpect(t);
+
+redir:
+       /* Now check for redirection which may follow command */
+       checkkwd = CHKKWD | CHKALIAS;
+       rpp = rpp2;
+       while (readtoken() == TREDIR) {
+               *rpp = n2 = redirnode;
+               rpp = &n2->nfile.next;
+               parsefname();
+       }
+       tokpushback++;
+       *rpp = NULL;
+       if (redir) {
+               if (n1->type != NSUBSHELL) {
+                       n2 = (union node *)stalloc(sizeof (struct nredir));
+                       n2->type = NREDIR;
+                       n2->nredir.n = n1;
+                       n1 = n2;
+               }
+               n1->nredir.redirect = redir;
+       }
+
+       return n1;
+}
+
+
+static union node *
+simplecmd(void) {
+       union node *args, **app;
+       union node *n = NULL;
+       union node *vars, **vpp;
+       union node **rpp, *redir;
+       int savecheckkwd;
+
+       args = NULL;
+       app = &args;
+       vars = NULL;
+       vpp = &vars;
+       redir = NULL;
+       rpp = &redir;
+
+       savecheckkwd = CHKALIAS;
+       for (;;) {
+               checkkwd = savecheckkwd;
+               switch (readtoken()) {
+               case TWORD:
+                       n = (union node *)stalloc(sizeof (struct narg));
+                       n->type = NARG;
+                       n->narg.text = wordtext;
+                       n->narg.backquote = backquotelist;
+                       if (savecheckkwd && isassignment(wordtext)) {
+                               *vpp = n;
+                               vpp = &n->narg.next;
+                       } else {
+                               *app = n;
+                               app = &n->narg.next;
+                               savecheckkwd = 0;
+                       }
+                       break;
+               case TREDIR:
+                       *rpp = n = redirnode;
+                       rpp = &n->nfile.next;
+                       parsefname();   /* read name of redirection file */
+                       break;
+               case TLP:
+                       if (
+                               args && app == &args->narg.next &&
+                               !vars && !redir
+                       ) {
+                               struct builtincmd *bcmd;
+                               const char *name;
+
+                               /* We have a function */
+                               if (readtoken() != TRP)
+                                       synexpect(TRP);
+                               name = n->narg.text;
+                               if (
+                                       !goodname(name) || (
+                                               (bcmd = find_builtin(name)) &&
+                                               IS_BUILTIN_SPECIAL(bcmd)
+                                       )
+                               )
+                                       synerror("Bad function name");
+                               n->type = NDEFUN;
+                               checkkwd = CHKNL | CHKKWD | CHKALIAS;
+                               n->narg.next = command();
+                               return n;
+                       }
+                       /* fall through */
+               default:
+                       tokpushback++;
+                       goto out;
+               }
+       }
+out:
+       *app = NULL;
+       *vpp = NULL;
+       *rpp = NULL;
+       n = (union node *)stalloc(sizeof (struct ncmd));
+       n->type = NCMD;
+       n->ncmd.args = args;
+       n->ncmd.assign = vars;
+       n->ncmd.redirect = redir;
+       return n;
+}
+
+static union node *
+makename(void)
+{
+       union node *n;
+
+       n = (union node *)stalloc(sizeof (struct narg));
+       n->type = NARG;
+       n->narg.next = NULL;
+       n->narg.text = wordtext;
+       n->narg.backquote = backquotelist;
+       return n;
+}
+
+void fixredir(union node *n, const char *text, int err)
+{
+       TRACE(("Fix redir %s %d\n", text, err));
+       if (!err)
+               n->ndup.vname = NULL;
+
+       if (is_digit(text[0]) && text[1] == '\0')
+               n->ndup.dupfd = digit_val(text[0]);
+       else if (text[0] == '-' && text[1] == '\0')
+               n->ndup.dupfd = -1;
+       else {
+
+               if (err)
+                       synerror("Bad fd number");
+               else
+                       n->ndup.vname = makename();
+       }
+}
+
+
+static void
+parsefname(void)
+{
+       union node *n = redirnode;
+
+       if (readtoken() != TWORD)
+               synexpect(-1);
+       if (n->type == NHERE) {
+               struct heredoc *here = heredoc;
+               struct heredoc *p;
+               int i;
+
+               if (quoteflag == 0)
+                       n->type = NXHERE;
+               TRACE(("Here document %d\n", n->type));
+               if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
+                       synerror("Illegal eof marker for << redirection");
+               rmescapes(wordtext);
+               here->eofmark = wordtext;
+               here->next = NULL;
+               if (heredoclist == NULL)
+                       heredoclist = here;
+               else {
+                       for (p = heredoclist ; p->next ; p = p->next);
+                       p->next = here;
+               }
+       } else if (n->type == NTOFD || n->type == NFROMFD) {
+               fixredir(n, wordtext, 0);
+       } else {
+               n->nfile.fname = makename();
+       }
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+static void
+parseheredoc(void)
+{
+       struct heredoc *here;
+       union node *n;
+
+       here = heredoclist;
+       heredoclist = 0;
+
+       while (here) {
+               if (needprompt) {
+                       setprompt(2);
+                       needprompt = 0;
+               }
+               readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+                               here->eofmark, here->striptabs);
+               n = (union node *)stalloc(sizeof (struct narg));
+               n->narg.type = NARG;
+               n->narg.next = NULL;
+               n->narg.text = wordtext;
+               n->narg.backquote = backquotelist;
+               here->here->nhere.doc = n;
+               here = here->next;
+       }
+}
+
+static char peektoken(void)
+{
+       int t;
+
+       t = readtoken();
+       tokpushback++;
+       return tokname_array[t][0];
+}
+
+static int
+readtoken(void)
+{
+       int t;
+#ifdef DEBUG
+       int alreadyseen = tokpushback;
+#endif
+
+#ifdef BB_ASH_ALIAS
+top:
+#endif
+
+       t = xxreadtoken();
+
+       /*
+        * eat newlines
+        */
+       if (checkkwd & CHKNL) {
+               while (t == TNL) {
+                       parseheredoc();
+                       t = xxreadtoken();
+               }
+       }
+
+       if (t != TWORD || quoteflag) {
+               goto out;
+       }
+
+       /*
+        * check for keywords
+        */
+       if (checkkwd & CHKKWD) {
+               const char *const *pp;
+
+               if ((pp = findkwd(wordtext))) {
+                       lasttoken = t = pp - tokname_array;
+                       TRACE(("keyword %s recognized\n", tokname(t)));
+                       goto out;
+               }
+       }
+
+       if (checkkwd & CHKALIAS) {
+#ifdef BB_ASH_ALIAS
+               struct alias *ap;
+               if ((ap = lookupalias(wordtext, 1)) != NULL) {
+                       if (*ap->val) {
+                               pushstring(ap->val, ap);
+                       }
+                       goto top;
+               }
+#endif
+       }
+out:
+       checkkwd = 0;
+#ifdef DEBUG
+       if (!alreadyseen)
+           TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
+       else
+           TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
+#endif
+       return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ *      backquotes.  We set quoteflag to true if any part of the word was
+ *      quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ *      the redirection.
+ * In all cases, the variable startlinno is set to the number of the line
+ *      on which the token starts.
+ *
+ * [Change comment:  here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments.  Perhaps we should make the
+ *  word parsing code into a separate routine.  In this case, readtoken
+ *  doesn't need to have any internal procedures, but parseword does.
+ *  We could also make parseoperator in essence the main routine, and
+ *  have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define NEW_xxreadtoken
+#ifdef NEW_xxreadtoken
+
+/* singles must be first! */
+static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
+
+static const char xxreadtoken_tokens[] = {
+       TNL, TLP, TRP,          /* only single occurrence allowed */
+       TBACKGND, TPIPE, TSEMI, /* if single occurrence */
+       TEOF,                   /* corresponds to trailing nul */
+       TAND, TOR, TENDCASE,    /* if double occurrence */
+};
+
+#define xxreadtoken_doubles \
+       (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
+#define xxreadtoken_singles \
+       (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
+
+static int xxreadtoken()
+{
+       int c;
+
+       if (tokpushback) {
+               tokpushback = 0;
+               return lasttoken;
+       }
+       if (needprompt) {
+               setprompt(2);
+               needprompt = 0;
+       }
+       startlinno = plinno;
+       for (;;) {                      /* until token or start of word found */
+               c = pgetc_macro();
+
+               if ((c != ' ') && (c != '\t')
+#ifdef BB_ASH_ALIAS
+                       && (c != PEOA)
+#endif
+                       ) {
+                       if (c == '#') {
+                               while ((c = pgetc()) != '\n' && c != PEOF);
+                               pungetc();
+                       } else if (c == '\\') {
+                               if (pgetc() != '\n') {
+                                       pungetc();
+                                       goto READTOKEN1;
+                               }
+                               startlinno = ++plinno;
+                               if (doprompt)
+                                       setprompt(2);
+                       } else {
+                               const char *p
+                                       = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
+
+                               if (c != PEOF) {
+                                       if (c == '\n') {
+                                               plinno++;
+                                               needprompt = doprompt;
+                                       }
+
+                                       p = strchr(xxreadtoken_chars, c);
+                                       if (p == NULL) {
+                                         READTOKEN1:
+                                               return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
+                                       }
+
+                                       if (p - xxreadtoken_chars >= xxreadtoken_singles) {
+                                               if (pgetc() == *p) {    /* double occurrence? */
+                                                       p += xxreadtoken_doubles + 1;
+                                               } else {
+                                                       pungetc();
+                                               }
+                                       }
+                               }
+
+                               return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
+                       }
+               }
+       }
+}
+
+
+#else
+#define RETURN(token)   return lasttoken = token
+
+static int
+xxreadtoken(void)
+{
+       int c;
+
+       if (tokpushback) {
+               tokpushback = 0;
+               return lasttoken;
+       }
+       if (needprompt) {
+               setprompt(2);
+               needprompt = 0;
+       }
+       startlinno = plinno;
+       for (;;) {      /* until token or start of word found */
+               c = pgetc_macro();
+               switch (c) {
+               case ' ': case '\t':
+#ifdef BB_ASH_ALIAS
+               case PEOA:
+#endif
+                       continue;
+               case '#':
+                       while ((c = pgetc()) != '\n' && c != PEOF);
+                       pungetc();
+                       continue;
+               case '\\':
+                       if (pgetc() == '\n') {
+                               startlinno = ++plinno;
+                               if (doprompt)
+                                       setprompt(2);
+                               continue;
+                       }
+                       pungetc();
+                       goto breakloop;
+               case '\n':
+                       plinno++;
+                       needprompt = doprompt;
+                       RETURN(TNL);
+               case PEOF:
+                       RETURN(TEOF);
+               case '&':
+                       if (pgetc() == '&')
+                               RETURN(TAND);
+                       pungetc();
+                       RETURN(TBACKGND);
+               case '|':
+                       if (pgetc() == '|')
+                               RETURN(TOR);
+                       pungetc();
+                       RETURN(TPIPE);
+               case ';':
+                       if (pgetc() == ';')
+                               RETURN(TENDCASE);
+                       pungetc();
+                       RETURN(TSEMI);
+               case '(':
+                       RETURN(TLP);
+               case ')':
+                       RETURN(TRP);
+               default:
+                       goto breakloop;
+               }
+       }
+breakloop:
+       return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+#undef RETURN
+}
+#endif /* NEW_xxreadtoken */
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
+ * is not NULL, read a here document.  In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document.  The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage.  The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define CHECKEND()      {goto checkend; checkend_return:;}
+#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
+#define PARSESUB()      {goto parsesub; parsesub_return:;}
+#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
+#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
+#define PARSEARITH()    {goto parsearith; parsearith_return:;}
+
+static int
+readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
+{
+       int c = firstc;
+       char *out;
+       int len;
+       char line[EOFMARKLEN + 1];
+       struct nodelist *bqlist;
+       int quotef;
+       int dblquote;
+       int varnest;    /* levels of variables expansion */
+       int arinest;    /* levels of arithmetic expansion */
+       int parenlevel; /* levels of parens in arithmetic */
+       int dqvarnest;  /* levels of variables expansion within double quotes */
+       int oldstyle;
+       int prevsyntax; /* syntax before arithmetic */
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &out;
+       (void) &quotef;
+       (void) &dblquote;
+       (void) &varnest;
+       (void) &arinest;
+       (void) &parenlevel;
+       (void) &dqvarnest;
+       (void) &oldstyle;
+       (void) &prevsyntax;
+       (void) &syntax;
+#endif
+
+       startlinno = plinno;
+       dblquote = 0;
+       if (syntax == DQSYNTAX)
+               dblquote = 1;
+       quotef = 0;
+       bqlist = NULL;
+       varnest = 0;
+       arinest = 0;
+       parenlevel = 0;
+       dqvarnest = 0;
+
+       STARTSTACKSTR(out);
+       loop: { /* for each line, until end of word */
+               CHECKEND();     /* set c to PEOF if at end of here document */
+               for (;;) {      /* until end of line or end of word */
+                       CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
+                       switch(SIT(c, syntax)) {
+                       case CNL:       /* '\n' */
+                               if (syntax == BASESYNTAX)
+                                       goto endword;   /* exit outer loop */
+                               USTPUTC(c, out);
+                               plinno++;
+                               if (doprompt)
+                                       setprompt(2);
+                               c = pgetc();
+                               goto loop;              /* continue outer loop */
+                       case CWORD:
+                               USTPUTC(c, out);
+                               break;
+                       case CCTL:
+                               if (eofmark == NULL || dblquote)
+                                       USTPUTC(CTLESC, out);
+                               USTPUTC(c, out);
+                               break;
+                       case CBACK:     /* backslash */
+                               c = pgetc2();
+                               if (c == PEOF) {
+                                       USTPUTC(CTLESC, out);
+                                       USTPUTC('\\', out);
+                                       pungetc();
+                               } else if (c == '\n') {
+                                       if (doprompt)
+                                               setprompt(2);
+                               } else {
+                                       if (
+                                               dblquote &&
+                                               c != '\\' && c != '`' &&
+                                               c != '$' && (
+                                                       c != '"' ||
+                                                       eofmark != NULL
+                                               )
+                                       ) {
+                                               USTPUTC(CTLESC, out);
+                                               USTPUTC('\\', out);
+                                       }
+                                       if (SIT(c, SQSYNTAX) == CCTL)
+                                               USTPUTC(CTLESC, out);
+                                       USTPUTC(c, out);
+                                       quotef++;
+                               }
+                               break;
+                       case CSQUOTE:
+                               syntax = SQSYNTAX;
+quotemark:
+                               if (eofmark == NULL) {
+                                       USTPUTC(CTLQUOTEMARK, out);
+                               }
+                               break;
+                       case CDQUOTE:
+                               syntax = DQSYNTAX;
+                               dblquote = 1;
+                               goto quotemark;
+                       case CENDQUOTE:
+                               if (eofmark != NULL && arinest == 0 &&
+                                   varnest == 0) {
+                                       USTPUTC(c, out);
+                               } else {
+                                       if (dqvarnest == 0) {
+                                               syntax = BASESYNTAX;
+                                               dblquote = 0;
+                                       }
+                                       quotef++;
+                                       goto quotemark;
+                               }
+                               break;
+                       case CVAR:      /* '$' */
+                               PARSESUB();             /* parse substitution */
+                               break;
+                       case CENDVAR:   /* '}' */
+                               if (varnest > 0) {
+                                       varnest--;
+                                       if (dqvarnest > 0) {
+                                               dqvarnest--;
+                                       }
+                                       USTPUTC(CTLENDVAR, out);
+                               } else {
+                                       USTPUTC(c, out);
+                               }
+                               break;
+#ifdef BB_ASH_MATH_SUPPORT
+                       case CLP:       /* '(' in arithmetic */
+                               parenlevel++;
+                               USTPUTC(c, out);
+                               break;
+                       case CRP:       /* ')' in arithmetic */
+                               if (parenlevel > 0) {
+                                       USTPUTC(c, out);
+                                       --parenlevel;
+                               } else {
+                                       if (pgetc() == ')') {
+                                               if (--arinest == 0) {
+                                                       USTPUTC(CTLENDARI, out);
+                                                       syntax = prevsyntax;
+                                                       if (syntax == DQSYNTAX)
+                                                               dblquote = 1;
+                                                       else
+                                                               dblquote = 0;
+                                               } else
+                                                       USTPUTC(')', out);
+                                       } else {
+                                               /*
+                                                * unbalanced parens
+                                                *  (don't 2nd guess - no error)
+                                                */
+                                               pungetc();
+                                               USTPUTC(')', out);
+                                       }
+                               }
+                               break;
+#endif
+                       case CBQUOTE:   /* '`' */
+                               PARSEBACKQOLD();
+                               break;
+                       case CENDFILE:
+                               goto endword;           /* exit outer loop */
+                       case CIGN:
+                               break;
+                       default:
+                               if (varnest == 0)
+                                       goto endword;   /* exit outer loop */
+#ifdef BB_ASH_ALIAS
+                               if (c != PEOA)
+#endif
+                                       USTPUTC(c, out);
+
+                       }
+                       c = pgetc_macro();
+               }
+       }
+endword:
+#ifdef BB_ASH_MATH_SUPPORT
+       if (syntax == ARISYNTAX)
+               synerror("Missing '))'");
+#endif
+       if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
+               synerror("Unterminated quoted string");
+       if (varnest != 0) {
+               startlinno = plinno;
+               /* { */
+               synerror("Missing '}'");
+       }
+       USTPUTC('\0', out);
+       len = out - (char *)stackblock();
+       out = stackblock();
+       if (eofmark == NULL) {
+               if ((c == '>' || c == '<')
+                && quotef == 0
+                && len <= 2
+                && (*out == '\0' || is_digit(*out))) {
+                       PARSEREDIR();
+                       return lasttoken = TREDIR;
+               } else {
+                       pungetc();
+               }
+       }
+       quoteflag = quotef;
+       backquotelist = bqlist;
+       grabstackblock(len);
+       wordtext = out;
+       return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+
+/*
+ * Check to see whether we are at the end of the here document.  When this
+ * is called, c is set to the first character of the next input line.  If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ */
+
+checkend: {
+       if (eofmark) {
+#ifdef BB_ASH_ALIAS
+               if (c == PEOA) {
+                       c = pgetc2();
+               }
+#endif
+               if (striptabs) {
+                       while (c == '\t') {
+                               c = pgetc2();
+                       }
+               }
+               if (c == *eofmark) {
+                       if (pfgets(line, sizeof line) != NULL) {
+                               char *p, *q;
+
+                               p = line;
+                               for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
+                               if (*p == '\n' && *q == '\0') {
+                                       c = PEOF;
+                                       plinno++;
+                                       needprompt = doprompt;
+                               } else {
+                                       pushstring(line, NULL);
+                               }
+                       }
+               }
+       }
+       goto checkend_return;
+}
+
+
+/*
+ * Parse a redirection operator.  The variable "out" points to a string
+ * specifying the fd to be redirected.  The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+parseredir: {
+       char fd = *out;
+       union node *np;
+
+       np = (union node *)stalloc(sizeof (struct nfile));
+       if (c == '>') {
+               np->nfile.fd = 1;
+               c = pgetc();
+               if (c == '>')
+                       np->type = NAPPEND;
+               else if (c == '|')
+                       np->type = NCLOBBER;
+               else if (c == '&')
+                       np->type = NTOFD;
+               else {
+                       np->type = NTO;
+                       pungetc();
+               }
+       } else {        /* c == '<' */
+               np->nfile.fd = 0;
+               switch (c = pgetc()) {
+               case '<':
+                       if (sizeof (struct nfile) != sizeof (struct nhere)) {
+                               np = (union node *)stalloc(sizeof (struct nhere));
+                               np->nfile.fd = 0;
+                       }
+                       np->type = NHERE;
+                       heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+                       heredoc->here = np;
+                       if ((c = pgetc()) == '-') {
+                               heredoc->striptabs = 1;
+                       } else {
+                               heredoc->striptabs = 0;
+                               pungetc();
+                       }
+                       break;
+
+               case '&':
+                       np->type = NFROMFD;
+                       break;
+
+               case '>':
+                       np->type = NFROMTO;
+                       break;
+
+               default:
+                       np->type = NFROM;
+                       pungetc();
+                       break;
+               }
+       }
+       if (fd != '\0')
+               np->nfile.fd = digit_val(fd);
+       redirnode = np;
+       goto parseredir_return;
+}
+
+
+/*
+ * Parse a substitution.  At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+       int subtype;
+       int typeloc;
+       int flags;
+       char *p;
+       static const char types[] = "}-+?=";
+
+       c = pgetc();
+       if (
+               c <= PEOA_OR_PEOF  ||
+               (c != '(' && c != '{' && !is_name(c) && !is_special(c))
+       ) {
+               USTPUTC('$', out);
+               pungetc();
+       } else if (c == '(') {  /* $(command) or $((arith)) */
+               if (pgetc() == '(') {
+#ifdef BB_ASH_MATH_SUPPORT
+                       PARSEARITH();
+#else
+                       synerror("We unsupport $((arith))");
+#endif
+               } else {
+                       pungetc();
+                       PARSEBACKQNEW();
+               }
+       } else {
+               USTPUTC(CTLVAR, out);
+               typeloc = out - (char *)stackblock();
+               USTPUTC(VSNORMAL, out);
+               subtype = VSNORMAL;
+               if (c == '{') {
+                       c = pgetc();
+                       if (c == '#') {
+                               if ((c = pgetc()) == '}')
+                                       c = '#';
+                               else
+                                       subtype = VSLENGTH;
+                       }
+                       else
+                               subtype = 0;
+               }
+               if (c > PEOA_OR_PEOF && is_name(c)) {
+                       do {
+                               STPUTC(c, out);
+                               c = pgetc();
+                       } while (c > PEOA_OR_PEOF && is_in_name(c));
+               } else if (is_digit(c)) {
+                       do {
+                               STPUTC(c, out);
+                               c = pgetc();
+                       } while (is_digit(c));
+               }
+               else if (is_special(c)) {
+                       USTPUTC(c, out);
+                       c = pgetc();
+               }
+               else
+badsub:                 synerror("Bad substitution");
+
+               STPUTC('=', out);
+               flags = 0;
+               if (subtype == 0) {
+                       switch (c) {
+                       case ':':
+                               flags = VSNUL;
+                               c = pgetc();
+                               /*FALLTHROUGH*/
+                       default:
+                               p = strchr(types, c);
+                               if (p == NULL)
+                                       goto badsub;
+                               subtype = p - types + VSNORMAL;
+                               break;
+                       case '%':
+                       case '#':
+                               {
+                                       int cc = c;
+                                       subtype = c == '#' ? VSTRIMLEFT :
+                                                            VSTRIMRIGHT;
+                                       c = pgetc();
+                                       if (c == cc)
+                                               subtype++;
+                                       else
+                                               pungetc();
+                                       break;
+                               }
+                       }
+               } else {
+                       pungetc();
+               }
+               if (dblquote || arinest)
+                       flags |= VSQUOTE;
+               *((char *)stackblock() + typeloc) = subtype | flags;
+               if (subtype != VSNORMAL) {
+                       varnest++;
+                       if (dblquote || arinest) {
+                               dqvarnest++;
+                       }
+               }
+       }
+       goto parsesub_return;
+}
+
+
+/*
+ * Called to parse command substitutions.  Newstyle is set if the command
+ * is enclosed inside $(...); nlpp is a pointer to the head of the linked
+ * list of commands (passed by reference), and savelen is the number of
+ * characters on the top of the stack which must be preserved.
+ */
+
+parsebackq: {
+       struct nodelist **nlpp;
+       int savepbq;
+       union node *n;
+       char *volatile str;
+       struct jmploc jmploc;
+       struct jmploc *volatile savehandler;
+       size_t savelen;
+       int saveprompt;
+#ifdef __GNUC__
+       (void) &saveprompt;
+#endif
+
+       savepbq = parsebackquote;
+       if (setjmp(jmploc.loc)) {
+               if (str)
+                       ckfree(str);
+               parsebackquote = 0;
+               handler = savehandler;
+               longjmp(handler->loc, 1);
+       }
+       INTOFF;
+       str = NULL;
+       savelen = out - (char *)stackblock();
+       if (savelen > 0) {
+               str = ckmalloc(savelen);
+               memcpy(str, stackblock(), savelen);
+       }
+       savehandler = handler;
+       handler = &jmploc;
+       INTON;
+       if (oldstyle) {
+               /* We must read until the closing backquote, giving special
+                  treatment to some slashes, and then push the string and
+                  reread it as input, interpreting it normally.  */
+               char *pout;
+               int pc;
+               size_t psavelen;
+               char *pstr;
+
+
+               STARTSTACKSTR(pout);
+               for (;;) {
+                       if (needprompt) {
+                               setprompt(2);
+                               needprompt = 0;
+                       }
+                       switch (pc = pgetc()) {
+                       case '`':
+                               goto done;
+
+                       case '\\':
+                               if ((pc = pgetc()) == '\n') {
+                                       plinno++;
+                                       if (doprompt)
+                                               setprompt(2);
+                                       /*
+                                        * If eating a newline, avoid putting
+                                        * the newline into the new character
+                                        * stream (via the STPUTC after the
+                                        * switch).
+                                        */
+                                       continue;
+                               }
+                               if (pc != '\\' && pc != '`' && pc != '$'
+                                   && (!dblquote || pc != '"'))
+                                       STPUTC('\\', pout);
+                               if (pc > PEOA_OR_PEOF) {
+                                       break;
+                               }
+                               /* fall through */
+
+                       case PEOF:
+#ifdef BB_ASH_ALIAS
+                       case PEOA:
+#endif
+                               startlinno = plinno;
+                               synerror("EOF in backquote substitution");
+
+                       case '\n':
+                               plinno++;
+                               needprompt = doprompt;
+                               break;
+
+                       default:
+                               break;
+                       }
+                       STPUTC(pc, pout);
+               }
+done:
+               STPUTC('\0', pout);
+               psavelen = pout - (char *)stackblock();
+               if (psavelen > 0) {
+                       pstr = grabstackstr(pout);
+                       setinputstring(pstr);
+               }
+       }
+       nlpp = &bqlist;
+       while (*nlpp)
+               nlpp = &(*nlpp)->next;
+       *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+       (*nlpp)->next = NULL;
+       parsebackquote = oldstyle;
+
+       if (oldstyle) {
+               saveprompt = doprompt;
+               doprompt = 0;
+       }
+
+       n = list(2);
+
+       if (oldstyle)
+               doprompt = saveprompt;
+       else {
+               if (readtoken() != TRP)
+                       synexpect(TRP);
+       }
+
+       (*nlpp)->n = n;
+       if (oldstyle) {
+               /*
+                * Start reading from old file again, ignoring any pushed back
+                * tokens left from the backquote parsing
+                */
+               popfile();
+               tokpushback = 0;
+       }
+       while (stackblocksize() <= savelen)
+               growstackblock();
+       STARTSTACKSTR(out);
+       if (str) {
+               memcpy(out, str, savelen);
+               STADJUST(savelen, out);
+               INTOFF;
+               ckfree(str);
+               str = NULL;
+               INTON;
+       }
+       parsebackquote = savepbq;
+       handler = savehandler;
+       if (arinest || dblquote)
+               USTPUTC(CTLBACKQ | CTLQUOTE, out);
+       else
+               USTPUTC(CTLBACKQ, out);
+       if (oldstyle)
+               goto parsebackq_oldreturn;
+       else
+               goto parsebackq_newreturn;
+}
+
+#ifdef BB_ASH_MATH_SUPPORT
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+       if (++arinest == 1) {
+               prevsyntax = syntax;
+               syntax = ARISYNTAX;
+               USTPUTC(CTLARI, out);
+               if (dblquote)
+                       USTPUTC('"',out);
+               else
+                       USTPUTC(' ',out);
+       } else {
+               /*
+                * we collapse embedded arithmetic expansion to
+                * parenthesis, which should be equivalent
+                */
+               USTPUTC('(', out);
+       }
+       goto parsearith_return;
+}
+#endif
+
+} /* end of readtoken */
+
+
+
+/*
+ * Returns true if the text contains nothing to expand (no dollar signs
+ * or backquotes).
+ */
+
+static int
+noexpand(char *text)
+{
+       char *p;
+       char c;
+
+       p = text;
+       while ((c = *p++) != '\0') {
+               if (c == CTLQUOTEMARK)
+                       continue;
+               if (c == CTLESC)
+                       p++;
+               else if (SIT(c, BASESYNTAX) == CCTL)
+                       return 0;
+       }
+       return 1;
+}
+
+
+/*
+ * Return of a legal variable name (a letter or underscore followed by zero or
+ * more letters, underscores, and digits).
+ */
+
+char *
+endofname(const char *name)
+{
+       char *p;
+
+       p = (char *) name;
+       if (! is_name(*p))
+               return p;
+       while (*++p) {
+               if (! is_in_name(*p))
+                       break;
+       }
+       return p;
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse.  The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+static void synexpect(int token)
+{
+       char msg[64];
+       int l;
+
+       l = sprintf(msg, "%s unexpected", tokname(lasttoken));
+       if (token >= 0)
+               sprintf(msg + l, " (expecting %s)", tokname(token));
+       synerror(msg);
+       /* NOTREACHED */
+}
+
+static void
+synerror(const char *msg)
+{
+       error("Syntax error: %s", msg);
+       /* NOTREACHED */
+}
+
+
+/*
+ * called by editline -- any expansions to the prompt
+ *    should be added here.
+ */
+
+static void setprompt(int whichprompt)
+{
+       const char *prompt;
+
+       switch (whichprompt) {
+       case 1:
+               prompt = ps1val();
+               break;
+       case 2:
+               prompt = ps2val();
+               break;
+       default:                        /* 0 */
+               prompt = nullstr;
+       }
+       putprompt(prompt);
+}
+
+
+static const char *const *findkwd(const char *s)
+{
+       return bsearch(s, tokname_array + KWDOFFSET,
+                      (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
+                                  sizeof(const char *), pstrcmp);
+}
+
+/*      $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $      */
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#define EMPTY -2                /* marks an unused slot in redirtab */
+#ifndef PIPE_BUF
+# define PIPESIZE 4096          /* amount of buffering in a pipe */
+#else
+# define PIPESIZE PIPE_BUF
+#endif
+
+/*
+ * Open a file in noclobber mode.
+ * The code was copied from bash.
+ */
+static inline int
+noclobberopen(const char *fname)
+{
+       int r, fd;
+       struct stat finfo, finfo2;
+
+       /*
+        * If the file exists and is a regular file, return an error
+        * immediately.
+        */
+       r = stat(fname, &finfo);
+       if (r == 0 && S_ISREG(finfo.st_mode)) {
+               errno = EEXIST;
+               return -1;
+       }
+
+       /*
+        * If the file was not present (r != 0), make sure we open it
+        * exclusively so that if it is created before we open it, our open
+        * will fail.  Make sure that we do not truncate an existing file.
+        * Note that we don't turn on O_EXCL unless the stat failed -- if the
+        * file was not a regular file, we leave O_EXCL off.
+        */
+       if (r != 0)
+               return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
+       fd = open(fname, O_WRONLY|O_CREAT, 0666);
+
+       /* If the open failed, return the file descriptor right away. */
+       if (fd < 0)
+               return fd;
+
+       /*
+        * OK, the open succeeded, but the file may have been changed from a
+        * non-regular file to a regular file between the stat and the open.
+        * We are assuming that the O_EXCL open handles the case where FILENAME
+        * did not exist and is symlinked to an existing file between the stat
+        * and open.
+        */
+
+       /*
+        * If we can open it and fstat the file descriptor, and neither check
+        * revealed that it was a regular file, and the file has not been
+        * replaced, return the file descriptor.
+        */
+        if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
+            finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
+               return fd;
+
+       /* The file has been replaced.  badness. */
+       close(fd);
+       errno = EEXIST;
+       return -1;
+}
+
+/*
+ * Handle here documents.  Normally we fork off a process to write the
+ * data to a pipe.  If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+static inline int
+openhere(union node *redir)
+{
+       int pip[2];
+       size_t len = 0;
+
+       if (pipe(pip) < 0)
+               error("Pipe call failed");
+       if (redir->type == NHERE) {
+               len = strlen(redir->nhere.doc->narg.text);
+               if (len <= PIPESIZE) {
+                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
+                       goto out;
+               }
+       }
+       if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+               close(pip[0]);
+               signal(SIGINT, SIG_IGN);
+               signal(SIGQUIT, SIG_IGN);
+               signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP
+               signal(SIGTSTP, SIG_IGN);
+#endif
+               signal(SIGPIPE, SIG_DFL);
+               if (redir->type == NHERE)
+                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
+               else
+                       expandhere(redir->nhere.doc, pip[1]);
+               _exit(0);
+       }
+out:
+       close(pip[1]);
+       return pip[0];
+}
+
+static int
+openredirect(union node *redir)
+{
+       char *fname;
+       int f;
+
+       switch (redir->nfile.type) {
+       case NFROM:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_RDONLY)) < 0)
+                       goto eopen;
+               break;
+       case NFROMTO:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
+                       goto ecreate;
+               break;
+       case NTO:
+               /* Take care of noclobber mode. */
+               if (Cflag) {
+                       fname = redir->nfile.expfname;
+                       if ((f = noclobberopen(fname)) < 0)
+                               goto ecreate;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case NCLOBBER:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+                       goto ecreate;
+               break;
+       case NAPPEND:
+               fname = redir->nfile.expfname;
+               if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+                       goto ecreate;
+               break;
+       default:
+#ifdef DEBUG
+               abort();
+#endif
+               /* Fall through to eliminate warning. */
+       case NTOFD:
+       case NFROMFD:
+               f = -1;
+               break;
+       case NHERE:
+       case NXHERE:
+               f = openhere(redir);
+               break;
+       }
+
+       return f;
+ecreate:
+       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+       error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+}
+
+static inline void
+dupredirect(union node *redir, int f)
+{
+       int fd = redir->nfile.fd;
+
+       if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
+               if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
+                               ash_copyfd(redir->ndup.dupfd, fd);
+               }
+               return;
+       }
+
+       if (f != fd) {
+               ash_copyfd(f, fd);
+               close(f);
+       }
+       return;
+}
+
+/*
+ * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+ */
+
+static void
+redirect(union node *redir, int flags)
+{
+       union node *n;
+       struct redirtab *sv;
+       int i;
+       int fd;
+       int newfd;
+       int *p;
+       nullredirs++;
+       if (!redir) {
+               return;
+       }
+       sv = NULL;
+       INTOFF;
+       if (flags & REDIR_PUSH) {
+               struct redirtab *q;
+               q = ckmalloc(sizeof (struct redirtab));
+               q->next = redirlist;
+               redirlist = q;
+               q->nullredirs = nullredirs - 1;
+               for (i = 0 ; i < 10 ; i++)
+                       q->renamed[i] = EMPTY;
+               nullredirs = 0;
+               sv = q;
+       }
+       n = redir;
+       do {
+               fd = n->nfile.fd;
+               if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
+                   n->ndup.dupfd == fd)
+                       continue; /* redirect from/to same file descriptor */
+
+               newfd = openredirect(n);
+               if (fd == newfd)
+                       continue;
+               if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
+                       i = fcntl(fd, F_DUPFD, 10);
+
+                       if (i == -1) {
+                               i = errno;
+                               if (i != EBADF) {
+                                       close(newfd);
+                                       errno = i;
+                                       error("%d: %m", fd);
+                                       /* NOTREACHED */
+                               }
+                       } else {
+                               *p = i;
+                               close(fd);
+                       }
+               } else {
+                       close(fd);
+               }
+               dupredirect(n, newfd);
+       } while ((n = n->nfile.next));
+       INTON;
+       if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
+               preverrout_fd = sv->renamed[2];
+}
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(int drop)
+{
+       struct redirtab *rp;
+       int i;
+
+       if (--nullredirs >= 0)
+               return;
+       INTOFF;
+       rp = redirlist;
+       for (i = 0 ; i < 10 ; i++) {
+               if (rp->renamed[i] != EMPTY) {
+                       if (!drop) {
+                               close(i);
+                               ash_copyfd(rp->renamed[i], i);
+                       }
+                       close(rp->renamed[i]);
+               }
+       }
+       redirlist = rp->next;
+       nullredirs = rp->nullredirs;
+       ckfree(rp);
+       INTON;
+}
+
+/*
+ * Undo all redirections.  Called on error or interrupt.
+ */
+
+/*
+ * Discard all saved file descriptors.
+ */
+
+void
+clearredir(int drop)
+{
+       for (;;) {
+               nullredirs = 0;
+               if (!redirlist)
+                       break;
+               popredir(drop);
+       }
+}
+
+
+/*
+ * Copy a file descriptor to be >= to.  Returns -1
+ * if the source file descriptor is closed, EMPTY if there are no unused
+ * file descriptors left.
+ */
+
+int
+ash_copyfd(int from, int to)
+{
+       int newfd;
+
+       newfd = fcntl(from, F_DUPFD, to);
+       if (newfd < 0) {
+               if (errno == EMFILE)
+                       return EMPTY;
+               else
+                       error("%d: %m", from);
+       }
+       return newfd;
+}
+
+
+int
+redirectsafe(union node *redir, int flags)
+{
+       int err;
+       volatile int saveint;
+       struct jmploc *volatile savehandler = handler;
+       struct jmploc jmploc;
+
+       SAVEINT(saveint);
+       if (!(err = setjmp(jmploc.loc) * 2)) {
+               handler = &jmploc;
+               redirect(redir, flags);
+       }
+       handler = savehandler;
+       if (err && exception != EXERROR)
+               longjmp(handler->loc, 1);
+       RESTOREINT(saveint);
+       return err;
+}
+
+/*      $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $    */
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+       trputs("showtree called\n");
+       shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+       struct nodelist *lp;
+       const char *s;
+
+       if (n == NULL)
+               return;
+
+       indent(ind, pfx, fp);
+       switch(n->type) {
+       case NSEMI:
+               s = "; ";
+               goto binop;
+       case NAND:
+               s = " && ";
+               goto binop;
+       case NOR:
+               s = " || ";
+binop:
+               shtree(n->nbinary.ch1, ind, NULL, fp);
+          /*    if (ind < 0) */
+                       fputs(s, fp);
+               shtree(n->nbinary.ch2, ind, NULL, fp);
+               break;
+       case NCMD:
+               shcmd(n, fp);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       case NPIPE:
+               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+                       shcmd(lp->n, fp);
+                       if (lp->next)
+                               fputs(" | ", fp);
+               }
+               if (n->npipe.backgnd)
+                       fputs(" &", fp);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       default:
+               fprintf(fp, "<node type %d>", n->type);
+               if (ind >= 0)
+                       putc('\n', fp);
+               break;
+       }
+}
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+       union node *np;
+       int first;
+       const char *s;
+       int dftfd;
+
+       first = 1;
+       for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+               if (! first)
+                       putchar(' ');
+               sharg(np, fp);
+               first = 0;
+       }
+       for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+               if (! first)
+                       putchar(' ');
+               switch (np->nfile.type) {
+                       case NTO:       s = ">";  dftfd = 1; break;
+                       case NCLOBBER:  s = ">|"; dftfd = 1; break;
+                       case NAPPEND:   s = ">>"; dftfd = 1; break;
+                       case NTOFD:     s = ">&"; dftfd = 1; break;
+                       case NFROM:     s = "<";  dftfd = 0; break;
+                       case NFROMFD:   s = "<&"; dftfd = 0; break;
+                       case NFROMTO:   s = "<>"; dftfd = 0; break;
+                       default:        s = "*error*"; dftfd = 0; break;
+               }
+               if (np->nfile.fd != dftfd)
+                       fprintf(fp, "%d", np->nfile.fd);
+               fputs(s, fp);
+               if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+                       fprintf(fp, "%d", np->ndup.dupfd);
+               } else {
+                       sharg(np->nfile.fname, fp);
+               }
+               first = 0;
+       }
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+       char *p;
+       struct nodelist *bqlist;
+       int subtype;
+
+       if (arg->type != NARG) {
+               out1fmt("<node type %d>\n", arg->type);
+               abort();
+       }
+       bqlist = arg->narg.backquote;
+       for (p = arg->narg.text ; *p ; p++) {
+               switch (*p) {
+               case CTLESC:
+                       putc(*++p, fp);
+                       break;
+               case CTLVAR:
+                       putc('$', fp);
+                       putc('{', fp);
+                       subtype = *++p;
+                       if (subtype == VSLENGTH)
+                               putc('#', fp);
+
+                       while (*p != '=')
+                               putc(*p++, fp);
+
+                       if (subtype & VSNUL)
+                               putc(':', fp);
+
+                       switch (subtype & VSTYPE) {
+                       case VSNORMAL:
+                               putc('}', fp);
+                               break;
+                       case VSMINUS:
+                               putc('-', fp);
+                               break;
+                       case VSPLUS:
+                               putc('+', fp);
+                               break;
+                       case VSQUESTION:
+                               putc('?', fp);
+                               break;
+                       case VSASSIGN:
+                               putc('=', fp);
+                               break;
+                       case VSTRIMLEFT:
+                               putc('#', fp);
+                               break;
+                       case VSTRIMLEFTMAX:
+                               putc('#', fp);
+                               putc('#', fp);
+                               break;
+                       case VSTRIMRIGHT:
+                               putc('%', fp);
+                               break;
+                       case VSTRIMRIGHTMAX:
+                               putc('%', fp);
+                               putc('%', fp);
+                               break;
+                       case VSLENGTH:
+                               break;
+                       default:
+                               out1fmt("<subtype %d>", subtype);
+                       }
+                       break;
+               case CTLENDVAR:
+                    putc('}', fp);
+                    break;
+               case CTLBACKQ:
+               case CTLBACKQ|CTLQUOTE:
+                       putc('$', fp);
+                       putc('(', fp);
+                       shtree(bqlist->n, -1, NULL, fp);
+                       putc(')', fp);
+                       break;
+               default:
+                       putc(*p, fp);
+                       break;
+               }
+       }
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+       int i;
+
+       for (i = 0 ; i < amount ; i++) {
+               if (pfx && i == amount - 1)
+                       fputs(pfx, fp);
+               putc('\t', fp);
+       }
+}
+
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+
+void
+trputc(int c)
+{
+       if (debug != 1)
+               return;
+       putc(c, tracefile);
+}
+
+void
+trace(const char *fmt, ...)
+{
+       va_list va;
+
+       if (debug != 1)
+               return;
+       va_start(va, fmt);
+       (void) vfprintf(tracefile, fmt, va);
+       va_end(va);
+}
+
+void
+tracev(const char *fmt, va_list va)
+{
+       if (debug != 1)
+               return;
+       (void) vfprintf(tracefile, fmt, va);
+}
+
+
+void
+trputs(const char *s)
+{
+       if (debug != 1)
+               return;
+       fputs(s, tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+       char *p;
+       char c;
+
+       if (debug != 1)
+               return;
+       putc('"', tracefile);
+       for (p = s ; *p ; p++) {
+               switch (*p) {
+               case '\n':  c = 'n';  goto backslash;
+               case '\t':  c = 't';  goto backslash;
+               case '\r':  c = 'r';  goto backslash;
+               case '"':  c = '"';  goto backslash;
+               case '\\':  c = '\\';  goto backslash;
+               case CTLESC:  c = 'e';  goto backslash;
+               case CTLVAR:  c = 'v';  goto backslash;
+               case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
+               case CTLBACKQ:  c = 'q';  goto backslash;
+               case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
+backslash:        putc('\\', tracefile);
+                       putc(c, tracefile);
+                       break;
+               default:
+                       if (*p >= ' ' && *p <= '~')
+                               putc(*p, tracefile);
+                       else {
+                               putc('\\', tracefile);
+                               putc(*p >> 6 & 03, tracefile);
+                               putc(*p >> 3 & 07, tracefile);
+                               putc(*p & 07, tracefile);
+                       }
+                       break;
+               }
+       }
+       putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+       if (debug != 1)
+               return;
+       while (*ap) {
+               trstring(*ap++);
+               if (*ap)
+                       putc(' ', tracefile);
+               else
+                       putc('\n', tracefile);
+       }
+}
+
+
+void
+opentrace(void)
+{
+       char s[100];
+#ifdef O_APPEND
+       int flags;
+#endif
+
+       if (debug != 1) {
+               if (tracefile)
+                       fflush(tracefile);
+               /* leave open because libedit might be using it */
+               return;
+       }
+       scopy("./trace", s);
+       if (tracefile) {
+               if (!freopen(s, "a", tracefile)) {
+                       fprintf(stderr, "Can't re-open %s\n", s);
+                       debug = 0;
+                       return;
+               }
+       } else {
+               if ((tracefile = fopen(s, "a")) == NULL) {
+                       fprintf(stderr, "Can't open %s\n", s);
+                       debug = 0;
+                       return;
+               }
+       }
+#ifdef O_APPEND
+       if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+               fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+#endif
+       setlinebuf(tracefile);
+       fputs("\nTracing started.\n", tracefile);
+}
+#endif /* DEBUG */
+
+
+/*      $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $       */
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes.  A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1                 /* default signal handling (SIG_DFL) */
+#define S_CATCH 2               /* signal is caught */
+#define S_IGN 3                 /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4            /* signal is ignored permenantly */
+#define S_RESET 5               /* temporary - to reset a hard ignored sig */
+
+
+
+/*
+ * The trap builtin.
+ */
+
+int
+trapcmd(int argc, char **argv)
+{
+       char *action;
+       char **ap;
+       int signo;
+
+       nextopt(nullstr);
+       ap = argptr;
+       if (!*ap) {
+               for (signo = 0 ; signo < NSIG ; signo++) {
+                       if (trap[signo] != NULL) {
+                               const char *sn;
+
+                               sn = u_signal_names(0, &signo, 0);
+                               if (sn == NULL)
+                                       sn = "???";
+                               out1fmt("trap -- %s %s\n",
+                                       single_quote(trap[signo]), sn);
+                       }
+               }
+               return 0;
+       }
+       if (!ap[1])
+               action = NULL;
+       else
+               action = *ap++;
+       while (*ap) {
+               if ((signo = decode_signal(*ap, 0)) < 0)
+                       error("%s: bad trap", *ap);
+               INTOFF;
+               if (action) {
+                       if (action[0] == '-' && action[1] == '\0')
+                               action = NULL;
+                       else
+                               action = savestr(action);
+               }
+               if (trap[signo])
+                       ckfree(trap[signo]);
+               trap[signo] = action;
+               if (signo != 0)
+                       setsignal(signo);
+               INTON;
+               ap++;
+       }
+       return 0;
+}
+
+
+/*
+ * Clear traps on a fork.
+ */
+
+void
+clear_traps(void)
+{
+       char **tp;
+
+       for (tp = trap ; tp < &trap[NSIG] ; tp++) {
+               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
+                       INTOFF;
+                       ckfree(*tp);
+                       *tp = NULL;
+                       if (tp != &trap[0])
+                               setsignal(tp - trap);
+                       INTON;
+               }
+       }
+}
+
+
+/*
+ * Set the signal handler for the specified signal.  The routine figures
+ * out what it should be set to.
+ */
+
+void
+setsignal(int signo)
+{
+       int action;
+       char *t, tsig;
+       struct sigaction act;
+
+       if ((t = trap[signo]) == NULL)
+               action = S_DFL;
+       else if (*t != '\0')
+               action = S_CATCH;
+       else
+               action = S_IGN;
+       if (rootshell && action == S_DFL) {
+               switch (signo) {
+               case SIGINT:
+                       if (iflag || minusc || sflag == 0)
+                               action = S_CATCH;
+                       break;
+               case SIGQUIT:
+#ifdef DEBUG
+                       if (debug)
+                               break;
+#endif
+                       /* FALLTHROUGH */
+               case SIGTERM:
+                       if (iflag)
+                               action = S_IGN;
+                       break;
+#if JOBS
+               case SIGTSTP:
+               case SIGTTOU:
+                       if (mflag)
+                               action = S_IGN;
+                       break;
+#endif
+               }
+       }
+
+       t = &sigmode[signo - 1];
+       tsig = *t;
+       if (tsig == 0) {
+               /*
+                * current setting unknown
+                */
+               if (sigaction(signo, 0, &act) == -1) {
+                       /*
+                        * Pretend it worked; maybe we should give a warning
+                        * here, but other shells don't. We don't alter
+                        * sigmode, so that we retry every time.
+                        */
+                       return;
+               }
+               if (act.sa_handler == SIG_IGN) {
+                       if (mflag && (signo == SIGTSTP ||
+                            signo == SIGTTIN || signo == SIGTTOU)) {
+                               tsig = S_IGN;   /* don't hard ignore these */
+                       } else
+                               tsig = S_HARD_IGN;
+               } else {
+                       tsig = S_RESET; /* force to be set */
+               }
+       }
+       if (tsig == S_HARD_IGN || tsig == action)
+               return;
+       switch (action) {
+       case S_CATCH:
+               act.sa_handler = onsig;
+               break;
+       case S_IGN:
+               act.sa_handler = SIG_IGN;
+               break;
+       default:
+               act.sa_handler = SIG_DFL;
+       }
+       *t = action;
+       act.sa_flags = 0;
+       sigfillset(&act.sa_mask);
+       sigaction(signo, &act, 0);
+}
+
+/*
+ * Ignore a signal.
+ */
+
+void
+ignoresig(int signo)
+{
+       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+               signal(signo, SIG_IGN);
+       }
+       sigmode[signo - 1] = S_HARD_IGN;
+}
+
+
+/*
+ * Signal handler.
+ */
+
+void
+onsig(int signo)
+{
+       gotsig[signo - 1] = 1;
+       pendingsigs = signo;
+
+       if (exsig || (signo == SIGINT && !trap[SIGINT])) {
+               if (!suppressint)
+                       onint();
+               intpending = 1;
+       }
+}
+
+
+/*
+ * Called to execute a trap.  Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+
+void
+dotrap(void)
+{
+       char *p;
+       char *q;
+       int savestatus;
+
+       savestatus = exitstatus;
+       q = gotsig;
+       while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
+               *p = 0;
+               p = trap[p - q + 1];
+               if (!p)
+                       continue;
+               evalstring(p, 0);
+               exitstatus = savestatus;
+       }
+}
+
+
+/*
+ * Controls whether the shell is interactive or not.
+ */
+
+void
+setinteractive(int on)
+{
+       static int is_interactive;
+
+       if (++on == is_interactive)
+               return;
+       is_interactive = on;
+       setsignal(SIGINT);
+       setsignal(SIGQUIT);
+       setsignal(SIGTERM);
+#ifndef BB_FEATURE_SH_EXTRA_QUIET
+               if(is_interactive > 1) {
+                       /* Looks like they want an interactive shell */
+                       static int do_banner;
+
+                               if(!do_banner) {
+                                       out1fmt(
+                       "\n\n" BB_BANNER " Built-in shell (ash)\n"
+                       "Enter 'help' for a list of built-in commands.\n\n");
+                                       do_banner++;
+                               }
+               }
+#endif
+}
+
+
+#ifndef BB_FEATURE_SH_EXTRA_QUIET
+/*** List the available builtins ***/
+
+static int helpcmd(int argc, char **argv)
+{
+       int col, i;
+
+       out1fmt("\nBuilt-in commands:\n-------------------\n");
+       for (col = 0, i = 0; i < NUMBUILTINS; i++) {
+               col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
+                                         builtincmd[i].name + 1);
+               if (col > 60) {
+                       out1fmt("\n");
+                       col = 0;
+               }
+       }
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       {
+               extern const struct BB_applet applets[];
+               extern const size_t NUM_APPLETS;
+
+               for (i = 0; i < NUM_APPLETS; i++) {
+
+                       col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
+                       if (col > 60) {
+                               out1fmt("\n");
+                               col = 0;
+                       }
+               }
+       }
+#endif
+       out1fmt("\n\n");
+       return EXIT_SUCCESS;
+}
+#endif /* BB_FEATURE_SH_EXTRA_QUIET */
+
+/*
+ * Called to exit the shell.
+ */
+
+void
+exitshell(void)
+{
+       struct jmploc loc;
+       char *p;
+       int status;
+
+       status = exitstatus;
+       TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+       if (setjmp(loc.loc)) {
+               goto out;
+       }
+       handler = &loc;
+       if ((p = trap[0]) != NULL && *p != '\0') {
+               trap[0] = NULL;
+               evalstring(p, 0);
+       }
+       flushall();
+#ifdef BB_FEATURE_COMMAND_SAVEHISTORY
+       if (iflag && rootshell) {
+               const char *hp = lookupvar("HISTFILE");
+
+               if(hp != NULL )
+                       save_history ( hp );
+       }
+#endif
+out:
+       _exit(status);
+       /* NOTREACHED */
+}
+
+static int decode_signal(const char *string, int minsig)
+{
+       int signo;
+       const char *name = u_signal_names(string, &signo, minsig);
+
+       return name ? signo : -1;
+}
+
+/*      $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $     */
+
+static struct var *vartab[VTABSIZE];
+
+static int vpcmp(const void *, const void *);
+static struct var **findvar(struct var **, const char *);
+
+/*
+ * Initialize the varable symbol tables and import the environment
+ */
+
+
+#ifdef BB_ASH_GETOPTS
+/*
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+
+int
+setvarsafe(const char *name, const char *val, int flags)
+{
+       int err;
+       volatile int saveint;
+       struct jmploc *volatile savehandler = handler;
+       struct jmploc jmploc;
+
+       SAVEINT(saveint);
+       if (setjmp(jmploc.loc))
+               err = 1;
+       else {
+               handler = &jmploc;
+               setvar(name, val, flags);
+               err = 0;
+       }
+       handler = savehandler;
+       RESTOREINT(saveint);
+       return err;
+}
+#endif
+
+/*
+ * Set the value of a variable.  The flags argument is ored with the
+ * flags of the variable.  If val is NULL, the variable is unset.
+ */
+
+static void
+setvar(const char *name, const char *val, int flags)
+{
+       char *p, *q;
+       size_t namelen;
+       char *nameeq;
+       size_t vallen;
+
+       q = endofname(name);
+       p = strchrnul(q, '=');
+       namelen = p - name;
+       if (!namelen || p != q)
+               error("%.*s: bad variable name", namelen, name);
+       vallen = 0;
+       if (val == NULL) {
+               flags |= VUNSET;
+       } else {
+               vallen = strlen(val);
+       }
+       INTOFF;
+       p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
+       *p++ = '\0';
+       if (vallen) {
+               p[-1] = '=';
+               p = mempcpy(p, val, vallen);
+       }
+       *p = '\0';
+       setvareq(nameeq, flags | VNOSAVE);
+       INTON;
+}
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value.  Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ * Called with interrupts off.
+ */
+
+void
+setvareq(char *s, int flags)
+{
+       struct var *vp, **vpp;
+
+       vpp = hashvar(s);
+       flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
+       vp = *findvar(vpp, s);
+       if (vp) {
+               if (vp->flags & VREADONLY) {
+                       if (flags & VNOSAVE)
+                               free(s);
+                       error("%.*s: is read only", strchrnul(s, '=') - s, s);
+               }
+
+               if (flags & VNOSET)
+                       return;
+
+               if (vp->func && (flags & VNOFUNC) == 0)
+                       (*vp->func)(strchrnul(s, '=') + 1);
+
+               if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+                       ckfree(vp->text);
+
+               flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
+       } else {
+               if (flags & VNOSET)
+                       return;
+               /* not found */
+               vp = ckmalloc(sizeof (*vp));
+               vp->next = *vpp;
+               vp->func = NULL;
+               *vpp = vp;
+       }
+       if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
+               s = savestr(s);
+       vp->text = s;
+       vp->flags = flags;
+}
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+static void
+listsetvar(struct strlist *list_set_var, int flags)
+{
+       struct strlist *lp = list_set_var;
+
+       if (!lp)
+               return;
+       INTOFF;
+       do {
+               setvareq(lp->text, flags);
+       } while ((lp = lp->next));
+       INTON;
+}
+
+
+/*
+ * Find the value of a variable.  Returns NULL if not set.
+ */
+
+static char *
+lookupvar(const char *name)
+{
+       struct var *v;
+
+       if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
+               return strchrnul(v->text, '=') + 1;
+       }
+       return NULL;
+}
+
+
+/*
+ * Search the environment of a builtin command.
+ */
+
+static char *
+bltinlookup(const char *name)
+{
+       struct strlist *sp;
+
+       for (sp = cmdenviron ; sp ; sp = sp->next) {
+               if (varequal(sp->text, name))
+                       return strchrnul(sp->text, '=') + 1;
+       }
+       return lookupvar(name);
+}
+
+
+/*
+ * Generate a list of variables satisfying the given conditions.
+ */
+
+static char **
+listvars(int on, int off, char ***end)
+{
+       struct var **vpp;
+       struct var *vp;
+       char **ep;
+       int mask;
+
+       STARTSTACKSTR(ep);
+       vpp = vartab;
+       mask = on | off;
+       do {
+               for (vp = *vpp ; vp ; vp = vp->next)
+                       if ((vp->flags & mask) == on) {
+                               if (ep == stackstrend())
+                                       ep = growstackstr();
+                               *ep++ = (char *) vp->text;
+                       }
+       } while (++vpp < vartab + VTABSIZE);
+       if (ep == stackstrend())
+               ep = growstackstr();
+       if (end)
+               *end = ep;
+       *ep++ = NULL;
+       return grabstackstr(ep);
+}
+
+
+/*
+ * POSIX requires that 'set' (but not export or readonly) output the
+ * variables in lexicographic order - by the locale's collating order (sigh).
+ * Maybe we could keep them in an ordered balanced binary tree
+ * instead of hashed lists.
+ * For now just roll 'em through qsort for printing...
+ */
+
+static int
+showvars(const char *sep_prefix, int on, int off)
+{
+       const char *sep;
+       char **ep, **epend;
+
+       ep = listvars(on, off, &epend);
+       qsort(ep, epend - ep, sizeof(char *), vpcmp);
+
+       sep = *sep_prefix ? spcstr : sep_prefix;
+
+       for (; ep < epend; ep++) {
+               const char *p;
+               const char *q;
+
+               p = strchrnul(*ep, '=');
+               q = nullstr;
+               if (*p)
+                       q = single_quote(++p);
+
+               out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
+       }
+
+       return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+static int
+exportcmd(int argc, char **argv)
+{
+       struct var *vp;
+       char *name;
+       const char *p;
+       char **aptr;
+       int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+       int notp;
+
+       notp = nextopt("p") - 'p';
+       if (notp && ((name = *(aptr = argptr)))) {
+               do {
+                       if ((p = strchr(name, '=')) != NULL) {
+                               p++;
+                       } else {
+                               if ((vp = *findvar(hashvar(name), name))) {
+                                       vp->flags |= flag;
+                                       continue;
+                               }
+                       }
+                       setvar(name, p, flag);
+               } while ((name = *++aptr) != NULL);
+       } else {
+               showvars(argv[0], flag, 0);
+       }
+       return 0;
+}
+
+
+/*
+ * Make a variable a local variable.  When a variable is made local, it's
+ * value and flags are saved in a localvar structure.  The saved values
+ * will be restored when the shell function returns.  We handle the name
+ * "-" as a special case.
+ */
+
+static inline void
+mklocal(char *name)
+{
+       struct localvar *lvp;
+       struct var **vpp;
+       struct var *vp;
+
+       INTOFF;
+       lvp = ckmalloc(sizeof (struct localvar));
+       if (name[0] == '-' && name[1] == '\0') {
+               char *p;
+               p = ckmalloc(sizeof(optlist));
+               lvp->text = memcpy(p, optlist, sizeof(optlist));
+               vp = NULL;
+       } else {
+               char *eq;
+
+               vpp = hashvar(name);
+               vp = *findvar(vpp, name);
+               eq = strchr(name, '=');
+               if (vp == NULL) {
+                       if (eq)
+                               setvareq(name, VSTRFIXED);
+                       else
+                               setvar(name, NULL, VSTRFIXED);
+                       vp = *vpp;      /* the new variable */
+                       lvp->flags = VUNSET;
+               } else {
+                       lvp->text = vp->text;
+                       lvp->flags = vp->flags;
+                       vp->flags |= VSTRFIXED|VTEXTFIXED;
+                       if (eq)
+                               setvareq(name, 0);
+               }
+       }
+       lvp->vp = vp;
+       lvp->next = localvars;
+       localvars = lvp;
+       INTON;
+}
+
+/*
+ * The "local" command.
+ */
+
+static int
+localcmd(int argc, char **argv)
+{
+       char *name;
+
+       argv = argptr;
+       while ((name = *argv++) != NULL) {
+               mklocal(name);
+       }
+       return 0;
+}
+
+
+/*
+ * Called after a function returns.
+ * Interrupts must be off.
+ */
+
+static void
+poplocalvars(void)
+{
+       struct localvar *lvp;
+       struct var *vp;
+
+       while ((lvp = localvars) != NULL) {
+               localvars = lvp->next;
+               vp = lvp->vp;
+               TRACE(("poplocalvar %s", vp ? vp->text : "-"));
+               if (vp == NULL) {       /* $- saved */
+                       memcpy(optlist, lvp->text, sizeof(optlist));
+                       ckfree(lvp->text);
+                       optschanged();
+               } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
+                       unsetvar(vp->text);
+               } else {
+                       if (vp->func)
+                               (*vp->func)(strchrnul(lvp->text, '=') + 1);
+                       if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+                               ckfree(vp->text);
+                       vp->flags = lvp->flags;
+                       vp->text = lvp->text;
+               }
+               ckfree(lvp);
+       }
+}
+
+
+/*
+ * The unset builtin command.  We unset the function before we unset the
+ * variable to allow a function to be unset when there is a readonly variable
+ * with the same name.
+ */
+
+int
+unsetcmd(int argc, char **argv)
+{
+       char **ap;
+       int i;
+       int flag = 0;
+       int ret = 0;
+
+       while ((i = nextopt("vf")) != '\0') {
+               flag = i;
+       }
+
+       for (ap = argptr; *ap ; ap++) {
+               if (flag != 'f') {
+                       i = unsetvar(*ap);
+                       ret |= i;
+                       if (!(i & 2))
+                               continue;
+               }
+               if (flag != 'v')
+                       unsetfunc(*ap);
+       }
+       return ret & 1;
+}
+
+
+/*
+ * Unset the specified variable.
+ */
+
+int
+unsetvar(const char *s)
+{
+       struct var **vpp;
+       struct var *vp;
+       int retval;
+
+       vpp = findvar(hashvar(s), s);
+       vp = *vpp;
+       retval = 2;
+       if (vp) {
+               int flags = vp->flags;
+
+               retval = 1;
+               if (flags & VREADONLY)
+                       goto out;
+               if (flags & VUNSET)
+                       goto ok;
+               if ((flags & VSTRFIXED) == 0) {
+                       INTOFF;
+                       if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+                               ckfree(vp->text);
+                       *vpp = vp->next;
+                       ckfree(vp);
+                       INTON;
+               } else {
+                       setvar(s, 0, 0);
+                       vp->flags &= ~VEXPORT;
+               }
+ok:
+               retval = 0;
+       }
+
+out:
+       return retval;
+}
+
+
+
+/*
+ * Find the appropriate entry in the hash table from the name.
+ */
+
+static struct var **
+hashvar(const char *p)
+{
+       unsigned int hashval;
+
+       hashval = ((unsigned char) *p) << 4;
+       while (*p && *p != '=')
+               hashval += (unsigned char) *p++;
+       return &vartab[hashval % VTABSIZE];
+}
+
+
+
+/*
+ * Compares two strings up to the first = or '\0'.  The first
+ * string must be terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+int
+varcmp(const char *p, const char *q)
+{
+       int c, d;
+
+       while ((c = *p) == (d = *q)) {
+               if (!c || c == '=')
+                       goto out;
+               p++;
+               q++;
+       }
+       if (c == '=')
+               c = 0;
+       if (d == '=')
+               d = 0;
+out:
+       return c - d;
+}
+
+static int
+vpcmp(const void *a, const void *b)
+{
+       return varcmp(*(const char **)a, *(const char **)b);
+}
+
+static struct var **
+findvar(struct var **vpp, const char *name)
+{
+       for (; *vpp; vpp = &(*vpp)->next) {
+               if (varequal((*vpp)->text, name)) {
+                       break;
+               }
+       }
+       return vpp;
+}
+/*      $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $      */
+
+#include <sys/times.h>
+
+static const unsigned char timescmd_str[] = {
+       ' ',  offsetof(struct tms, tms_utime),
+       '\n', offsetof(struct tms, tms_stime),
+       ' ',  offsetof(struct tms, tms_cutime),
+       '\n', offsetof(struct tms, tms_cstime),
+       0
+};
+
+static int timescmd(int ac, char **av)
+{
+       long int clk_tck, s, t;
+       const unsigned char *p;
+       struct tms buf;
+
+       clk_tck = sysconf(_SC_CLK_TCK);
+       times(&buf);
+
+       p = timescmd_str;
+       do {
+               t = *(clock_t *)(((char *) &buf) + p[1]);
+               s = t / clk_tck;
+               out1fmt("%ldm%ld.%.3lds%c",
+                       s/60, s%60,
+                       ((t - s * clk_tck) * 1000) / clk_tck,
+                       p[0]);
+       } while (*(p += 2));
+
+       return 0;
+}
+
+#ifdef BB_ASH_MATH_SUPPORT
+static int
+dash_arith(const char *s)
+{
+       long result;
+       int errcode = 0;
+
+       INTOFF;
+       result = arith(s, &errcode);
+       if (errcode < 0) {
+               if (errcode == -3)
+                       error("exponent less than 0");
+               else if (errcode == -2)
+                       error("divide by zero");
+               else if (errcode == -5)
+                       error("expression recursion loop detected");
+               else
+                       synerror(s);
+       }
+       INTON;
+
+       return (result);
+}
+
+
+/*
+ *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
+ *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
+ *
+ *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ */
+
+static int
+letcmd(int argc, char **argv)
+{
+       char **ap;
+       long i;
+
+       ap = argv + 1;
+       if(!*ap)
+               error("expression expected");
+       for (ap = argv + 1; *ap; ap++) {
+               i = dash_arith(*ap);
+       }
+
+       return (!i);
+}
+#endif /* BB_ASH_MATH_SUPPORT */
+
+/*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
+
+/*
+ * Miscelaneous builtins.
+ */
+
+#undef rflag
+
+#ifdef __GLIBC__
+#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+typedef enum __rlimit_resource rlim_t;
+#endif
+#endif
+
+
+/*
+ * The read builtin.  The -e option causes backslashes to escape the
+ * following character.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ */
+
+static int
+readcmd(int argc, char **argv)
+{
+       char **ap;
+       int backslash;
+       char c;
+       int rflag;
+       char *prompt;
+       const char *ifs;
+       char *p;
+       int startword;
+       int status;
+       int i;
+
+       rflag = 0;
+       prompt = NULL;
+       while ((i = nextopt("p:r")) != '\0') {
+               if (i == 'p')
+                       prompt = optionarg;
+               else
+                       rflag = 1;
+       }
+       if (prompt && isatty(0)) {
+               out2str(prompt);
+       }
+       if (*(ap = argptr) == NULL)
+               error("arg count");
+       if ((ifs = bltinlookup("IFS")) == NULL)
+               ifs = defifs;
+       status = 0;
+       startword = 1;
+       backslash = 0;
+       STARTSTACKSTR(p);
+       for (;;) {
+               if (read(0, &c, 1) != 1) {
+                       status = 1;
+                       break;
+               }
+               if (c == '\0')
+                       continue;
+               if (backslash) {
+                       backslash = 0;
+                       if (c != '\n')
+                               goto put;
+                       continue;
+               }
+               if (!rflag && c == '\\') {
+                       backslash++;
+                       continue;
+               }
+               if (c == '\n')
+                       break;
+               if (startword && *ifs == ' ' && strchr(ifs, c)) {
+                       continue;
+               }
+               startword = 0;
+               if (ap[1] != NULL && strchr(ifs, c) != NULL) {
+                       STACKSTRNUL(p);
+                       setvar(*ap, stackblock(), 0);
+                       ap++;
+                       startword = 1;
+                       STARTSTACKSTR(p);
+               } else {
+put:
+                       STPUTC(c, p);
+               }
+       }
+       STACKSTRNUL(p);
+       /* Remove trailing blanks */
+       while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
+               *p = '\0';
+       setvar(*ap, stackblock(), 0);
+       while (*++ap != NULL)
+               setvar(*ap, nullstr, 0);
+       return status;
+}
+
+
+static int umaskcmd(int argc, char **argv)
+{
+       static const char permuser[3] = "ugo";
+       static const char permmode[3] = "rwx";
+       static const short int permmask[] = {
+               S_IRUSR, S_IWUSR, S_IXUSR,
+               S_IRGRP, S_IWGRP, S_IXGRP,
+               S_IROTH, S_IWOTH, S_IXOTH
+       };
+
+       char *ap;
+       mode_t mask;
+       int i;
+       int symbolic_mode = 0;
+
+       while (nextopt("S") != '\0') {
+               symbolic_mode = 1;
+       }
+
+       INTOFF;
+       mask = umask(0);
+       umask(mask);
+       INTON;
+
+       if ((ap = *argptr) == NULL) {
+               if (symbolic_mode) {
+                       char buf[18];
+                       char *p = buf;
+
+                       for (i = 0; i < 3; i++) {
+                               int j;
+
+                               *p++ = permuser[i];
+                               *p++ = '=';
+                               for (j = 0; j < 3; j++) {
+                                       if ((mask & permmask[3 * i + j]) == 0) {
+                                               *p++ = permmode[j];
+                                       }
+                               }
+                               *p++ = ',';
+                       }
+                       *--p = 0;
+                       puts(buf);
+               } else {
+                       out1fmt("%.4o\n", mask);
+               }
+       } else {
+               if (is_digit((unsigned char) *ap)) {
+                       mask = 0;
+                       do {
+                               if (*ap >= '8' || *ap < '0')
+                                       error(illnum, argv[1]);
+                               mask = (mask << 3) + (*ap - '0');
+                       } while (*++ap != '\0');
+                       umask(mask);
+               } else {
+                       mask = ~mask & 0777;
+                       if (!parse_mode(ap, &mask)) {
+                               error("Illegal mode: %s", ap);
+                       }
+                       umask(~mask & 0777);
+               }
+       }
+       return 0;
+}
+
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+       const char *name;
+       int     cmd;
+       int     factor; /* multiply by to get rlim_{cur,max} values */
+       char    option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+       { "time(seconds)",              RLIMIT_CPU,        1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+       { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+       { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+       { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
+#endif
+#ifdef  RLIMIT_CORE
+       { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+       { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+       { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+       { "process(processes)",         RLIMIT_NPROC,      1, 'p' },
+#endif
+#ifdef RLIMIT_NOFILE
+       { "nofiles(descriptors)",       RLIMIT_NOFILE,     1, 'n' },
+#endif
+#ifdef RLIMIT_VMEM
+       { "vmemory(kbytes)",            RLIMIT_VMEM,    1024, 'v' },
+#endif
+#ifdef RLIMIT_SWAP
+       { "swap(kbytes)",               RLIMIT_SWAP,    1024, 'w' },
+#endif
+       { (char *) 0,                   0,                 0,  '\0' }
+};
+
+int
+ulimitcmd(int argc, char **argv)
+{
+       int     c;
+       rlim_t val = 0;
+       enum { SOFT = 0x1, HARD = 0x2 }
+                       how = SOFT | HARD;
+       const struct limits     *l;
+       int             set, all = 0;
+       int             optc, what;
+       struct rlimit   limit;
+
+       what = 'f';
+       while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
+               switch (optc) {
+               case 'H':
+                       how = HARD;
+                       break;
+               case 'S':
+                       how = SOFT;
+                       break;
+               case 'a':
+                       all = 1;
+                       break;
+               default:
+                       what = optc;
+               }
+
+       for (l = limits; l->name && l->option != what; l++)
+               ;
+       if (!l->name)
+               error("internal error (%c)", what);
+
+       set = *argptr ? 1 : 0;
+       if (set) {
+               char *p = *argptr;
+
+               if (all || argptr[1])
+                       error("too many arguments");
+               if (strncmp(p, "unlimited\n", 9) == 0)
+                       val = RLIM_INFINITY;
+               else {
+                       val = (rlim_t) 0;
+
+                       while ((c = *p++) >= '0' && c <= '9')
+                       {
+                               val = (val * 10) + (long)(c - '0');
+                               if (val < (rlim_t) 0)
+                                       break;
+                       }
+                       if (c)
+                               error("bad number");
+                       val *= l->factor;
+               }
+       }
+       if (all) {
+               for (l = limits; l->name; l++) {
+                       getrlimit(l->cmd, &limit);
+                       if (how & SOFT)
+                               val = limit.rlim_cur;
+                       else if (how & HARD)
+                               val = limit.rlim_max;
+
+                       out1fmt("%-20s ", l->name);
+                       if (val == RLIM_INFINITY)
+                               out1fmt("unlimited\n");
+                       else
+                       {
+                               val /= l->factor;
+                               out1fmt("%lld\n", (long long) val);
+                       }
+               }
+               return 0;
+       }
+
+       getrlimit(l->cmd, &limit);
+       if (set) {
+               if (how & HARD)
+                       limit.rlim_max = val;
+               if (how & SOFT)
+                       limit.rlim_cur = val;
+               if (setrlimit(l->cmd, &limit) < 0)
+                       error("error setting limit (%m)");
+       } else {
+               if (how & SOFT)
+                       val = limit.rlim_cur;
+               else if (how & HARD)
+                       val = limit.rlim_max;
+
+               if (val == RLIM_INFINITY)
+                       out1fmt("unlimited\n");
+               else
+               {
+                       val /= l->factor;
+                       out1fmt("%lld\n", (long long) val);
+               }
+       }
+       return 0;
+}
+
+
+#ifdef BB_ASH_MATH_SUPPORT
+
+/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* This is my infix parser/evaluator. It is optimized for size, intended
+ * as a replacement for yacc-based parsers. However, it may well be faster
+ * than a comparable parser writen in yacc. The supported operators are
+ * listed in #defines below. Parens, order of operations, and error handling
+ * are supported. This code is threadsafe. The exact expression format should
+ * be that which POSIX specifies for shells. */
+
+/* The code uses a simple two-stack algorithm. See
+ * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
+ * for a detailed explaination of the infix-to-postfix algorithm on which
+ * this is based (this code differs in that it applies operators immediately
+ * to the stack instead of adding them to a queue to end up with an
+ * expression). */
+
+/* To use the routine, call it with an expression string and error return
+ * pointer */
+
+/*
+ * Aug 24, 2001              Manuel Novoa III
+ *
+ * Reduced the generated code size by about 30% (i386) and fixed several bugs.
+ *
+ * 1) In arith_apply():
+ *    a) Cached values of *numptr and &(numptr[-1]).
+ *    b) Removed redundant test for zero denominator.
+ *
+ * 2) In arith():
+ *    a) Eliminated redundant code for processing operator tokens by moving
+ *       to a table-based implementation.  Also folded handling of parens
+ *       into the table.
+ *    b) Combined all 3 loops which called arith_apply to reduce generated
+ *       code size at the cost of speed.
+ *
+ * 3) The following expressions were treated as valid by the original code:
+ *       1()  ,    0!  ,    1 ( *3 )   .
+ *    These bugs have been fixed by internally enclosing the expression in
+ *    parens and then checking that all binary ops and right parens are
+ *    preceded by a valid expression (NUM_TOKEN).
+ *
+ * Note: It may be desireable to replace Aaron's test for whitespace with
+ * ctype's isspace() if it is used by another busybox applet or if additional
+ * whitespace chars should be considered.  Look below the "#include"s for a
+ * precompiler test.
+ */
+
+/*
+ * Aug 26, 2001              Manuel Novoa III
+ *
+ * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
+ *
+ * Merge in Aaron's comments previously posted to the busybox list,
+ * modified slightly to take account of my changes to the code.
+ *
+ */
+
+/*
+ *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * - allow access to variable,
+ *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
+ * - realize assign syntax (VAR=expr, +=, *= etc)
+ * - realize exponentiation (** operator)
+ * - realize comma separated - expr, expr
+ * - realise ++expr --expr expr++ expr--
+ * - realise expr ? expr : expr (but, second expr calculate always)
+ * - allow hexdecimal and octal numbers
+ * - was restored loses XOR operator
+ * - remove one goto label, added three ;-)
+ * - protect $((num num)) as true zero expr (Manuel`s error)
+ * - always use special isspace(), see comment from bash ;-)
+ */
+
+
+#define arith_isspace(arithval) \
+       (arithval == ' ' || arithval == '\n' || arithval == '\t')
+
+
+typedef unsigned char operator;
+
+/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
+ * precedence, and 3 high bits are an ID unique accross operators of that
+ * precedence. The ID portion is so that multiple operators can have the
+ * same precedence, ensuring that the leftmost one is evaluated first.
+ * Consider * and /. */
+
+#define tok_decl(prec,id) (((id)<<5)|(prec))
+#define PREC(op) ((op) & 0x1F)
+
+#define TOK_LPAREN tok_decl(0,0)
+
+#define TOK_COMMA tok_decl(1,0)
+
+#define TOK_ASSIGN tok_decl(2,0)
+#define TOK_AND_ASSIGN tok_decl(2,1)
+#define TOK_OR_ASSIGN tok_decl(2,2)
+#define TOK_XOR_ASSIGN tok_decl(2,3)
+#define TOK_PLUS_ASSIGN tok_decl(2,4)
+#define TOK_MINUS_ASSIGN tok_decl(2,5)
+#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
+#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
+
+#define TOK_MUL_ASSIGN tok_decl(3,0)
+#define TOK_DIV_ASSIGN tok_decl(3,1)
+#define TOK_REM_ASSIGN tok_decl(3,2)
+
+/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
+#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
+
+/* conditional is right associativity too */
+#define TOK_CONDITIONAL tok_decl(4,0)
+#define TOK_CONDITIONAL_SEP tok_decl(4,1)
+
+#define TOK_OR tok_decl(5,0)
+
+#define TOK_AND tok_decl(6,0)
+
+#define TOK_BOR tok_decl(7,0)
+
+#define TOK_BXOR tok_decl(8,0)
+
+#define TOK_BAND tok_decl(9,0)
+
+#define TOK_EQ tok_decl(10,0)
+#define TOK_NE tok_decl(10,1)
+
+#define TOK_LT tok_decl(11,0)
+#define TOK_GT tok_decl(11,1)
+#define TOK_GE tok_decl(11,2)
+#define TOK_LE tok_decl(11,3)
+
+#define TOK_LSHIFT tok_decl(12,0)
+#define TOK_RSHIFT tok_decl(12,1)
+
+#define TOK_ADD tok_decl(13,0)
+#define TOK_SUB tok_decl(13,1)
+
+#define TOK_MUL tok_decl(14,0)
+#define TOK_DIV tok_decl(14,1)
+#define TOK_REM tok_decl(14,2)
+
+/* exponent is right associativity */
+#define TOK_EXPONENT tok_decl(15,1)
+
+/* For now unary operators. */
+#define UNARYPREC 16
+#define TOK_BNOT tok_decl(UNARYPREC,0)
+#define TOK_NOT tok_decl(UNARYPREC,1)
+
+#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
+#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
+
+#define PREC_PRE (UNARYPREC+2)
+
+#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
+#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
+
+#define PREC_POST (UNARYPREC+3)
+
+#define TOK_POST_INC tok_decl(PREC_POST, 0)
+#define TOK_POST_DEC tok_decl(PREC_POST, 1)
+
+#define SPEC_PREC (UNARYPREC+4)
+
+#define TOK_NUM tok_decl(SPEC_PREC, 0)
+#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
+
+#define NUMPTR (*numstackptr)
+
+static inline int tok_have_assign(operator op)
+{
+       operator prec = PREC(op);
+
+       convert_prec_is_assing(prec);
+       return (prec == PREC(TOK_ASSIGN) ||
+                       prec == PREC_PRE || prec == PREC_POST);
+}
+
+static inline int is_right_associativity(operator prec)
+{
+    return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
+           prec == PREC(TOK_CONDITIONAL));
+}
+
+
+typedef struct ARITCH_VAR_NUM {
+       long val;
+       long contidional_second_val;
+       char contidional_second_val_initialized;
+       char *var;      /* if NULL then is regular number,
+                          else is varable name */
+} v_n_t;
+
+
+typedef struct CHK_VAR_RECURSIVE_LOOPED {
+       const char *var;
+       struct CHK_VAR_RECURSIVE_LOOPED *next;
+} chk_var_recursive_looped_t;
+
+static chk_var_recursive_looped_t *prev_chk_var_recursive;
+
+
+static int arith_lookup_val(v_n_t *t)
+{
+    if(t->var) {
+       const char * p = lookupvar(t->var);
+
+       if(p) {
+           int errcode;
+
+           /* recursive try as expression */
+           chk_var_recursive_looped_t *cur;
+           chk_var_recursive_looped_t cur_save;
+
+           for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
+               if(strcmp(cur->var, t->var) == 0) {
+                   /* expression recursion loop detected */
+                   return -5;
+               }
+           }
+           /* save current lookuped var name */
+           cur = prev_chk_var_recursive;
+           cur_save.var = t->var;
+           cur_save.next = cur;
+           prev_chk_var_recursive = &cur_save;
+
+           t->val = arith (p, &errcode);
+           /* restore previous ptr after recursiving */
+           prev_chk_var_recursive = cur;
+           return errcode;
+       } else {
+           /* allow undefined var as 0 */
+           t->val = 0;
+       }
+    }
+    return 0;
+}
+
+/* "applying" a token means performing it on the top elements on the integer
+ * stack. For a unary operator it will only change the top element, but a
+ * binary operator will pop two arguments and push a result */
+static inline int
+arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
+{
+       long numptr_val;
+       v_n_t *numptr_m1;
+       long rez;
+       int ret_arith_lookup_val;
+
+       if (NUMPTR == numstack) goto err; /* There is no operator that can work
+                                                                                without arguments */
+       numptr_m1 = NUMPTR - 1;
+
+       /* check operand is var with noninteger value */
+       ret_arith_lookup_val = arith_lookup_val(numptr_m1);
+       if(ret_arith_lookup_val)
+               return ret_arith_lookup_val;
+
+       rez = numptr_m1->val;
+       if (op == TOK_UMINUS)
+               rez *= -1;
+       else if (op == TOK_NOT)
+               rez = !rez;
+       else if (op == TOK_BNOT)
+               rez = ~rez;
+       else if (op == TOK_POST_INC || op == TOK_PRE_INC)
+               rez++;
+       else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
+               rez--;
+       else if (op != TOK_UPLUS) {
+               /* Binary operators */
+
+           /* check and binary operators need two arguments */
+           if (numptr_m1 == numstack) goto err;
+
+           /* ... and they pop one */
+           --NUMPTR;
+           numptr_val = rez;
+           if (op == TOK_CONDITIONAL) {
+               if(! numptr_m1->contidional_second_val_initialized) {
+                   /* protect $((expr1 ? expr2)) without ": expr" */
+                   goto err;
+               }
+               rez = numptr_m1->contidional_second_val;
+           } else if(numptr_m1->contidional_second_val_initialized) {
+                   /* protect $((expr1 : expr2)) without "expr ? " */
+                   goto err;
+           }
+           numptr_m1 = NUMPTR - 1;
+           if(op != TOK_ASSIGN) {
+               /* check operand is var with noninteger value for not '=' */
+               ret_arith_lookup_val = arith_lookup_val(numptr_m1);
+               if(ret_arith_lookup_val)
+                   return ret_arith_lookup_val;
+           }
+           if (op == TOK_CONDITIONAL) {
+                   numptr_m1->contidional_second_val = rez;
+           }
+           rez = numptr_m1->val;
+           if (op == TOK_BOR || op == TOK_OR_ASSIGN)
+                       rez |= numptr_val;
+           else if (op == TOK_OR)
+                       rez = numptr_val || rez;
+           else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
+                       rez &= numptr_val;
+           else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
+                       rez ^= numptr_val;
+           else if (op == TOK_AND)
+                       rez = rez && numptr_val;
+           else if (op == TOK_EQ)
+                       rez = (rez == numptr_val);
+           else if (op == TOK_NE)
+                       rez = (rez != numptr_val);
+           else if (op == TOK_GE)
+                       rez = (rez >= numptr_val);
+           else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
+                       rez >>= numptr_val;
+           else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
+                       rez <<= numptr_val;
+           else if (op == TOK_GT)
+                       rez = (rez > numptr_val);
+           else if (op == TOK_LT)
+                       rez = (rez < numptr_val);
+           else if (op == TOK_LE)
+                       rez = (rez <= numptr_val);
+           else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
+                       rez *= numptr_val;
+           else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
+                       rez += numptr_val;
+           else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
+                       rez -= numptr_val;
+           else if (op == TOK_ASSIGN || op == TOK_COMMA)
+                       rez = numptr_val;
+           else if (op == TOK_CONDITIONAL_SEP) {
+                       if (numptr_m1 == numstack) {
+                           /* protect $((expr : expr)) without "expr ? " */
+                           goto err;
+                       }
+                       numptr_m1->contidional_second_val_initialized = op;
+                       numptr_m1->contidional_second_val = numptr_val;
+           }
+           else if (op == TOK_CONDITIONAL) {
+                       rez = rez ?
+                             numptr_val : numptr_m1->contidional_second_val;
+           }
+           else if(op == TOK_EXPONENT) {
+                       if(numptr_val < 0)
+                               return -3;      /* exponent less than 0 */
+                       else {
+                               long c = 1;
+
+                               if(numptr_val)
+                                       while(numptr_val--)
+                                               c *= rez;
+                               rez = c;
+                       }
+           }
+           else if(numptr_val==0)          /* zero divisor check */
+                       return -2;
+           else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
+                       rez /= numptr_val;
+           else if (op == TOK_REM || op == TOK_REM_ASSIGN)
+                       rez %= numptr_val;
+       }
+       if(tok_have_assign(op)) {
+               char buf[32];
+
+               if(numptr_m1->var == NULL) {
+                       /* Hmm, 1=2 ? */
+                       goto err;
+               }
+               /* save to shell variable */
+               sprintf(buf, "%ld", rez);
+               setvar(numptr_m1->var, buf, 0);
+               /* after saving, make previous value for v++ or v-- */
+               if(op == TOK_POST_INC)
+                       rez--;
+               else if(op == TOK_POST_DEC)
+                       rez++;
+       }
+       numptr_m1->val = rez;
+       /* protect geting var value, is number now */
+       numptr_m1->var = NULL;
+       return 0;
+err: return(-1);
+}
+
+/* longest must first */
+static const char op_tokens[] = {
+       '<','<','=',0, TOK_LSHIFT_ASSIGN,
+       '>','>','=',0, TOK_RSHIFT_ASSIGN,
+       '<','<',    0, TOK_LSHIFT,
+       '>','>',    0, TOK_RSHIFT,
+       '|','|',    0, TOK_OR,
+       '&','&',    0, TOK_AND,
+       '!','=',    0, TOK_NE,
+       '<','=',    0, TOK_LE,
+       '>','=',    0, TOK_GE,
+       '=','=',    0, TOK_EQ,
+       '|','=',    0, TOK_OR_ASSIGN,
+       '&','=',    0, TOK_AND_ASSIGN,
+       '*','=',    0, TOK_MUL_ASSIGN,
+       '/','=',    0, TOK_DIV_ASSIGN,
+       '%','=',    0, TOK_REM_ASSIGN,
+       '+','=',    0, TOK_PLUS_ASSIGN,
+       '-','=',    0, TOK_MINUS_ASSIGN,
+       '-','-',    0, TOK_POST_DEC,
+       '^','=',    0, TOK_XOR_ASSIGN,
+       '+','+',    0, TOK_POST_INC,
+       '*','*',    0, TOK_EXPONENT,
+       '!',        0, TOK_NOT,
+       '<',        0, TOK_LT,
+       '>',        0, TOK_GT,
+       '=',        0, TOK_ASSIGN,
+       '|',        0, TOK_BOR,
+       '&',        0, TOK_BAND,
+       '*',        0, TOK_MUL,
+       '/',        0, TOK_DIV,
+       '%',        0, TOK_REM,
+       '+',        0, TOK_ADD,
+       '-',        0, TOK_SUB,
+       '^',        0, TOK_BXOR,
+       /* uniq */
+       '~',        0, TOK_BNOT,
+       ',',        0, TOK_COMMA,
+       '?',        0, TOK_CONDITIONAL,
+       ':',        0, TOK_CONDITIONAL_SEP,
+       ')',        0, TOK_RPAREN,
+       '(',        0, TOK_LPAREN,
+       0
+};
+/* ptr to ")" */
+#define endexpression &op_tokens[sizeof(op_tokens)-7]
+
+
+extern long arith (const char *expr, int *perrcode)
+{
+    register char arithval; /* Current character under analysis */
+    operator lasttok, op;
+    operator prec;
+
+    const char *p = endexpression;
+    int errcode;
+
+    size_t datasizes = strlen(expr) + 2;
+
+    /* Stack of integers */
+    /* The proof that there can be no more than strlen(startbuf)/2+1 integers
+     * in any given correct or incorrect expression is left as an excersize to
+     * the reader. */
+    v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
+           *numstackptr = numstack;
+    /* Stack of operator tokens */
+    operator *stack = alloca((datasizes) * sizeof(operator)),
+           *stackptr = stack;
+
+    *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
+    *perrcode = errcode = 0;
+
+    while(1) {
+       if ((arithval = *expr) == 0) {
+               if (p == endexpression) {
+                       /* Null expression. */
+                       return 0;
+               }
+
+               /* This is only reached after all tokens have been extracted from the
+                * input stream. If there are still tokens on the operator stack, they
+                * are to be applied in order. At the end, there should be a final
+                * result on the integer stack */
+
+               if (expr != endexpression + 1) {
+                       /* If we haven't done so already, */
+                       /* append a closing right paren */
+                       expr = endexpression;
+                       /* and let the loop process it. */
+                       continue;
+               }
+               /* At this point, we're done with the expression. */
+               if (numstackptr != numstack+1) {
+                       /* ... but if there isn't, it's bad */
+                 err:
+                       return (*perrcode = -1);
+               }
+               if(numstack->var) {
+                   /* expression is $((var)) only, lookup now */
+                   errcode = arith_lookup_val(numstack);
+               }
+       ret:
+               *perrcode = errcode;
+               return numstack->val;
+       } else {
+               /* Continue processing the expression. */
+               if (arith_isspace(arithval)) {
+                       /* Skip whitespace */
+                       goto prologue;
+               }
+               if((p = endofname(expr)) != expr) {
+                       int var_name_size = (p-expr) + 1;  /* trailing zero */
+
+                       numstackptr->var = alloca(var_name_size);
+                       safe_strncpy(numstackptr->var, expr, var_name_size);
+                       expr = p;
+               num:
+                       numstackptr->contidional_second_val_initialized = 0;
+                       numstackptr++;
+                       lasttok = TOK_NUM;
+                       continue;
+               } else if (is_digit(arithval)) {
+                       numstackptr->var = NULL;
+                       numstackptr->val = strtol(expr, (char **) &expr, 0);
+                       goto num;
+               }
+               for(p = op_tokens; ; p++) {
+                       const char *o;
+
+                       if(*p == 0) {
+                               /* strange operator not found */
+                               goto err;
+                       }
+                       for(o = expr; *p && *o == *p; p++)
+                               o++;
+                       if(! *p) {
+                               /* found */
+                               expr = o - 1;
+                               break;
+                       }
+                       /* skip tail uncompared token */
+                       while(*p)
+                               p++;
+                       /* skip zero delim */
+                       p++;
+               }
+               op = p[1];
+
+               /* post grammar: a++ reduce to num */
+               if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
+                   lasttok = TOK_NUM;
+
+               /* Plus and minus are binary (not unary) _only_ if the last
+                * token was as number, or a right paren (which pretends to be
+                * a number, since it evaluates to one). Think about it.
+                * It makes sense. */
+               if (lasttok != TOK_NUM) {
+                       switch(op) {
+                               case TOK_ADD:
+                                   op = TOK_UPLUS;
+                                   break;
+                               case TOK_SUB:
+                                   op = TOK_UMINUS;
+                                   break;
+                               case TOK_POST_INC:
+                                   op = TOK_PRE_INC;
+                                   break;
+                               case TOK_POST_DEC:
+                                   op = TOK_PRE_DEC;
+                                   break;
+                       }
+               }
+               /* We don't want a unary operator to cause recursive descent on the
+                * stack, because there can be many in a row and it could cause an
+                * operator to be evaluated before its argument is pushed onto the
+                * integer stack. */
+               /* But for binary operators, "apply" everything on the operator
+                * stack until we find an operator with a lesser priority than the
+                * one we have just extracted. */
+               /* Left paren is given the lowest priority so it will never be
+                * "applied" in this way.
+                * if associativity is right and priority eq, applied also skip
+                */
+               prec = PREC(op);
+               if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
+                       /* not left paren or unary */
+                       if (lasttok != TOK_NUM) {
+                               /* binary op must be preceded by a num */
+                               goto err;
+                       }
+                       while (stackptr != stack) {
+                           if (op == TOK_RPAREN) {
+                               /* The algorithm employed here is simple: while we don't
+                                * hit an open paren nor the bottom of the stack, pop
+                                * tokens and apply them */
+                               if (stackptr[-1] == TOK_LPAREN) {
+                                   --stackptr;
+                                   /* Any operator directly after a */
+                                   lasttok = TOK_NUM;
+                                   /* close paren should consider itself binary */
+                                   goto prologue;
+                               }
+                           } else {
+                               operator prev_prec = PREC(stackptr[-1]);
+
+                               convert_prec_is_assing(prec);
+                               convert_prec_is_assing(prev_prec);
+                               if (prev_prec < prec)
+                                       break;
+                               /* check right assoc */
+                               if(prev_prec == prec && is_right_associativity(prec))
+                                       break;
+                           }
+                           errcode = arith_apply(*--stackptr, numstack, &numstackptr);
+                           if(errcode) goto ret;
+                       }
+                       if (op == TOK_RPAREN) {
+                               goto err;
+                       }
+               }
+
+               /* Push this operator to the stack and remember it. */
+               *stackptr++ = lasttok = op;
+
+         prologue:
+               ++expr;
+       }
+    }
+}
+#endif /* BB_ASH_MATH_SUPPORT */
+
+
+#ifdef DEBUG
+const char *bb_applet_name = "debug stuff usage";
+int main(int argc, char **argv)
+{
+       return ash_main(argc, argv);
+}
+#endif
+
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ *
+ * 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.
+ */
diff --git a/basename.c b/basename.c
new file mode 100644 (file)
index 0000000..bdbcec1
--- /dev/null
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini basename implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdlib.h>
+#include "busybox.h"
+#include <string.h>
+
+extern int basename_main(int argc, char **argv)
+{
+       int m, n;
+       char *s;
+
+       if ((argc < 2) || (**(argv + 1) == '-')) {
+               show_usage();
+       }
+
+       argv++;
+
+       s = get_last_path_component(*argv);
+
+       if (argc>2) {
+               argv++;
+               n = strlen(*argv);
+               m = strlen(s);
+               if (m>n && strncmp(s+m-n, *argv, n)==0)
+                       s[m-n] = '\0';
+       }
+       puts(s);
+       return EXIT_SUCCESS;
+}
diff --git a/busybox.c b/busybox.c
new file mode 100644 (file)
index 0000000..f6e0642
--- /dev/null
+++ b/busybox.c
@@ -0,0 +1,172 @@
+/* vi: set sw=4 ts=4: */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+#ifdef BB_LOCALE_SUPPORT
+#include <locale.h>
+#endif
+
+int been_there_done_that = 0; /* Also used in applets.c */
+const char *applet_name;
+
+#ifdef BB_FEATURE_INSTALLER
+/* 
+ * directory table
+ *             this should be consistent w/ the enum, busybox.h::Location,
+ *             or else...
+ */
+static const char usr_bin [] ="/usr/bin";
+static const char usr_sbin[] ="/usr/sbin";
+static const char* const install_dir[] = {
+       &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
+       &usr_bin [4], /* "/bin" */
+       &usr_sbin[4], /* "/sbin" */
+       usr_bin,
+       usr_sbin
+};     
+
+/* abstract link() */
+typedef int (*__link_f)(const char *, const char *);
+
+/* create (sym)links for each applet */
+static void install_links(const char *busybox, int use_symbolic_links)
+{
+       __link_f Link = link;
+
+       char *fpc;
+       int i;
+       int rc;
+
+       if (use_symbolic_links) 
+               Link = symlink;
+
+       for (i = 0; applets[i].name != NULL; i++) {
+               fpc = concat_path_file(
+                       install_dir[applets[i].location], applets[i].name);
+               rc = Link(busybox, fpc);
+               if (rc!=0 && errno!=EEXIST) {
+                       perror_msg("%s", fpc);
+               }
+               free(fpc);
+       }
+}
+
+#endif /* BB_FEATURE_INSTALLER */
+
+int main(int argc, char **argv)
+{
+       const char *s;
+
+       applet_name = argv[0];
+
+       if (applet_name[0] == '-')
+               applet_name++;
+
+       for (s = applet_name; *s != '\0';) {
+               if (*s++ == '/')
+                       applet_name = s;
+       }
+
+#ifdef BB_LOCALE_SUPPORT 
+#ifdef BB_INIT
+       if(getpid()!=1) /* Do not set locale for `init' */
+#endif
+       {
+               setlocale(LC_ALL, "");
+       }
+#endif
+
+       run_applet_by_name(applet_name, argc, argv);
+       error_msg_and_die("applet not found");
+}
+
+
+int busybox_main(int argc, char **argv)
+{
+       int col = 0, len, i;
+
+#ifdef BB_FEATURE_INSTALLER    
+       /* 
+        * This style of argument parsing doesn't scale well 
+        * in the event that busybox starts wanting more --options.
+        * If someone has a cleaner approach, by all means implement it.
+        */
+       if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
+               int use_symbolic_links = 0;
+               int rc = 0;
+               char *busybox;
+
+               /* to use symlinks, or not to use symlinks... */
+               if (argc > 2) {
+                       if ((strcmp(argv[2], "-s") == 0)) { 
+                               use_symbolic_links = 1; 
+                       }
+               }
+
+               /* link */
+               busybox = xreadlink("/proc/self/exe");
+               if (busybox) {
+                       install_links(busybox, use_symbolic_links);
+                       free(busybox);
+               } else {
+                       rc = 1;
+               }
+               return rc;
+       }
+#endif /* BB_FEATURE_INSTALLER */
+
+       argc--;
+
+       /* If we've already been here once, exit now */
+       if (been_there_done_that == 1 || argc < 1) {
+               const struct BB_applet *a = applets;
+
+               fprintf(stderr, "%s\n\n"
+                               "Usage: busybox [function] [arguments]...\n"
+                               "   or: [function] [arguments]...\n\n"
+                               "\tBusyBox is a multi-call binary that combines many common Unix\n"
+                               "\tutilities into a single executable.  Most people will create a\n"
+                               "\tlink to busybox for each function they wish to use, and BusyBox\n"
+                               "\twill act like whatever it was invoked as.\n" 
+                               "\nCurrently defined functions:\n", full_version);
+
+               while (a->name != 0) {
+                       col +=
+                               fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
+                                               (a++)->name);
+                       if (col > 60 && a->name != 0) {
+                               fprintf(stderr, ",\n");
+                               col = 0;
+                       }
+               }
+               fprintf(stderr, "\n\n");
+               exit(0);
+       }
+
+       /* Flag that we've been here already */
+       been_there_done_that = 1;
+       
+       /* Move the command line down a notch */
+       len = argv[argc] + strlen(argv[argc]) - argv[1];
+       memmove(argv[0], argv[1], len);
+       memset(argv[0] + len, 0, argv[1] - argv[0]);
+
+       /* Fix up the argv pointers */
+       len = argv[1] - argv[0];
+       memmove(argv, argv + 1, sizeof(char *) * (argc + 1));
+       for (i = 0; i < argc; i++)
+               argv[i] -= len;
+
+       return (main(argc, argv));
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox.h b/busybox.h
new file mode 100644 (file)
index 0000000..1ef90bb
--- /dev/null
+++ b/busybox.h
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ */
+#ifndef        _BB_INTERNAL_H_
+#define        _BB_INTERNAL_H_    1
+
+#include "Config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#include <features.h>
+
+
+enum Location {
+       _BB_DIR_ROOT = 0,
+       _BB_DIR_BIN,
+       _BB_DIR_SBIN,
+       _BB_DIR_USR_BIN,
+       _BB_DIR_USR_SBIN
+};
+
+struct BB_applet {
+       const   char*   name;
+       int     (*main)(int argc, char** argv);
+       enum    Location        location;
+};
+/* From busybox.c */
+extern const struct BB_applet applets[];
+
+/* Automagically pull in all the applet function prototypes and
+ * applet usage strings.  These are all of the form:
+ *             extern int foo_main(int argc, char **argv);
+ *             extern const char foo_usage[];
+ * These are all autogenerated from the set of currently defined applets. 
+ */
+#define PROTOTYPES
+#include "applets.h"
+#undef PROTOTYPES
+
+#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK
+#define RESERVE_BB_BUFFER(buffer,len)           char buffer[len]
+#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len]
+#define RELEASE_BB_BUFFER(buffer)      ((void)0)
+#else
+#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS
+#define RESERVE_BB_BUFFER(buffer,len)  static          char buffer[len]
+#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len]
+#define RELEASE_BB_BUFFER(buffer)      ((void)0)
+#else
+#define RESERVE_BB_BUFFER(buffer,len)           char *buffer=xmalloc(len)
+#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len)
+#define RELEASE_BB_BUFFER(buffer)      free (buffer)
+#endif
+#endif
+
+
+/* Bit map related macros -- libc5 doens't provide these... sigh.  */
+#ifndef setbit
+#define NBBY            CHAR_BIT
+#define setbit(a,i)     ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a,i)     ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a,i)      (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+#ifndef RB_POWER_OFF
+/* Stop system and switch power off if possible.  */
+#define RB_POWER_OFF   0x4321fedc
+#endif
+
+
+/* Pull in the utility routines from libbb */
+#include "libbb/libbb.h"
+
+/* Try to pull in PATH_MAX */
+#include <limits.h>
+/* for PATH_MAX on systems that don't have it in limits.h */
+#include <sys/param.h> 
+#ifndef PATH_MAX 
+#define  PATH_MAX         256
+#endif
+
+#endif /* _BB_INTERNAL_H_ */
diff --git a/busybox.mkll b/busybox.mkll
new file mode 100755 (executable)
index 0000000..4e15e16
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Make busybox links list file.
+
+# input $1: full path to Config.h
+# input $2: full path to applets.h
+# output (stdout): list of pathnames that should be linked to busybox
+
+# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+CONFIG_H=${1:-Config.h}
+APPLETS_H=${2:-applets.h}
+gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
+  awk '/^[ \t]*LINK/{
+       dir=substr($2,8)
+       gsub("_","/",dir)
+       if(dir=="/ROOT") dir=""
+       file=$3
+       gsub("\"","",file)
+       if (file=="busybox") next
+       print tolower(dir) "/" file
+  }'
diff --git a/busybox.sh b/busybox.sh
new file mode 100755 (executable)
index 0000000..9ab0f4b
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+RAW=` \
+    $CC -E -dM ${1:-Config.h} | \
+    sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
+    | tr A-Z a-z | sort
+`
+test "${RAW}" != "" ||  exit
+if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi
+# By running $RAW through "ls", we avoid listing
+# source files that don't exist.
+ls $RAW 2>/dev/null | tr '\n' ' '
+
diff --git a/busybox.spec b/busybox.spec
new file mode 100644 (file)
index 0000000..c44823a
--- /dev/null
@@ -0,0 +1,44 @@
+%define name   busybox
+%define epoch   0
+%define version        0.60.3
+%define release        %(date -I | sed -e 's/-/_/g')
+%define serial  1
+
+Name:   %{name}
+#Epoch:   %{epoch}
+Version: %{version}
+Release: %{release}
+Serial:         %{serial}
+Copyright: GPL
+Group: System/Utilities
+Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
+URL:    http://busybox.net/
+Source:         ftp://busybox.net/busybox/%{name}-%{version}.tar.gz
+Buildroot: /var/tmp/%{name}-%{version}
+Packager : Erik Andersen <andersen@codepoet.org>
+
+%Description
+BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides minimalist replacements for most of the utilities
+you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
+tar, etc.  BusyBox provides a fairly complete POSIX environment for any small
+or emdedded system.  The utilities in BusyBox generally have fewer options then
+their full featured GNU cousins; however, the options that are provided behave
+very much like their GNU counterparts.
+
+%Prep
+%setup -q -n %{name}-%{version}
+
+%Build
+make
+
+%Install
+rm -rf $RPM_BUILD_ROOT
+make PREFIX=$RPM_BUILD_ROOT install
+
+%Clean
+rm -rf $RPM_BUILD_ROOT
+
+%Files 
+%defattr(-,root,root)
+/
diff --git a/busybox/.cvsignore b/busybox/.cvsignore
deleted file mode 100644 (file)
index 71269c5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-busybox
-busybox.links
-_install
-applet_source_list
diff --git a/busybox/.indent.pro b/busybox/.indent.pro
deleted file mode 100644 (file)
index 492ecf1..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
---blank-lines-after-declarations
---blank-lines-after-procedures
---break-before-boolean-operator
---no-blank-lines-after-commas
---braces-on-if-line
---braces-on-struct-decl-line
---comment-indentation25
---declaration-comment-column25
---no-comment-delimiters-on-blank-lines
---cuddle-else
---continuation-indentation4
---case-indentation0
---else-endif-column33
---space-after-cast
---line-comments-indentation0
---declaration-indentation1
---dont-format-first-column-comments
---dont-format-comments
---honour-newlines
---indent-level4
-/* changed from 0 to 4 */
---parameter-indentation4
---line-length78 /* changed from 75 */
---continue-at-parentheses
---no-space-after-function-call-names
---dont-break-procedure-type
---dont-star-comments
---leave-optional-blank-lines
---dont-space-special-semicolon
---tab-size4
-/* additions by Mark */
---case-brace-indentation0
---leave-preprocessor-space
diff --git a/busybox/AUTHORS b/busybox/AUTHORS
deleted file mode 100644 (file)
index 4258e5a..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-List of the authors of code contained in BusyBox.
-
-If you have code in BusyBox, you should be listed here.  If you should be
-listed, or the description of what you have done needs more detail, or is
-incorect, _please_ let me know.
-
- -Erik
-
------------
-
-Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
-    Tons of new stuff, major rewrite of most of the
-    core apps, tons of new apps as noted in header files.
-
-Edward Betts <edward@debian.org>
-    expr, hostid, logname, tty, wc, whoami, yes
-John Beppu <beppu@lineo.com>
-    du, head, nslookup, sort, tee, uniq
-
-Brian Candler <B.Candler@pobox.com>
-    tiny-ls(ls)
-
-Randolph Chung <tausq@debian.org>
-    fbset, ping, hostname, and mkfifo
-
-Dave Cinege <dcinege@psychosis.com>    
-    more(v2), makedevs, dutmp, modularization, auto links file, 
-    various fixes, Linux Router Project maintenance
-
-Larry Doolittle <ldoolitt@recycle.lbl.gov>
-    pristine source directory compilation, lots of patches and fixes.
-
-Karl M. Hegbloom <karlheg@debian.org>
-    cp_mv.c, the test suite, various fixes to utility.c, &c.
-
-Daniel Jacobowitz <dan@debian.org>
-    mktemp.c
-
-Matt Kraai <kraai@alumni.carnegiemellon.edu>
-    documentation, bugfixes
-
-John Lombardo <john@deltanet.com>      
-    dirname, tr
-
-Glenn McGrath <bug1@optushome.com.au>
-    ar, dpkg, dpkg-deb
-
-Bruce Perens <bruce@pixar.com>
-    Original author of BusyBox. His code is still in many apps.
-
-Kent Robotti <robotti@metconnect.com>
-    reset, tons and tons of bug reports and patchs.
-
-Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
-    wget - Contributed by permission of Covad Communications
-
-Pavel Roskin <proski@gnu.org>
-    Lots of bugs fixes and patches.
-
-Gyepi Sam <gyepi@praxis-sw.com>
-    Remote logging feature for syslogd
-
-Linus Torvalds <torvalds@transmeta.com>
-    mkswap, fsck.minix, mkfs.minix
-
-Mark Whitley <markw@lineo.com> <markw@codepoet.org>
-    grep, sed, cut, xargs, style-guide, new-applet-HOWTO, bug fixes, etc.
-
-Charles P. Wright <cpwright@villagenet.com>
-    gzip, mini-netcat(nc)
-
-Enrique Zanardi <ezanardi@ull.es>
-    tarcat (since removed), loadkmap, various fixes, Debian maintenance
-
-Vladimir Oleynik <dzo@simtreas.ru>
-    cmdedit; ports: ash, stty, traceroute; locale, various fixes
-    and irreconcilable critic of everything not perfect.
-
-Tim Riker <Tim@Rikers.org>
-    bug fixes, member of fan club
diff --git a/busybox/Changelog b/busybox/Changelog
deleted file mode 100644 (file)
index 314bc8a..0000000
+++ /dev/null
@@ -1,1276 +0,0 @@
-0.60.2.pre
-
-    Stable Release
-
-
-    New Applets & New Features:
-       none.  :)
-
-    Known Problems (to be fixed in 0.60.2)
-       * msh can segfault on constructs such as
-               for i in `ls *.c` ; do echo $i ; done
-         due to a memory allocation problem.  This only seems to cause
-         problems when the backtick expands to be several k in size.
-
-    Bugfixes:
-       * Matt Kraai
-           -- Fix sed s/[/]// handling (noted by Dumas Patrice).
-           -- Fix dirname(3) improper consts, allow libc version to override.
-           -- Fixed invoking applets when their names contain a leading dash 
-               and a full pathname.
-           -- Fix ash exec
-           -- Fixed basename to be SUSv2 compliant (which specifies that the
-               extension should stay if it is identical to the basename.
-           -- Fixed rmdir, since SuS2 says rmdir must provide -p
-       * Ethan Benson <erbenson@alaska.net>
-           -- Fix mount's noauto option to not automount as "usbdevfs"
-       * Vladimir Oleynik
-           -- Add support for `busybox --help APPLET'
-           -- Fixed route so it properly displays all route entries
-           -- Fix for ash leading redirections (i.e. '2>/dev/null ls rubbish')
-       * Laurence Anderson
-           -- Removed some traces of no-longer existant rpmunpack (which
-               has been obsoleted by the rpm2cpio applet).
-           -- Fixed unarchive.c to use the correct buffer when calling 
-               dirname, improve an error message, and plug some memory leaks.
-           -- Fixed rpm2cpio.c mkfs_minix.c fsck_minix.c fbset.c to use
-               standard types (s/u16/u_int16_t/g  s/u32/u_int32_t/g  etc)
-
-        
-        
-        -Erik Andersen, --not yet released--
-
-
-
-
-
-0.60.1
-
-    Stable Release
-
-
-    New Applets & New Features:
-       none.  :)
-
-    Known Problems (to be fixed in 0.60.2)
-       * msh can segfault on constructs such as
-               for i in `ls *.c` ; do echo $i ; done
-         due to a memory allocation problem.  This only seems to cause
-         problems when the backtick expands to be several k in size.
-
-
-    Bugfixes:
-       * Matt Kraai
-           -- Fixed msh to support underscores in variable names.
-           -- Fixed a sed problem with unsatisfied backrefs (the problem was
-               noted by Martin Bene).
-           -- Removed BB_SH define entirely.  Now one simply picks the shell
-               or shells they want as BB_<foo> in Config.h
-           -- Fixed head to use ferror(3) to check for errors, not errno.
-       * Shu-Hao Chang <shuhao_chang@trend.com.tw>
-           -- Fixed sed handling of multiple -e commands
-       * Magick <magick@linux-fan.com>
-           -- Fixed an init bug with AskFirst and /dev/null
-       * Jaspreet Singh <jsingh@somanetworks.com>
-           -- Fixed both a segfault and cosmetic bug in route
-       * Erik Andersen
-           -- Made the insmod options BB_FEATURE_NEW_MODULE_INTERFACE and 
-               BB_FEATURE_OLD_MODULE_INTERFACE mutually exclusive
-           -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined
-           -- Fixed a potential segfault with lash + BB_FEATURE_CLEAN_UP
-           -- Removed uint64_t from dos2unix, avoiding C lib compat. problems.
-       * Glenn McGrath
-           -- Rewrite of tftp (commands match atftp, accepts -b, can use 
-               non-standard ports, and is smaller).
-           -- Fixed unarchive exclude list handling
-       * Manuel Novoa III
-           -- rewrite of simplify_path so it behaves itself (fixing some
-               problems with mount and other applets).
-           -- Fixed ifconfig 'broadcast +' handling and disabled it by default
-       * Matthias ? <matthias@corelatus.com>
-           -- Fixed syslogd to log all messages from a single connection, not
-               just the first.
-        
-        
-        -Erik Andersen, 23 August 2001
-
-
-
-
-0.60.0
-
-    Note: 
-
-       For this release I have bumped the version number to 0.60.0.  This
-       reflects the fact that this release is intended to form a new stable
-       BusyBox release series.  If you need to rely on a stable version of
-       BusyBox, you should plan on using the stable 0.60.x series.  If bugs
-       show up then I will release 0.60.1, then 0.60.2, etc...  This is also
-       intended to deal with the fact that the BusyBox build system will be
-       getting a major overhaul for the next release and I don't want that to
-       break products that people are shipping.  To avoid that, the new build
-       system will be released as part of a new BusyBox development series
-       that will have some not-yet-decided-on odd version number.  Once things
-       stabablize and the new build system is working for everyone, then I
-       will release that as a new stable release series. 
-
-    Critical Bugfixes:
-       * Matt Kraai 
-           -- Fixed wget output file opening (wget failed in 0.52).
-           -- Fixed a memory leak in syslogd (found by Adam Slattery).
-       * Vladimir Oleynik, Matt Kraai, Erik Andersen
-           -- several nasty bugs in ash and msh.  msh could not assign
-               any variables and had debug code still enabled.  ash
-               had several compile errors (depending on selected options)
-               and variable assignment problems as well.
-
-    New Applets:
-       * David McCullough <davidm@lineo.com> -- modprobe
-       * Vladimir Oleynik -- traceroute
-       * Erik Andersen -- pidof
-
-    New Scripts:
-       * David Schleef, Erik Andersen, Stuart Hughes -- depmod.pl
-           This is a replacement for the depmod program from the modutils 
-           package, but is fully cross platform and is designed to run on 
-           your host system (not on the target).
-
-    Other Changes:
-       * Erik Andersen 
-           -- fixed busybox.spec so it should now work on redhat systems
-           -- fixed dos2unix and unix2dos so they should work once again
-           -- Adjustments to make busybox more uClinux friendly.  Busybox
-               should now work on uClinux systems without needing and source
-               code changes (applets that won't work on uClinux systems are 
-               now automagicaly disabled).
-           -- various things (cleanups, libc compatibility work, etc, etc)
-       * Jim Gleason <jimg@lineo.com>
-           -- Fixed for sed, where it failed to preserve whether or not the 
-               line was previously altered when running a subst command.
-       * Matt Kraai 
-           -- Made tar read 20 512byte blocks at a time (like GNU tar)
-           -- Allow msh.c assignments with the export and readonly commands.
-           -- Added BB_FEATURE_DEVFS to enable devfs device names.
-           -- Better devfs support
-           -- Don't save/restore vi readonly flag if vi is compiled read-only.
-           -- Reworked rdate option handling (is now smaller).
-           -- Size reduction in ping
-           -- Always write dd counts to stderr
-           -- Allow multiple shells to be enabled
-       * Aaron Lehmann 
-           -- slimmed down md5sum 
-           -- contributed a nice new (hand written, not lex/yacc) Posix math 
-               support for ash, which is once again a full posix shell.
-       * Felix von Leitner <leitner@convergence.de> -- patches to make busybox 
-           work with dietlibc.
-       * David McCullough
-           -- Adjustments to make busybox more uClinux friendly
-       * Glenn McGrath 
-           -- Fixed gzip so when a filename is '-' it will use stdin/stdout
-           -- dpkg rewrite.  Should now be compatable with the real dpkg, 
-               but needs more testing.
-           -- Updates to archiving tools (gunzip/gzip/cpio/ar/etc) 
-           -- Rewrote uuencode, will allow base64 encoding to be used by wget
-       * Vladimir Oleynik 
-           -- Fixed tr to support 'tr a-z A-Z' syntax,
-           -- Many ash corrections, optimizations, and cleanups.
-           -- optimizations for traceroute, md5sum, chown, ping
-           -- cmdedit updates and API change
-           -- Namespace cleanup (i.e. adding 'static' private function calls)
-           -- added "stopped jobs" warning to ash on exit
-       * Adam Slattery
-           -- Fixed ping compile problem
-       * Robert J. Osborne <rj@resourceinternational.com>
-           -- fixed a vi bug with delete and escape sequences on empty files.
-
-
-        -Erik Andersen, 31 July 2001
-
-
-
-0.52
-       
-    Critical Bugfixes:
-       * Glenn McGrath -- Fixed gunzip, zcat when reading from stdin
-       * Marc Karasek and Kanoj (kernel serial.c maintainer) -- fixed init
-           problem on serial consoles with 2.4.3+ kernels.
-       
-    New Applets:
-       * Laurence Anderson -- rpm2cpio applet, this obsoletes rpmunpack 
-           which has now been removed from BusyBox 
-       * Laurence Anderson and Glenn McGrath -- cpio applet, currently 
-           only supports unpacking the ascii cpio format.
-       * Vladimir Oleynik and Erik Andersen -- added ash, the most correct
-           busybox shell.
-       * Larry Doolittle -- hush, small shell designed specifically
-           for busybox.  Quite usable but still a work in progress.
-       * Erik Andersen -- msh, minix shell.  A very small but capable shell
-           that only uses vfork, so it can be used on uClinux systems.
-
-    Other Changes:
-       * Sterling Huxley -- Several bugfixes for the vi applet.
-       * Glenn McGrath -- Restructure unarchiving code to make more code
-           common to the ar, cpio, dpkg, dpkg-deb applets.
-           tar applet has not yet been assimilated...
-       * Matt Kraai -- Rewrote cp, dirname, mkdir, mv, and rm.
-       * Paul J.Y. Lahaie <pjlahaie@linuxcare.com> -- Fixed an endian-ness
-           bug in md5sum (in 0.51, md5sum on big endian machines was broken)
-       * Mark Whitley -- rewrote cut, major updates to grep and sed. 
-       * Erik Andersen -- bunches of insmod fixes.  It should now always 
-           work (no more segfault or missing symbols problems).
-       * Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de> and Jinux Kim
-           added uClinux/m68k insmod support.
-       * Manuel Novoa III -- rewrote make_human_readable so ls, du, and df
-           should work as expected.  Eliminated use of floats.
-       * Aaron Lehmann <aaronl@vitelus.com> -- Scrubbed gzip.c
-       * Alan Modra <amodra@bigpond.net.au> -- fixed an hard to spot
-           bug breaking gunzip checksum checking.
-       * Gennady Feldman -- Fixed 'syslog -C' 
-       * Gernot Poerner <gp@it-netservice.de> -- Added mount bind support.
-       * Adam Heath <doogie@debian.org>  -- wget arbitrary header support
-       * John Beppu -- updated the automagical doc generator
-       * Zillions of other bugfixes, optimizations, and cleanups.
-
-
-
-        -Erik Andersen, 7 July 2001
-
-
-0.51
-    Critical Bugfixes:
-       * Erik Andersen -- Fixed a bug that could crash the shell in 0.50
-           when pressing <Enter> on an empty line.
-       * Gennady Feldman -- Fixed a bug that could crash the shell in 0.50
-           when performing an 'export' in the shell.
-       * Gennady Feldman -- fixed a syslogd bug where syslogd could cause
-           the init process to block (which can break systems badly).
-
-    New Applets:
-       * Sterling Huxley -- contributed a new vi applet!  This is a very
-           functional vi implementation in Only 22k.
-       * Erik Andersen -- added env applet
-       
-    Other changes:
-       * Erik Andersen -- Split utility.c into libbb, which provides a
-           much cleaner was for us to include shared functionality.
-       * Erik Andersen -- Reorganized how and when busybox includes 
-           syscalls, aiding portability and (in this case) making the
-           busybox work on ia64 systems.
-       * Erik Andersen -- dpkg.c cleanup to use the updated gunzip interface.
-       * Erik Andersen -- Cleanups for libc5, glibc, and uClibc.
-       * Erik Andersen and Matt Kraai -- Cleanups for the human-readable
-           output from ls, du, and df.
-       * Laurence Anderson <laurence@zxmail.com> -- Fixed wget HTTP 1.1
-           support and added chunked encoding so it is now RFC compliant.
-       * John Beppu -- The busybox.pod documentation is now automagically
-           generated from the source code.  This makes it _much_ simpler.  
-           Now to update the docs, just update the usage message...
-       * Dirk Behme <dirk.behme@de.bosch.com> -- Adjusted MIPS insmod 
-           support a bit for Mips RS3.
-       * Christophe Boyanique -- egrep invoked the "init" applet in 0.50!
-       * Larry Doolittle -- Added -Wshadow and fixed a number of shadowed
-           variables
-       * David Douthitt -- fixed 'find -print' 
-       * Gennady Feldman -- fixes for the syslogd circular buffer code 
-       * Jeff Garzik -- a number of structural cleanups, fixes for -Wshadow 
-           bugs, and similar problems.
-       * Matt Kraai -- Added a new 'shutdown' action to busybox init.  Now
-           you can specify arbitrary behavior for 'ctrlaltdel' so now
-           pressing CTL-ALT-DEL can do something else (or nothing).
-       * Andreas Neuhaus <andy@fasta.fh-dortmund.de> -- fix for merging
-           kernel command line environment variables into child environment
-           for init.c
-       * Glenn McGrath -- Fixed problems with dpkg and dpkg-deb applets
-       * Glenn McGrath -- Don't try to automount devfs 
-       * Vladimir Oleynik -- optimizations for more.c
-       * Vladimir Oleynik -- Added locale support to the shell, and fixed
-           locale support in several other places
-       * Vladimir Oleynik -- moved struct applet from busybox.c to applets.c
-       * Vladimir Oleynik -- A size optimization for rdate
-       * Vladimir Oleynik -- Fixed printf applets's locale handling
-       * Vladimir Oleynik -- More cmdedit updates
-       * Vladimir Oleynik -- Fixed `du' applet so it continues running 
-           after permission errors.
-       * Vladimir Oleynik -- Reduced stack usage in recursive_action()
-       * Pierre Peiffer <pierre.peiffer@sxb.bsf.alcatel.fr> -- made
-               find_pid_by_name() cope with swapped out processes.
-       * Jari Ruusu <jari.ruusu@pp.inet.fi> -- updates so that setting
-           D_FILE_OFFSET_BITS=64 now works as expected. 
-       * Anthony Towns <aj@azure.humbug.org.au> -- fixed a bug with 
-           sed address range handling
-       * Dmitry Zakharov <dmit@crp.bank.gov.ua> -- a number of updates
-           to wget: support for ftp downloads, basic HTTP basic auth, handling
-           of http redirects, when attempting to continue an aborted download
-           but server doesn't support restarts then reopen output file in
-           write mode, bugfix: when content-length not given, wget didn't
-           download anything, if -c is not specified, it no longer default to
-           restarting an aborted download. 
-
-
-        -Erik Andersen, 10 April 2001
-
-
-0.50
-       * Erik Andersen -- added ifconfig interface status reporting 
-       * Erik Andersen -- Debian packaging updates
-       * Erik Andersen -- lash environment variable expansion rewritten,
-           with lots of help/fixes/testing from Larry Doolittle.
-       * Erik Andersen -- Fix use of busybox with dmalloc debugging lib
-       * Erik Andersen -- fixed ls behavior for broken or very narrow terminals
-       * Erik Andersen -- stub umount2 and pivot_root if they are not available
-       * Erik Andersen -- libc5 fixes
-       * Erik Andersen -- make init work with devfsd
-       * Erik Andersen -- fixed df for nfs and dos where blksize = 512
-       * Erik Andersen -- Make sure libpwd.a is linked _last_ so it 
-           overrides the system pwd/grp 
-       * Christophe Boyanique -- added an optional egrep alias for grep.
-       * Christophe Boyanique -- added optional 'rm -i' support.
-       * Kenneth Chalmers and Erik Andersen -- fixed ln so it
-           behaves when given no arguments (prints usage) and when
-           given just one arg (tries to make a link in the cwd).
-       * Magnus Damm -- added a tftp applet  
-       * Magnus Damm -- powerpc support for busybox insmod.
-       * David Douthitt -- fixed a build error in df.c when 
-           BB_FEATURE_HUMAN_READABLE was disabled
-       * John Beppu -- wrote autodocifier.pl, which will be used to auto-
-           generate the documentation from the source code, making life
-           much simpler for all.
-       * Magnus Damm <damm@opensource.se> -- Fixed an 'inner scope var
-           masking outer scope var with same name' bug that prevented 
-           the loopback device from being unmounted if mount() failed.
-       * Larry Doolittle -- rewrote ifconfig to make it smaller 
-       * Larry Doolittle and Erik Andersen -- cleanups to pristine source
-       * Larry Doolittle -- many bugfixes resulting from regression testing
-       * Gennady Feldman -- split syslogd.c into syslogd and klogd
-       * Gennady Feldman -- make syslogd single threaded -- no more forking
-       * Jeff Garzik -- getopt-ified rmmod.
-       * Jeff Garzik -- glibc 2.2 warning cleanups
-       * Jeff Garzik -- namespace pollution cleanup (staticified variables).
-       * Erik Gustavsson <cyrano@algonet.se> -- allow env variables set on the
-           kernel command line to be inherited into init and its children.
-       * Erik Habbinga -- fixed an uninitialized substitution delimiter in sed.
-       * Chris Jaeger -- Makefile cleanup to make option setting less error-prone
-       * Chris Jaeger <cjaeger@ensim.com> -- Carefully check NFS_MOUNT_VERSION
-           depending on what kernel is being used.
-       * Quinn Jensen <jensenq@lineo.com> -- MIPS support for busybox insmod.
-       * Evin Robertson -- new pivot_root applet 
-       * Kent Robotti -- usage message cleanups
-       * Kent Robotti -- reworked dos2unix/unix2dos
-       * Evin Robertson and Manuel Novoa III -- reworked how usage messages 
-           are stored to save several k of space.
-       * Matt Kraai -- Keep trying if an NFS mount fails 
-       * Matt Kraai -- fixed insmod so it won't try to insmod directories.
-       * Matt Kraai -- added nc listening support
-       * Matt Kraai and David Douthitt -- reworked fine to support -type, 
-           -perm, -mtime, and other improvements.
-       * Matt Kraai -- added find_applet_by_name and saved some memory thereby
-       * Matt Kraai -- added chomp to reduce redundant code elsewhere
-       * Matt Kraai -- Removed trailing \n chars from error_msg{,_and_die} messages. 
-       * John Lombardo -- fixed OOM in insmod.
-       * Glenn McGrath -- bypass /proc in mount, now uses sysfs. 
-       * Glenn McGrath -- several updates to dpkg and dpkg-deb. 
-       * Manuel Novoa III -- several size optimizations: parse_mode, 
-           process_escape_sequence, format, and get_kernel_revision. 
-       * Manuel Novoa III -- rewrote ifconfig again to make it smaller still 
-       * Manuel Novoa III -- added ifconfig -a, updated interface reporting
-       * Vladimir N. Oleynik -- Fixed a bug where init set PATH incorrectly 
-       * Vladimir N. Oleynik -- cleanups to route, cmdedit, mkdir, 
-           mkfs_minix, mkswap, chmod_chown_chgrp and utility.c
-       * Vladimir N. Oleynik -- many fixes to cmdedit. so tab completion
-           is now working and general editing is much improved, and to
-           improve complex prompt handling.
-       * Vladimir N. Oleynik -- added route status reporting.
-       * Vladimir N. Oleynik -- fixed wget to use xfopen
-       * Vladimir N. Oleynik -- new stty applet 
-       * Vladimir N. Oleynik -- fixed find, it used to stop on perm errors.
-       * Vladimir N. Oleynik -- locale forced to posix for scripts 
-       * Vladimir N. Oleynik -- saved 128 bytes by moving error checking 
-           for several my_* functions into utility.c
-       * Bjorn Wesen -- new ifconfig and route applet (taken from 
-           work done by Axis Communications).
-       * Mark Whitley -- Added a 'How to contribute to Busybox' doc
-           and updated the style guide.
-       * Mark Whitley -- implemented grep -A, -B, and -C
-       * Mark Whitley -- overhauled the test suite.
-
-
-        -Erik Andersen, 15 March 2001
-       
-0.49
-
-       * Matt Kraai -- new sort.c
-       * Matt Kraai -- new tail.c
-       * Glenn McGrath -- new 'dpkg-deb' applet
-       * Glenn McGrath -- new ar code
-       * spoon -- new watchdog applet
-       * Vladimir N. Oleynik <dzo@simtreas.ru> -- fixed cmdedit.c so now 
-           scrolling and tab completion in lash work properly.  Also several
-           byte saving optimizations.
-       * Erik Andersen -- disabled many less commonly used applets by default
-       * Mark Whitley -- more thrashing about to get clean perror_msg usage
-       * Matt Kraai -- new command line munging
-       * Larry Doolittle -- keep some locales from messing up busybox.sh
-       * Matt Kraai -- cleaned up dd and tail with new parse_number routine
-       * Mark Whitley -- remove debugging messages from deallocvt
-       * Matt Kraai and Mark Whitley -- new document "How to Add a New Applet 
-           to BusyBox"
-       * David Douthitt -- fixed "grep -qv" bug
-       * Larry Doolittle -- fixed insmod bug with old kernels
-       * Matt Kraai -- logger remixed to use getopt, selection of stdin made 
-           util-linux compatible
-       * Erik Andersen -- many more internal symbols classified static to 
-           avoid namespace pollution
-       * Matt Kraai -- nc listening support
-       * Erik Andersen -- made sed understand arbitrary regexp delimiters
-       * Matt Kraai et al. -- more tar improvements and bug fixes, now 
-           handles regexp file exclusion
-       * Larry Doolittle -- new script (multibuild.pl) to automate build rule
-           checking
-       * Matt Kraai -- update/cleanup of the docs on how to use init
-       * Erik Andersen -- renamed all sh.c symbols per the style guide, 
-           better if-then-else-fi handling
-       * Erik Andersen -- cleaner division of labor between cmdedit.c and sh.c
-       * Larry Doolittle -- shell data structure cleanup, fixed buglets
-           in read, exec, and piped builtins
-       * Erik Andersen -- md5sum was broken in 0.48.  Now fixed (and doesn't 
-           use getline, shrinking static compiles (since nothing else used it).
-       * ?? -- squashed memory leak in shell prompt handling
-       * Mark Whitley -- Updates to style guide
-       * Mark Whitley -- Big cleanup in utility.c: style guide compliance,
-           de-macro-ifying some variables and functions
-       * Erik Andersen -- ls now honors BB_FEATURE_AUTOWIDTH so it can find
-           the width and height of the console.
-       * Erik Andersen -- insmod now ignores -L and accepts the -o option.
-       * Erik Andersen -- updates so you can now select from the Makefile
-           whether or not to use the system's passwd and group functions.
-           Since most systems use GNU libc, this can save you from having to
-           install the /etc/nsswitch.conf configuration file and the required
-           libnss_* libraries.  Adds 1.5k.  You can now, also, disable this, 
-           causing busybox to use the system's pwd.h and grp.h functions.
-
-
-        -Erik Andersen, 27 January 2001
-
-0.48
-
-       * Glenn McGrath -- tar now supports uncompressing tar files,
-           define BB_FEATURE_TAR_GZIP to use the -z option.
-       * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now
-           return EXIT_SUCCESS or EXIT_FAILURE to the system.
-           Now TRUE and FALSE are set to the C standard where TRUE=1.
-       * me -- Fixed uname problem causing the kernel version to be
-           mis-detected (causing problems with poweroff, init,
-           and other things).  
-       * Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and 
-           Nicolas Ferre <nicolas.ferre@alcove.fr> -- insmod support on ARM 
-           and StrongArm, and suport for lsmod on older 2.0.x kernels.
-       * Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use 
-           an included shell script called unrpm as a front end to it.  There's
-           also a shell script called undeb included for debian packages.  
-       * Matt Kraai -- fix an infinite loop with ls -aR
-       * Larry Doolittle -- Shaved off about 100 bytes and 200 bytes heap 
-           from date.c.  Also document the "-d" option in the usage message.
-       * Gennady Feldman -- fixed dd to use blocksize when reading/writing, 
-           (it was reading the whole thing and then writing it out).  Also 
-           updated usage information (was missing conv=notrunc) and added 
-           conv=sync feature.
-       * Larry Doolittle (in collaboration with Matt Kraai) -- allow for a 
-           pristine source directory -- where all the .o files and such are 
-           not placed into the source tree.  Thanks Larry!
-       * Larry Doolittle -- use the applet definitions in applets.h 
-           to autogenerate the applet function and usage prototypes.
-       * Sebastien Huet, Arne Bernin, and Kent Robotti -- Add in tar -X and
-           fixed a bug breaking tar --exclude.  
-       * Jonas Holmberg -- echo option handling made GNU-echo compatible
-       * Aleksey Demidov <asd@ixcelerator.com> -- date option handling made 
-           GNU-date compatible
-       * me -- Progress meter (optional) in wget
-       * Doolittle/me -- programs invoked by full path name take
-           precedence over applets unless BB_FEATURE_SH_BUILTINS_ALWAYS_WIN
-       * Gaute B Strokkenes <gs234@cam.ac.uk> -- applets found using a
-           binary search instead of linear search.  Much faster!
-       * new applets: cmp readlink
-       * Mark Whitley -- Removed advertising clause of Berkeley license
-           according to decision by the Regents of the University of
-           California; included reference
-       * tail's confusing special treatment of single digit options removed;
-           people should use -n instead
-       * Larry Doolittle -- \r handled now in echo and tr
-       * Matt Kraai -- rewrite of uniq
-       * Mark Whitley -- remix of xargs
-       * Jim Gleason <jimg@lineo.com> -- fixed tar so it no longer breaks 
-           hard links.
-       * Matt Kraai -- logger now logs all arguments, not just the first
-       * Gennady Feldman -- syslogd no longer logs to localhost if compiled
-           for remote logging...
-       * Richard June <rjune@ims1.imagestream-is.com> -- support for 'gzip -d'
-       * various artists -- Other good stuff that I forgot to document.
-
-
-        -Erik Andersen, 13 December 2000
-
-0.47
-
-       * A bug in syslogd was fixed that allowed it to potentially fork-bomb
-           your system.  Anyone using 0.46 syslogd should upgrade.
-       * Renamed busybox.defs.h to the more sensible "Config.h"
-       * Improved portability between different libcs.
-       * Many apps ported to use getopt()
-       * Common handling of '--help'
-       * All usage messages centralized.
-       * Added a bunch of new commands:
-           * 'rdate' contributed by Sterling Huxley <sterling@europa.com>
-           * 'wget' contributed by Chip Rosenthal <chip@unicom.com>, 
-                   <crosenth@covad.com> and Covad Communications
-           * 'getopt' from "Alfred M. Szmidt" <ams@trillian.itslinux.org>
-           * dos2unix, unix2dos, reset, and unrpm.c (and lots of help
-               debugging) thanks to Kent Robotti <robotti@metconnect.com>.
-           * 'renice' command, thanks to Dave Cinege <dcinege@psychosis.com>
-           * 'xargs' (written by me)
-           * 'expr' contributed by Edward Betts <edward@debian.org>, based
-               on GNY expr
-       * lsmod now uses the query_module syscall, rather then /proc (me)
-       * syslogd can now log messages to remote hosts -- patch thanks
-           to Gyepi Sam <gyepi@praxis-sw.com>
-       * chroot can now call the builtin shell - Pavel Roskin <proski@gnu.org>
-       * 'make install' now creates relative symlinks, and added a new
-           'make install-hardlinks' target to (tada) install hardlinks.
-       * Rewrite of 'tail' to make it simpler, smaller, and more robust.  
-           It now weighs only 2.25k (3k when full featured).  The code is
-           cleaner too, thanks to Allen Soard <esp-software@mail.hypermart.net>
-       * Add optional ls file sorting, thanks to a patch from 
-           Sterling Huxley <sterling@europa.com>
-       * Fixed chmod option parsing so things like 'chmod -r /tmp/file'
-           now work (previously it thought -r was an option).  Doh!
-       * Fixed tar handling of stdin and stdout
-       * Renamed "internal.h" to the more sensible "busybox.h"
-       * Preliminary support for GNU HURD.
-       * Updated my devps and devmtab kernel patches for the latest 2.2.x
-           kernel, for those wanting to go proc-less.
-       * Tons of other bugfixes.
-
-
-        -Erik Andersen, 25 September 2000
-
-
-0.46
-
-       * Better portability.  Now should compile cleanly with libc5, 
-           GNU libc 2.0 and 2.1, and various Linux kernels including 
-           2.0.x, 2.2.x, and to 2.4.0-test*. (patch for 2.4.x kernels
-           to make /proc/mounts behave included in the kernel-patches dir). 
-       * Fixed a _horrible_ bug where 'tar -tvf' could unlink
-           local files that matched tarball contents!!!  Fix thanks 
-           to Marius Groeger <mgroeger@sysgo.de>
-       * Fixed a nasty bug in tar when could mess up saved symlinks.
-       * Fixed tar creation support when reading from stdin ('tar -cf - . ') 
-           thanks to Daniel Quinlan <quinlan@transmeta.com>
-       * Updates to handle Linux 2.4.0 kernels (kludged around the
-           "none" entries in /proc/mounts, added a hack to make sysinfo
-           work with both old and new kernels).
-       * Fixed insmod module option parsing for options lacking an '='.
-           Fix thanks to Marc Nijdam <marc_nijdam@hp.com>
-       * Fixed segfault with 'cut -f 1 -d:' and added 'cut -s' suport.
-           Fix thanks to Arne Bernin <arne@matrix.loopback.org>
-       * Several fixes from Marius Groeger <mag@sysgo.de>
-           - Added support for "sh -c command args..."
-           - Fixed globbing, i.e. 'echo * *' and 'echo "******"' now work.
-           - Added shell environment variable substitution 
-           - Added the "read" shell builtin.
-       * Fixed cursor editing in cmdedit.c. The following keyboard sequence 
-           used to create an infinite loop: ls, cursor up, left, down.
-       * Added support for being a login shell, so things like
-           '-su' or '-sh' (stuff where argv[0][0]=='-') will now always 
-           invoke the shell.  Now you can use BusyBox as a login shell.
-       * ls.c now ignores '-g', since some ftp clients like that sort 
-           of thing.  Patch thanks to David Vrabel <dvrabel@arcom.co.uk>
-       * Fix to init.c from Stuart Menefy <Stuart.Menefy@st.com> so that
-           it always sets the controlling terminal before running any programs
-       * Several fixes from Matt Kraai <kraai@alumni.carnegiemellon.edu>
-           - Fixed tr so it recognizes standard escape sequences.  
-               Merged common escape seq. code from tr and echo into utility.c.
-           - Major work in updating/cleaning up the docs, and getting the
-               new SGML based docs into shape.
-           - cleanup of ar.c
-           - BusyBox should now poweroff when asked to do so.
-           - Fixed 'ln -n' and 'ln -s' so they both work properly.
-       * Reorganized signal names in kill.c for better architecture support 
-           -- patch thanks to simon wood <simon@mungewell.uklinux.net>
-       * In 0.43, backspace and delete worked properly, but with 0.45, 
-           it just echoed a ^? for backspace, and ^H for control-h.  This
-           was due to a broken macro in init.c, that is now fixed.
-       * Removed sfdisk from BusyBox.  It was buggy, fat, and we really
-           couldn't maintain it very well, so including it was not really
-           very appropriate.  Those wanting an fdisk are invited to
-           grab a copy from util-linux.
-       * Added 'dumpkmap' to allow people to dump a binary keymap, which can 
-           then be loaded in by 'loadkmap' -- submitted by
-           Arne Bernin <arne@matrix.loopback.org>
-       * Fixed NFS so it supports 2.4.x kernels and NFSv3.
-       * Brand, new versions of grep and sed which use libc regex routines,
-           thanks to Mark Whitley <markw@lineo.com>.  The hand-tooled 
-           "regexp.[ch]" files have been removed. Much help on these from 
-           Matt Kraai as well.
-
-
-        -Erik Andersen, 11 July 2000
-
-
-0.45
-       * Now compiles vs libc5 (which can save lots of space for 
-           embedded systems).
-       * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the
-           help messages (i.e --help).  Saves 17k over a full compile.
-       * Added cut and tr from minix, since due to the license change, 
-           we can now use minix code.  Minix tr saves 4k. 
-       * insmod now works.  It costs 29k, but imagine an initrd with a 
-           staticly linked busybox containing only insmod and sh, a few /dev 
-           entries, and a kernel module or two...  It doesn't get smaller
-           then this folks (I pity the fool that writes insmod in asm ;-).
-           Many kudos go to Ron Alder <alder@lineo.com> for finishing this off!
-       * Added a mini ar archive utility, especially written for BusyBox by 
-           Glenn McGrath <bug1@netconnect.com.au>
-       * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org>
-       * Added setkeycodes, for those that have wierd keyboard buttons.
-       * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt 
-           <ams@trillian.itslinux.org> for contributing these.
-        * Added 'grep -v' option (inverted search) and updated 
-           docs accordingly.  -beppu
-       * Wrote which
-       * Replaced the telnet implementation with one written by 
-           Tomi Ollila <too@iki.fi> It works great and costs 3k.
-       * BusyBox sh (lash) now supports being used as a standalone shell.  When
-           BB_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may
-           be invoked as shell internals.  Best used when compiling staticly 
-           (i.e. DOSTATIC=true)
-       * BusyBox sh (lash) internals now behave as expected wrt pipes 
-           and redirects. 
-       * Fixed ping warnings -- fix from Sascha Ziemann <szi@aibon.ping.de>
-       * Fixed update segfault
-       * Fixed mknod -- minor number was always 0
-       * Fixed tar option parsing, so both "tar xvf foo.tar" and 
-           "tar -xvf foo.tar" now work (i.e. no "-" before options) 
-           (this was very broken in 0.43).
-       * Several contributions from Randolph Chung <tausq@debian.org>.
-           * cp/mv now accepts the -f flag
-           * tail can now accept -<num> commands (e.g. -10) for better 
-               compatibility with the standard tail command
-           * added a simple id implementation; doesn't support sup. groups yet
-       * logname used getlogin(3) which uses utmp.  Now it doesn't. 
-       * whoami used getpwuid(3) which uses libc NSS.  Now it behaves. 
-       * Add support for "noatime" and "nodiratime" mount flags to mount.
-       * Changed 'umount -f' to mean force, and actually use umount2.
-       * Changed 'umount -l' to mean "Do not free loop device".
-       * Fixed basename to support stripping of suffixes.  Patch thanks
-           to xiong jianxin <jxiong@uiuc.edu>
-       * cp -fa now works as expected for symlinks (it didn't before)
-       * zcat now works (wasn't working since option parsing was broken)
-       * Renamed "mnc" to the more correct "nc" (for netcat).
-       * Makefile intelligence updates
-       * Changed the way init parses /etc/inittab entries to avoid problems
-           with commands that contain colons in them.  Fix thanks to 
-           Pavel Roskin <proski@gnu.org>
-       * Fixed a warning in utility.c due to char being unsigned on Linux/PPC, 
-           Fix thanks to Pavel Roskin <proski@gnu.org>
-       * Made "killall" complain (not error and exit) about processes that it 
-           cannot find by name -- Pavel Roskin <proski@gnu.org> 
-       * Fixed more and ps to have sensible terminal width defaults, thanks 
-           to Pavel Roskin.
-       * Fixed all fatalError() calls lacking a "\n", thanks to Pavel Roskin.
-       * Fixed a segfault in yes when no args were given -- Pavel Roskin.
-       * Simplified freeramdisk and added argument checking -- Pavel Roskin. 
-       * Fixed segfault caused by "touch -c"
-       * Fixed segfault caused by "rm -f"
-       * Fixed segfault caused by "ln -s -s" and similar abuses. Further fixes
-           and "--" support from Pavel Roskin.
-       * Fixed segfault caused by "cp -a -a" and similar abuses.
-       * Implemented "rm -- <foo>". Implementation fixed by Pavel Roskin.
-       * "which" rewritten to use stat(). Fixes to improve its compatability
-           with traditional implementations -- Pavel Roskin.
-       * "mount" now reports errors from nfsmount() and assumes NFS mount
-           if ':' is present in the device name - Pavel Roskin
-       * Fixed exit status for killall - Pavel Roskin
-       * Fixed 'swapon -a' and 'swapoff -a', which were broken.
-       * Fixed 'mount -a' so it works as expected.
-       * Implemented 'ls -R' (enabled by enabling BB_FEATURE_LS_RECURSIVE)
-       * Implemented "ping -s", fixed error messages and argument parsing -
-           Pavel Roskin
-       * Syslogd will not go to background if "-n" is given. Better help
-           and argument checking -- Pavel Roskin
-       * Fixed a small bug that could cause tar to emit warning messages
-           and not extract the first file in a directory in some cases
-           of nested directories.  Thanks to Kevin Traas <kevin@netmaster.com>
-           for helping track this one down.
-       * More doc updates
-       * Fixed grep "Line too long" problem -- John Beppu
-       * Fixed 'grep -q -i B some_file' so it works
-       * math takes input from stdin if no args are given.  -- John Beppu
-       * math was renamed to dc.  Although it deviates from dc's behaviour,
-           this will probably be remedied in the future.  -- John Beppu
-
-
-        -Erik Andersen, June 21, 2000
-
-
-0.44
-       Previously, an erronous announcement of BusyBox 0.44 was made, so to 
-       avoid possible confusion, we are skipping straight to 0.45, and calling
-       it good.
-
-        -Erik Andersen
-
-
-0.43
-       * Major update to the provided documentation.
-       * Busybox now includes a shell!  It currently costs 7.5 k (plus an
-           additional 2.5 k if you compile in command line editing).  Handles
-           job control, has the usual set of builtins, and does everything
-           except for handling programming statements (if, while, etc...)
-       * Busybox can now work perfectly when /proc is disabled, thereby 
-           saving a bunch of memory (kernel /proc support is not thin).  This
-           is done by making use of some nice kernel patches I wrote up to
-           support the features that busybox requires and that /proc usually
-           provides.  To enable this, turn on BB_FEATURE_USE_DEVPS_PATCH and
-           patch your kernel with the devps patch in the kernel-patches/
-           directory. 
-       * Wrote basename, dirname, killall, and uptime.
-       * tar has been completely rewritten by me.  Both tar creation and 
-           extraction are now well behaved.  Costs 7.6k with all optional
-           tar features enabled, and 5k for just tar extraction support. 
-       * Added freeramdisk, which will free up all memory associated
-           with a ram disk.  Contributed by Emanuele Caratti <wiz@iol.it>
-           and then adjusted a bit by me.
-       * Added tr from John Lombardo <john@deltanet.com> 
-       * Added echo and test (from me).
-       * Added usleep contributed by Nicolas Pitre <nico@cam.org>
-       * BusyBox's bss size has been majorly reduced (was 384668, is now 28740).
-       * Several fixes from Pavel Roskin <proski@gnu.org>:
-           - When `tail' fails to open a file it now exits.
-           - When `syslogd' is given the `-n' option it should still use 
-               fork() for running klogd.
-       * nslookup types are now changed to u_int32_t (instead of uint32_t)
-           changed per a patch from Pascal Bellard <pascal.bellard@ascend.com>
-       * Fixed "du" so it gives the same answers as GNU "du" (busybox du used 
-           to count hard-linked files more then once).  Many thanks to 
-           Friedrich Vedder <fwv@myrtle.lahn.de> for the fix.
-       * Removed /proc dependancies for init and free (while maintaining 
-           exactly the same functionality).  /proc takes up 90k of kernel 
-           space, so it is nice to avoid using it at all costs.
-       * init no longer tries to mount /proc (unless there is less the 1 meg 
-           free).  Use of /proc (or not) is policy that should be set up in 
-           /etc/fstab (or in hardcoded scripts), not in init.
-       * Fixed rebooting when init runs as an initrd.
-       * Fixes and updates from Karl M. Hegbloom  <karlheg@debian.org>
-           - update.c rewritten to look more like update-2.11
-           - moveed the inode hash out of du.c and into utility.c to make 
-               it a common resource that can be used by other apps.
-           - cp_mv.c now checks inodes to see if a source and dest are
-               the same, and prints an error (instead of endlessly looping).
-           - mv now attempts to do a rename, and will fall back to doing
-               a copy only if the rename fails.
-           - Syslogd now supports multiple concurrent connections
-       * Several fixes from Pavel Roskin <proski@gnu.org>:
-           - Fixes to sort.  Removed "-g", fixed and added "-r"
-           - Fixes to the makefile for handling "strip"
-       * An initial telnet implementation was added by 
-           Randolph Chung <tausq@debian.org>.
-       * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e")
-       * ps now supports BB_FEATURE_AUTOWIDTH, and can adjust its width
-           to match the terminal (defaults to width=79 when this is off).
-       * ps now accepts (and ignores) all options except for "--help" (which
-               as would be expected displays help).
-       * Fixed mount'ing loop devices when the filesystem type was not 
-           specified.  It used to revert to non-loop after the first try.
-       * all mallocs now use xmalloc (and so are OOM error safe), and
-           the common error handling saves a few bytes.  Thanks to 
-           Bob Tinsley <bob@earthrise.demon.co.uk> for the patch.
-       * Fix "+" parsing bug in date, from "Merle F. McClelland" <mfm@cts.com>.
-       * Fix symlink following bug in chmod -R and friends.  
-       * Now allows SYSV style 'chown foo:bar' in addition to 'chown foo.bar'
-       * Fixed a bug in the busybox globbing routine such that 'find /dir -name [i]' 
-           no longer segfaults.
-
-
-       -Erik Andersen
-
-
-0.42
-
-        * Fairly massive restructuring of umount.c to deal with remounting 
-         busy devices read-only. Adds a -r option to control that; it is 
-         optionally compiled in with BB_FEATURE_REMOUNT
-       * Added a bunch of functions to mtab.c to interact with the
-         {get,set,end}mntent interface; as it turns out, those functions do
-         not appear to be re-entrant, and that causes a lot of problems with
-         the way umount was originally written.
-       * Makes init send TERM and KILL (instead of HUP and KILL) on reboot
-         to be more consistent with sysvinit
-       * Changes to init.c to use the new -r option to umount. Also increased
-         the sleep time between the time the TERM and KILL signals are sent
-
-        - Randolph Chung
-
-
-       * cp.c, mv.c: removed, replaced by cp_mv.c which has been
-           extensively rewritten from the original cp.c.
-       * Fixed cp and mv so if the source and destination are a the
-           same directory it will print an error and continue.
-       * Also added a warning message to the `mv' usage string saying that
-           this is not GNU mv, and it will break hard links. cp also breaks
-           hard links.
-       * ln.c: implemented `-n' switch, no-deref symlinks.
-       * include<sys/param.h>: and use PATH_MAX everywhere.  busybox: File
-       * name buffer overrun guards to prevent future crashes.
-           - Always check exit status.
-           - Purge all use of `creat()', replace with `open()'.
-       * utility.c 
-           - recursiveAction was overriding the value of followLinks thus
-             ignoring it.
-           - isDirectory now takes a followLinks boolean, updated all callers
-           - copyFile had the followLinks logic reversed.
-       * messages.c: New file. Put common error message strings all in
-           one place in an attempt to shrink the binary a little.
-
-       -Karl M. Hegbloom
-
-
-       * changed fsck_minix.c to reduce its .bss size significantly
-         -beppu -piptigger
-       * Made tar creation support in busybox tar optional.  You no longer
-       * _have_ to put a "-" in front of tar options.  Tar could inadvertently
-       * change permissions and ownership on
-           certain directories pointed to by symlinks.
-       * Made grep and grep -h do the right thing wrt printing
-           the file name (it failed to print files names in many cases).
-       * Fix a namespace aliasing problem wereby if du was built in, the 
-           symlink for both du and dutmp would be installed, or then rm was
-           built in, the symlinks for both rm and rmmod would be installed.
-       * Added a closelog() to init.c after loging -- fix thanks to 
-           Taketoshi Sano <kgh12351@nifty.ne.jp>
-       * Rewrote and simplified logger.  Added the "-t" option, and made it
-           behave itself a bit better.
-       * Optional support contributed by Ben Collins <bcollins@debian.org> 
-           for the kernel init chroot patch by Werner Almesberger, which
-           allows init to chroot to a new device, and umount the old one.
-       * Fixed bug that wouldn't let one chown a symlink -- it would
-           always dereference before.  -beppu
-       * Fixed a bug where init could have reference already freed memory.
-           Found and fixed by Taketoshi Sano <kgh12351@nifty.ne.jp>
-       * Several contributions from Friedrich Vedder <fwv@myrtle.lahn.de>
-       * Added (and documented) "-n" option for head
-       * Cleanup for a number of usage messages -- also 
-           contributed Friedrich Vedder <fwv@myrtle.lahn.de>
-       * Cosmetic fix to busybox.c (Don't print a comma at the
-           end of line if there are no more application names).
-       * Fixed a stupid bug in "head" option handling ("head -n" 
-           would segfault).
-       * Moved commonly used functions "xmalloc()" and "exit()"
-           to utility.c (with proper #ifdef's).
-       * Created a tiny tail implementation, removing -c, -q, -v, and making
-           tail -f work only with a single file.  This reduced tail from 6k to
-           2.4k.  The bigger/more featured tail can still be had by disabling
-           BB_FEATURE_SIMPLE_TAIL in busybox.defs.h
-       * Ping now falls back to doing the right thing if /etc/protocols
-           turns up missing.
-       * Fixed mount and umount.  Previously they could leak loop device 
-           allocations, causing the system to quickly run out.  Fix for umount
-           by Ben Collins <bcollins@debian.org>, and mount was fixed by me.
-       * ls formatting on eight charactor user names fixed by 
-           Randolph Chung <tausq@debian.org>.
-       * cp could, when copying symlinks, change permissions of the
-           files pointed to by the symlinks.
-       * Several fixes from Pavel Roskin <proski@gnu.org>:
-           - `chown' with 1 argument displayed the error incorrectly
-           - `fdflush', `length' and `printf' crashed if run without arguments
-           - `fdflush' tried to flush itself using *argv
-           - added "skip" and "seek" to dd.
-           - ls no longer messus up output when combining files and
-             directories on the command line 
-       * swapoff -a was not working.  Now it is.  
-       * init did not cleanly unmount filesystems on reboot.  Now it does.  
-       * "sed -ne s/foo/bar/" worked but "sed -n -e s/foo/bar/" didn't.
-           Now both work.
-       * Some architectures (PowerPc) assume chars are unsigned, so they could
-           not distinguish between EOF and '\0xFF' in sed.  Sed now uses ints.
-       * Began converting error handling to use some common routines
-           in utility.c
-       * syslogd now has better message handling and ignores SIGHUP.
-       * install.sh had a bug preventing installation to the specified
-           target directory.  Fix from Gilbert Coville <gilbert@mvista.com>
-       * You can now spefify alternative strip commands -- change 
-           also from Gilbert Coville.
-
-
-       -Erik Andersen
-
-0.41
-       * New Apps: wc, hostid, logname, tty, whoami, yes -- all contributed 
-           by Edward Betts <edward@debian.org>
-       * Fixed a bug in both cp and mv preventing 'cp foo/README bar'
-           type commands (file in a directory to another directory) from
-           working.
-       * Fixed a logger bug that caused garbage to be written to the syslog 
-           (unless you used busybox syslog, which hid the bug).  Thanks to
-           Alex Holden <alex@linuxhacker.org> for the fix.
-       * /bin/true and /bin/false were echoing a blank line when run.  
-           Now fixed.
-       * mkdir -p would print an error when asked to mkdir an existing dir
-           with no interveining subdirectories.
-       * Fixed "syslogd -O" so that it works.  Added -o loop option for mount,
-       * and support in umount for loop
-         devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins
-         <bcollins@debian.org>
-       * Several fixes from Marco Pantaleoni <panta@prosa.it> compile in
-       * fullWrite() not only if BB_TAR is defined, but also
-               if BB_CP or BB_MV are (fullWrite() is referenced by copyFile())
-           * add some compiler optimizations to further reduce executable size
-               (as a side note, on my machines the largest code is generated
-               by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with
-               -O2 -m386 ...)
-           * Compile now won't fail if busybox.def.h defines 
-               BB_FEATURE_LINUXRC but not BB_INIT.  (init_main used to be
-               referenced, but not compiled)
-       * Fixed a bug in setting TERM for serial console support.  TERM now
-           defaults to "ansi" for serial consoles.
-       * Fixed a bug in handling the CONSOLE env. variable for serial
-       * consoles.
-
-       -Erik Andersen, Jan 15, 2000
-
-0.40
-       * New Apps: sort, uniq. -beppu New Apps: lsmod, rmmod -erik New Apps:
-       * fbset contributed by Randolph Chung <tausq@debian.org>.  New App::
-       * loadacm contributed by Peter Novodvorsky <petya@logic.ru>
-           for loading application character maps for Unicode fonts.
-       * Major init re-work.  init now supports inittab (slightly different
-           but similar to sysvinit), allowing me to get all the policy out of
-           init and into the conf file.  It works just fine without inittab
-           being present, but if you dont like the default behavior you can
-           now do something about it.  Init is much cleaner as a result.
-       * Fixed an bug in syslogd causing it to stop after 20 minutes. -erik
-       * Fixed an embarrasing segfault in head -beppu Fixed the embarrasing
-       * failure of 'logger -p'. -erik Added the -s option to du -beppu
-       * Re-worked the source tree a bit so it will compile under glibc 2.0.7 
-           with the 2.0.x Linux kernel.
-       * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" 
-           <konst@voshod.com>.
-       * Grep -i previously failed on UPPER CASE patterns due to a silly 
-           regexp implementation bug that is now fixed.
-       * Fixed a bug where tar would set, and then clear SGID and SUID bits.
-       * Fixed a bug where tar would not set the user and group on device
-           special files.
-       * Fixed a bug where tar would not restore the time to files.  Fixed a
-       * major security problem with tar -- it changed ownership 
-           of any file pointed to by a symlink to 777 (like say libc....)
-           Ouch!!!
-       * cp and mv were very broken when moving directories.  I have rewritten 
-           them so they should now work as expected. 
-       * sed now supports addresses (numeric or regexp, with negation) and 
-           has an append command, thanks to Marco Pantaleoni <panta@prosa.it>
-       * Fixed dmesg.  It wasn't parsing its options (-n or -s) properly.
-       * Some cosmetic fixes to ls output formatting to make it behave more
-           like GNU ls.
-       * Fixed a stupid segfault in kill.  Several fixes from Friedrich Vedder
-       * <fwv@myrtle.lahn.de>:
-           - Added gunzip -t, removed gunzip.c dead code,
-           - fixed several typos
-           - Glibc 2.0.7 and libc5 compile fixes
-       * Fixed a bug where 'mknod --help' would segfault.
-           
-
-       -Erik Andersen, Jan 07, 2000
-
-0.39 
-       * New Apps: ping, hostname, and mkfifo contributed by Randolph Chung
-           <tausq@debian.org>.  3 items off the TODO list!
-       * I wrote free (just calls "cat /proc/meminfo").  Added tail, based on
-       * tail from GNU textutils-1.19, but adjusted
-           to suit my evil purposes.  Costs 6k.  I'll make it smaller
-           sometime.
-       * on reboot, init called 'umount -a -n', which caused errors
-           when BB_MTAB was not enabled.  Changed to 'umount -a', which does
-           the right thing.
-       * init will now try to run /sbin/getty if it is present (for easy
-           integration with the about-to-be-released tinylogin.)
-       * kill now behaves itself properly, added 'kill -l' to list signals 'ls
-       * -l' was failing on long directories, since my_getid was leaking 
-           one file descriptor per file.  Oops.
-       * Fixed rebooting from init.  I'd accidently left some debugging code
-       * in
-           which blocked reboots.
-       * Fixed reboot, halt (and added poweroff) such that they handle it when
-           init is not at PID 1 (like when running in an initrd).
-       * Added a prelinary du implementation.  Some parameter parsing
-           stuff still needs to be added. -beppu (John Beppu
-           <beppu@lineo.com>)
-       * Implemented tee.  -beppu Implemented head. -beppu
-
-       -Erik Andersen, Dec 10, 1999
-
-0.38
-       * Fixed a segfault in 'umount -a' when a badly formed /etc/fstab
-           file existed.
-       * df will not exit on error, but will stat all mounted filesystems.
-       * Fixed tar so uid/gid/permissions on extracted tarballs will be 
-           correct.
-       * Fixed find -name so it properly uses shell wildcard patterns 
-           (i.e. `*', `?', and `[]') instead of regular expressions, which
-           was causing some confusing and unexpected behavior.
-       * Added klogd to syslogd, so now the log will contain both system and
-           kernel messages.
-       * syslogd now creates the /dev/log socket to make sure it is there, and
-           is actually a socket with the right permissions.
-       * I've taken a first step to making busybox not need the /proc 
-           filesystem.  Most apps don't need it.  Those that _require_ it, 
-           will complain if you enable them when you disable 
-           BB_FEATURE_USE_PROCFS.
-          
-       -Erik Andersen, Dec 5, 1999
-
-0.37
-       * Wrote a micro syslogd, and a logger util (to log things to the syslog
-           from the command line or scripts)  With both compiled in, costs 4k.
-       * Fixed 'make install' so symlinks are installed in their proper
-       * locations.  Changed the build system slightly so that features can
-       * now be enabled
-           or disabled from the busybox.defs.h header file, without trying to
-           compile in a source file named after that featue (unless that file
-           exists).
-       * Several options are now moved into busybox.defs.h Now 'rm -R' and 'rm
-       * -r' both work.  dd now properly handles input beyond 1 block from
-       * stdin.  Fixed a bug where tar unpacked everything a directories.
-       * Moved some code 
-           from createPath into mkdir where it belonged, thereby making tar
-           work properly.
-       * Fixed an off-by-one bug in cat.  Given a list of file it wouldn't cat
-       * out the
-           last file in the list.
-       * Fixed 'ls -ln' so numeric group/uid are presented properly, and fixed
-       * 'ls -l' 
-           so when uid/gid is not in /etc/{passwd,group} the numeric group/uid
-           are presented properly.  
-       * Also added a TODO.
-
-
-       -Erik Andersen, Nov 25, 1999
-
-0.36
-       * fixed dd so it properly defaults to stdin and stdout when no 
-           if= and of= are set (fix thanks to Eric Delaunay).
-       * Don't try to close the file descriptor of a pipein tar. (fix also
-       * from
-           Eric Delaunay).
-       * Made createPath be quiet (again thanks to Eric Delaunay).  If
-       * BB_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever
-           command you define it as will be run if the init script exits.
-       * Updated install.sh to make it more robust (thanks to Adam Di Carlo)
-       * NFS support added to mount by Eric Delaunay.  It costs 10k when
-       * compiled
-           in, but that is still a big win for those that use NFS.
-       * Made 'rm -f' be silent for non-existant files (thanks to Eric
-       * Delaunay).  changed zcat.c to gunzip.c.  It now obeys the principle
-       * of least surprise 
-           and acts as god intended gunzip and zcat to act.  They answer
-           --help and obey the '-c' flag.
-       * Fixed a bug in mv which caused it to not move files when the
-       * destination
-           was a directory.
-       * Fixed a decimal-instead-of-octal bug causing mkdir to make
-       * directories
-           with very wrong permissions.
-       * chmod would overwrite file permissions instead of modifying them.
-           Now it properly modifies permissions.
-       * Init now sends warnings destined for the console to /dev/console to
-       * ensure
-           they show up on whatever the active console it.  Otherwise
-           important messages (for example that the system is rebooting) were
-           not seen when switched to a different VT.
-
-       -Erik Andersen, Nov 17, 1999
-       
-0.35
-       * gzip now obeys the principle of least surprise and acts like god
-       * intended 
-           (i.e. it accepts a file name, answers --help, and obeys the '-c'
-           flag and only then outputs to stdout).
-       * Fixed more.c to compile autowidth on sparc and set initial winsize 
-           to 0,0 in case the TIOCGWINSZ ioctl fails.  Fix thanks to Eric
-           Delaunay.
-       * Fixed tar so it now works as expected (it had TRUE/FALSE backwards)
-       * tar now accepts --help chmod, chown, and chgrp usage now works
-       * General usage (i.e. --help) cleanups for most apps umount now parses
-       * options correctly tar can now unpack tarballs containing device
-       * special files, 
-           sockets, and fifos (though it can't pack them up) thanks to Matt
-           Porter.  Creating archives containing these is still left to the
-           interested student.
-       * fixed up the license in more.c to properly point to Bruce Perens.
-
-       -Erik Andersen, Nov  11, 1999
-
-0.34
-       * ls -l now displays link names outside the current directory,
-           Patch thanks to Eric Delaunay
-       * init now properly handles sparc serial consoles and does a
-           better job of finding the real console device rather than using
-           /dev/console which doesn't support job control. Patch also thanks
-           to Eric Delaunay.
-       * more started to read from stdin after the last file was finished, and 
-           options were not parsed correctly (fix thanks to Eric Delaunay).
-       * more will now use the terminal size if BB_FEATURE_AUTOWIDTH is on.
-       * rm wouldn't remove a symlink unless the symlink was valid.  This was
-           a side effect of the busybox 0.32 recursiveAction() fix.  Things
-           should now work correctly.
-       * grep wouldn't grep stdin.  Now it does.  sed wouldn't sed stdin.  Now
-       * it does.  sed was appending a \n to the end of lines with
-       * replacements.
-           Now it doesn't do that.
-       * ls -l now bypasses libc6 nss when displaying user/group names.
-           Now uses my_getpwuid and my_getgrgid.
-
-        -Erik Andersen, Nov  8, 1999
-
-0.33
-       * Fixed a bug where init could hang instead of rebooting.
-       * Removed some debugging noise from init.c
-       * Fixed ln so it works now (it was very broken).
-       * Fixed df so it won't segfault when there is no /etc/fstab,
-       * If BB_MTAB is not defined, df and mount will whine if /etc/fstab
-           is not installed (since they cannot fixup "/dev/root" to 
-           state the real root device name)
-       * merged some redundant code from mtab.c/df.c into utility.c
-
-        -Erik Andersen, Nov  5, 1999
-
-0.32
-       * More changes -- many thanks to Lineo for paying me to work on
-           busybox.  If you have any problems please let me know ASAP at
-           andersen@lineo.com or andersee@debian.org
-       * usage() now prints the BusyBox version.  This will help folks
-           realize that they are not in Kansas anymore.
-       * Fixed mkdir -m option so that it works.  kill segfaulted w/o any
-       * arguments.  Now it doesn't do that.  kill wasn't properly accepting
-       * signal names.  It does now.  Added new apps chvt and deallocvt (I
-       * should probably add open) Major rewrite of init.c.  Code is now
-       * readable by mere mortals IMHO.  Wrote sed -- weighs only 1.8k (5.8k
-       * with full regular expressions!).  Fixed a stupid seg-fault in sync
-       * Fixed mount -- mount -a failed to parse and apply mount options Fixed
-       * umount -n (patch thanks to Matthew Grant <grantma@anathoth.gen.nz>)
-       * umount -a no longer umounts /proc Added BB_MTAB, allowing (at the
-       * cost of ~1.5k and the need for a rw /etc)
-           folks to use a real /etc/mtab file instead of a symlink to
-           /proc/mounts.  mount, and umount will add/remove entries and df
-           will now use /etc/mtab if BB_MTAB is defined. 
-       * Fixed a nice bug in recursiveAction() which caused it to infinitely
-           hunt through /proc/../fd/* creating new file descriptors if it
-           followed the /dev/fd link over to /proc.  recursiveAction() now
-           lstat's the file when followLinks==FALSE so it won't follow links
-           as the name suggests.  Fix thanks to Matt Porter
-           <porter@debian.org>.
-
-
-        -Erik Andersen, Nov  4, 1999
-
-0.31
-       * I added a changelog for version 0.30.  adjusted find internals to
-       * make it smaller, and removed 
-           some redundancy.
-       * Fixed a segfault in ps when /etc/passwd or /etc/group 
-           are absent.  Now will warn you and carry on.
-       * Added in optional _real_ regular expression support (to be
-           the basis for a future sed utility).  When compiled in it adds
-           3.9k, but makes grep much more capable.
-       * Checked out using nftw(3) for recursive stuff, but unfortunatly
-           it wasn't supported before GNU libc 2.1, and some folks use glibc
-           2.0.7 since it is much smaller than that latest and greatest.
-
-        -Erik Andersen, Oct 21, 1999
-
-0.30
-       Major changes -- lots of stuff rewritten. Many thanks to Lineo for
-       paying me to make these updates. If you have any problems with busybox, 
-       or notice any bugs -- please let me know so I can fix it.  These 
-       changes include:
-
-       Core Changes:
-           * busybox can now invoke apps in two ways: via symlinks to the
-               busybox binary, and as 'busybox [function] [arguments]...'
-           * When invoked as busybox, the list of currently compiled in 
-               functions is printed out (no this is not bloat -- the list has
-               to be there anyway to map invocation name to function).
-           * busybox no longer parses command lines for apps or displays their
-               usage info.  Each app gets to handle (or not handle) this for
-               itself.
-           * Eliminated monadic, dyadic, descend, block_device, and 
-               postprocess.  It was cumbersome to have so many programs
-               cobbled together in this way.  Without them, the app is much
-               more granular.
-           * All shared code now lives in utility.c, and is properly
-               ifdef'ed to be only included for those apps requiring it.
-           * Eliminated struct FileInfo (the basis of monadic, dyadic, etc)
-               so now each app has the function prototype of (da-dum): extern
-               int foo_main(int argc, char** argv); which speeds integration
-               of new apps.
-           * Adjusted the Makefile to make it easier to 
-               {en|dis}able debugging.
-           * Changed default compiler optimization to -Os 
-               (optimize for smaller binaries).
-
-       App Changes:
-           * To cope with the new app function prototype and the removal of
-               monadic, dyadic, etc, the following apps were re-written:
-                   * cat - Works same as always.  chgrp, chmod, chown -
-                   * rewrite.  Combined into a single 
-                       source file.  Absorbed patches from Enrique Zanardi
-                       <ezanard@debian.org> that removes the dependency on
-                       libc6 libnss* libraries.
-                   * cp - Can now do 'cp -a' can can copy devices,
-                       pipes, symlinks, as well as recursive or non-recursive
-                       dir copies.
-                   * fdflush - adjusted to remove dependancy on struct
-                   * FileInfo.  find - Now includes some basic regexp matching 
-                       which will be the basic of a future mini-sed.
-                   * ln - Same functionality.  mkdir - Added -p flag to
-                   * feature set.  mv - rewrite.  rm - Added -f flag to
-                   * feature set.  rmdir - Same functionality.  swapon,
-                   * swapoff - Combined into a single binary. No longer
-                       uses /etc/swaps.  swap{on|off} -a uses /etc/fstab
-                       instead.
-                   * touch - Same functionality.  date - adjusted with a patch
-                   * from Matthew Grant <grantma@anathoth.gen.nz>
-               to accomodate glibc timezone support.  I then ripped out GNU
-               getopt.
-           * mkswap -- new version merged from util-linux.  Can now make 
-                       >128Meg swaps.  
-               * Replaced the old and star, unstar, and tarcat with the tar 
-                       implementation from sash.   Now tar behaves as god intended it
-                       to (i.e. tar -xvf <file> and tar -cf <file> <dir> work).
-           * dd -- rewritten.  Can with with files, stdin, stdout.  Added the
-           * following new apps: loadfont -- added from debian boot floppies
-           * chroot -- added based on a patch from Paolo Molaro
-           * <lupus@lettere.unipd.it> grep -- I just wrote it.  Only matches
-           * simple strings ps -- I just wrote it.  Has _no_ options at all,
-           * but works.  fsck_minix, mkfs_minix -- added from util-linux, but
-           * I ripped out
-                       internationalization and such to make them smaller.
-                   * sfdisk -- Added from util-linux (minus
-                   * internationalization and such).  Probably some other
-                   * changes that I forgot to document...
-
-        -Erik Andersen, Oct 20, 1999
-
-0.29   
-       This version was a messy pre-alpha.  stay away or it will bite you.
-        -Erik Andersen, Sep 24, 1999
-       
-0.28   
-       mini-netcat (mnc) rewritten.
-       
-0.27
-       Mount now supports -a, and -t auto.
-       Mount now updates mtab correctly for 'ro'.
-       More checks screen rows size, outputs bytes percentage.
-       Printf added as module.
-0.26
-       Touch now creates files. -c option for no create.
-       
diff --git a/busybox/Config.h b/busybox/Config.h
deleted file mode 100644 (file)
index e832eae..0000000
+++ /dev/null
@@ -1,483 +0,0 @@
-/* vi: set sw=4 ts=4: */
-// This file defines the feature set to be compiled into busybox.
-// When you turn things off here, they won't be compiled in at all.
-//
-//// This file is parsed by sed.  You MUST use single line comments.
-//   i.e.,  //#define BB_BLAH
-//
-//
-// BusyBox Applications
-//#define BB_ADJTIMEX
-//#define BB_AR
-//#define BB_ASH
-#define BB_BASENAME
-#define BB_CAT
-#define BB_CHGRP
-#define BB_CHMOD
-#define BB_CHOWN
-#define BB_CHROOT
-#define BB_CHVT
-#define BB_CLEAR
-//#define BB_CMP
-#define BB_CP
-//#define BB_CPIO
-#define BB_CUT
-#define BB_DATE
-//#define BB_DC
-#define BB_DD
-//#define BB_DEALLOCVT
-#define BB_DF
-#define BB_DIRNAME
-#define BB_DMESG
-//#define BB_DOS2UNIX
-//#define BB_DPKG
-//#define BB_DPKG_DEB
-//#define BB_DUTMP
-#define BB_DU
-//#define BB_DUMPKMAP
-#define BB_ECHO
-#define BB_ENV
-//#define BB_EXPR
-//#define BB_FBSET
-//#define BB_FDFLUSH
-#define BB_FIND
-#define BB_FREE
-//#define BB_FREERAMDISK
-//#define BB_FSCK_MINIX
-//#define BB_GETOPT
-#define BB_GREP
-#define BB_GUNZIP
-#define BB_GZIP
-#define BB_HALT
-#define BB_HEAD
-//#define BB_HOSTID
-//#define BB_HOSTNAME
-//#define BB_HUSH
-#define BB_ID
-//#define BB_IFCONFIG
-#define BB_INIT
-//#define BB_INSMOD
-#define BB_KILL
-#define BB_KILLALL
-#define BB_KLOGD
-//#define BB_LASH
-//#define BB_LENGTH
-#define BB_LN
-//#define BB_LOADACM
-//#define BB_LOADFONT
-//#define BB_LOADKMAP
-#define BB_LOGGER
-//#define BB_LOGNAME
-#define BB_LS
-#define BB_LSMOD
-//#define BB_MAKEDEVS
-//#define BB_MD5SUM
-#define BB_MKDIR
-//#define BB_MKFIFO
-//#define BB_MKFS_MINIX
-#define BB_MKNOD
-#define BB_MKSWAP
-//#define BB_MKTEMP
-#define BB_MODPROBE
-#define BB_MORE
-#define BB_MOUNT
-#define BB_MSH
-//#define BB_MT
-#define BB_MV
-//#define BB_NC
-//#define BB_NSLOOKUP
-#define BB_PIDOF
-//#define BB_PING
-//#define BB_PIVOT_ROOT
-#define BB_POWEROFF
-//#define BB_PRINTF
-#define BB_PS
-#define BB_PWD
-//#define BB_RDATE
-//#define BB_READLINK
-#define BB_REBOOT
-//#define BB_RENICE
-#define BB_RESET
-#define BB_RM
-#define BB_RMDIR
-//#define BB_RMMOD
-//#define BB_ROUTE
-//#define BB_RPM2CPIO
-#define BB_SED
-//#define BB_SETKEYCODES
-#define BB_SLEEP
-#define BB_SORT
-//#define BB_STTY
-#define BB_SWAPONOFF
-#define BB_SYNC
-#define BB_SYSLOGD
-#define BB_TAIL
-#define BB_TAR
-//#define BB_TEE
-//#define BB_TEST
-//#define BB_TELNET
-//#define BB_TFTP
-#define BB_TOUCH
-//#define BB_TR
-//#define BB_TRACEROUTE
-#define BB_TRUE_FALSE
-#define BB_TTY
-//#define BB_UNIX2DOS
-//#define BB_UUENCODE
-//#define BB_UUDECODE
-#define BB_UMOUNT
-#define BB_UNIQ
-#define BB_UNAME
-//#define BB_UPDATE
-#define BB_UPTIME
-//#define BB_USLEEP
-//#define BB_VI
-//#define BB_WATCHDOG
-#define BB_WC
-//#define BB_WGET
-#define BB_WHICH
-#define BB_WHOAMI
-#define BB_XARGS
-#define BB_YES
-// End of Applications List
-//
-//
-//
-// ---------------------------------------------------------
-// This is where feature definitions go.  Generally speaking,
-// turning this stuff off makes things a bit smaller (and less 
-// pretty/useful).
-//
-//
-// If you enabled one or more of the shells, you may select which one
-// should be run when sh is invoked:
-//#define BB_FEATURE_SH_IS_ASH
-//#define BB_FEATURE_SH_IS_HUSH
-//#define BB_FEATURE_SH_IS_LASH
-#define BB_FEATURE_SH_IS_MSH
-//
-// BusyBox will, by default, malloc space for its buffers.  This costs code
-// size for the call to xmalloc.  You can use the following feature to have
-// them put on the stack.  For some very small machines with limited stack
-// space, this can be deadly.  For most folks, this works just fine...
-//#define BB_FEATURE_BUFFERS_GO_ON_STACK
-// The third alternative for buffer allocation is to use BSS.  This works
-// beautifully for computers with a real MMU (and OS support), but wastes
-// runtime RAM for uCLinux.  This behavior was the only one available for
-// BusyBox versions 0.48 and earlier.
-//#define BB_FEATURE_BUFFERS_GO_IN_BSS
-//
-// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
-// thereby eliminating the need for the /proc filesystem and thereby saving
-// lots and lots memory for more important things.  NOTE:  If you enable this
-// feature, you _must_ have patched the kernel to include the devps patch that
-// is included in the busybox/kernel-patches directory.  You will also need to
-// create some device special files in /dev on your embedded system:
-//        mknod /dev/mtab c 10 22
-//        mknod /dev/ps c 10 21
-// I emailed Linus and this patch will not be going into the stock kernel.
-//#define BB_FEATURE_USE_DEVPS_PATCH
-//
-// show verbose usage messages
-//#define BB_FEATURE_VERBOSE_USAGE
-//
-// Use termios to manipulate the screen ('more' is prettier with this on)
-//#define BB_FEATURE_USE_TERMIOS
-//
-// calculate terminal & column widths (for more and ls)
-#define BB_FEATURE_AUTOWIDTH
-//
-// show username/groupnames for ls
-#define BB_FEATURE_LS_USERNAME
-//
-// show file timestamps in ls
-#define BB_FEATURE_LS_TIMESTAMPS
-//
-// enable ls -p and -F
-#define BB_FEATURE_LS_FILETYPES
-//
-// sort the file names
-#define BB_FEATURE_LS_SORTFILES
-//
-// enable ls -R
-#define BB_FEATURE_LS_RECURSIVE
-//
-// enable ls -L
-#define BB_FEATURE_LS_FOLLOWLINKS
-//
-// Disable for a smaller (but less functional) ping
-#define BB_FEATURE_FANCY_PING
-//
-// Make init use a simplified /etc/inittab file (recommended).
-#define BB_FEATURE_USE_INITTAB
-//
-//Enable init being called as /linuxrc
-#define BB_FEATURE_LINUXRC
-//
-//Have init enable core dumping for child processes (for debugging only) 
-//#define BB_FEATURE_INIT_COREDUMPS
-//
-//Make sure nothing is printed to the console on boot
-//#define BB_FEATURE_EXTRA_QUIET
-//
-// enable syslogd -R remotehost
-#define BB_FEATURE_REMOTE_LOG
-//
-// enable syslogd -C
-//#define BB_FEATURE_IPC_SYSLOG
-//
-//Disable for a simple tail implementation (2.34k vs 3k for the full one).
-//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
-#define BB_FEATURE_FANCY_TAIL
-//
-// Enable support for loop devices in mount
-#define BB_FEATURE_MOUNT_LOOP
-//
-// Enable support for a real /etc/mtab file instead of /proc/mounts
-//#define BB_FEATURE_MTAB_SUPPORT
-//
-// Enable support for mounting remote NFS volumes. 
-// You may need to mount with "-o nolock" if you are
-// not running a local portmapper daemon...
-//
-// If you are using uClibc, be sure that you've already compiled
-// uClibc with INCLUDE_RPC=true (contained in the Config file)
-//#define BB_FEATURE_NFSMOUNT
-//
-// Enable support forced filesystem unmounting 
-// (i.e., in case of an unreachable NFS system).
-#define BB_FEATURE_MOUNT_FORCE
-//
-// Enable support for creation of tar files.
-#define BB_FEATURE_TAR_CREATE
-//
-// Enable support for "--exclude" and "-X" for excluding files
-#define BB_FEATURE_TAR_EXCLUDE
-//
-// Enable support for tar -z option (currently only works for inflating)
-#define BB_FEATURE_TAR_GZIP 
-//
-// Enable reverse sort
-#define BB_FEATURE_SORT_REVERSE
-//
-// Enable uniqe sort
-#define BB_FEATURE_SORT_UNIQUE
-//
-// Enable command line editing in the shell.  
-// Only relevant if a shell is enabled. On by default.
-#define BB_FEATURE_COMMAND_EDITING
-//
-// Enable tab completion in the shell.  This is now working quite nicely.
-// This feature adds a bit over 4k. Only relevant if a shell is enabled.
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-//
-// Attempts to match usernames in a ~-prefixed path
-//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-//
-//Allow the shell to invoke all the compiled in BusyBox applets as if they
-//were shell builtins.  Nice for staticly linking an emergency rescue shell,
-//among other things. Off by default.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_STANDALONE_SHELL
-//
-//When this is enabled, busybox shell applets can be called using full path
-//names.  This causes applets (i.e., most busybox commands) to override
-//real commands on the filesystem.  For example, if you run run /bin/cat, it
-//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
-//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
-//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
-// Only relevant if a shell is enabled. Off by default.
-//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-//
-// Uncomment this option for a fancy shell prompt that includes the
-// current username and hostname.  On systems that don't have usernames
-// or hostnames, this can look hideous.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_FANCY_PROMPT
-//
-//Turn on extra fbset options
-//#define BB_FEATURE_FBSET_FANCY
-//
-//Turn on fbset readmode support
-//#define BB_FEATURE_FBSET_READMODE
-//
-// Support insmod/lsmod/rmmod for post 2.1 kernels
-//#define BB_FEATURE_NEW_MODULE_INTERFACE
-//
-// Support insmod/lsmod/rmmod for pre 2.1 kernels
-//#define BB_FEATURE_OLD_MODULE_INTERFACE
-//
-// Support module version checking
-//#define BB_FEATURE_INSMOD_VERSION_CHECKING
-//
-// Support for uClinux memory usage optimization, which will load the image
-// directly into the kernel memory.  This divides memory requrements by three.
-// If you are not running uClinux (i.e., your CPU has an MMU) leave this
-// disabled...
-//#define BB_FEATURE_INSMOD_LOADINKMEM
-//
-// Support for Minix filesystem, version 2
-//#define BB_FEATURE_MINIX2
-//
-// Enable ifconfig status reporting output -- this feature adds 7k.
-//#define BB_FEATURE_IFCONFIG_STATUS
-//
-// Enable ifconfig slip-specific options "keepalive" and "outfill"
-//#define BB_FEATURE_IFCONFIG_SLIP
-//
-// Enable ifconfig options "mem_start", "io_addr", and "irq".
-//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-//
-// Enable ifconfig option "hw".  Currently works for only with "ether".
-//#define BB_FEATURE_IFCONFIG_HW
-//
-// Allows "broadcast +" to set broadcast automatically based on hostaddr
-// and netmask, at a cost of about 100 bytes of code (i386).
-//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
-//
-// Enable busybox --install [-s]
-// to create links (or symlinks) for all the commands that are 
-// compiled into the binary.  (needs /proc filesystem)
-//#define BB_FEATURE_INSTALLER
-//
-// Enable a nifty progress meter in wget (adds just under 2k)
-#define BB_FEATURE_WGET_STATUSBAR
-//
-// Enable HTTP authentication in wget
-#define BB_FEATURE_WGET_AUTHENTICATION
-//
-// Clean up all memory before exiting -- usually not needed
-// as the OS can clean up...  Don't enable this unless you
-// have a really good reason for cleaning things up manually.
-//#define BB_FEATURE_CLEAN_UP
-//
-// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
-#define BB_FEATURE_HUMAN_READABLE
-//
-// Support for the find -type option.
-#define BB_FEATURE_FIND_TYPE
-//
-// Support for the find -perm option.
-#define BB_FEATURE_FIND_PERM
-//
-// Support for the find -mtine option.
-#define BB_FEATURE_FIND_MTIME
-//
-// Support for the -A -B and -C context flags in grep
-//#define BB_FEATURE_GREP_CONTEXT
-//
-// Support for the EGREP applet (alias to the grep applet)
-//#define BB_FEATURE_GREP_EGREP_ALIAS
-//
-// Tell tftp what commands that should be supported.
-#define BB_FEATURE_TFTP_PUT
-#define BB_FEATURE_TFTP_GET
-//
-// features for vi
-#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
-#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
-#define BB_FEATURE_VI_SEARCH           // search and replace cmds
-#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
-#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
-#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
-#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
-#define BB_FEATURE_VI_SET              // :set
-#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
-//
-// Enable a if you system have setuped locale
-//#define BB_LOCALE_SUPPORT
-//
-// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
-#define BB_FEATURE_TELNET_TTYPE
-//
-// Support for devfs.
-//#define BB_FEATURE_DEVFS
-//
-// End of Features List
-//
-//
-//
-//
-//
-//
-//---------------------------------------------------
-// Nothing beyond this point should ever be touched by 
-// mere mortals so leave this stuff alone.
-//
-#include <features.h>
-#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
-       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
-       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
-       #undef BB_ASH                   /* Uses fork() */
-       #undef BB_HUSH                  /* Uses fork() */
-       #undef BB_LASH                  /* Uses fork() */
-       #undef BB_INIT                  /* Uses fork() */
-       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
-       #undef BB_SYSLOGD               /* Uses daemon() */
-       #undef BB_KLOGD                 /* Uses daemon() */
-       #undef BB_UPDATE                /* Uses daemon() */
-#endif
-#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
-       #if defined BB_FEATURE_COMMAND_EDITING
-               #define BB_CMDEDIT
-       #else
-               #undef BB_FEATURE_COMMAND_EDITING
-               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
-               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               #undef BB_FEATURE_SH_FANCY_PROMPT
-       #endif
-#else
-       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       #undef BB_FEATURE_SH_STANDALONE_SHELL
-       #undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-//
-#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
-       #define BB_TEST
-#endif
-//
-#ifdef BB_KILLALL
-       #ifndef BB_KILL
-               #define BB_KILL
-       #endif
-#endif
-//
-#ifndef BB_INIT
-       #undef BB_FEATURE_LINUXRC
-#endif
-//
-#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
-       #define BB_NFSMOUNT
-#endif
-//
-#if defined BB_FEATURE_AUTOWIDTH
-       #ifndef BB_FEATURE_USE_TERMIOS
-               #define BB_FEATURE_USE_TERMIOS
-       #endif
-#endif
-//
-#if defined BB_INSMOD || defined BB_LSMOD
-       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
-               #define BB_FEATURE_NEW_MODULE_INTERFACE
-       #endif
-#endif
-//
-#ifdef BB_UNIX2DOS
-       #define BB_DOS2UNIX
-#endif 
-//
-#ifdef BB_SYSLOGD
-       #if defined BB_FEATURE_IPC_SYSLOG
-               #define BB_LOGREAD
-       #endif
-#endif
-//
-#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
-# define shell_main ash_main
-#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
-# define shell_main hush_main
-#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
-# define shell_main lash_main
-#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
-# define shell_main msh_main
-#endif
diff --git a/busybox/INSTALL b/busybox/INSTALL
deleted file mode 100644 (file)
index e17bd80..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-1) Check Config.h and adjust if you need a different functionality than
-   defined by default.
-
-2) Check the Makefile
-
-3) make
-
-4) make install
diff --git a/busybox/LICENSE b/busybox/LICENSE
deleted file mode 100644 (file)
index 8e5a143..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-Original release code (unless otherwise noted)
-Copyright 1995, 1996 Bruce Perens <bruce@pixar.com>
-
-mkswap
-Copyright 1991 Linus Torvalds
-
-tiny-ls(ls)
-Copyright 1996 Brian Candler <B.Candler@pobox.com>
-
-tarcat, loadkmap, various fixes, Debian maintenance
-Copyright 1998 Enrique Zanardi <ezanardi@ull.es>
-
-more(v2), makedevs, dutmp, modularization, auto links file, 
-various fixes, Linux Router Project maintenance
-Copyright 1998 Dave Cinege <dcinege@psychosis.com>     
-
-mini-gzip(gzip), mini-netcat(mnc)
-Copyright 1998 Charles P. Wright <cpwright@villagenet.com>
-
-Tons of new stuff as noted in header files
-Copyright (C) 1999,2000,2001 by Lineo, inc. and written by 
-Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
-
-
-
-Please feed suggestions, bug reports, insults, and bribes back to:
-       Erik Andersen 
-       <andersen@lineo.com>
-       <andersee@debian.org>
-
-
-
-Busybox may be used and distributed under the GNU General Public License.
-
----------------------------------------------------------------------------
-
-
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-\f
-                   GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                           NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-\f
-           How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year  name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
-
diff --git a/busybox/Makefile b/busybox/Makefile
deleted file mode 100644 (file)
index d231f69..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999,2000,2001 Erik Andersen <andersee@debian.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-PROG      := busybox
-VERSION   := 0.60.2.pre
-BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z")
-export VERSION
-
-# With a modern GNU make(1) (highly recommended, that's what all the
-# developers use), all of the following configuration values can be
-# overridden at the command line.  For example:
-#   make CROSS=powerpc-linux- BB_SRC_DIR=$HOME/busybox PREFIX=/mnt/app
-
-# If you want to add some simple compiler switches (like -march=i686),
-# especially from the command line, use this instead of CFLAGS directly.
-# For optimization overrides, it's better still to set OPTIMIZATION.
-CFLAGS_EXTRA =
-# If you want a static binary, turn this on.
-DOSTATIC = false
-
-# Set the following to `true' to make a debuggable build.
-# Leave this set to `false' for production use.
-DODEBUG = false
-
-# Setting this to `true' will cause busybox to directly use the system's
-# password and group functions.  Assuming you use GNU libc, when this is
-# `true', you will need to install the /etc/nsswitch.conf configuration file
-# and the required libnss_* libraries. This generally makes your embedded
-# system quite a bit larger... If you leave this off, busybox will directly use
-# the /etc/password, /etc/group files (and your system will be smaller, and I
-# will get fewer emails asking about how glibc NSS works).  Enabling this adds
-# just 1.4k to the binary size (which is a _lot_ less then glibc NSS costs).
-# Note that if you want hostname resolution to work with glibc, you still need
-# the libnss_* libraries.  
-USE_SYSTEM_PWD_GRP = true
-
-# This enables compiling with dmalloc ( http://dmalloc.com/ )
-# which is an excellent public domain mem leak and malloc problem
-# detector.  To enable dmalloc, before running busybox you will
-# want to first set up your environment.
-# eg: `export DMALLOC_OPTIONS=debug=0x14f47d83,inter=100,log=logfile`
-# Do not enable this for production builds...
-DODMALLOC = false
-
-# Electric-fence is another very useful malloc debugging library.
-# Do not enable this for production builds...
-DOEFENCE  = false
-
-# If you want large file summit support, turn this on.
-# This has no effect if you don't have a kernel with lfs
-# support, and a system with libc-2.1.3 or later.
-# Some of the programs that can benefit from lfs support
-# are dd, gzip, mount, tar, and mkfs_minix.
-# LFS allows you to use the above programs for files
-# larger than 2GB!
-DOLFS = false
-
-# If you have a "pristine" source directory, point BB_SRC_DIR to it.
-# Experimental and incomplete; tell the mailing list
-# <busybox@opensource.lineo.com> if you do or don't like it so far.
-BB_SRC_DIR =
-
-# If you are running a cross compiler, you may want to set this
-# to something more interesting, like "powerpc-linux-".
-CROSS =
-CC = $(CROSS)gcc
-AR = $(CROSS)ar
-STRIPTOOL = $(CROSS)strip
-
-# To compile vs uClibc, just use the compiler wrapper built by uClibc...
-# Everything should compile and work as expected these days...
-#CC = ../uClibc/extra/gcc-uClibc/i386-uclibc-gcc
-
-# To compile vs some other alternative libc, you may need to use/adjust
-# the following lines to meet your needs...
-#
-# If you are using Red Hat 6.x with the compatible RPMs (for developing under
-# Red Hat 5.x and glibc 2.0) uncomment the following.  Be sure to read about
-# using the compatible RPMs (compat-*) at http://www.redhat.com !
-#LIBCDIR=/usr/i386-glibc20-linux
-#
-# The following is used for libc5 (if you install altgcc and libc5-altdev
-# on a Debian system).  
-#LIBCDIR=/usr/i486-linuxlibc1
-#
-# For other libraries, you are on your own...
-#LDFLAGS+=-nostdlib
-#LIBRARIES = $(LIBCDIR)/lib/libc.a -lgcc
-#CROSS_CFLAGS+=-nostdinc -I$(LIBCDIR)/include -I$(GCCINCDIR)
-#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
-
-# use '-Os' optimization if available, else use -O2
-OPTIMIZATION := $(shell if $(CC) -Os -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \
-    then echo "-Os"; else echo "-O2" ; fi)
-
-WARNINGS = -Wall -Wshadow
-
-ARFLAGS = -r
-
-#
-#--------------------------------------------------------
-# If you're going to do a lot of builds with a non-vanilla configuration,
-# it makes sense to adjust parameters above, so you can type "make"
-# by itself, instead of following it by the same half-dozen overrides
-# every time.  The stuff below, on the other hand, is probably less
-# prone to casual user adjustment.
-# 
-
-ifeq ($(strip $(DOLFS)),true)
-    # For large file summit support
-    CFLAGS+=-D_FILE_OFFSET_BITS=64
-endif
-ifeq ($(strip $(DODMALLOC)),true)
-    # For testing mem leaks with dmalloc
-    CFLAGS+=-DDMALLOC
-    LIBRARIES = -ldmalloc
-    # Force debug=true, since this is useless when not debugging...
-    DODEBUG = true
-else
-    ifeq ($(strip $(DOEFENCE)),true)
-       LIBRARIES = -lefence
-       # Force debug=true, since this is useless when not debugging...
-       DODEBUG = true
-    endif
-endif
-ifeq ($(strip $(DODEBUG)),true)
-    CFLAGS  += $(WARNINGS) -g -D_GNU_SOURCE
-    LDFLAGS += -Wl,-warn-common
-    STRIP    =
-else
-    CFLAGS  += $(WARNINGS) $(OPTIMIZATION) -fomit-frame-pointer -D_GNU_SOURCE
-    LDFLAGS += -s -Wl,-warn-common
-    STRIP    = $(STRIPTOOL) --remove-section=.note --remove-section=.comment $(PROG)
-endif
-ifeq ($(strip $(DOSTATIC)),true)
-    LDFLAGS += --static
-    #
-    #use '-ffunction-sections -fdata-sections' and '--gc-sections' (if they 
-    # work) to try and strip out any unused junk.  Doesn't do much for me, 
-    # but you may want to give it a shot...
-    #
-    #ifeq ($(shell $(CC) -ffunction-sections -fdata-sections -S \
-    #  -o /dev/null -xc /dev/null 2>/dev/null && $(LD) \
-    #                  --gc-sections -v >/dev/null && echo 1),1)
-    #  CFLAGS += -ffunction-sections -fdata-sections
-    #  LDFLAGS += --gc-sections
-    #endif
-endif
-
-ifndef $(PREFIX)
-    PREFIX = `pwd`/_install
-endif
-
-# Additional complications due to support for pristine source dir.
-# Include files in the build directory should take precedence over
-# the copy in BB_SRC_DIR, both during the compilation phase and the
-# shell script that finds the list of object files.
-# Work in progress by <ldoolitt@recycle.lbl.gov>.
-#
-ifneq ($(strip $(BB_SRC_DIR)),)
-    VPATH = $(BB_SRC_DIR)
-endif
-#ifneq ($(strip $(VPATH)),)
-#    CFLAGS += -I- -I. $(patsubst %,-I%,$(subst :, ,$(VPATH)))
-#endif
-
-# We need to set APPLET_SOURCES to something like
-#   $(shell busybox.sh Config.h)
-# but in a manner that works with VPATH and BB_SRC_DIR.
-# Possible ways to approach this:
-#
-#   1. Explicitly search through .:$(VPATH) for busybox.sh and config.h,
-#      then $(shell $(BUSYBOX_SH) $(CONFIG_H) $(BB_SRC_DIR))
-#
-#   2. Explicity search through .:$(VPATH) for slist.mk,
-#      then $(shell $(MAKE) -f $(SLIST_MK) VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR))
-#
-#   3. Create slist.mk in this directory, with commands embedded in
-#      a $(shell ...) command, and $(MAKE) it immediately.
-#
-#   4. Use a real rule within this makefile to create a file that sets 
-#      APPLET_SOURCE_LIST, then include that file.  Has complications
-#      with the first trip through the makefile (before processing the
-#      include) trying to do too much, and a spurious warning the first
-#      time make is run.
-#
-# This is option 3:
-#
-#APPLET_SOURCES = $(shell \
-#   echo -e 'all: busybox.sh Config.h\n\t@ $$(SHELL) $$^ $$(BB_SRC_DIR)' >slist.mk; \
-#   make -f slist.mk VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR) \
-#)
-# And option 4:
--include applet_source_list
-
-OBJECTS   = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o
-CFLAGS    += $(CROSS_CFLAGS)
-CFLAGS    += -DBB_VER='"$(VERSION)"'
-CFLAGS    += -DBB_BT='"$(BUILDTIME)"'
-ifdef BB_INIT_SCRIPT
-    CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"'
-endif
-
-ifneq ($(strip $(USE_SYSTEM_PWD_GRP)),true)
-    PWD_GRP    = pwd_grp
-    PWD_GRP_DIR = $(BB_SRC_DIR:=/)$(PWD_GRP)
-    PWD_LIB     = libpwd.a
-    PWD_CSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c \
-           fgetpwent.c __getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c \
-           initgroups.c setgroups.c
-    PWD_OBJS=$(patsubst %.c,$(PWD_GRP)/%.o, $(PWD_CSRC))
-ifneq ($(strip $(BB_SRC_DIR)),)
-    PWD_CFLAGS = -I- -I.
-endif
-    PWD_CFLAGS += -I$(PWD_GRP_DIR)
-else
-    CFLAGS    += -DUSE_SYSTEM_PWD_GRP
-endif
-    
-LIBBB    = libbb
-LIBBB_LIB = libbb.a
-LIBBB_CSRC= ask_confirmation.c chomp.c concat_path_file.c copy_file.c \
-copy_file_chunk.c libc5.c device_open.c error_msg.c \
-error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \
-find_root_device.c full_read.c full_write.c get_console.c \
-get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \
-isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \
-mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \
-my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \
-print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \
-safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \
-trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
-xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
-copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
-dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \
-simplify_path.c
-LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
-ifeq ($(strip $(BB_SRC_DIR)),)
-    LIBBB_CFLAGS += -I$(LIBBB)
-else
-    LIBBB_CFLAGS = -I- -I. -I./$(LIBBB) -I$(BB_SRC_DIR)/$(LIBBB) -I$(BB_SRC_DIR)
-endif
-
-LIBBB_MSRC=libbb/messages.c
-LIBBB_MESSAGES= full_version name_too_long omitting_directory not_a_directory \
-memory_exhausted invalid_date invalid_option io_error dash_dash_help \
-write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket
-LIBBB_MOBJ=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_MESSAGES))
-
-LIBBB_ARCSRC=libbb/unarchive.c
-LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \
-get_header_ar get_header_cpio get_header_tar deb_extract
-LIBBB_AROBJS=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_ARCOBJ))
-
-
-# Put user-supplied flags at the end, where they
-# have a chance of winning.
-CFLAGS += $(CFLAGS_EXTRA)
-
-.EXPORT_ALL_VARIABLES:
-
-all: applet_source_list busybox busybox.links doc
-
-applet_source_list: busybox.sh Config.h
-       (echo -n "APPLET_SOURCES := "; CC="$(CC)" BB_SRC_DIR="$(BB_SRC_DIR)" $(SHELL) $^) > $@
-
-doc: olddoc
-
-# Old Docs...
-olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html
-
-docs/busybox.pod : docs/busybox_header.pod usage.h docs/busybox_footer.pod
-       - ( cat docs/busybox_header.pod; \
-           docs/autodocifier.pl usage.h; \
-           cat docs/busybox_footer.pod ) > docs/busybox.pod
-
-docs/BusyBox.txt: docs/busybox.pod
-       @echo
-       @echo BusyBox Documentation
-       @echo
-       -mkdir -p docs
-       -pod2text $< > $@
-
-docs/BusyBox.1: docs/busybox.pod
-       - mkdir -p docs
-       - pod2man --center=BusyBox --release="version $(VERSION)" \
-               $< > $@
-
-docs/BusyBox.html: docs/busybox.lineo.com/BusyBox.html
-       - mkdir -p docs
-       -@ rm -f docs/BusyBox.html
-       -@ ln -s busybox.lineo.com/BusyBox.html docs/BusyBox.html
-
-docs/busybox.lineo.com/BusyBox.html: docs/busybox.pod
-       -@ mkdir -p docs/busybox.lineo.com
-       -  pod2html --noindex $< > \
-           docs/busybox.lineo.com/BusyBox.html
-       -@ rm -f pod2htm*
-
-
-# New docs based on DOCBOOK SGML
-newdoc: docs/busybox.txt docs/busybox.pdf docs/busybox/busyboxdocumentation.html
-
-docs/busybox.txt: docs/busybox.sgml
-       @echo
-       @echo BusyBox Documentation
-       @echo
-       - mkdir -p docs
-       (cd docs; sgmltools -b txt busybox.sgml)
-
-docs/busybox.dvi: docs/busybox.sgml
-       - mkdir -p docs
-       (cd docs; sgmltools -b dvi busybox.sgml)
-
-docs/busybox.ps: docs/busybox.sgml
-       - mkdir -p docs
-       (cd docs; sgmltools -b ps busybox.sgml)
-
-docs/busybox.pdf: docs/busybox.ps
-       - mkdir -p docs
-       (cd docs; ps2pdf busybox.ps)
-
-docs/busybox/busyboxdocumentation.html: docs/busybox.sgml
-       - mkdir -p docs
-       (cd docs/busybox.lineo.com; sgmltools -b html ../busybox.sgml)
-
-
-busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) 
-       $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES)
-       $(STRIP)
-
-# Without VPATH, rule expands to "/bin/sh busybox.mkll Config.h applets.h"
-# but with VPATH, some or all of those file names are resolved to the
-# directories in which they live.
-busybox.links: busybox.mkll Config.h applets.h
-       - $(SHELL) $^ >$@
-
-nfsmount.o cmdedit.o: %.o: %.h
-ash.o hush.o lash.o msh.o: cmdedit.h
-$(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile
-ifeq ($(strip $(BB_SRC_DIR)),)
-       $(CC) $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
-else
-       $(CC) $(CFLAGS) -I- -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o
-endif
-
-$(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile
-       - mkdir -p $(PWD_GRP)
-       $(CC) $(CFLAGS) $(PWD_CFLAGS) -c $< -o $*.o
-
-$(LIBBB_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile libbb/libbb.h
-       - mkdir -p $(LIBBB)
-       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o
-
-$(LIBBB_MOBJ): $(LIBBB_MSRC)
-       - mkdir -p $(LIBBB)
-       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o
-
-$(LIBBB_AROBJS): $(LIBBB_ARCSRC)
-       - mkdir -p $(LIBBB)
-       $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o
-
-libpwd.a: $(PWD_OBJS)
-       $(AR) $(ARFLAGS) $@ $^
-
-libbb.a:  $(LIBBB_MOBJ) $(LIBBB_AROBJS) $(LIBBB_OBJS)
-       $(AR) $(ARFLAGS) $@ $^
-
-usage.o: usage.h
-
-libbb/loop.o: libbb/loop.h
-
-libbb/loop.h: mk_loop_h.sh
-       @ $(SHELL) $< > $@
-
-test tests:
-       # old way of doing it
-       #cd tests && $(MAKE) all
-       # new way of doing it
-       cd tests && ./tester.sh
-
-clean:
-       - cd tests && $(MAKE) clean
-       - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \
-           docs/busybox.lineo.com/BusyBox.html
-       - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \
-           docs/busybox.pdf docs/busybox.lineo.com/busybox.html
-       - rm -f multibuild.log Config.h.orig *.gdb *.elf
-       - rm -rf docs/busybox _install libpwd.a libbb.a pod2htm*
-       - rm -f busybox.links libbb/loop.h *~ slist.mk core applet_source_list
-       - find -name \*.o -exec rm -f {} \;
-
-distclean: clean
-       - cd tests && $(MAKE) distclean
-       - rm -f busybox applet_source_list
-
-install: install.sh busybox busybox.links
-       $(SHELL) $< $(PREFIX)
-
-install-hardlinks: install.sh busybox busybox.links
-       $(SHELL) $< $(PREFIX) --hardlinks
-
-debug_pristine:
-       @ echo VPATH=\"$(VPATH)\"
-       @ echo OBJECTS=\"$(OBJECTS)\"
-
-dist release: distclean doc
-       cd ..;                                  \
-       rm -rf busybox-$(VERSION);              \
-       cp -a busybox busybox-$(VERSION);       \
-                                               \
-       find busybox-$(VERSION)/ -type d        \
-                                -name CVS      \
-                                -print         \
-               -exec rm -rf {} \; ;            \
-                                               \
-       find busybox-$(VERSION)/ -type f        \
-                                -name .\#*     \
-                                -print         \
-               -exec rm -f {} \;  ;            \
-                                               \
-       tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/;
-
-.PHONY: tags
-tags:
-       ctags -R .
diff --git a/busybox/README b/busybox/README
deleted file mode 100644 (file)
index b45ef57..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-Please see the LICENSE file for copyright information.
-    
-BusyBox combines tiny versions of many common UNIX utilities into a single
-small executable. It provides minimalist replacements for most of the utilities
-you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
-tar, etc. BusyBox provides a fairly complete POSIX environment for any small or
-embedded system. The utilities in BusyBox generally have fewer options than
-their full featured GNU cousins; however, the options that are included provide
-the expected functionality and behave very much like their GNU counterparts.
-
-BusyBox has been written with size-optimization and limited resources in mind.
-It is also extremely modular so you can easily include or exclude commands (or
-features) at compile time. This makes it easy to customize your embedded
-systems. To create a working system, just add /dev, /etc, and a kernel.
-
-BusyBox was originally written to support the Debian Rescue/Install disks, but
-it also makes an excellent environment for any small or embedded system.
-
-As of version 0.20 there is now a version number. : ) Also as of version 0.20,
-BusyBox is now modularized to easily allow you to build only the components you
-need, thereby reducing binary size. To turn off unwanted BusyBox components,
-simply edit the file "Config.h" and comment out the components you do not need
-using C++ style (//) comments.
-
-After the build is complete, a busybox.links file is generated.  This is
-used by 'make install' to create symlinks to the busybox binary for all
-compiled in functions.  By default, 'make install' will place the symlink
-forest into `pwd`/_install unless you have defined the PREFIX environment
-variable (i.e., 'make PREFIX=/tmp/foo install')
-
-----------------
-    
-Supported architectures:
-
-   Busybox in general will build on any architecture supported by gcc.  It has
-   a few specialized features added for __sparc__ and __alpha__.  insmod
-   functionality is currently limited to x86, ARM, SH3/4, powerpc, m68k, 
-   and MIPS.
-
-Supported libcs:
-
-   glibc-2.0.x, glibc-2.1.x, Linux-libc5, uClibc.  People are looking at
-   newlib and diet-libc, but consider them unsupported, untested, or worse.
-
-Supported kernels:
-
-   Full functionality requires Linux 2.0.x, 2.2.x, or 2.4.x.  A large fraction
-   of the code should run on just about anything.
-
-----------------
-
-Shells:
-
-lash is the very smallest shell (adds just 10k) and it is quite usable as 
-a command prompt, but it is not suitable for any but the most trivial
-scripting (such as an initrd that calls insmod a few times) since it does
-not understand Bourne shell grammer.  It does handle pipes, redirects, and
-job control though.  Adding in command editing makes it a very nice
-lightweight command prompt.
-
-hush is also quite small (just 18k) and it has very complete Bourne shell
-grammer.  It handles if/then/else/fi just fine, but doesn't handle loops
-like for/do/done or case/esac and such.  It also currently has a problem
-with job control.  Using hush is not yet recommended.
-
-msh: The minix shell (adds just 30k) is quite complete and handles things
-like for/do/done, case/esac and all the things you expect a Bourne shell to
-do.  It is not always pedantically correct about Bourne shell grammer (try
-running the shell testscript "tests/sh.testcases" on it and compare vs bash)
-but for most things it works quite well.  It also uses only vfork, so it can
-be used on uClinux systems.  This was only recently added, so there is still
-room to shrink it further...
-
-ash: This adds about 60k in the default configuration and is the most
-complete and most pedantically correct shell included with busybox.  This
-shell was also recently added, and several people (mainly Vladimir and Erik)
-have been working on it.  There are a number of configurable things at the
-top of ash.c as well, so check those out if you want to tweak things.
-
-----------------
-
-Getting help:
-
-When you find you need help, you can check out the BusyBox mailing list
-archives at http://opensource.lineo.com/lists/busybox/ or even join
-the mailing list if you are interested.
-
-----------------
-
-Bugs:
-
-If you find bugs, please submit a bug report.  Full instructions on how to
-report a bug are found at http://bugs.lineo.com/Reporting.html.
-
-For the impatient: To submit a bug, simply send an email describing the problem
-to submit@bugs.lineo.com.  Bug reports should look something like this:
-
-    To: submit@bugs.lineo.com
-    From: diligent@testing.linux.org
-    Subject: /bin/true doesn't work
-
-    Package: busybox
-    Version: 0.51
-
-    When I invoke '/bin/true' it doesn't work.  I expected it to return 
-    a "0" but it returned a "1" instead.  Here is the transcript:
-       $ /bin/true ; echo $?
-       1
-    With GNU /bin/true, I get the following output:
-       $ /bin/true ; echo $?
-       0
-    I am using Debian 2.2r2, kernel version 2.2.18, and the latest
-    uClibc from CVS.  Thanks for the wonderful program!
-       -Diligent
-
-Note the careful description and use of examples showing not only what BusyBox
-does, but also a counter example showing what an equivalent GNU app does.  Bug
-reports lacking such detail may take a _long_ time to be fixed...  Thanks for
-understanding.
-
-----------------
-
-FTP:
-
-Source for the latest released version can always be downloaded from 
-    ftp://ftp.lineo.com/pub/busybox. 
-
-----------------
-
-CVS:
-
-BusyBox now has its own publicly browsable CVS tree at:
-    http://opensource.lineo.com/cgi-bin/cvsweb/busybox/
-
-Anonymous CVS access is available.  For instructions, check out:
-    http://opensource.lineo.com/cvs_anon.html
-
-For those that are actively contributing there is even CVS write access:
-    http://opensource.lineo.com/cvs_write.html
-
-----------------
-
-Please feed suggestions, bug reports, insults, and bribes back to:
-       Erik Andersen 
-       <andersen@lineo.com>
-       <andersee@debian.org>
-       <andersee@codepoet.org>
-
-<blatant plug>
-Many thanks to go to Lineo for paying me to work on busybox. 
-</blatant plug>
-
diff --git a/busybox/TODO b/busybox/TODO
deleted file mode 100644 (file)
index 3d9af20..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-TODO list for busybox in no particular order. Just because something
-is listed here doesn't mean that it is going to be added to busybox,
-or that doing so is even a good idea. It just means that I _might_ get
-around to it some time. If you have any good ideas, please let me know.
-
-* login/sulogin/passwd/getty/etc are part of tinylogin, and so are not
-    needed or wanted in busybox (or else I'd have to link to libcrypt).
-
-* We _were_ going to split networking apps into a new package called 
-    netkit-tiny.  Per discussions on the mailing list, this isn't going
-    to happen.  False alarm.  Sorry about the confusion.  
-
-
- -Erik
-
------------
-
-Possible apps to include some time:
-
-* hwclock
-* start-stop-daemon
-* group/commonize strings, remove dups (for i18n, l10n)
-
------------
-
-With sysvinit, reboot, poweroff and halt all used a named pipe, 
-/dev/initctl, to communicate with the init process.  Busybox
-currently uses signals to communicate with init.  This makes
-busybox incompatible with sysvinit.  We should probably use
-a named pipe as well so we can be compatible.
-
------------------------
-
-Run the following:
-
-    rm -f busybox && make LDFLAGS+=-nostdlib 2>&1 | \
-       sed -ne 's/.*undefined reference to `\(.*\)..*/\1/gp' | sort | uniq
-
-reveals the list of all external (i.e., libc) things that BusyBox depends on.
-It would be a very nice thing to reduce this list to an absolute minimum, to
-reduce the footprint of busybox, especially when staticly linking with
-libraries such as uClibc.
-
------------------------
-
-Compile with debugging on, run 'nm --size-sort ./busybox'
-and then start with the biggest things and make them smaller...
-
------------------------
-
- du.c probably ought to have an -x switch like GNU du does...
-
------------------------
-
-xargs could use a -l option
-
-------------------------------------------------------------------
diff --git a/busybox/adjtimex.c b/busybox/adjtimex.c
deleted file mode 100644 (file)
index e3c160d..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables.
- *
- * Originally written: October 1997
- * Last hack: March 2001
- * Copyright 1997, 2000, 2001 Larry Doolittle <LRDoolittle@lbl.gov>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License (Version 2,
- *  June 1991) as published by the Free Software Foundation.  At the
- *  time of writing, that license was published by the FSF with the URL
- *  http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
- *  reference.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- * This adjtimex(1) is very similar in intent to adjtimex(8) by Steven
- * Dick <ssd@nevets.oau.org> and Jim Van Zandt <jrv@vanzandt.mv.com>
- * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*).
- * That version predates this one, and is _much_ bigger and more
- * featureful.  My independently written version was very similar to
- * Steven's from the start, because they both follow the kernel timex
- * structure.  I further tweaked this version to be equivalent to Steven's
- * where possible, but I don't like getopt_long, so the actual usage
- * syntax is incompatible.
- *
- * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes)
- * don't actually give a prototype for adjtimex(2), so building
- * this code (with -Wall) gives a warning.  Later versions of
- * glibc fix this issue.
- *
- * This program is too simple for a Makefile, just build with:
- *  gcc -Wall -O adjtimex.c -o adjtimex
- *
- * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
- * It will autosense if it is built in a busybox environment, based
- * on the BB_VER preprocessor macro.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#if __GNU_LIBRARY__ < 5
-#include <sys/timex.h>
-extern int adjtimex(struct timex *buf);
-#else
-#include <sys/timex.h>
-#endif
-
-#ifdef BB_VER
-#include "busybox.h"
-#endif
-
-static struct {int bit; char *name;} statlist[] = {
-       { STA_PLL,       "PLL"       },
-       { STA_PPSFREQ,   "PPSFREQ"   },
-       { STA_PPSTIME,   "PPSTIME"   },
-       { STA_FLL,       "FFL"       },
-       { STA_INS,       "INS"       },
-       { STA_DEL,       "DEL"       },
-       { STA_UNSYNC,    "UNSYNC"    },
-       { STA_FREQHOLD,  "FREQHOLD"  },
-       { STA_PPSSIGNAL, "PPSSIGNAL" },
-       { STA_PPSJITTER, "PPSJITTER" },
-       { STA_PPSWANDER, "PPSWANDER" },
-       { STA_PPSERROR,  "PPSERROR"  },
-       { STA_CLOCKERR,  "CLOCKERR"  },
-       { 0, NULL } };
-
-static char *ret_code_descript[] = {
-       "clock synchronized",
-       "insert leap second",
-       "delete leap second",
-       "leap second in progress",
-       "leap second has occurred",
-       "clock not synchronized" };
-
-#ifdef BB_VER
-#define main adjtimex_main
-#else
-void usage(char *prog)
-{
-       fprintf(stderr, 
-               "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n",
-               prog);
-}
-#define show_usage() usage(argv[0])
-#endif
-
-int main(int argc, char ** argv)
-{
-       struct timex txc;
-       int quiet=0;
-       int c, i, ret, sep;
-       char *descript;
-       txc.modes=0;
-       for (;;) {
-               c = getopt( argc, argv, "qo:f:p:t:");
-               if (c == EOF) break;
-               switch (c) {
-                       case 'q':
-                               quiet=1;
-                               break;
-                       case 'o':
-                               txc.offset = atoi(optarg);
-                               txc.modes |= ADJ_OFFSET_SINGLESHOT;
-                               break;
-                       case 'f':
-                               txc.freq = atoi(optarg);
-                               txc.modes |= ADJ_FREQUENCY;
-                               break;
-                       case 'p':
-                               txc.constant = atoi(optarg);
-                               txc.modes |= ADJ_TIMECONST;
-                               break;
-                       case 't':
-                               txc.tick = atoi(optarg);
-                               txc.modes |= ADJ_TICK;
-                               break;
-                       default:
-                               show_usage();
-                               exit(1);
-               }
-       }
-       if (argc != optind) { /* no valid non-option parameters */
-               show_usage();
-               exit(1);
-       }
-
-       ret = adjtimex(&txc);
-
-       if (ret < 0) perror("adjtimex");
-       
-       if (!quiet && ret>=0) {
-               printf(
-                       "    mode:         %d\n"
-                       "-o  offset:       %ld\n"
-                       "-f  frequency:    %ld\n"
-                       "    maxerror:     %ld\n"
-                       "    esterror:     %ld\n"
-                       "    status:       %d ( ",
-               txc.modes, txc.offset, txc.freq, txc.maxerror,
-               txc.esterror, txc.status);
-
-               /* representative output of next code fragment:
-                  "PLL | PPSTIME" */
-               sep=0;
-               for (i=0; statlist[i].name; i++) {
-                       if (txc.status & statlist[i].bit) {
-                               if (sep) fputs(" | ",stdout);
-                               fputs(statlist[i].name,stdout);
-                               sep=1;
-                       }
-               }
-
-               descript = "error";
-               if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret];
-               printf(" )\n"
-                       "-p  timeconstant: %ld\n"
-                       "    precision:    %ld\n"
-                       "    tolerance:    %ld\n"
-                       "-t  tick:         %ld\n"
-                       "    time.tv_sec:  %ld\n"
-                       "    time.tv_usec: %ld\n"
-                       "    return value: %d (%s)\n",
-               txc.constant,
-               txc.precision, txc.tolerance, txc.tick,
-               (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
-       }
-       return (ret<0);
-}
diff --git a/busybox/applets.c b/busybox/applets.c
deleted file mode 100644 (file)
index f3e56a9..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-#undef APPLET
-#undef APPLET_NOUSAGE
-#undef PROTOTYPES
-#include "applets.h"
-
-struct BB_applet *applet_using;
-
-/* The -1 arises because of the {0,NULL,0,-1} entry above. */
-const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
-
-extern void show_usage(void)
-{
-       const char *format_string;
-       const char *usage_string = usage_messages;
-       int i;
-
-       for (i = applet_using - applets; i > 0; ) {
-               if (!*usage_string++) {
-                       --i;
-               }
-       }
-       format_string = "%s\n\nUsage: %s %s\n\n";
-       if(*usage_string == 0)
-               format_string = "%s\n\nNo help available.\n\n";
-       fprintf(stderr, format_string,
-                       full_version, applet_using->name, usage_string);
-       exit(EXIT_FAILURE);
-}
-
-static int applet_name_compare(const void *x, const void *y)
-{
-       const char *name = x;
-       const struct BB_applet *applet = y;
-
-       return strcmp(name, applet->name);
-}
-
-extern const size_t NUM_APPLETS;
-
-struct BB_applet *find_applet_by_name(const char *name)
-{
-       return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
-                       applet_name_compare);
-}
-
-void run_applet_by_name(const char *name, int argc, char **argv)
-{
-       static int recurse_level = 0;
-       extern int been_there_done_that; /* From busybox.c */
-
-       recurse_level++;
-       /* Do a binary search to find the applet entry given the name. */
-       if ((applet_using = find_applet_by_name(name)) != NULL) {
-               applet_name = applet_using->name;
-               if (argv[1] && strcmp(argv[1], "--help") == 0) {
-                       if (strcmp(applet_using->name, "busybox")==0) {
-                               if(argv[2])
-                                 applet_using = find_applet_by_name(argv[2]);
-                                else
-                                 applet_using = NULL;
-                       }
-                       if(applet_using)
-                               show_usage();
-                       been_there_done_that=1;
-                       busybox_main(0, NULL);
-               }
-               exit((*(applet_using->main)) (argc, argv));
-       }
-       /* Just in case they have renamed busybox - Check argv[1] */
-       if (recurse_level == 1) {
-               run_applet_by_name("busybox", argc, argv);
-       }
-       recurse_level--;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/applets.h b/busybox/applets.h
deleted file mode 100644 (file)
index 7d75173..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * applets.h - a listing of all busybox applets.
- *
- * If you write a new applet, you need to add an entry to this list to make
- * busybox aware of it.
- *
- * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary
- * search lookup contributed by Gaute B Strokkenes stops working. If you value
- * your kneecaps, you'll be sure to *make sure* that any changes made to this
- * file result in the listing remaining in ascii order. You have been warned.
- */
-
-#undef APPLET
-#undef APPLET_ODDNAME
-#undef APPLET_NOUSAGE
-
-
-#if defined(PROTOTYPES)
-  #define APPLET(a,b,c) extern int b(int argc, char **argv);
-  #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv);
-  #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv);
-  extern const char usage_messages[];
-#elif defined(MAKE_USAGE)
-  #ifdef BB_FEATURE_VERBOSE_USAGE
-    #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0"
-    #define APPLET_NOUSAGE(a,b,c) "\0"
-    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0"
-  #else
-    #define APPLET(a,b,c) a##_trivial_usage "\0"
-    #define APPLET_NOUSAGE(a,b,c) "\0"
-    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0"
-  #endif
-#elif defined(MAKE_LINKS)
-#  define APPLET(a,b,c) LINK c a
-#  define APPLET_NOUSAGE(a,b,c) LINK c a
-#  define APPLET_ODDNAME(a,b,c,d) LINK c a
-#else
-  const struct BB_applet applets[] = {
-  #define APPLET(a,b,c) {#a,b,c},
-  #define APPLET_NOUSAGE(a,b,c) {a,b,c},
-  #define APPLET_ODDNAME(a,b,c,d) {a,b,c},
-#endif
-
-
-
-#ifdef BB_TEST
-       APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_ADJTIMEX
-       APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_AR
-       APPLET(ar, ar_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_ASH
-       APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_BASENAME
-       APPLET(basename, basename_main, _BB_DIR_USR_BIN)
-#endif
-       APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN)
-#ifdef BB_CAT
-       APPLET(cat, cat_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHGRP
-       APPLET(chgrp, chgrp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHMOD
-       APPLET(chmod, chmod_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHOWN
-       APPLET(chown, chown_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHROOT
-       APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_CHVT
-       APPLET(chvt, chvt_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CLEAR
-       APPLET(clear, clear_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CMP
-       APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CP
-       APPLET(cp, cp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CPIO
-       APPLET(cpio, cpio_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CUT
-       APPLET(cut, cut_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DATE
-       APPLET(date, date_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DC
-       APPLET(dc, dc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DD
-       APPLET(dd, dd_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DEALLOCVT
-       APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DF
-       APPLET(df, df_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DIRNAME
-       APPLET(dirname, dirname_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DMESG
-       APPLET(dmesg, dmesg_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DOS2UNIX
-       APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DPKG
-       APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DPKG_DEB
-       APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb)
-#endif
-#ifdef BB_DU
-       APPLET(du, du_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DUMPKMAP
-       APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DUTMP
-       APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_ECHO
-       APPLET(echo, echo_main, _BB_DIR_BIN)
-#endif
-#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP)
-       APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_ENV
-       APPLET(env, env_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_EXPR
-       APPLET(expr, expr_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRUE_FALSE
-       APPLET(false, false_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_FBSET
-       APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_FDFLUSH
-       APPLET(fdflush, fdflush_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_FIND
-       APPLET(find, find_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FREE
-       APPLET(free, free_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FREERAMDISK
-       APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_FSCK_MINIX
-       APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix)
-#endif
-#ifdef BB_GETOPT
-       APPLET(getopt, getopt_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GREP
-       APPLET(grep, grep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GUNZIP
-       APPLET(gunzip, gunzip_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GZIP
-       APPLET(gzip, gzip_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_HALT
-       APPLET(halt, halt_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_HEAD
-       APPLET(head, head_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_HOSTID
-       APPLET(hostid, hostid_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_HOSTNAME
-       APPLET(hostname, hostname_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_HUSH
-       APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_ID
-       APPLET(id, id_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_IFCONFIG
-       APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_INIT
-       APPLET(init, init_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_INSMOD
-       APPLET(insmod, insmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_KILL
-       APPLET(kill, kill_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_KILLALL
-       APPLET(killall, kill_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_KLOGD
-       APPLET(klogd, klogd_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LASH
-       APPLET(lash, lash_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LENGTH
-       APPLET(length, length_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FEATURE_LINUXRC
-       APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT)
-#endif
-#ifdef BB_LN
-       APPLET(ln, ln_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LOADACM
-       APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOADFONT
-       APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOADKMAP
-       APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LOGGER
-       APPLET(logger, logger_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOGNAME
-       APPLET(logname, logname_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOGREAD
-       APPLET(logread, logread_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LS
-       APPLET(ls, ls_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LSMOD
-       APPLET(lsmod, lsmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MAKEDEVS
-       APPLET(makedevs, makedevs_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MD5SUM
-       APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_MKDIR
-       APPLET(mkdir, mkdir_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MKFIFO
-       APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_MKFS_MINIX
-       APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix)
-#endif
-#ifdef BB_MKNOD
-       APPLET(mknod, mknod_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MKSWAP
-       APPLET(mkswap, mkswap_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MKTEMP
-       APPLET(mktemp, mktemp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MODPROBE
-       APPLET(modprobe, modprobe_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MORE
-       APPLET(more, more_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MOUNT
-       APPLET(mount, mount_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MSH
-       APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MT
-       APPLET(mt, mt_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MV
-       APPLET(mv, mv_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_NC
-       APPLET(nc, nc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_NSLOOKUP
-       APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_PIDOF
-       APPLET(pidof, pidof_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PING
-       APPLET(ping, ping_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PIVOT_ROOT
-       APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_POWEROFF
-       APPLET(poweroff, poweroff_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_PRINTF
-       APPLET(printf, printf_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_PS
-       APPLET(ps, ps_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PWD
-       APPLET(pwd, pwd_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RDATE
-       APPLET(rdate, rdate_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_READLINK
-       APPLET(readlink, readlink_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_REBOOT
-       APPLET(reboot, reboot_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_RENICE
-       APPLET(renice, renice_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_RESET
-       APPLET(reset, reset_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_RM
-       APPLET(rm, rm_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RMDIR
-       APPLET(rmdir, rmdir_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RMMOD
-       APPLET(rmmod, rmmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_ROUTE
-       APPLET(route, route_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_RPM2CPIO
-       APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_SED
-       APPLET(sed, sed_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SETKEYCODES
-       APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN)
-#endif
-#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH)
-       APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH)
-       APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH)
-       APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH)
-       APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SLEEP
-       APPLET(sleep, sleep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SORT
-       APPLET(sort, sort_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_STTY
-       APPLET(stty, stty_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SWAPONOFF
-       APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_SWAPONOFF
-       APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_SYNC
-       APPLET(sync, sync_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SYSLOGD
-       APPLET(syslogd, syslogd_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_TAIL
-       APPLET(tail, tail_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TAR
-       APPLET(tar, tar_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TEE
-       APPLET(tee, tee_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TELNET
-       APPLET(telnet, telnet_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TEST
-       APPLET(test, test_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TFTP
-       APPLET(tftp, tftp_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TOUCH
-       APPLET(touch, touch_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TR
-       APPLET(tr, tr_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRACEROUTE
-       APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRUE_FALSE
-       APPLET(true, true_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TTY
-       APPLET(tty, tty_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UMOUNT
-       APPLET(umount, umount_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UNAME
-       APPLET(uname, uname_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UNIQ
-       APPLET(uniq, uniq_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UNIX2DOS
-       APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UPDATE
-       APPLET(update, update_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_UPTIME
-       APPLET(uptime, uptime_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_USLEEP
-       APPLET(usleep, usleep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UUDECODE
-       APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UUENCODE
-       APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_VI
-       APPLET(vi, vi_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_WATCHDOG
-       APPLET(watchdog, watchdog_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_WC
-       APPLET(wc, wc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WGET
-       APPLET(wget, wget_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WHICH
-       APPLET(which, which_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WHOAMI
-       APPLET(whoami, whoami_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_XARGS
-       APPLET(xargs, xargs_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_YES
-       APPLET(yes, yes_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_GUNZIP
-       APPLET(zcat, gunzip_main, _BB_DIR_BIN)
-#endif
-
-#if !defined(PROTOTYPES) && !defined(MAKE_USAGE)
-       { 0,NULL,0 }
-};
-
-#endif
diff --git a/busybox/applets/applets.c b/busybox/applets/applets.c
deleted file mode 100644 (file)
index f3e56a9..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-#undef APPLET
-#undef APPLET_NOUSAGE
-#undef PROTOTYPES
-#include "applets.h"
-
-struct BB_applet *applet_using;
-
-/* The -1 arises because of the {0,NULL,0,-1} entry above. */
-const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1);
-
-extern void show_usage(void)
-{
-       const char *format_string;
-       const char *usage_string = usage_messages;
-       int i;
-
-       for (i = applet_using - applets; i > 0; ) {
-               if (!*usage_string++) {
-                       --i;
-               }
-       }
-       format_string = "%s\n\nUsage: %s %s\n\n";
-       if(*usage_string == 0)
-               format_string = "%s\n\nNo help available.\n\n";
-       fprintf(stderr, format_string,
-                       full_version, applet_using->name, usage_string);
-       exit(EXIT_FAILURE);
-}
-
-static int applet_name_compare(const void *x, const void *y)
-{
-       const char *name = x;
-       const struct BB_applet *applet = y;
-
-       return strcmp(name, applet->name);
-}
-
-extern const size_t NUM_APPLETS;
-
-struct BB_applet *find_applet_by_name(const char *name)
-{
-       return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet),
-                       applet_name_compare);
-}
-
-void run_applet_by_name(const char *name, int argc, char **argv)
-{
-       static int recurse_level = 0;
-       extern int been_there_done_that; /* From busybox.c */
-
-       recurse_level++;
-       /* Do a binary search to find the applet entry given the name. */
-       if ((applet_using = find_applet_by_name(name)) != NULL) {
-               applet_name = applet_using->name;
-               if (argv[1] && strcmp(argv[1], "--help") == 0) {
-                       if (strcmp(applet_using->name, "busybox")==0) {
-                               if(argv[2])
-                                 applet_using = find_applet_by_name(argv[2]);
-                                else
-                                 applet_using = NULL;
-                       }
-                       if(applet_using)
-                               show_usage();
-                       been_there_done_that=1;
-                       busybox_main(0, NULL);
-               }
-               exit((*(applet_using->main)) (argc, argv));
-       }
-       /* Just in case they have renamed busybox - Check argv[1] */
-       if (recurse_level == 1) {
-               run_applet_by_name("busybox", argc, argv);
-       }
-       recurse_level--;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/applets/busybox.c b/busybox/applets/busybox.c
deleted file mode 100644 (file)
index 33efb5d..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-#endif
-
-int been_there_done_that = 0; /* Also used in applets.c */
-const char *applet_name;
-
-#ifdef BB_FEATURE_INSTALLER
-/* 
- * directory table
- *             this should be consistent w/ the enum, busybox.h::Location,
- *             or else...
- */
-static char* install_dir[] = {
-       "/",
-       "/bin",
-       "/sbin",
-       "/usr/bin",
-       "/usr/sbin",
-};
-
-/* abstract link() */
-typedef int (*__link_f)(const char *, const char *);
-
-/* 
- * Where in the filesystem is this busybox?
- * [return]
- *             malloc'd string w/ full pathname of busybox's location
- *             NULL on failure
- */
-static char *busybox_fullpath()
-{
-       return xreadlink("/proc/self/exe");
-}
-
-/* create (sym)links for each applet */
-static void install_links(const char *busybox, int use_symbolic_links)
-{
-       __link_f Link = link;
-
-       char *fpc;
-       int i;
-       int rc;
-
-       if (use_symbolic_links) 
-               Link = symlink;
-
-       for (i = 0; applets[i].name != NULL; i++) {
-               fpc = concat_path_file(
-                       install_dir[applets[i].location], applets[i].name);
-               rc = Link(busybox, fpc);
-               if (rc!=0 && errno!=EEXIST) {
-                       perror_msg("%s", fpc);
-               }
-               free(fpc);
-       }
-}
-
-#endif /* BB_FEATURE_INSTALLER */
-
-int main(int argc, char **argv)
-{
-       const char *s;
-
-       applet_name = argv[0];
-
-       if (applet_name[0] == '-')
-               applet_name++;
-
-       for (s = applet_name; *s != '\0';) {
-               if (*s++ == '/')
-                       applet_name = s;
-       }
-
-#ifdef BB_LOCALE_SUPPORT 
-#ifdef BB_INIT
-       if(getpid()!=1) /* Do not set locale for `init' */
-#endif
-       {
-               setlocale(LC_ALL, "");
-       }
-#endif
-
-       run_applet_by_name(applet_name, argc, argv);
-       error_msg_and_die("applet not found");
-}
-
-
-int busybox_main(int argc, char **argv)
-{
-       int col = 0, len, i;
-
-#ifdef BB_FEATURE_INSTALLER    
-       /* 
-        * This style of argument parsing doesn't scale well 
-        * in the event that busybox starts wanting more --options.
-        * If someone has a cleaner approach, by all means implement it.
-        */
-       if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
-               int use_symbolic_links = 0;
-               int rc = 0;
-               char *busybox;
-
-               /* to use symlinks, or not to use symlinks... */
-               if (argc > 2) {
-                       if ((strcmp(argv[2], "-s") == 0)) { 
-                               use_symbolic_links = 1; 
-                       }
-               }
-
-               /* link */
-               busybox = busybox_fullpath();
-               if (busybox) {
-                       install_links(busybox, use_symbolic_links);
-                       free(busybox);
-               } else {
-                       rc = 1;
-               }
-               return rc;
-       }
-#endif /* BB_FEATURE_INSTALLER */
-
-       argc--;
-
-       /* If we've already been here once, exit now */
-       if (been_there_done_that == 1 || argc < 1) {
-               const struct BB_applet *a = applets;
-
-               fprintf(stderr, "%s\n\n"
-                               "Usage: busybox [function] [arguments]...\n"
-                               "   or: [function] [arguments]...\n\n"
-                               "\tBusyBox is a multi-call binary that combines many common Unix\n"
-                               "\tutilities into a single executable.  Most people will create a\n"
-                               "\tlink to busybox for each function they wish to use, and BusyBox\n"
-                               "\twill act like whatever it was invoked as.\n" 
-                               "\nCurrently defined functions:\n", full_version);
-
-               while (a->name != 0) {
-                       col +=
-                               fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
-                                               (a++)->name);
-                       if (col > 60 && a->name != 0) {
-                               fprintf(stderr, ",\n");
-                               col = 0;
-                       }
-               }
-               fprintf(stderr, "\n\n");
-               exit(0);
-       }
-
-       /* Flag that we've been here already */
-       been_there_done_that = 1;
-       
-       /* Move the command line down a notch */
-       len = argv[argc] + strlen(argv[argc]) - argv[1];
-       memmove(argv[0], argv[1], len);
-       memset(argv[0] + len, 0, argv[1] - argv[0]);
-
-       /* Fix up the argv pointers */
-       len = argv[1] - argv[0];
-       memmove(argv, argv + 1, sizeof(char *) * (argc + 1));
-       for (i = 0; i < argc; i++)
-               argv[i] -= len;
-
-       return (main(argc, argv));
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/applets/busybox.mkll b/busybox/applets/busybox.mkll
deleted file mode 100755 (executable)
index 4e15e16..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# Make busybox links list file.
-
-# input $1: full path to Config.h
-# input $2: full path to applets.h
-# output (stdout): list of pathnames that should be linked to busybox
-
-# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-CONFIG_H=${1:-Config.h}
-APPLETS_H=${2:-applets.h}
-gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
-  awk '/^[ \t]*LINK/{
-       dir=substr($2,8)
-       gsub("_","/",dir)
-       if(dir=="/ROOT") dir=""
-       file=$3
-       gsub("\"","",file)
-       if (file=="busybox") next
-       print tolower(dir) "/" file
-  }'
diff --git a/busybox/applets/busybox.sh b/busybox/applets/busybox.sh
deleted file mode 100755 (executable)
index 9ab0f4b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-RAW=` \
-    $CC -E -dM ${1:-Config.h} | \
-    sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
-    | tr A-Z a-z | sort
-`
-test "${RAW}" != "" ||  exit
-if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi
-# By running $RAW through "ls", we avoid listing
-# source files that don't exist.
-ls $RAW 2>/dev/null | tr '\n' ' '
-
diff --git a/busybox/applets/install.sh b/busybox/applets/install.sh
deleted file mode 100755 (executable)
index d163a2e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-prefix=$1
-if [ "$prefix" = "" ]; then
-    echo "No installation directory, aborting."
-    exit 1;
-fi
-if [ "$2" = "--hardlinks" ]; then
-    linkopts="-f"
-else
-    linkopts="-fs"
-fi
-h=`sort busybox.links | uniq`
-
-
-rm -f $prefix/bin/busybox || exit 1
-mkdir -p $prefix/bin || exit 1
-install -m 755 busybox $prefix/bin/busybox || exit 1
-
-for i in $h ; do
-       appdir=`dirname $i`
-       mkdir -p $prefix/$appdir || exit 1
-       if [ "$2" = "--hardlinks" ]; then
-           bb_path="$prefix/bin/busybox"
-       else
-           case "$appdir" in
-               /)
-                   bb_path="bin/busybox"
-               ;;
-               /bin)
-                   bb_path="busybox"
-               ;;
-               /sbin)
-                   bb_path="../bin/busybox"
-               ;;
-               /usr/bin|/usr/sbin)
-                   bb_path="../../bin/busybox"
-               ;;
-               *)
-               echo "Unknown installation directory: $appdir"
-               exit 1
-               ;;
-           esac
-       fi
-       echo "  $prefix$i -> $bb_path"
-       ln $linkopts $bb_path $prefix$i || exit 1
-done
-
-exit 0
diff --git a/busybox/applets/usage.c b/busybox/applets/usage.c
deleted file mode 100644 (file)
index dfea1f9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "busybox.h"
-
-const char usage_messages[] =
-
-#define MAKE_USAGE
-#include "usage.h"
-
-#include "applets.h"
-
-;
diff --git a/busybox/applets/usage.h b/busybox/applets/usage.h
deleted file mode 100644 (file)
index 4d38c43..0000000
+++ /dev/null
@@ -1,1826 +0,0 @@
-#define adjtimex_trivial_usage \
-       "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
-#define adjtimex_full_usage \
-       "Reads and optionally sets system timebase parameters.\n" \
-       "See adjtimex(2).\n\n" \
-       "Options:\n" \
-       "\t-q\t\tquiet mode - do not print\n" \
-       "\t-o offset\ttime offset, microseconds\n" \
-       "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \
-       "\t\t\t(positive values make the system clock run fast)\n" \
-       "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \
-       "\t-p timeconstant\n"
-
-#define ar_trivial_usage \
-       "-[ov][ptx] ARCHIVE FILES"
-#define ar_full_usage \
-       "Extract or list FILES from an ar archive.\n\n" \
-       "Options:\n" \
-       "\t-o\t\tpreserve original dates\n" \
-       "\t-p\t\textract to stdout\n" \
-       "\t-t\t\tlist\n" \
-       "\t-x\t\textract\n" \
-       "\t-v\t\tverbosely list files processed\n"
-
-#define basename_trivial_usage \
-       "FILE [SUFFIX]"
-#define basename_full_usage \
-       "Strips directory path and suffixes from FILE.\n" \
-       "If specified, also removes any trailing SUFFIX."
-#define basename_example_usage \
-       "$ basename /usr/local/bin/foo\n" \
-       "foo\n" \
-       "$ basename /usr/local/bin/\n" \
-       "bin\n" \
-       "$ basename /foo/bar.txt .txt\n" \
-       "bar"
-
-#define cat_trivial_usage \
-       "[FILE]..."
-#define cat_full_usage \
-       "Concatenates FILE(s) and prints them to stdout."
-#define cat_example_usage \
-       "$ cat /proc/uptime\n" \
-       "110716.72 17.67"
-
-#define chgrp_trivial_usage \
-       "[OPTION]... GROUP FILE..."
-#define chgrp_full_usage \
-       "Change the group membership of each FILE to GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chgrp_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chgrp root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chmod_trivial_usage \
-       "[-R] MODE[,MODE]... FILE..."
-#define chmod_full_usage \
-       "Each MODE is one or more of the letters ugoa, one of the\n" \
-       "symbols +-= and one or more of the letters rwxst.\n\n" \
-       "Options:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chmod_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chmod u+x /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*\n" \
-       "$ chmod 444 /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chown_trivial_usage \
-       "[ -Rh ]...  OWNER[<.|:>[GROUP]] FILE..."
-#define chown_full_usage \
-       "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively.\n" \
-       "\t-h\tDo not dereference symbolic links."
-#define chown_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root.root /tmp/foo\n" \
-       "ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chroot_trivial_usage \
-       "NEWROOT [COMMAND...]"
-#define chroot_full_usage \
-       "Run COMMAND with root directory set to NEWROOT."
-#define chroot_example_usage \
-       "$ ls -l /bin/ls\n" \
-       "lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
-       "$ mount /dev/hdc1 /mnt -t minix\n" \
-       "$ chroot /mnt\n" \
-       "$ ls -l /bin/ls\n" \
-       "-rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*\n"
-
-#define chvt_trivial_usage \
-       "N"
-#define chvt_full_usage \
-       "Changes the foreground virtual terminal to /dev/ttyN"
-
-#define clear_trivial_usage \
-       ""
-#define clear_full_usage \
-       "Clear screen."
-
-#define cmp_trivial_usage \
-       "FILE1 [FILE2]"
-#define cmp_full_usage \
-       "\t-s\tquiet mode - do not print\n" \
-       "Compare files."
-
-#define cp_trivial_usage \
-       "[OPTION]... SOURCE DEST"
-#define cp_full_usage \
-       "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
-       "\n" \
-       "\t-a\tSame as -dpR\n" \
-       "\t-d\tPreserves links\n" \
-       "\t-p\tPreserves file attributes if possible\n" \
-       "\t-f\tforce (implied; ignored) - always set\n" \
-       "\t-R\tCopies directories recursively"
-
-#define cpio_trivial_usage \
-       "-[dimtuv][F cpiofile]"
-#define cpio_full_usage \
-       "Extract or list files from a cpio archive\n" \
-       "Main operation mode:\n" \
-       "\td\t\tmake leading directories\n" \
-       "\ti\t\textract\n" \
-       "\tm\t\tpreserve mtime\n" \
-       "\tt\t\tlist\n" \
-       "\tu\t\tunconditional overwrite\t" \
-       "\tF\t\tinput from file\t"
-       
-#define cut_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define cut_full_usage \
-       "Prints selected fields from each input FILE to standard output.\n\n" \
-       "Options:\n" \
-       "\t-b LIST\t\tOutput only bytes from LIST\n" \
-       "\t-c LIST\t\tOutput only characters from LIST\n" \
-       "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \
-       "\t-s\t\tOutput only the lines containing delimiter\n" \
-       "\t-f N\t\tPrint only these fields\n" \
-       "\t-n\t\tIgnored"
-#define cut_example_usage \
-       "$ echo "Hello world" | cut -f 1 -d ' '\n" \
-       "Hello\n" \
-       "$ echo "Hello world" | cut -f 2 -d ' '\n" \
-       "world\n"
-
-#define date_trivial_usage \
-       "[OPTION]... [+FORMAT]"
-#define date_full_usage \
-       "Displays the current time in the given FORMAT, or sets the system date.\n" \
-       "\nOptions:\n" \
-       "\t-R\t\tOutputs RFC-822 compliant date string\n" \
-       "\t-d STRING\tdisplay time described by STRING, not `now'\n" \
-       "\t-s\t\tSets time described by STRING\n" \
-       "\t-u\t\tPrints or sets Coordinated Universal Time"
-#define date_example_usage \
-       "$ date\n" \
-       "Wed Apr 12 18:52:41 MDT 2000\n"
-
-#define dc_trivial_usage \
-       "expression ..."
-#define dc_full_usage \
-       "This is a Tiny RPN calculator that understands the\n" \
-       "following operations: +, -, /, *, and, or, not, eor.\n" \
-       "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16"
-#define dc_example_usage \
-       "$ dc 2 2 +\n" \
-       "4\n" \
-       "$ dc 8 8 \* 2 2 + /\n" \
-       "16\n" \
-       "$ dc 0 1 and\n" \
-       "0\n" \
-       "$ dc 0 1 or\n" \
-       "1\n" \
-       "$ echo 72 9 div 8 mul | dc\n" \
-       "64\n"
-
-#define dd_trivial_usage \
-       "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \
-       "\t  [seek=N] [conv=notrunc|sync]"
-#define dd_full_usage \
-       "Copy a file, converting and formatting according to options\n\n" \
-       "\tif=FILE\t\tread from FILE instead of stdin\n" \
-       "\tof=FILE\t\twrite to FILE instead of stdout\n" \
-       "\tbs=N\t\tread and write N bytes at a time\n" \
-       "\tcount=N\t\tcopy only N input blocks\n" \
-       "\tskip=N\t\tskip N input blocks\n" \
-       "\tseek=N\t\tskip N output blocks\n" \
-       "\tconv=notrunc\tdon't truncate output file\n" \
-       "\tconv=sync\tpad blocks with zeros\n" \
-       "\n" \
-       "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
-       "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
-#define dd_example_usage \
-       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
-       "4+0 records in\n" \
-       "4+0 records out\n"
-
-#define deallocvt_trivial_usage \
-       "N"
-#define deallocvt_full_usage \
-        "Deallocate unused virtual terminal /dev/ttyN"
-
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-  #define USAGE_HUMAN_READABLE(a) a
-  #define USAGE_NOT_HUMAN_READABLE(a)
-#else
-  #define USAGE_HUMAN_READABLE(a) 
-  #define USAGE_NOT_HUMAN_READABLE(a) a
-#endif
-#define df_trivial_usage \
-       "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
-#define df_full_usage \
-       "Print the filesystem space used and space available.\n\n" \
-       "Options:\n" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define df_example_usage \
-       "$ df\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n" \
-       "/dev/sda1                64216     36364     27852  57% /boot\n" \
-       "$ df /dev/sda3\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n"
-
-#define dirname_trivial_usage \
-       "[FILENAME ...]"
-#define dirname_full_usage \
-       "Strips non-directory suffix from FILENAME"
-#define dirname_example_usage \
-       "$ dirname /tmp/foo\n" \
-       "/tmp\n" \
-       "$ dirname /tmp/foo/\n" \
-       "/tmp\n"
-
-#define dmesg_trivial_usage \
-       "[-c] [-n LEVEL] [-s SIZE]"
-#define dmesg_full_usage \
-       "Prints or controls the kernel ring buffer\n\n" \
-       "Options:\n" \
-       "\t-c\t\tClears the ring buffer's contents after printing\n" \
-       "\t-n LEVEL\tSets console logging level\n" \
-       "\t-s SIZE\t\tUse a buffer of size SIZE"
-
-#define dos2unix_trivial_usage \
-       "[option] [FILE]"
-#define dos2unix_full_usage \
-       "Converts FILE from dos format to unix format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define dpkg_trivial_usage \
-       "-i package_file\n"
-       "[-CPru] package_name"
-#define dpkg_full_usage \
-       "\t-i\tInstall the package\n" \
-       "\t-C\tConfigure an unpackaged package\n" \
-       "\t-P\tPurge all files of a package\n" \
-       "\t-r\tRemove all but the configuration files for a package\n" \
-       "\t-u\tUnpack a package, but dont configure it\n"
-
-#define dpkg_deb_trivial_usage \
-       "[-cefItxX] FILE [argument]"
-#define dpkg_deb_full_usage \
-       "Perform actions on debian packages (.debs)\n\n" \
-       "Options:\n" \
-       "\t-c\tList contents of filesystem tree\n" \
-       "\t-e\tExtract control files to [argument] directory\n" \
-       "\t-f\tDisplay control field name starting with [argument]\n" \
-       "\t-I\tDisplay the control filenamed [argument]\n" \
-       "\t-t\tExtract filesystem tree to stdout in tar format\n" \
-       "\t-x\tExtract packages filesystem tree to directory\n" \
-       "\t-X\tVerbose extract"
-#define dpkg_deb_example_usage \
-       "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
-
-#define du_trivial_usage \
-       "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..."
-#define du_full_usage \
-       "Summarizes disk space used for each FILE and/or directory.\n" \
-       "Disk space is printed in units of 1024 bytes.\n\n" \
-       "Options:\n" \
-       "\t-l\tcount sizes many times if hard linked\n" \
-       "\t-s\tdisplay only a total for each argument" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define du_example_usage \
-       "$ du\n" \
-       "16      ./CVS\n" \
-       "12      ./kernel-patches/CVS\n" \
-       "80      ./kernel-patches\n" \
-       "12      ./tests/CVS\n" \
-       "36      ./tests\n" \
-       "12      ./scripts/CVS\n" \
-       "16      ./scripts\n" \
-       "12      ./docs/CVS\n" \
-       "104     ./docs\n" \
-       "2417    .\n"
-
-#define dumpkmap_trivial_usage \
-       "> keymap"
-#define dumpkmap_full_usage \
-       "Prints out a binary keyboard translation table to standard output."
-#define dumpkmap_example_usage \
-       "$ dumpkmap > keymap\n"
-
-#define dutmp_trivial_usage \
-       "[FILE]"
-#define dutmp_full_usage \
-       "Dump utmp file format (pipe delimited) from FILE\n" \
-       "or stdin to stdout.  (i.e., 'dutmp /var/run/utmp')"
-#define dutmp_example_usage \
-       "$ dutmp /var/run/utmp\n" \
-       "8|7||si|||0|0|0|955637625|760097|0\n" \
-       "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \
-       "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \
-       "8|125||l4|||0|0|0|955637629|998367|0\n" \
-       "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \
-       "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \
-       "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n"
-
-#define echo_trivial_usage \
-       "[-neE] [ARG ...]"
-#define echo_full_usage \
-       "Prints the specified ARGs to stdout\n\n" \
-       "Options:\n" \
-       "\t-n\tsuppress trailing newline\n" \
-       "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
-       "\t-E\tdisable interpretation of backslash-escaped characters"
-#define echo_example_usage \
-       "$ echo "Erik is cool"\n" \
-       "Erik is cool\n" \
-       "$  echo -e "Erik\\nis\\ncool"\n" \
-       "Erik\n" \
-       "is\n" \
-       "cool\n" \
-       "$ echo "Erik\\nis\\ncool"\n" \
-       "Erik\\nis\\ncool\n"
-
-#define env_trivial_usage \
-       "[-iu] [-] [name=value]... [command]"
-#define env_full_usage \
-       "Prints the current environment or runs a program after setting\n" \
-       "up the specified environment.\n\n" \
-       "Options:\n" \
-       "\t-, -i\tstart with an empty environment\n" \
-       "\t-u\tremove variable from the environment\n"
-
-#define expr_trivial_usage \
-       "EXPRESSION"
-#define expr_full_usage \
-       "Prints the value of EXPRESSION to standard output.\n\n" \
-       "EXPRESSION may be:\n" \
-       "\tARG1 |  ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
-       "\tARG1 &  ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
-       "\tARG1 <  ARG2 ARG1 is less than ARG2\n" \
-       "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \
-       "\tARG1 =  ARG2 ARG1 is equal to ARG2\n" \
-       "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \
-       "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \
-       "\tARG1 >  ARG2 ARG1 is greater than ARG2\n" \
-       "\tARG1 +  ARG2 arithmetic sum of ARG1 and ARG2\n" \
-       "\tARG1 -  ARG2 arithmetic difference of ARG1 and ARG2\n" \
-       "\tARG1 *  ARG2 arithmetic product of ARG1 and ARG2\n" \
-       "\tARG1 /  ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \
-       "\tARG1 %  ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \
-       "\tSTRING : REGEXP             anchored pattern match of REGEXP in STRING\n" \
-       "\tmatch STRING REGEXP         same as STRING : REGEXP\n" \
-       "\tsubstr STRING POS LENGTH    substring of STRING, POS counted from 1\n" \
-       "\tindex STRING CHARS          index in STRING where any CHARS is found,\n" \
-       "\t                            or 0\n" \
-       "\tlength STRING               length of STRING\n" \
-       "\tquote TOKEN                 interpret TOKEN as a string, even if\n" \
-       "\t                            it is a keyword like `match' or an\n" \
-       "\t                            operator like `/'\n" \
-       "\t( EXPRESSION )              value of EXPRESSION\n\n" \
-       "Beware that many operators need to be escaped or quoted for shells.\n" \
-       "Comparisons are arithmetic if both ARGs are numbers, else\n" \
-       "lexicographical.  Pattern matches return the string matched between \n" \
-       "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
-       "of characters matched or 0."
-
-#define false_trivial_usage \
-       ""
-#define false_full_usage \
-       "Return an exit code of FALSE (1)."
-#define false_example_usage \
-       "$ false\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#define fbset_trivial_usage \
-       "[options] [mode]"
-#define fbset_full_usage \
-       "Show and modify frame buffer settings"
-#define fbset_example_usage \
-       "$ fbset\n" \
-       "mode "1024x768-76"\n" \
-       "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
-       "\tgeometry 1024 768 1024 768 16\n" \
-       "\ttimings 12714 128 32 16 4 128 4\n" \
-       "\taccel false\n" \
-       "\trgba 5/11,6/5,5/0,0/0\n" \
-       "endmode\n"
-
-#define fdflush_trivial_usage \
-       "DEVICE"
-#define fdflush_full_usage \
-       "Forces floppy disk drive to detect disk change"
-
-#ifdef BB_FEATURE_FIND_TYPE
-  #define USAGE_FIND_TYPE(a) a
-#else
-  #define USAGE_FIND_TYPE(a)
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-  #define USAGE_FIND_PERM(a) a
-#else
-  #define USAGE_FIND_PERM(a)
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-  #define USAGE_FIND_MTIME(a) a
-#else
-  #define USAGE_FIND_MTIME(a)
-#endif
-
-#define find_trivial_usage \
-       "[PATH...] [EXPRESSION]"
-#define find_full_usage \
-       "Search for files in a directory hierarchy.  The default PATH is\n" \
-       "the current directory; default EXPRESSION is '-print'\n" \
-       "\nEXPRESSION may consist of:\n" \
-       "\t-follow\t\tDereference symbolic links.\n" \
-       "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
-       "\t-print\t\tPrint (default and assumed).\n" \
-       USAGE_FIND_TYPE( \
-       "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
-) USAGE_FIND_PERM( \
-       "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \
-) USAGE_FIND_MTIME( \
-       "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days")
-#define find_example_usage \
-       "$ find / -name /etc/passwd\n" \
-       "/etc/passwd\n"
-
-#define free_trivial_usage \
-       ""
-#define free_full_usage \
-       "Displays the amount of free and used system memory"
-#define free_example_usage \
-       "$ free\n" \
-       "              total         used         free       shared      buffers\n" \
-       "  Mem:       257628       248724         8904        59644        93124\n" \
-       " Swap:       128516         8404       120112\n" \
-       "Total:       386144       257128       129016\n" \
-
-#define freeramdisk_trivial_usage \
-       "DEVICE"
-#define freeramdisk_full_usage \
-       "Frees all memory used by the specified ramdisk."
-#define freeramdisk_example_usage \
-       "$ freeramdisk /dev/ram2\n"
-
-#define fsck_minix_trivial_usage \
-       "[-larvsmf] /dev/name"
-#define fsck_minix_full_usage \
-       "Performs a consistency check for MINIX filesystems.\n\n" \
-       "Options:\n" \
-       "\t-l\tLists all filenames\n" \
-       "\t-r\tPerform interactive repairs\n" \
-       "\t-a\tPerform automatic repairs\n" \
-       "\t-v\tverbose\n" \
-       "\t-s\tOutputs super-block information\n" \
-       "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
-       "\t-f\tForce file system check."
-
-#define getopt_trivial_usage \
-       "[OPTIONS]..."
-#define getopt_full_usage \
-       "Parse command options\n" \
-       "\t-a, --alternative            Allow long options starting with single -\n" \
-       "\t-l, --longoptions=longopts   Long options to be recognized\n" \
-       "\t-n, --name=progname          The name under which errors are reported\n" \
-       "\t-o, --options=optstring      Short options to be recognized\n" \
-       "\t-q, --quiet                  Disable error reporting by getopt(3)\n" \
-       "\t-Q, --quiet-output           No normal output\n" \
-       "\t-s, --shell=shell            Set shell quoting conventions\n" \
-       "\t-T, --test                   Test for getopt(1) version\n" \
-       "\t-u, --unqote                 Do not quote the output"
-#define getopt_example_usage \
-        "$ cat getopt.test\n" \
-        "#!/bin/sh\n" \
-        "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
-        "       -n 'example.busybox' -- "$@"`\n" \
-        "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
-        "eval set -- "$GETOPT"\n" \
-        "while true ; do\n" \
-        " case $1 in\n" \
-        "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
-        "   -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \
-        "   -c|--c-long)\n" \
-        "     case "$2" in\n" \
-        "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
-        "       *)  echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \
-        "     esac ;;\n" \
-        "   --) shift ; break ;;\n" \
-        "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
-        " esac\n" \
-        "done\n"
-
-#define grep_trivial_usage \
-       "[-ihHnqvs] PATTERN [FILEs...]"
-#define grep_full_usage \
-       "Search for PATTERN in each FILE or standard input.\n\n" \
-       "Options:\n" \
-       "\t-H\tprefix output lines with filename where match was found\n" \
-       "\t-h\tsuppress the prefixing filename on output\n" \
-       "\t-i\tignore case distinctions\n" \
-       "\t-l\tlist names of files that match\n" \
-       "\t-n\tprint line number with output lines\n" \
-       "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \
-       "\t-v\tselect non-matching lines\n" \
-       "\t-s\tsuppress file open/read error messages"
-#define grep_example_usage \
-       "$ grep root /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "$ grep ^[rR]oo. /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n"
-
-#define gunzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gunzip_full_usage \
-       "Uncompress FILE (or standard input if FILE is '-').\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output\n" \
-       "\t-t\tTest compressed file integrity"
-#define gunzip_example_usage \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
-
-#define gzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gzip_full_usage \
-       "Compress FILE with maximum compression.\n" \
-       "When FILE is '-', reads standard input.  Implies -c.\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output instead of FILE.gz\n" \
-       "\t-d\tdecompress"
-#define gzip_example_usage \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
-       "$ gzip /tmp/busybox.tar\n" \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
-
-#define halt_trivial_usage \
-       ""
-#define halt_full_usage \
-       "Halt the system."
-
-#define head_trivial_usage \
-       "[OPTION] [FILE]..."
-#define head_full_usage \
-       "Print first 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-n NUM\t\tPrint first NUM lines instead of first 10"
-#define head_example_usage \
-       "$ head -n 2 /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
-
-#define hostid_trivial_usage \
-       ""
-#define hostid_full_usage \
-       "Print out a unique 32-bit identifier for the machine."
-
-#define hostname_trivial_usage \
-       "[OPTION] {hostname | -F FILE}"
-#define hostname_full_usage \
-       "Get or set the hostname or DNS domain name. If a hostname is given\n" \
-       "(or FILE with the -F parameter), the host name will be set.\n\n" \
-       "Options:\n" \
-       "\t-s\t\tShort\n" \
-       "\t-i\t\tAddresses for the hostname\n" \
-       "\t-d\t\tDNS domain name\n" \
-       "\t-F, --file FILE\tUse the contents of FILE to specify the hostname"
-#define hostname_example_usage \
-       "$ hostname\n" \
-       "sage \n"
-
-#define id_trivial_usage \
-       "[OPTIONS]... [USERNAME]"
-#define id_full_usage \
-       "Print information for USERNAME or the current user\n\n" \
-       "Options:\n" \
-       "\t-g\tprints only the group ID\n" \
-       "\t-u\tprints only the user ID\n" \
-       "\t-n\tprint a name instead of a number (with for -ug)\n" \
-       "\t-r\tprints the real user ID instead of the effective ID (with -ug)"
-#define id_example_usage \
-       "$ id\n" \
-       "uid=1000(andersen) gid=1000(andersen)\n"
-
-#ifdef BB_FEATURE_IFCONFIG_SLIP
-  #define USAGE_SIOCSKEEPALIVE(a) a
-#else
-  #define USAGE_SIOCSKEEPALIVE(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-  #define USAGE_IFCONFIG_MII(a) a
-#else
-  #define USAGE_IFCONFIG_MII(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_HW
-  #define USAGE_IFCONFIG_HW(a) a
-#else
-  #define USAGE_IFCONFIG_HW(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-  #define USAGE_IFCONFIG_OPT_A(a) a
-#else
-  #define USAGE_IFCONFIG_OPT_A(a)
-#endif
-
-#define ifconfig_trivial_usage \
-       USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
-#define ifconfig_full_usage \
-       "configure a network interface\n\n" \
-       "Options:\n" \
-       "\t[[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n" \
-       "\t[netmask <address>]  [dstaddr <address>]\n" \
-       USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
-       "\t" USAGE_IFCONFIG_HW("[hw ether <address>]  ") \
-    "[metric <NN>]  [mtu <NN>]\n" \
-       "\t[[-]trailers]  [[-]arp]  [[-]allmulti]\n" \
-       "\t[multicast]  [[-]promisc]  [txqueuelen <NN>]  [[-]dynamic]\n" \
-       USAGE_IFCONFIG_MII("\t[mem_start <NN>]  [io_addr <NN>]  [irq <NN>]\n") \
-       "\t[up|down] ..."
-
-#define init_trivial_usage \
-       ""
-#define init_full_usage \
-       "Init is the parent of all processes."
-#define init_notes_usage \
-"This version of init is designed to be run only by the kernel.\n" \
-"\n" \
-"BusyBox init doesn't support multiple runlevels.  The runlevels field of\n" \
-"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \
-"runlevels, use sysvinit.\n" \
-"\n" \
-"BusyBox init works just fine without an inittab.  If no inittab is found, \n" \
-"it has the following default behavior:\n" \
-"\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      ::askfirst:/bin/sh\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/sbin/swapoff -a\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"\n" \
-"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
-"\n" \
-"      tty2::askfirst:/bin/sh\n" \
-"      tty3::askfirst:/bin/sh\n" \
-"      tty4::askfirst:/bin/sh\n" \
-"\n" \
-"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
-"\n" \
-"      <id>:<runlevels>:<action>:<process>\n" \
-"\n" \
-"      <id>: \n" \
-"\n" \
-"              WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
-"              The id field is used by BusyBox init to specify the controlling tty for\n" \
-"              the specified process to run on.  The contents of this field are\n" \
-"              appended to "/dev/" and used as-is.  There is no need for this field to\n" \
-"              be unique, although if it isn't you may have strange results.  If this\n" \
-"              field is left blank, the controlling tty is set to the console.  Also\n" \
-"              note that if BusyBox detects that a serial console is in use, then only\n" \
-"              entries whose controlling tty is either the serial console or /dev/null\n" \
-"              will be run.  BusyBox init does nothing with utmp.  We don't need no\n" \
-"              stinkin' utmp.\n" \
-"\n" \
-"      <runlevels>: \n" \
-"\n" \
-"              The runlevels field is completely ignored.\n" \
-"\n" \
-"      <action>: \n" \
-"\n" \
-"              Valid actions include: sysinit, respawn, askfirst, wait, \n" \
-"              once, ctrlaltdel, and shutdown.\n" \
-"\n" \
-"              The available actions can be classified into two groups: actions\n" \
-"              that are run only once, and actions that are re-run when the specified\n" \
-"              process exits.\n" \
-"\n" \
-"              Run only-once actions:\n" \
-"\n" \
-"                      'sysinit' is the first item run on boot.  init waits until all\n" \
-"                      sysinit actions are completed before continuing.  Following the\n" \
-"                      completion of all sysinit actions, all 'wait' actions are run.\n" \
-"                      'wait' actions, like  'sysinit' actions, cause init to wait until\n" \
-"                      the specified task completes.  'once' actions are asynchronous,\n" \
-"                      therefore, init does not wait for them to complete.  'ctrlaltdel'\n" \
-"                      actions are run when the system detects that someone on the system\n" \
-"                       console has pressed the CTRL-ALT-DEL key combination.  Typically one\n" \
-"                       wants to run 'reboot' at this point to cause the system to reboot.\n" \
-"                      Finally the 'shutdown' action specifies the actions to taken when\n" \
-"                       init is told to reboot.  Unmounting filesystems and disabling swap\n" \
-"                       is a very good here\n" \
-"\n" \
-"              Run repeatedly actions:\n" \
-"\n" \
-"                      'respawn' actions are run after the 'once' actions.  When a process\n" \
-"                      started with a 'respawn' action exits, init automatically restarts\n" \
-"                      it.  Unlike sysvinit, BusyBox init does not stop processes from\n" \
-"                      respawning out of control.  The 'askfirst' actions acts just like\n" \
-"                      respawn, except that before running the specified process it\n" \
-"                      displays the line "Please press Enter to activate this console."\n" \
-"                      and then waits for the user to press enter before starting the\n" \
-"                      specified process.  \n" \
-"\n" \
-"              Unrecognized actions (like initdefault) will cause init to emit an\n" \
-"              error message, and then go along with its business.  All actions are\n" \
-"              run in the reverse order from how they appear in /etc/inittab.\n" \
-"\n" \
-"      <process>: \n" \
-"\n" \
-"              Specifies the process to be executed and it's command line.\n" \
-"\n" \
-"Example /etc/inittab file:\n" \
-"\n" \
-"      # This is run first except when booting in single-user mode.\n" \
-"      #\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      \n" \
-"      # /bin/sh invocations on selected ttys\n" \
-"      #\n" \
-"      # Start an "askfirst" shell on the console (whatever that may be)\n" \
-"      ::askfirst:-/bin/sh\n" \
-"      # Start an "askfirst" shell on /dev/tty2-4\n" \
-"      tty2::askfirst:-/bin/sh\n" \
-"      tty3::askfirst:-/bin/sh\n" \
-"      tty4::askfirst:-/bin/sh\n" \
-"      \n" \
-"      # /sbin/getty invocations for selected ttys\n" \
-"      #\n" \
-"      tty4::respawn:/sbin/getty 38400 tty5\n" \
-"      tty5::respawn:/sbin/getty 38400 tty6\n" \
-"      \n" \
-"      \n" \
-"      # Example of how to put a getty on a serial line (for a terminal)\n" \
-"      #\n" \
-"      #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
-"      #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
-"      #\n" \
-"      # Example how to put a getty on a modem line.\n" \
-"      #::respawn:/sbin/getty 57600 ttyS2\n" \
-"      \n" \
-"      # Stuff to do before rebooting\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"      ::shutdown:/sbin/swapoff -a\n"
-
-#define insmod_trivial_usage \
-       "[OPTION]... MODULE [symbol=value]..."
-#define insmod_full_usage \
-       "Loads the specified kernel modules into the kernel.\n\n" \
-       "Options:\n" \
-       "\t-f\tForce module to load into the wrong kernel version.\n" \
-       "\t-k\tMake module autoclean-able.\n" \
-       "\t-v\tverbose output\n"  \
-       "\t-L\tLock to prevent simultaneous loads of a module\n" \
-       "\t-x\tdo not export externs"
-
-#define kill_trivial_usage \
-       "[-signal] process-id [process-id ...]"
-#define kill_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define kill_example_usage \
-       "$ ps | grep apache\n" \
-       "252 root     root     S [apache]\n" \
-       "263 www-data www-data S [apache]\n" \
-       "264 www-data www-data S [apache]\n" \
-       "265 www-data www-data S [apache]\n" \
-       "266 www-data www-data S [apache]\n" \
-       "267 www-data www-data S [apache]\n" \
-       "$ kill 252\n"
-
-#define killall_trivial_usage \
-       "[-signal] process-name [process-name ...]"
-#define killall_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define killall_example_usage \
-       "$ killall apache\n" 
-
-#define klogd_trivial_usage \
-       "-n"
-#define klogd_full_usage \
-       "Kernel logger.\n"\
-       "Options:\n"\
-       "\t-n\tRun as a foreground process."
-
-#define length_trivial_usage \
-       "STRING"
-#define length_full_usage \
-       "Prints out the length of the specified STRING."
-#define length_example_usage \
-       "$ length Hello\n" \
-       "5\n"
-
-#define ln_trivial_usage \
-       "[OPTION] TARGET... LINK_NAME|DIRECTORY"
-#define ln_full_usage \
-       "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
-       "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-s\tmake symbolic links instead of hard links\n" \
-       "\t-f\tremove existing destination files\n" \
-       "\t-n\tno dereference symlinks - treat like normal file"
-#define ln_example_usage \
-       "$ ln -s BusyBox /tmp/ls\n" \
-       "$ ls -l /tmp/ls\n" \
-       "lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -> BusyBox*\n" 
-
-#define loadacm_trivial_usage \
-       "< mapfile"
-#define loadacm_full_usage \
-       "Loads an acm from standard input."
-#define loadacm_example_usage \
-       "$ loadacm < /etc/i18n/acmname\n" 
-
-#define loadfont_trivial_usage \
-       "< font"
-#define loadfont_full_usage \
-       "Loads a console font from standard input."
-#define loadfont_example_usage \
-       "$ loadfont < /etc/i18n/fontname\n" 
-
-#define loadkmap_trivial_usage \
-       "< keymap"
-#define loadkmap_full_usage \
-       "Loads a binary keyboard translation table from standard input."
-#define loadkmap_example_usage \
-       "$ loadkmap < /etc/i18n/lang-keymap\n" 
-
-#define logger_trivial_usage \
-       "[OPTION]... [MESSAGE]"
-#define logger_full_usage \
-       "Write MESSAGE to the system log.  If MESSAGE is omitted, log stdin.\n\n" \
-       "Options:\n" \
-       "\t-s\tLog to stderr as well as the system log.\n" \
-       "\t-t\tLog using the specified tag (defaults to user name).\n" \
-       "\t-p\tEnter the message with the specified priority.\n" \
-       "\t\tThis may be numerical or a ``facility.level'' pair."
-#define logger_example_usage \
-       "$ logger "hello"\n" 
-
-#define logname_trivial_usage \
-       ""
-#define logname_full_usage \
-       "Print the name of the current user."
-#define logname_example_usage \
-       "$ logname\n" \
-       "root\n" 
-
-#define logread_trivial_usage \
-        ""
-
-#define logread_full_usage \
-        "Shows the messages from syslogd (using circular buffer)."
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-  #define USAGE_LS_TIMESTAMPS(a) a
-#else
-  #define USAGE_LS_TIMESTAMPS(a)
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-  #define USAGE_LS_FILETYPES(a) a
-#else
-  #define USAGE_LS_FILETYPES(a)
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-  #define USAGE_LS_FOLLOWLINKS(a) a
-#else
-  #define USAGE_LS_FOLLOWLINKS(a)
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-  #define USAGE_LS_RECURSIVE(a) a
-#else
-  #define USAGE_LS_RECURSIVE(a)
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-  #define USAGE_LS_SORTFILES(a) a
-#else
-  #define USAGE_LS_SORTFILES(a)
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-  #define USAGE_AUTOWIDTH(a) a
-#else
-  #define USAGE_AUTOWIDTH(a)
-#endif
-#define ls_trivial_usage \
-       "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]"
-#define ls_full_usage \
-       "List directory contents\n\n" \
-       "Options:\n" \
-       "\t-1\tlist files in a single column\n" \
-       "\t-A\tdo not list implied . and ..\n" \
-       "\t-a\tdo not hide entries starting with .\n" \
-       "\t-C\tlist entries by columns\n" \
-       USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \
-       "\t-d\tlist directory entries instead of contents\n" \
-       USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \
-       USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \
-       "\t-i\tlist the i-node for each file\n" \
-       "\t-l\tuse a long listing format\n" \
-       "\t-n\tlist numeric UIDs and GIDs instead of names\n" \
-       USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \
-       USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \
-       USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \
-       USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \
-       USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \
-       "\t-s\tlist the size of each file, in blocks\n" \
-       USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \
-       USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \
-       USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \
-       USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \
-       USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \
-       "\t-x\tlist entries by lines instead of by columns\n" \
-       USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \
-       USAGE_HUMAN_READABLE( \
-       "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\t-k\tprint sizes in kilobytes(compatibility)") 
-
-#define lsmod_trivial_usage \
-       ""
-#define lsmod_full_usage \
-       "List the currently loaded kernel modules."
-
-#define makedevs_trivial_usage \
-       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
-#define makedevs_full_usage \
-       "Creates a range of block or character special files\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
-       "FIRST specifies the number appended to NAME to create the first device.\n" \
-       "LAST specifies the number of the last item that should be created.\n" \
-       "If 's' is the last argument, the base device is created as well.\n\n" \
-       "For example:\n" \
-       "\tmakedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63\n" \
-       "\tmakedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8"
-#define makedevs_example_usage \
-       "$ makedevs /dev/ttyS c 4 66 2 63\n" \
-       "[creates ttyS2-ttyS63]\n" \
-       "$ makedevs /dev/hda b 3 0 0 8 s\n" \
-       "[creates hda,hda1-hda8]\n" 
-
-#define md5sum_trivial_usage \
-       "[OPTION] [FILE]...\n" \
-       "or: md5sum [OPTION] -c [FILE]"
-#define md5sum_full_usage \
-       "Print or check MD5 checksums.\n\n" \
-       "Options:\n" \
-       "With no FILE, or when FILE is -, read standard input.\n\n" \
-       "\t-b\tread files in binary mode\n" \
-       "\t-c\tcheck MD5 sums against given list\n" \
-       "\t-t\tread files in text mode (default)\n" \
-       "\t-g\tread a string\n" \
-       "\nThe following two options are useful only when verifying checksums:\n" \
-       "\t-s\tdon't output anything, status code shows success\n" \
-       "\t-w\twarn about improperly formated MD5 checksum lines"
-#define md5sum_example_usage \
-       "$ md5sum < busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003\n" \
-       "$ md5sum busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "$ md5sum -c -\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "busybox: OK\n" \
-       "^D\n"
-
-#define mkdir_trivial_usage \
-       "[OPTION] DIRECTORY..."
-#define mkdir_full_usage \
-       "Create the DIRECTORY(ies) if they do not already exist\n\n" \
-       "Options:\n" \
-       "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \
-       "\t-p\tno error if existing, make parent directories as needed"
-#define mkdir_example_usage \
-       "$ mkdir /tmp/foo\n" \
-       "$ mkdir /tmp/foo\n" \
-       "/tmp/foo: File exists\n" \
-       "$ mkdir /tmp/foo/bar/baz\n" \
-       "/tmp/foo/bar/baz: No such file or directory\n" \
-       "$ mkdir -p /tmp/foo/bar/baz\n" 
-
-#define mkfifo_trivial_usage \
-       "[OPTIONS] name"
-#define mkfifo_full_usage \
-       "Creates a named pipe (identical to 'mknod name p')\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the pipe using the specified mode (default a=rw)"
-
-#define mkfs_minix_trivial_usage \
-       "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
-#define mkfs_minix_full_usage \
-       "Make a MINIX filesystem.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck the device for bad blocks\n" \
-       "\t-n [14|30]\tSpecify the maximum length of filenames\n" \
-       "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \
-       "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \
-       "\t-v\t\tMake a Minix version 2 filesystem"
-
-#define mknod_trivial_usage \
-       "[OPTIONS] NAME TYPE MAJOR MINOR"
-#define mknod_full_usage \
-       "Create a special file (block, character, or pipe).\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
-#define mknod_example_usage \
-       "$ mknod /dev/fd0 b 2 0 \n" \
-       "$ mknod -m 644 /tmp/pipe p\n" 
-
-#define mkswap_trivial_usage \
-       "[-c] [-v0|-v1] device [block-count]"
-#define mkswap_full_usage \
-       "Prepare a disk partition to be used as a swap partition.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck for read-ability.\n" \
-       "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
-       "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
-       "\tblock-count\tNumber of block to use (default is entire partition)."
-
-#define mktemp_trivial_usage \
-       "[-q] TEMPLATE"
-#define mktemp_full_usage \
-       "Creates a temporary file with its name based on TEMPLATE.\n" \
-       "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)."
-#define mktemp_example_usage \
-       "$ mktemp /tmp/temp.XXXXXX\n" \
-       "/tmp/temp.mWiLjM\n" \
-       "$ ls -la /tmp/temp.mWiLjM\n" \
-       "-rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM\n" 
-
-#define modprobe_trivial_usage \
-       "[FILE ...]"
-#define modprobe_full_usage \
-       "Used for hight level module loading and unloading."
-#define modprobe_example_usage \
-       "$ modprobe cdrom\n" 
-
-#define more_trivial_usage \
-       "[FILE ...]"
-#define more_full_usage \
-       "More is a filter for viewing FILE one screenful at a time."
-#define more_example_usage \
-       "$ dmesg | more\n" 
-
-#ifdef BB_FEATURE_MOUNT_LOOP
-  #define USAGE_MOUNT_LOOP(a) a
-#else
-  #define USAGE_MOUNT_LOOP(a)
-#endif
-#ifdef BB_FEATURE_MTAB_SUPPORT
-  #define USAGE_MTAB(a) a
-#else
-  #define USAGE_MTAB(a)
-#endif
-#define mount_trivial_usage \
-       "[flags] DEVICE NODE [-o options,more-options]"
-#define mount_full_usage \
-       "Mount a filesystem\n\n" \
-       "Flags:\n"  \
-       "\t-a:\t\tMount all filesystems in fstab.\n" \
-       USAGE_MTAB( \
-       "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
-       "\t-n:\t\tDon't write a mount table entry.\n" \
-       ) \
-       "\t-o option:\tOne of many filesystem options, listed below.\n" \
-       "\t-r:\t\tMount the filesystem read-only.\n" \
-       "\t-t fs-type:\tSpecify the filesystem type.\n" \
-       "\t-w:\t\tMount for reading and writing (default).\n" \
-       "\n" \
-       "Options for use with the \"-o\" flag:\n" \
-       "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
-       "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
-       "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
-       "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
-       USAGE_MOUNT_LOOP( \
-       "\tloop:\t\tMounts a file via loop device.\n" \
-       ) \
-       "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
-       "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
-       "\tro/rw:\t\tMount for read-only / read-write.\n" \
-       "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
-       "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
-       "You'll have to see the written documentation for those filesystems."
-#define mount_example_usage \
-       "$ mount\n" \
-       "/dev/hda3 on / type minix (rw)\n" \
-       "proc on /proc type proc (rw)\n" \
-       "devpts on /dev/pts type devpts (rw)\n" \
-       "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
-       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" 
-
-#define mt_trivial_usage \
-       "[-f device] opcode value"
-#define mt_full_usage \
-       "Control magnetic tape drive operation\n" \
-       "\nAvailable Opcodes:\n\n" \
-       "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
-       "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
-       "ras3 reset retension rew rewoffline seek setblk setdensity\n" \
-       "setpart tell unload unlock weof wset"
-
-#define mv_trivial_usage \
-       "SOURCE DEST\n" \
-       "or: mv SOURCE... DIRECTORY"
-#define mv_full_usage \
-       "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY."
-#define mv_example_usage \
-       "$ mv /tmp/foo /bin/bar\n" 
-
-#define nc_trivial_usage \
-       "[IP] [port]" 
-#define nc_full_usage \
-       "Netcat opens a pipe to IP:port"
-#define nc_example_usage \
-       "$ nc foobar.somedomain.com 25\n" \
-       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
-       "help\n" \
-       "214-Commands supported:\n" \
-       "214-    HELO EHLO MAIL RCPT DATA AUTH\n" \
-       "214     NOOP QUIT RSET HELP\n" \
-       "quit\n" \
-       "221 foobar closing connection\n" 
-
-#define nslookup_trivial_usage \
-       "[HOST] [SERVER]"
-#define nslookup_full_usage \
-       "Queries the nameserver for the IP address of the given HOST\n" \
-       "optionally using a specified DNS server"
-#define nslookup_example_usage \
-       "$ nslookup localhost\n" \
-       "Server:     default\n" \
-       "Address:    default\n" \
-       "\n" \
-       "Name:       debian\n" \
-       "Address:    127.0.0.1\n" 
-
-#define pidof_trivial_usage \
-       "process-name [process-name ...]"
-#define pidof_full_usage \
-       "Lists the PIDs of all processes with names that match the names on the command line"
-#define pidof_example_usage \
-       "$ pidof init\n" \
-       "1\n"
-
-#ifndef BB_FEATURE_FANCY_PING
-#define ping_trivial_usage "host"
-#define ping_full_usage    "Send ICMP ECHO_REQUEST packets to network hosts"
-#else
-#define ping_trivial_usage \
-       "[OPTION]... host"
-#define ping_full_usage \
-       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
-       "Options:\n" \
-       "\t-c COUNT\tSend only COUNT pings.\n" \
-       "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
-       "\t-q\t\tQuiet mode, only displays output at start\n" \
-       "\t\t\tand when finished."
-#endif
-#define ping_example_usage \
-       "$ ping localhost\n" \
-       "PING slag (127.0.0.1): 56 data bytes\n" \
-       "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
-       "\n" \
-       "--- debian ping statistics ---\n" \
-       "1 packets transmitted, 1 packets received, 0% packet loss\n" \
-       "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 
-
-#define pivot_root_trivial_usage \
-       "NEW_ROOT PUT_OLD"
-#define pivot_root_full_usage \
-       "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
-       "the new root file system."
-
-#define poweroff_trivial_usage \
-       ""
-#define poweroff_full_usage \
-       "Halt the system and request that the kernel shut off the power."
-
-#define printf_trivial_usage \
-       "FORMAT [ARGUMENT...]"
-#define printf_full_usage \
-       "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
-       "Where FORMAT controls the output exactly as in C printf."
-#define printf_example_usage \
-       "$ printf "Val=%d\\n" 5\n" \
-       "Val=5\n" 
-
-#define ps_trivial_usage \
-       ""
-#define ps_full_usage \
-       "Report process status\n" \
-       "\nThis version of ps accepts no options."
-#define ps_example_usage \
-       "$ ps\n" \
-       "  PID  Uid      Gid State Command\n" \
-       "    1 root     root     S init\n" \
-       "    2 root     root     S [kflushd]\n" \
-       "    3 root     root     S [kupdate]\n" \
-       "    4 root     root     S [kpiod]\n" \
-       "    5 root     root     S [kswapd]\n" \
-       "  742 andersen andersen S [bash]\n" \
-       "  743 andersen andersen S -bash\n" \
-       "  745 root     root     S [getty]\n" \
-       " 2990 andersen andersen R ps\n"
-
-#define pwd_trivial_usage \
-       ""
-#define pwd_full_usage \
-       "Print the full filename of the current working directory."
-#define pwd_example_usage \
-       "$ pwd\n" \
-       "/root\n"
-
-#define rdate_trivial_usage \
-       "[OPTION] HOST"
-#define rdate_full_usage \
-       "Get and possibly set the system date and time from a remote HOST.\n\n" \
-       "Options:\n" \
-       "\t-s\tSet the system date and time (default).\n" \
-       "\t-p\tPrint the date and time."
-
-#define readlink_trivial_usage \
-       ""
-#define readlink_full_usage \
-       "Read a symbolic link."
-
-#define reboot_trivial_usage \
-       ""
-#define reboot_full_usage \
-       "Reboot the system."
-
-#define renice_trivial_usage \
-       "priority pid [pid ...]"
-#define renice_full_usage \
-       "Changes priority of running processes. Allowed priorities range\n" \
-       "from 20 (the process runs only when nothing else is running) to 0\n" \
-       "(default priority) to -20 (almost nothing else ever gets to run)."
-
-#define reset_trivial_usage \
-       ""
-#define reset_full_usage \
-       "Resets the screen."
-
-#define rm_trivial_usage \
-       "[OPTION]... FILE..."
-#define rm_full_usage \
-       "Remove (unlink) the FILE(s).  You may use '--' to\n" \
-       "indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-i\t\talways prompt before removing each destination" \
-       "\t-f\t\tremove existing destinations, never prompt\n" \
-       "\t-r or -R\tremove the contents of directories recursively"
-#define rm_example_usage \
-       "$ rm -rf /tmp/foo\n"
-
-#define rmdir_trivial_usage \
-       "[OPTION]... DIRECTORY..."
-#define rmdir_full_usage \
-       "Remove the DIRECTORY(ies), if they are empty."
-#define rmdir_example_usage \
-       "# rmdir /tmp/foo\n"
-
-#define rmmod_trivial_usage \
-       "[OPTION]... [MODULE]..."
-#define rmmod_full_usage \
-       "Unloads the specified kernel modules from the kernel.\n\n" \
-       "Options:\n" \
-       "\t-a\tTry to remove all unused kernel modules."
-#define rmmod_example_usage \
-       "$ rmmod tulip\n"
-
-#define route_trivial_usage \
-       "[{add|del|flush}]"
-#define route_full_usage \
-       "Edit the kernel's routing tables"
-
-#define rpm2cpio_trivial_usage \
-       "package.rpm"
-#define rpm2cpio_full_usage \
-       "Outputs a cpio archive of the rpm file."
-
-#define sed_trivial_usage \
-       "[-nef] pattern [files...]"
-#define sed_full_usage \
-       "Options:\n" \
-       "\t-n\t\tsuppress automatic printing of pattern space\n" \
-       "\t-e script\tadd the script to the commands to be executed\n" \
-       "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \
-       "\n" \
-       "If no -e or -f is given, the first non-option argument is taken as the\n" \
-       "sed script to interpret. All remaining arguments are names of input\n" \
-       "files; if no input files are specified, then the standard input is read."
-#define sed_example_usage \
-       "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
-       "bar\n"
-
-#define setkeycodes_trivial_usage \
-       "SCANCODE KEYCODE ..."
-#define setkeycodes_full_usage \
-       "Set entries into the kernel's scancode-to-keycode map,\n" \
-       "allowing unusual keyboards to generate usable keycodes.\n\n" \
-       "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
-       "and KEYCODE is given in decimal"
-#define setkeycodes_example_usage \
-       "$ setkeycodes e030 127\n"
-
-#define lash_trivial_usage \
-       "[FILE]...\n" \
-       "or: sh -c command [args]..."
-#define lash_full_usage \
-       "lash: The BusyBox LAme SHell (command interpreter)"
-#define lash_notes_usage \
-"This command does not yet have proper documentation.\n" \
-"\n" \
-"Use lash just as you would use any other shell.  It properly handles pipes,\n" \
-"redirects, job control, can be used as the shell for scripts, and has a\n" \
-"sufficient set of builtins to do what is needed.  It does not (yet) support\n" \
-"Bourne Shell syntax.  If you need things like "if-then-else", "while", and such\n" \
-"use ash or bash.  If you just need a very simple and extremely small shell,\n" \
-"this will do the job."
-
-#define sleep_trivial_usage \
-       "N"
-#define sleep_full_usage \
-       "Pause for N seconds."
-#define sleep_example_usage \
-       "$ sleep 2\n" \
-       "[2 second delay results]\n"
-
-
-#ifdef BB_FEATURE_SORT_UNIQUE
-  #define USAGE_SORT_UNIQUE(a) a
-#else
-  #define USAGE_SORT_UNIQUE(a)
-#endif
-#ifdef BB_FEATURE_SORT_REVERSE
-  #define USAGE_SORT_REVERSE(a) a
-#else
-  #define USAGE_SORT_REVERSE(a)
-#endif
-#define sort_trivial_usage \
-       "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
-#define sort_full_usage \
-       "Sorts lines of text in the specified files\n\n"\
-       "Options:\n" \
-       USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
-       USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
-       "\t-n\tsort numerics"
-#define sort_example_usage \
-       "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
-       "a\n" \
-       "b\n" \
-       "c\n" \
-       "d\n" \
-       "e\n" \
-       "f\n"
-
-#define stty_trivial_usage \
-       "[-a|g] [-F DEVICE] [SETTING]..."
-#define stty_full_usage \
-       "Without arguments, prints baud rate, line discipline," \
-       "\nand deviations from stty sane." \
-       "\n\nOptions:" \
-       "\n\t-F DEVICE\topen device instead of stdin" \
-       "\n\t-a\t\tprint all current settings in human-readable form" \
-       "\n\t-g\t\tprint in stty-readable form" \
-       "\n\t[SETTING]\tsee manpage"
-
-#define swapoff_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapoff_full_usage \
-       "Stop swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStop swapping on all swap devices"
-
-#define swapon_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapon_full_usage \
-       "Start swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStart swapping on all swap devices"
-
-#define sync_trivial_usage \
-       ""
-#define sync_full_usage \
-       "Write all buffered filesystem blocks to disk."
-
-
-#ifdef BB_FEATURE_REMOTE_LOG
-  #define USAGE_REMOTE_LOG(a) a
-#else
-  #define USAGE_REMOTE_LOG(a)
-#endif
-#define syslogd_trivial_usage \
-       "[OPTION]..."
-#define syslogd_full_usage \
-       "Linux system and kernel logging utility.\n" \
-       "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \
-       "Options:\n" \
-       "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \
-       "\t-n\t\tRun as a foreground process\n" \
-       "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \
-       USAGE_REMOTE_LOG( \
-       "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \
-       "\t-L\t\tLog locally and via network logging (default is network only)")
-#define syslogd_example_usage \
-       "$ syslogd -R masterlog:514\n" \
-       "$ syslogd -R 192.168.1.1:601\n"
-
-
-#ifndef BB_FEATURE_FANCY_TAIL
-  #define USAGE_UNSIMPLE_TAIL(a)
-#else
-  #define USAGE_UNSIMPLE_TAIL(a) a
-#endif
-#define tail_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tail_full_usage \
-       "Print last 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \
-       "\t-n N[kbm]\tprint last N lines instead of last 10\n" \
-       "\t-f\t\toutput data as the file grows" \
-       USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \
-       "\t-s SEC\t\twait SEC seconds between reads with -f\n" \
-       "\t-v\t\talways output headers giving file names\n\n" \
-       "If the first character of N (bytes or lines) is a '+', output begins with \n" \
-       "the Nth item from the start of each file, otherwise, print the last N items\n" \
-       "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." )
-#define tail_example_usage \
-       "$ tail -n 1 /etc/resolv.conf\n" \
-       "nameserver 10.0.0.1\n"
-
-#ifdef BB_FEATURE_TAR_CREATE
-  #define USAGE_TAR_CREATE(a) a
-#else
-  #define USAGE_TAR_CREATE(a)
-#endif
-#ifdef BB_FEATURE_TAR_EXCLUDE
-  #define USAGE_TAR_EXCLUDE(a) a
-#else
-  #define USAGE_TAR_EXCLUDE(a)
-#endif
-#define tar_trivial_usage \
-       "-[" USAGE_TAR_CREATE("c") "xtvO] " \
-       USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \
-       "[-f TARFILE] [-C DIR] [FILE(s)] ..."
-#define tar_full_usage \
-       "Create, extract, or list files from a tar file.\n\n" \
-       "Options:\n" \
-       USAGE_TAR_CREATE("\tc\t\tcreate\n") \
-       "\tx\t\textract\n" \
-       "\tt\t\tlist\n" \
-       "\nFile selection:\n" \
-       "\tf\t\tname of TARFILE or \"-\" for stdin\n" \
-       "\tO\t\textract to stdout\n" \
-       USAGE_TAR_EXCLUDE( \
-       "\texclude\t\tfile to exclude\n" \
-        "\tX\t\tfile with names to exclude\n" \
-       ) \
-       "\tC\t\tchange to directory DIR before operation\n" \
-       "\tv\t\tverbosely list files processed"
-#define tar_example_usage \
-       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
-       "$ tar -cf /tmp/tarball.tar /usr/local\n"
-
-#define tee_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tee_full_usage \
-       "Copy standard input to each FILE, and also to standard output.\n\n" \
-       "Options:\n" \
-       "\t-a\tappend to the given FILEs, do not overwrite"
-#define tee_example_usage \
-       "$ echo "Hello" | tee /tmp/foo\n" \
-       "$ cat /tmp/foo\n" \
-       "Hello\n"
-
-#define telnet_trivial_usage \
-       "HOST [PORT]"
-#define telnet_full_usage \
-       "Telnet is used to establish interactive communication with another\n"\
-       "computer over a network using the TELNET protocol."
-
-#define test_trivial_usage \
-       "EXPRESSION\n  or   [ EXPRESSION ]"
-#define test_full_usage \
-       "Checks file types and compares values returning an exit\n" \
-       "code determined by the value of EXPRESSION."
-#define test_example_usage \
-       "$ test 1 -eq 2\n" \
-       "$ echo $?\n" \
-       "1\n" \
-       "$ test 1 -eq 1\n" \
-       "$ echo $? \n" \
-       "0\n" \
-       "$ [ -d /etc ]\n" \
-       "$ echo $?\n" \
-       "0\n" \
-       "$ [ -d /junk ]\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#ifdef BB_FEATURE_TFTP_GET
-  #define USAGE_TFTP_GET(a) a
-#else
-  #define USAGE_TFTP_GET(a)
-#endif
-#ifdef BB_FEATURE_TFTP_PUT
-  #define USAGE_TFTP_PUT(a) a
-#else
-  #define USAGE_TFTP_PUT(a)
-#endif
-
-#define tftp_trivial_usage \
-       "[OPTION]... HOST [PORT]"
-#define tftp_full_usage \
-       "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
-       "Options:\n" \
-       "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
-        USAGE_TFTP_GET(        \
-        "\t-g\tGet file.\n" \
-        ) \
-       "\t-l FILE\tTransfer local FILE.\n" \
-        USAGE_TFTP_PUT(        \
-       "\t-p\tPut file.\n" \
-       ) \
-       "\t-r FILE\tTransfer remote FILE.\n"
-
-#define touch_trivial_usage \
-       "[-c] FILE [FILE ...]"
-#define touch_full_usage \
-       "Update the last-modified date on the given FILE[s].\n\n" \
-       "Options:\n" \
-       "\t-c\tDo not create any files"
-#define touch_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "/bin/ls: /tmp/foo: No such file or directory\n" \
-       "$ touch /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo\n" 
-
-#define tr_trivial_usage \
-       "[-cds] STRING1 [STRING2]"
-#define tr_full_usage \
-       "Translate, squeeze, and/or delete characters from\n" \
-       "standard input, writing to standard output.\n\n" \
-       "Options:\n" \
-       "\t-c\ttake complement of STRING1\n" \
-       "\t-d\tdelete input characters coded STRING1\n" \
-       "\t-s\tsqueeze multiple output characters of STRING2 into one character"
-#define tr_example_usage \
-       "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
-       "hello world\n" 
-
-#define traceroute_trivial_usage \
-       "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\
-       [-s src_addr] [-t tos] [-w wait] host [data size]"
-#define traceroute_full_usage \
-       "trace the route ip packets follow going to \"host\"\n" \
-       "Options:\n" \
-       "\t-d\tset SO_DEBUG options to socket\n" \
-       "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
-       "\t-r\tBypass the normal routing tables and send directly to a host\n" \
-       "\t-v\tVerbose output\n" \
-       "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \
-       "\t-p port#\tSet the base UDP port number used in probes\n" \
-       "\t\t(default is 33434)\n" \
-       "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \
-       "\t\t(default is 3)\n" \
-       "\t-s src_addr\tUse the following IP address as the source address\n" \
-       "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
-       "\t\t(default 0)\n" \
-       "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
-       "\t\t(default 3 sec.)."
-
-
-#define true_trivial_usage \
-       ""
-#define true_full_usage \
-       "Return an exit code of TRUE (0)."
-#define true_example_usage \
-       "$ true\n" \
-       "$ echo $?\n" \
-       "0\n"
-
-#define tty_trivial_usage \
-       ""
-#define tty_full_usage \
-       "Print the file name of the terminal connected to standard input.\n\n"\
-       "Options:\n" \
-       "\t-s\tprint nothing, only return an exit status"
-#define tty_example_usage \
-       "$ tty\n" \
-       "/dev/tty2\n"
-
-#ifdef BB_FEATURE_MOUNT_FORCE
-  #define USAGE_MOUNT_FORCE(a) a
-#else
-  #define USAGE_MOUNT_FORCE(a)
-#endif
-#define umount_trivial_usage \
-       "[flags] FILESYSTEM|DIRECTORY"
-#define umount_full_usage \
-       "Unmount file systems\n" \
-       "\nFlags:\n" "\t-a\tUnmount all file systems" \
-       USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \
-       "\n\t-r\tTry to remount devices as read-only if mount is busy" \
-       USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \
-       USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)")
-#define umount_example_usage \
-       "$ umount /dev/hdc1 \n"
-
-#define uname_trivial_usage \
-       "[OPTION]..."
-#define uname_full_usage \
-       "Print certain system information.  With no OPTION, same as -s.\n\n" \
-       "Options:\n" \
-       "\t-a\tprint all information\n" \
-       "\t-m\tthe machine (hardware) type\n" \
-       "\t-n\tprint the machine's network node hostname\n" \
-       "\t-r\tprint the operating system release\n" \
-       "\t-s\tprint the operating system name\n" \
-       "\t-p\tprint the host processor type\n" \
-       "\t-v\tprint the operating system version"
-#define uname_example_usage \
-       "$ uname -a\n" \
-       "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" 
-
-#define uniq_trivial_usage \
-       "[OPTION]... [INPUT [OUTPUT]]"
-#define uniq_full_usage \
-       "Discard all but one of successive identical lines from INPUT\n" \
-       "(or standard input), writing to OUTPUT (or standard output).\n\n" \
-       "Options:\n" \
-       "\t-c\tprefix lines by the number of occurrences\n" \
-       "\t-d\tonly print duplicate lines\n" \
-       "\t-u\tonly print unique lines"
-#define uniq_example_usage \
-       "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
-       "a\n" \
-       "b\n" \
-       "c\n"
-
-#define unix2dos_trivial_usage \
-       "[option] [FILE]"
-#define unix2dos_full_usage \
-       "Converts FILE from unix format to dos format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define update_trivial_usage \
-       "[options]"
-#define update_full_usage \
-       "Periodically flushes filesystem buffers.\n\n" \
-       "Options:\n" \
-       "\t-S\tforce use of sync(2) instead of flushing\n" \
-       "\t-s SECS\tcall sync this often (default 30)\n" \
-       "\t-f SECS\tflush some buffers this often (default 5)"
-
-#define uptime_trivial_usage \
-       ""
-#define uptime_full_usage \
-       "Display the time since the last boot."
-#define uptime_example_usage \
-       "$ uptime\n" \
-       "  1:55pm  up  2:30, load average: 0.09, 0.04, 0.00\n" 
-
-#define usleep_trivial_usage \
-       "N" 
-#define usleep_full_usage \
-       "Pause for N microseconds."
-#define usleep_example_usage \
-       "$ usleep 1000000\n" \
-       "[pauses for 1 second]\n"
-
-#define uudecode_trivial_usage \
-       "[FILE]..."
-#define uudecode_full_usage \
-       "Uudecode a file that is uuencoded.\n\n" \
-       "Options:\n" \
-       "\t-o FILE\tdirect output to FILE" 
-#define uudecode_example_usage \
-       "$ uudecode -o busybox busybox.uu\n" \
-       "$ ls -l busybox\n" \
-       "-rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox\n" 
-
-#define uuencode_trivial_usage \
-       "[OPTION] [INFILE] REMOTEFILE"
-#define uuencode_full_usage \
-       "Uuencode a file.\n\n" \
-       "Options:\n" \
-       "\t-m\tuse base64 encoding per RFC1521"
-#define uuencode_example_usage \
-       "$ uuencode busybox busybox\n" \
-       "begin 755 busybox\n" \
-       "<encoded file snipped>\n" \
-       "$ uudecode busybox busybox > busybox.uu\n" \
-       "$\n"
-
-#define vi_trivial_usage \
-       "[OPTION] [FILE]..."
-#define vi_full_usage \
-       "edit FILE.\n\n" \
-       "Options:\n" \
-       "\t-R\tRead-only- do not write to the file." 
-
-#define watchdog_trivial_usage \
-       "DEV"
-#define watchdog_full_usage \
-       "Periodically write to watchdog device DEV"
-
-#define wc_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define wc_full_usage \
-       "Print line, word, and byte counts for each FILE, and a total line if\n" \
-       "more than one FILE is specified.  With no FILE, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-c\tprint the byte counts\n" \
-       "\t-l\tprint the newline counts\n" \
-       "\t-L\tprint the length of the longest line\n" \
-       "\t-w\tprint the word counts"
-#define wc_example_usage \
-       "$ wc /etc/passwd\n" \
-       "     31      46    1365 /etc/passwd\n" 
-
-#define wget_trivial_usage \
-       "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url"
-#define wget_full_usage \
-       "wget retrieves files via HTTP or FTP\n\n" \
-       "Options:\n" \
-       "\t-c\tcontinue retrieval of aborted transfers\n" \
-       "\t-q\tquiet mode - do not print\n" \
-       "\t-P\tSet directory prefix to DIR\n" \
-       "\t-O\tsave to filename ('-' for stdout)"
-
-#define which_trivial_usage \
-       "[COMMAND ...]"
-#define which_full_usage \
-       "Locates a COMMAND."
-#define which_example_usage \
-       "$ which login\n" \
-       "/bin/login\n"
-
-#define whoami_trivial_usage \
-       ""
-#define whoami_full_usage \
-       "Prints the user name associated with the current effective user id."
-
-#define xargs_trivial_usage \
-       "[COMMAND] [ARGS...]"
-#define xargs_full_usage \
-       "Executes COMMAND on every item given by standard input."
-#define xargs_example_usage \
-       "$ ls | xargs gzip\n" \
-       "$ find . -name '*.c' -print | xargs rm\n" 
-
-#define yes_trivial_usage \
-       "[OPTION]... [STRING]..."
-#define yes_full_usage \
-       "Repeatedly outputs a line with all specified STRING(s), or 'y'."
-
-#define zcat_trivial_usage \
-       "FILE"
-#define zcat_full_usage \
-       "Uncompress to stdout."
diff --git a/busybox/ar.c b/busybox/ar.c
deleted file mode 100644 (file)
index 7f3396c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ar implementation for busybox 
- *
- * Copyright (C) 2000 by Glenn McGrath
- * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000
- *             
- * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int ar_main(int argc, char **argv)
-{
-       FILE *src_stream = NULL;
-       char **extract_names = NULL;
-       char ar_magic[8];
-       int extract_function =  extract_unconditional;
-       int opt;
-       int num_of_entries = 0;
-       extern off_t archive_offset;
-
-       while ((opt = getopt(argc, argv, "ovtpx")) != -1) {
-               switch (opt) {
-               case 'o':
-                       extract_function |= extract_preserve_date;
-                       break;
-               case 'v':
-                       extract_function |= extract_verbose_list;
-                       break;
-               case 't':
-                       extract_function |= extract_list;
-                       break;
-               case 'p':
-                       extract_function |= extract_to_stdout;
-                       break;
-               case 'x':
-                       extract_function |= extract_all_to_fs;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-       /* check the src filename was specified */
-       if (optind == argc) {
-               show_usage();
-       }
-
-       src_stream = xfopen(argv[optind++], "r");
-
-       /* check ar magic */
-       fread(ar_magic, 1, 8, src_stream);
-       archive_offset = 8;
-       if (strncmp(ar_magic,"!<arch>",7) != 0) {
-               error_msg_and_die("invalid magic");
-       }
-
-       /* Create a list of files to extract */
-       while (optind < argc) {
-               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
-               extract_names[num_of_entries] = xstrdup(argv[optind]);
-               num_of_entries++;
-               extract_names[num_of_entries] = NULL;
-               optind++;
-       }
-
-       unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/archival/ar.c b/busybox/archival/ar.c
deleted file mode 100644 (file)
index 7f3396c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ar implementation for busybox 
- *
- * Copyright (C) 2000 by Glenn McGrath
- * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000
- *             
- * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int ar_main(int argc, char **argv)
-{
-       FILE *src_stream = NULL;
-       char **extract_names = NULL;
-       char ar_magic[8];
-       int extract_function =  extract_unconditional;
-       int opt;
-       int num_of_entries = 0;
-       extern off_t archive_offset;
-
-       while ((opt = getopt(argc, argv, "ovtpx")) != -1) {
-               switch (opt) {
-               case 'o':
-                       extract_function |= extract_preserve_date;
-                       break;
-               case 'v':
-                       extract_function |= extract_verbose_list;
-                       break;
-               case 't':
-                       extract_function |= extract_list;
-                       break;
-               case 'p':
-                       extract_function |= extract_to_stdout;
-                       break;
-               case 'x':
-                       extract_function |= extract_all_to_fs;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-       /* check the src filename was specified */
-       if (optind == argc) {
-               show_usage();
-       }
-
-       src_stream = xfopen(argv[optind++], "r");
-
-       /* check ar magic */
-       fread(ar_magic, 1, 8, src_stream);
-       archive_offset = 8;
-       if (strncmp(ar_magic,"!<arch>",7) != 0) {
-               error_msg_and_die("invalid magic");
-       }
-
-       /* Create a list of files to extract */
-       while (optind < argc) {
-               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
-               extract_names[num_of_entries] = xstrdup(argv[optind]);
-               num_of_entries++;
-               extract_names[num_of_entries] = NULL;
-               optind++;
-       }
-
-       unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/archival/cpio.c b/busybox/archival/cpio.c
deleted file mode 100644 (file)
index 7f68715..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cpio implementation for busybox
- *
- * Copyright (C) 2001 by Glenn McGrath 
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Limitations:
- *             Doesn't check CRC's
- *             Only supports new ASCII and CRC formats
- *
- */
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int cpio_main(int argc, char **argv)
-{
-       FILE *src_stream = stdin;
-       char **extract_names = NULL;
-       int extract_function = 0;
-       int num_of_entries = 0;
-       int opt = 0;
-       mode_t oldmask = 0;
-
-       while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
-               switch (opt) {
-               case 'i': // extract
-                       extract_function |= extract_all_to_fs;
-                       break;
-               case 'd': // create _leading_ directories
-                       extract_function |= extract_create_leading_dirs;
-                       oldmask = umask(077); /* Make make_directory act like GNU cpio */
-                       break;
-               case 'm': // preserve modification time
-                       extract_function |= extract_preserve_date;
-                       break;
-               case 'v': // verbosly list files
-                       extract_function |= extract_verbose_list;
-                       break;
-               case 'u': // unconditional
-                       extract_function |= extract_unconditional;
-                       break;
-               case 't': // list files
-                       extract_function |= extract_list;
-                       break;
-               case 'F':
-                       src_stream = xfopen(optarg, "r");
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) {
-               extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
-       }
-
-       if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) {
-               /* The meaning of v changes on extract */
-               extract_function ^= extract_verbose_list;
-               extract_function |= extract_list;
-       }
-
-       while (optind < argc) {
-               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
-               extract_names[num_of_entries] = xstrdup(argv[optind]);
-               num_of_entries++;
-               extract_names[num_of_entries] = NULL;
-               optind++;
-       }
-
-       unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names);
-       if (oldmask) {
-               umask(oldmask); /* Restore umask if we changed it */
-       }
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/archival/dpkg.c b/busybox/archival/dpkg.c
deleted file mode 100644 (file)
index 48c3928..0000000
+++ /dev/null
@@ -1,1445 +0,0 @@
-/*
- *  Mini dpkg implementation for busybox.
- *  This is not meant as a replacemnt for dpkg
- *
- *  Copyright (C) 2001 by Glenn McGrath
- *             
- *  Started life as a busybox implementation of udpkg
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Known difference between busybox dpkg and the official dpkg that i dont
- * consider important, its worth keeping a note of differences anyway, just to
- * make it easier to maintain.
- *  - The first value for the Confflile: field isnt placed on a new line.
- *  - The <package>.control file is extracted and kept in the info dir.
- *  - When installing a package the Status: field is placed at the end of the
- *      section, rather than just after the Package: field.
- *  - Packages with previously unknown status are inserted at the begining of
- *      the status file
- *
- * Bugs that need to be fixed
- *  - (unknown, please let me know when you find any)
- *
- */
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* NOTE: If you vary HASH_PRIME sizes be aware,
- * 1) Tweaking these will have a big effect on how much memory this program uses.
- * 2) For computational efficiency these hash tables should be at least 20%
- *    larger than the maximum number of elements stored in it.
- * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking
- *    for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
- * 4) If you go bigger than 15 bits you may get into trouble (untested) as its
- *    sometimes cast to an unsigned int, if you go to 16 bit you will overlap
- *    int's and chaos is assured, 16381 is the max prime for 14 bit field
- */
-
-/* NAME_HASH_PRIME, Stores package names and versions, 
- * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
- * as there a lot of duplicate version numbers */
-#define NAME_HASH_PRIME 16381
-char *name_hashtable[NAME_HASH_PRIME + 1];
-
-/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
- * It must not be smaller than STATUS_HASH_PRIME,
- * Currently only packages from status_hashtable are stored in here, but in
- * future this may be used to store packages not only from a status file,
- * but an available_hashtable, and even multiple packages files.
- * Package can be stored more than once if they have different versions.
- * e.g. The same package may have different versions in the status file
- *      and available file */
-#define PACKAGE_HASH_PRIME 10007
-typedef struct edge_s {
-       unsigned int operator:3;
-       unsigned int type:4;
-       unsigned int name:14;
-       unsigned int version:14;
-} edge_t;
-
-typedef struct common_node_s {
-       unsigned int name:14;
-       unsigned int version:14;
-       unsigned int num_of_edges:14;
-       edge_t **edge;
-} common_node_t;
-common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
-
-/* Currently it doesnt store packages that have state-status of not-installed
- * So it only really has to be the size of the maximum number of packages
- * likely to be installed at any one time, so there is a bit of leaway here */
-#define STATUS_HASH_PRIME 8191
-typedef struct status_node_s {
-       unsigned int package:14;        /* has to fit PACKAGE_HASH_PRIME */
-       unsigned int status:14;         /* has to fit STATUS_HASH_PRIME */
-} status_node_t;
-status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
-
-/* Even numbers are for 'extras', like ored dependecies or null */
-enum edge_type_e {
-       EDGE_NULL = 0,
-       EDGE_PRE_DEPENDS = 1,
-       EDGE_OR_PRE_DEPENDS = 2,
-       EDGE_DEPENDS = 3,
-       EDGE_OR_DEPENDS = 4,
-       EDGE_REPLACES = 5,
-       EDGE_PROVIDES = 7,
-       EDGE_CONFLICTS = 9,
-       EDGE_SUGGESTS = 11,
-       EDGE_RECOMMENDS = 13,
-       EDGE_ENHANCES = 15
-};
-enum operator_e {
-       VER_NULL = 0,
-       VER_EQUAL = 1,
-       VER_LESS = 2,
-       VER_LESS_EQUAL = 3,
-       VER_MORE = 4,
-       VER_MORE_EQUAL = 5,
-       VER_ANY = 6
-};
-
-enum dpkg_opt_e {
-       dpkg_opt_purge = 1,
-       dpkg_opt_remove = 2,
-       dpkg_opt_unpack = 4,
-       dpkg_opt_configure = 8,
-       dpkg_opt_install = 16,
-       dpkg_opt_package_name = 32,
-       dpkg_opt_filename = 64,
-       dpkg_opt_list_installed = 128,
-       dpkg_opt_force_ignore_depends = 256
-};
-
-typedef struct deb_file_s {
-       char *control_file;
-       char *filename;
-       unsigned int package:14;
-} deb_file_t;
-
-
-void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
-{
-       unsigned long int hash_num = key[0];
-       int len = strlen(key);
-       int i;
-
-       /* Maybe i should have uses a "proper" hashing algorithm here instead
-        * of making one up myself, seems to be working ok though. */
-       for(i = 1; i < len; i++) {
-               /* shifts the ascii based value and adds it to previous value
-                * shift amount is mod 24 because long int is 32 bit and data
-                * to be shifted is 8, dont want to shift data to where it has
-                * no effect*/
-               hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); 
-       }
-       *start = (unsigned int) hash_num % hash_prime;
-       *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1));
-}
-
-/* this adds the key to the hash table */
-int search_name_hashtable(const char *key)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-//     char *temp;
-
-       make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
-       while(name_hashtable[probe_address] != NULL) {
-               if (strcmp(name_hashtable[probe_address], key) == 0) {
-                       return(probe_address);
-               } else {
-                       probe_address -= probe_decrement;
-                       if ((int)probe_address < 0) {
-                               probe_address += NAME_HASH_PRIME;
-                       }
-               }
-       }
-       name_hashtable[probe_address] = xstrdup(key);
-       return(probe_address);
-}
-
-/* this DOESNT add the key to the hashtable
- * TODO make it consistent with search_name_hashtable
- */
-unsigned int search_status_hashtable(const char *key)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-
-       make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
-       while(status_hashtable[probe_address] != NULL) {
-               if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
-                       break;
-               } else {
-                       probe_address -= probe_decrement;
-                       if ((int)probe_address < 0) {
-                               probe_address += STATUS_HASH_PRIME;
-                       }
-               }
-       }
-       return(probe_address);
-}
-
-/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
-int version_compare_part(const char *version1, const char *version2)
-{
-       int upstream_len1 = 0;
-       int upstream_len2 = 0;
-       char *name1_char;
-       char *name2_char;
-       int len1 = 0;
-       int len2 = 0;
-       int tmp_int;
-       int ver_num1;
-       int ver_num2;
-       int ret;
-
-       if (version1 == NULL) {
-               version1 = xstrdup("");
-       }
-       if (version2 != NULL) {
-               version2 = xstrdup("");
-       }
-       upstream_len1 = strlen(version1);
-       upstream_len2 = strlen(version2);
-
-       while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
-               /* Compare non-digit section */
-               tmp_int = strcspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strcspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               tmp_int = strcmp(name1_char, name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (tmp_int != 0) {
-                       ret = tmp_int;
-                       goto cleanup_version_compare_part;
-               }
-
-               /* Compare digits */
-               tmp_int = strspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               ver_num1 = atoi(name1_char);
-               ver_num2 = atoi(name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (ver_num1 < ver_num2) {
-                       ret = -1;
-                       goto cleanup_version_compare_part;
-               }
-               else if (ver_num1 > ver_num2) {
-                       ret = 1;
-                       goto cleanup_version_compare_part;
-               }
-       }
-       ret = 0;
-cleanup_version_compare_part:
-       return(ret);
-}
-
-/* if ver1 < ver2 return -1,
- * if ver1 = ver2 return 0,
- * if ver1 > ver2 return 1,
- */
-int version_compare(const unsigned int ver1, const unsigned int ver2)
-{
-       char *ch_ver1 = name_hashtable[ver1];
-       char *ch_ver2 = name_hashtable[ver2];
-
-       char epoch1, epoch2;
-       char *deb_ver1, *deb_ver2;
-       char *ver1_ptr, *ver2_ptr;
-       char *upstream_ver1;
-       char *upstream_ver2;
-       int result;
-
-       /* Compare epoch */
-       if (ch_ver1[1] == ':') {
-               epoch1 = ch_ver1[0];
-               ver1_ptr = strchr(ch_ver1, ':') + 1;
-       } else {
-               epoch1 = '0';
-               ver1_ptr = ch_ver1;
-       }
-       if (ch_ver2[1] == ':') {
-               epoch2 = ch_ver2[0];
-               ver2_ptr = strchr(ch_ver2, ':') + 1;
-       } else {
-               epoch2 = '0';
-               ver2_ptr = ch_ver2;
-       }
-       if (epoch1 < epoch2) {
-               return(-1);
-       }
-       else if (epoch1 > epoch2) {
-               return(1);
-       }
-
-       /* Compare upstream version */
-       upstream_ver1 = xstrdup(ver1_ptr);
-       upstream_ver2 = xstrdup(ver2_ptr);
-
-       /* Chop off debian version, and store for later use */
-       deb_ver1 = strrchr(upstream_ver1, '-');
-       deb_ver2 = strrchr(upstream_ver2, '-');
-       if (deb_ver1) {
-               deb_ver1[0] = '\0';
-               deb_ver1++;
-       }
-       if (deb_ver2) {
-               deb_ver2[0] = '\0';
-               deb_ver2++;
-       }
-       result = version_compare_part(upstream_ver1, upstream_ver2);
-
-       free(upstream_ver1);
-       free(upstream_ver2);
-
-       if (result != 0) {
-               return(result);
-       }
-
-       /* Compare debian versions */
-       return(version_compare_part(deb_ver1, deb_ver2));
-}
-
-int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
-{
-       const int version_result = version_compare(version1, version2);
-       switch(operator) {
-               case (VER_ANY):
-                       return(TRUE);
-               case (VER_EQUAL):
-                       if (version_result == 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_LESS):
-                       if (version_result < 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_LESS_EQUAL):
-                       if (version_result <= 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_MORE):
-                       if (version_result > 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_MORE_EQUAL):
-                       if (version_result >= 0) {
-                               return(TRUE);
-                       }
-                       break;
-       }
-       return(FALSE);
-}
-
-
-int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-
-       make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
-       while(package_hashtable[probe_address] != NULL) {
-               if (package_hashtable[probe_address]->name == name) {
-                       if (operator == VER_ANY) {
-                               return(probe_address);
-                       }
-                       if (test_version(package_hashtable[probe_address]->version, version, operator)) {
-                               return(probe_address);
-                       }
-               }
-               probe_address -= probe_decrement;
-               if ((int)probe_address < 0) {
-                       probe_address += PACKAGE_HASH_PRIME;
-               }
-       }
-       return(probe_address);
-}
-
-/*
- * Create one new node and one new edge for every dependency.
- */
-void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
-{
-       char *line = xstrdup(whole_line);
-       char *line2;
-       char *line_ptr1 = NULL;
-       char *line_ptr2 = NULL;
-       char *field;
-       char *field2;
-       char *version;
-       edge_t *edge;
-       int offset_ch;
-       int type;
-
-       field = strtok_r(line, ",", &line_ptr1);
-       do {
-               line2 = xstrdup(field);
-               field2 = strtok_r(line2, "|", &line_ptr2);
-               if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) {
-                       type = EDGE_OR_DEPENDS;
-               }
-               else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) {
-                       type = EDGE_OR_PRE_DEPENDS;
-               } else {
-                       type = edge_type;
-               }
-
-               do {
-                       edge = (edge_t *) xmalloc(sizeof(edge_t));
-                       edge->type = type;
-
-                       /* Skip any extra leading spaces */
-                       field2 += strspn(field2, " ");
-
-                       /* Get dependency version info */
-                       version = strchr(field2, '(');
-                       if (version == NULL) {
-                               edge->operator = VER_ANY;
-                               /* Get the versions hash number, adding it if the number isnt already in there */
-                               edge->version = search_name_hashtable("ANY");
-                       } else {
-                               /* Skip leading ' ' or '(' */
-                               version += strspn(field2, " ");
-                               version += strspn(version, "(");
-                               /* Calculate length of any operator charactors */
-                               offset_ch = strspn(version, "<=>");
-                               /* Determine operator */
-                               if (offset_ch > 0) {
-                                       if (strncmp(version, "=", offset_ch) == 0) {
-                                               edge->operator = VER_EQUAL;
-                                       }
-                                       else if (strncmp(version, "<<", offset_ch) == 0) {
-                                               edge->operator = VER_LESS;
-                                       }
-                                       else if (strncmp(version, "<=", offset_ch) == 0) {
-                                               edge->operator = VER_LESS_EQUAL;
-                                       }
-                                       else if (strncmp(version, ">>", offset_ch) == 0) {
-                                               edge->operator = VER_MORE;
-                                       }
-                                       else if (strncmp(version, ">=", offset_ch) == 0) {
-                                               edge->operator = VER_MORE_EQUAL;
-                                       } else {
-                                               error_msg_and_die("Illegal operator\n");
-                                       }
-                               }
-                               /* skip to start of version numbers */
-                               version += offset_ch;
-                               version += strspn(version, " ");
-
-                               /* Truncate version at trailing ' ' or ')' */
-                               version[strcspn(version, " )")] = '\0';
-                               /* Get the versions hash number, adding it if the number isnt already in there */
-                               edge->version = search_name_hashtable(version);
-                       }
-
-                       /* Get the dependency name */
-                       field2[strcspn(field2, " (")] = '\0';
-                       edge->name = search_name_hashtable(field2);
-       
-                       /* link the new edge to the current node */
-                       parent_node->num_of_edges++;
-                       parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1));
-                       parent_node->edge[parent_node->num_of_edges - 1] = edge;
-               } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL);
-               free(line2);
-       } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL);
-       free(line);
-
-       return;
-}
-
-void free_package(common_node_t *node)
-{
-       int i;
-       if (node != NULL) {
-               for (i = 0; i < node->num_of_edges; i++) {
-                       if (node->edge[i] != NULL) {
-                               free(node->edge[i]);
-                       }
-               }
-               if (node->edge != NULL) {
-                       free(node->edge);
-               }
-               if (node != NULL) {
-                       free(node);
-               }
-       }
-}
-
-unsigned int fill_package_struct(char *control_buffer)
-{
-       common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t));
-
-       char **field_name = xmalloc(sizeof(char *));
-       char **field_value = xmalloc(sizeof(char *));
-       int field_start = 0;
-       int num = -1;
-       int buffer_length = strlen(control_buffer);
-
-       new_node->version = search_name_hashtable("unknown");
-       while (field_start < buffer_length) {
-               field_start += read_package_field(&control_buffer[field_start], field_name, field_value);
-
-               if (*field_name == NULL) {
-                       goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !!
-               }
-
-               if (strcmp(*field_name, "Package") == 0) {
-                       new_node->name = search_name_hashtable(*field_value);
-               }
-               else if (strcmp(*field_name, "Version") == 0) {
-                       new_node->version = search_name_hashtable(*field_value);
-               }
-               else if (strcmp(*field_name, "Pre-Depends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS);
-               }
-               else if (strcmp(*field_name, "Depends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_DEPENDS);
-               }
-               else if (strcmp(*field_name, "Replaces") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_REPLACES);
-               }
-               else if (strcmp(*field_name, "Provides") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_PROVIDES);
-               }
-               else if (strcmp(*field_name, "Conflicts") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS);
-               }
-               else if (strcmp(*field_name, "Suggests") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS);
-               }
-               else if (strcmp(*field_name, "Recommends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS);
-               }
-               else if (strcmp(*field_name, "Enhances") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_ENHANCES);
-               }
-fill_package_struct_cleanup:
-               if (*field_name) {
-                       free(*field_name);
-               }
-               if (*field_value) {
-                       free(*field_value);
-               }
-       }
-       free(field_name);
-       free(field_value);
-
-       if (new_node->version == search_name_hashtable("unknown")) {
-               free_package(new_node);
-               return(-1);
-       }
-       num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
-       if (package_hashtable[num] == NULL) {
-               package_hashtable[num] = new_node;
-       } else {
-               free_package(new_node);
-       }
-       return(num);
-}
-
-/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
-unsigned int get_status(const unsigned int status_node, const int num)
-{
-       char *status_string = name_hashtable[status_hashtable[status_node]->status];
-       char *state_sub_string;
-       unsigned int state_sub_num;
-       int len;
-       int i;
-
-       /* set tmp_string to point to the start of the word number */
-       for (i = 1; i < num; i++) {
-               /* skip past a word */
-               status_string += strcspn(status_string, " ");
-               /* skip past the seperating spaces */
-               status_string += strspn(status_string, " ");
-       }
-       len = strcspn(status_string, " \n\0");
-       state_sub_string = xstrndup(status_string, len);
-       state_sub_num = search_name_hashtable(state_sub_string);
-       free(state_sub_string);
-       return(state_sub_num);
-}
-
-void set_status(const unsigned int status_node_num, const char *new_value, const int position)
-{
-       const unsigned int new_value_len = strlen(new_value);
-       const unsigned int new_value_num = search_name_hashtable(new_value);
-       unsigned int want = get_status(status_node_num, 1);
-       unsigned int flag = get_status(status_node_num, 2);
-       unsigned int status = get_status(status_node_num, 3);
-       int want_len = strlen(name_hashtable[want]);
-       int flag_len = strlen(name_hashtable[flag]);
-       int status_len = strlen(name_hashtable[status]);
-       char *new_status;
-
-       switch (position) {
-               case (1):
-                       want = new_value_num;
-                       want_len = new_value_len;
-                       break;
-               case (2):
-                       flag = new_value_num;
-                       flag_len = new_value_len;
-                       break;
-               case (3):
-                       status = new_value_num;
-                       status_len = new_value_len;
-                       break;
-               default:
-                       error_msg_and_die("DEBUG ONLY: this shouldnt happen");
-       }
-
-       new_status = (char *) xmalloc(want_len + flag_len + status_len + 3);
-       sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
-       status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
-       free(new_status);
-       return;
-}
-
-void index_status_file(const char *filename)
-{
-       FILE *status_file;
-       char *control_buffer;
-       char *status_line;
-       status_node_t *status_node = NULL;
-       unsigned int status_num;
-
-       status_file = xfopen(filename, "r");
-       while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) {
-               const unsigned int package_num = fill_package_struct(control_buffer);
-               if (package_num != -1) {
-                       status_node = xmalloc(sizeof(status_node_t));
-                       /* fill_package_struct doesnt handle the status field */
-                       status_line = strstr(control_buffer, "Status:");
-                       if (status_line != NULL) {
-                               status_line += 7;
-                               status_line += strspn(status_line, " \n\t");
-                               status_line = xstrndup(status_line, strcspn(status_line, "\n\0"));
-                               status_node->status = search_name_hashtable(status_line);
-                               free(status_line);
-                       }
-                       status_node->package = package_num;
-                       status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
-                       status_hashtable[status_num] = status_node;
-               }
-               free(control_buffer);
-       }
-       fclose(status_file);
-       return;
-}
-
-
-char *get_depends_field(common_node_t *package, const int depends_type)
-{
-       char *depends = NULL;
-       char *old_sep = (char *)xcalloc(1, 3);
-       char *new_sep = (char *)xcalloc(1, 3);
-       int line_size = 0;
-       int depends_size;
-
-       int i;
-
-       for (i = 0; i < package->num_of_edges; i++) {
-               if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) ||
-                       (package->edge[i]->type == EDGE_OR_DEPENDS)) {
-               }
-
-               if ((package->edge[i]->type == depends_type) ||
-                       (package->edge[i]->type == depends_type + 1)) {
-                       /* Check if its the first time through */
-
-                       depends_size = 8 + strlen(name_hashtable[package->edge[i]->name])
-                               + strlen(name_hashtable[package->edge[i]->version]);
-                       line_size += depends_size;
-                       depends = (char *) xrealloc(depends, line_size + 1);
-
-                       /* Check to see if this dependency is the type we are looking for
-                        * +1 to check for 'extra' types, e.g. ored dependecies */
-                       strcpy(old_sep, new_sep);
-                       if (package->edge[i]->type == depends_type) {
-                               strcpy(new_sep, ", ");
-                       }
-                       else if (package->edge[i]->type == depends_type + 1) {
-                               strcpy(new_sep, "| ");
-                       }
-
-                       if (depends_size == line_size) {
-                               strcpy(depends, "");
-                       } else {
-                               if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) {
-                                       strcat(depends, " | ");
-                               } else {
-                                       strcat(depends, ", ");
-                               }
-                       }
-
-                       strcat(depends, name_hashtable[package->edge[i]->name]);
-                       if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) {
-                               if (package->edge[i]->operator == VER_EQUAL) {
-                                       strcat(depends, " (= ");
-                               }
-                               else if (package->edge[i]->operator == VER_LESS) {
-                                       strcat(depends, " (<< ");
-                               }
-                               else if (package->edge[i]->operator == VER_LESS_EQUAL) {
-                                       strcat(depends, " (<= ");
-                               }
-                               else if (package->edge[i]->operator == VER_MORE) {
-                                       strcat(depends, " (>> ");
-                               }
-                               else if (package->edge[i]->operator == VER_MORE_EQUAL) {
-                                       strcat(depends, " (>= ");
-                               } else {
-                                       strcat(depends, " (");
-                               }
-                               strcat(depends, name_hashtable[package->edge[i]->version]);
-                               strcat(depends, ")");
-                       }
-               }
-       }
-       return(depends);
-}
-
-void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
-{
-       char *name;
-       char *value;
-       int start = 0;
-       while (1) {
-               start += read_package_field(&control_buffer[start], &name, &value);
-               if (name == NULL) {
-                       break;
-               }
-               if (strcmp(name, "Status") != 0) {
-                       fprintf(new_status_file, "%s: %s\n", name, value);
-               }
-       }
-       return;
-}
-
-/* This could do with a cleanup */
-void write_status_file(deb_file_t **deb_file)
-{
-       FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
-       FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
-       char *package_name;
-       char *status_from_file;
-       char *control_buffer = NULL;
-       char *tmp_string;
-       int status_num;
-       int field_start = 0;
-       int write_flag;
-       int i = 0;
-
-       /* Update previously known packages */
-       while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) {
-               tmp_string = strstr(control_buffer, "Package:") + 8;
-               tmp_string += strspn(tmp_string, " \n\t");
-               package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0"));
-               write_flag = FALSE;
-               tmp_string = strstr(control_buffer, "Status:");
-               if (tmp_string != NULL) {
-                       /* Seperate the status value from the control buffer */
-                       tmp_string += 7;
-                       tmp_string += strspn(tmp_string, " \n\t");
-                       status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
-               } else {
-                       status_from_file = NULL;
-               }
-
-               /* Find this package in the status hashtable */
-               status_num = search_status_hashtable(package_name);
-               if (status_hashtable[status_num] != NULL) {
-                       const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
-                       if (strcmp(status_from_file, status_from_hashtable) != 0) {
-                               /* New status isnt exactly the same as old status */
-                               const int state_status = get_status(status_num, 3);
-                               if ((strcmp("installed", name_hashtable[state_status]) == 0) ||
-                                       (strcmp("unpacked", name_hashtable[state_status]) == 0)) {
-                                       /* We need to add the control file from the package */
-                                       i = 0;
-                                       while(deb_file[i] != NULL) {
-                                               if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
-                                                       /* Write a status file entry with a modified status */
-                                                       /* remove trailing \n's */
-                                                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
-                                                       set_status(status_num, "ok", 2);
-                                                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
-                                                       write_flag = TRUE;
-                                                       break;
-                                               }
-                                               i++;
-                                       }
-                                       /* This is temperary, debugging only */
-                                       if (deb_file[i] == NULL) {
-                                               error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name);
-                                       }
-                               }
-                               else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
-                                       /* Only write the Package, Status, Priority and Section lines */
-                                       fprintf(new_status_file, "Package: %s\n", package_name);
-                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
-
-                                       while (1) {
-                                               char *field_name;
-                                               char *field_value;
-                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
-                                               if (field_name == NULL) {
-                                                       break;
-                                               }
-                                               if ((strcmp(field_name, "Priority") == 0) ||
-                                                       (strcmp(field_name, "Section") == 0)) {
-                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
-                                               }
-                                       }
-                                       write_flag = TRUE;
-                                       fputs("\n", new_status_file);
-                               }
-                               else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
-                                       /* only change the status line */
-                                       while (1) {
-                                               char *field_name;
-                                               char *field_value;
-                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
-                                               if (field_name == NULL) {
-                                                       break;
-                                               }
-                                               /* Setup start point for next field */
-                                               if (strcmp(field_name, "Status") == 0) {
-                                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
-                                               } else {
-                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
-                                               }
-                                       }
-                                       write_flag = TRUE;
-                                       fputs("\n", new_status_file);
-                               }
-                       }
-               }
-               /* If the package from the status file wasnt handle above, do it now*/
-               if (write_flag == FALSE) {
-                       fprintf(new_status_file, "%s\n\n", control_buffer);
-               }
-
-               if (status_from_file != NULL) {
-                       free(status_from_file);
-               }
-               free(package_name);
-               free(control_buffer);
-       }
-
-       /* Write any new packages */
-       for(i = 0; deb_file[i] != NULL; i++) {
-               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
-               if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
-                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
-                       set_status(status_num, "ok", 2);
-                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
-               }
-       }
-       fclose(old_status_file);
-       fclose(new_status_file);
-
-
-       /* Create a seperate backfile to dpkg */
-       if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
-               struct stat stat_buf;   
-               if (stat("/var/lib/dpkg/status", &stat_buf) == 0) {
-                       error_msg_and_die("Couldnt create backup status file");
-               }
-               /* Its ok if renaming the status file fails becasue status 
-                * file doesnt exist, maybe we are starting from scratch */
-               error_msg("No status file found, creating new one");
-       }
-
-       if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) {
-               error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file");
-       }
-}
-
-int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
-{
-       int *conflicts = NULL;
-       int conflicts_num = 0;
-       int state_status;
-       int state_flag;
-       int state_want;
-       unsigned int status_package_num;
-       int i = deb_start;
-       int j, k;
-
-       /* Check for conflicts
-        * TODO: TEST if conflicts with other packages to be installed
-        *
-        * Add install packages and the packages they provide
-        * to the list of files to check conflicts for
-        */
-
-       /* Create array of package numbers to check against
-        * installed package for conflicts*/
-       while (deb_file[i] != NULL) {
-               const unsigned int package_num = deb_file[i]->package;
-               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
-               conflicts[conflicts_num] = package_num;
-               conflicts_num++;
-               /* add provides to conflicts list */
-               for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
-                       if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
-                               const int conflicts_package_num = search_package_hashtable(
-                                       package_hashtable[package_num]->edge[j]->name,
-                                       package_hashtable[package_num]->edge[j]->version,
-                                       package_hashtable[package_num]->edge[j]->operator);
-                               if (package_hashtable[conflicts_package_num] == NULL) {
-                                       /* create a new package */
-                                       common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t));
-                                       new_node->name = package_hashtable[package_num]->edge[j]->name;
-                                       new_node->version = package_hashtable[package_num]->edge[j]->version;
-                                       new_node->num_of_edges = 0;
-                                       new_node->edge = NULL;
-                                       package_hashtable[conflicts_package_num] = new_node;
-                               }
-                               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
-                               conflicts[conflicts_num] = conflicts_package_num;
-                               conflicts_num++;
-                       }
-               }
-               i++;
-       }
-
-       /* Check conflicts */
-       for (i = 0; i < conflicts_num; i++) {
-               /* Check for conflicts */
-               for (j = 0; j < STATUS_HASH_PRIME; j++) {
-                       if (status_hashtable[j] == NULL) {
-                               continue;
-                       }
-                       state_flag = get_status(j, 2);
-                       state_status = get_status(j, 3);
-                       if ((state_status != search_name_hashtable("installed"))
-                               && (state_flag != search_name_hashtable("want-install"))) {
-                               continue;
-                       }
-                       status_package_num = status_hashtable[j]->package;
-                       for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) {
-                               const edge_t *package_edge = package_hashtable[status_package_num]->edge[k];
-                               if (package_edge->type != EDGE_CONFLICTS) {
-                                       continue;
-                               }
-                               if (package_edge->name != package_hashtable[conflicts[i]]->name) {
-                                       continue;
-                               }
-                               /* There is a conflict against the package name
-                                * check if version conflict as well */
-                               if (test_version(package_hashtable[deb_file[i]->package]->version,
-                                               package_edge->version, package_edge->operator)) {
-                                       error_msg_and_die("Package %s conflict with %s",
-                                               name_hashtable[package_hashtable[deb_file[i]->package]->name],
-                                               name_hashtable[package_hashtable[status_package_num]->name]);
-                               }
-                       }
-               }
-       }
-
-       /* Check dependendcies */
-       i = 0;
-       while (deb_file[i] != NULL) {
-               const common_node_t *package_node = package_hashtable[deb_file[i]->package];
-               int status_num = 0;
-
-               for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) {
-                       const edge_t *package_edge = package_node->edge[j];
-                       const unsigned int package_num = search_package_hashtable(package_edge->name,
-                               package_edge->version, package_edge->operator);
-
-                       status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
-                       state_status = get_status(status_num, 3);
-                       state_want = get_status(status_num, 1);
-                       switch (package_edge->type) {
-                               case(EDGE_PRE_DEPENDS):
-                               case(EDGE_OR_PRE_DEPENDS):
-                                       /* It must be already installed */
-                                       /* NOTE: This is untested, nothing apropriate in my status file */
-                                       if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) {
-                                               error_msg_and_die("Package %s pre-depends on %s, but it is not installed",
-                                                       name_hashtable[package_node->name],
-                                                       name_hashtable[package_edge->name]);
-                                       }
-                                       break;
-                               case(EDGE_DEPENDS):
-                               case(EDGE_OR_DEPENDS):
-                                       /* It must be already installed, or to be installed */
-                                       if ((package_hashtable[package_num] == NULL) ||
-                                               ((state_status != search_name_hashtable("installed")) &&
-                                               (state_want != search_name_hashtable("want_install")))) {
-                                               error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
-                                                       name_hashtable[package_node->name],
-                                                       name_hashtable[package_edge->name]);
-                                       }
-                                       break;
-                       }
-               }
-               i++;
-       }
-       free(conflicts);
-       return(TRUE);
-}
-
-char **create_list(const char *filename)
-{
-       FILE *list_stream;
-       char **file_list = xmalloc(sizeof(char *));
-       char *line = NULL;
-       char *last_char;
-       int length = 0;
-       int count = 0;
-
-       /* dont use [xw]fopen here, handle error ourself */
-       list_stream = fopen(filename, "r");
-       if (list_stream == NULL) {
-               *file_list = NULL;
-               return(file_list);
-       }
-       while (getline(&line, &length, list_stream) != -1) {
-               file_list = xrealloc(file_list, sizeof(char *) * (length + 1));
-               last_char = last_char_is(line, '\n');
-               if (last_char) {
-                       *last_char = '\0';
-               }
-               file_list[count] = xstrdup(line);
-               free(line);
-               count++;
-               length = 0;
-       }
-       fclose(list_stream);
-
-       if (count == 0) {
-               return(NULL);
-       } else {
-               file_list[count] = NULL;
-               return(file_list);
-       }
-}
-
-/* maybe i should try and hook this into remove_file.c somehow */
-int remove_file_array(char **remove_names, char **exclude_names)
-{
-       struct stat path_stat;
-       int match_flag;
-       int remove_flag = FALSE;
-       int i,j;
-
-       if (remove_names == NULL) {
-               return(FALSE);
-       }
-       for (i = 0; remove_names[i] != NULL; i++) {
-               match_flag = FALSE;
-               if (exclude_names != NULL) {
-                       for (j = 0; exclude_names[j] != 0; j++) {
-                               if (strcmp(remove_names[i], exclude_names[j]) == 0) {
-                                       match_flag = TRUE;
-                                       break;
-                               }
-                       }
-               }
-               if (!match_flag) {
-                       if (lstat(remove_names[i], &path_stat) < 0) {
-                               continue;
-                       }
-                       if (S_ISDIR(path_stat.st_mode)) {
-                               if (rmdir(remove_names[i]) != -1) {
-                                       remove_flag = TRUE;
-                               }
-                       } else {
-                               if (unlink(remove_names[i]) != -1) {
-                                       remove_flag = TRUE;
-                               }
-                       }
-               }
-       }
-       return(remove_flag);
-}
-
-int run_package_script(const char *package_name, const char *script_type)
-{
-       struct stat path_stat;
-       char *script_path;
-
-       script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21);
-       sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type);
-
-       /* If the file doesnt exist is isnt a fatal */
-       if (lstat(script_path, &path_stat) < 0) {
-               free(script_path);
-               return(EXIT_SUCCESS);
-       } else {
-               free(script_path);
-               return(system(script_path));
-       }
-}
-
-void all_control_list(char **remove_files, const char *package_name)
-{
-       const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm",
-               "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL };
-       int i;
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       for(i = 0; i < 10; i++) {
-               remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21);
-               sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]);
-       }
-       remove_files[10] = NULL;
-}
-
-void remove_package(const unsigned int package_num)
-{
-       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       const int package_name_length = strlen(package_name);
-       char **remove_files;
-       char **exclude_files;
-       char list_name[package_name_length + 25];
-       char conffile_name[package_name_length + 30];
-       int return_value;
-
-       printf("Removing %s ...\n", package_name);
-
-       /* run prerm script */
-       return_value = run_package_script(package_name, "prem");
-       if (return_value == -1) {
-               error_msg_and_die("script failed, prerm failure");
-       }
-
-       /* Create a list of files to remove, and a seperate list of those to keep */
-       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
-       remove_files = create_list(list_name);
-
-       sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name);
-       exclude_files = create_list(conffile_name);
-
-       /* Some directories cant be removed straight away, so do multiple passes */
-       while (remove_file_array(remove_files, exclude_files) == TRUE);
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       remove_files = xmalloc(11);
-       all_control_list(remove_files, package_name);
-
-       /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep  */
-       exclude_files = xmalloc(sizeof(char*) * 3);
-       exclude_files[0] = xstrdup(conffile_name);
-       exclude_files[1] = xmalloc(package_name_length + 27);
-       sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name);
-       exclude_files[2] = NULL;
-
-       remove_file_array(remove_files, exclude_files);
-
-       /* rename <package>.conffile to <package>.list */
-       rename(conffile_name, list_name);
-
-       /* Change package status */
-       set_status(status_num, "deinstall", 1);
-       set_status(status_num, "config-files", 3);
-}
-
-void purge_package(const unsigned int package_num)
-{
-       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       char **remove_files;
-       char **exclude_files;
-       char list_name[strlen(package_name) + 25];
-
-       /* run prerm script */
-       if (run_package_script(package_name, "prerm") == -1) {
-               error_msg_and_die("script failed, prerm failure");
-       }
-
-       /* Create a list of files to remove */
-       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
-       remove_files = create_list(list_name);
-
-       exclude_files = xmalloc(1);
-       exclude_files[0] = NULL;
-
-       /* Some directories cant be removed straight away, so do multiple passes */
-       while (remove_file_array(remove_files, exclude_files) == TRUE);
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       remove_files = xmalloc(11);
-       all_control_list(remove_files, package_name);
-       remove_file_array(remove_files, exclude_files);
-
-       /* run postrm script */
-       if (run_package_script(package_name, "postrm") == -1) {
-               error_msg_and_die("postrm fialure.. set status to what?");
-       }
-
-       /* Change package status */
-       set_status(status_num, "purge", 1);
-       set_status(status_num, "not-installed", 3);
-}
-
-void unpack_package(deb_file_t *deb_file)
-{
-       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       const unsigned int status_package_num = status_hashtable[status_num]->status;
-
-       FILE *out_stream;
-       char *info_prefix;
-
-       /* If existing version, remove it first */
-       if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
-               /* Package is already installed, remove old version first */
-               printf("Preparing to replace %s %s (using %s) ...\n", package_name,
-                       name_hashtable[package_hashtable[status_package_num]->version],
-                       deb_file->filename);
-               remove_package(status_package_num);
-       } else {
-               printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename);
-       }
-
-       /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
-       info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1);
-       sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name);
-       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL);
-
-       /* Extract data.tar.gz to the root directory */
-       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL);
-
-       /* Create the list file */
-       strcat(info_prefix, "list");
-       out_stream = xfopen(info_prefix, "w");                  
-       deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL);
-       fclose(out_stream);
-
-       /* change status */
-       set_status(status_num, "install", 1);
-       set_status(status_num, "unpacked", 3);
-
-       free(info_prefix);
-}
-
-void configure_package(deb_file_t *deb_file)
-{
-       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
-       const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
-       const int status_num = search_status_hashtable(package_name);
-       int return_value;
-
-       printf("Setting up %s (%s)\n", package_name, package_version);
-
-       /* Run the preinst prior to extracting */
-       return_value = run_package_script(package_name, "postinst");
-       if (return_value == -1) {
-               /* TODO: handle failure gracefully */
-               error_msg_and_die("postrm failure.. set status to what?");
-       }
-       /* Change status to reflect success */
-       set_status(status_num, "install", 1);
-       set_status(status_num, "installed", 3);
-}
-
-extern int dpkg_main(int argc, char **argv)
-{
-       deb_file_t **deb_file = NULL;
-       status_node_t *status_node;
-       char opt = 0;
-       int package_num;
-       int dpkg_opt = 0;
-       int deb_count = 0;
-       int state_status;
-       int status_num;
-       int i;
-
-       while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) {
-               switch (opt) {
-                       case 'C': // equivalent to --configure in official dpkg
-                               dpkg_opt |= dpkg_opt_configure;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'F': // equivalent to --force in official dpkg
-                               if (strcmp(optarg, "depends") == 0) {
-                                       dpkg_opt |= dpkg_opt_force_ignore_depends;
-                               }                               
-                       case 'i':
-                               dpkg_opt |= dpkg_opt_install;
-                               dpkg_opt |= dpkg_opt_filename;
-                               break;
-                       case 'l':
-                               dpkg_opt |= dpkg_opt_list_installed;
-                       case 'P':
-                               dpkg_opt |= dpkg_opt_purge;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'r':
-                               dpkg_opt |= dpkg_opt_remove;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'u':       /* Equivalent to --unpack in official dpkg */
-                               dpkg_opt |= dpkg_opt_unpack;
-                               dpkg_opt |= dpkg_opt_filename;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((argc == optind) || (dpkg_opt == 0)) {
-               show_usage();
-       } 
-
-       puts("(Reading database ... xxxxx files and directories installed.)");
-       index_status_file("/var/lib/dpkg/status");
-
-       /* Read arguments and store relevant info in structs */
-       deb_file = xmalloc(sizeof(deb_file_t));
-       while (optind < argc) {
-               deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t));
-               if (dpkg_opt & dpkg_opt_filename) {
-                       deb_file[deb_count]->filename = xstrdup(argv[optind]);
-                       deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control");
-                       if (deb_file[deb_count]->control_file == NULL) {
-                               error_msg_and_die("Couldnt extract control file");
-                       }
-                       package_num = fill_package_struct(deb_file[deb_count]->control_file);
-
-                       if (package_num == -1) {
-                               error_msg("Invalid control file in %s", argv[optind]);
-                               continue;
-                       }
-                       deb_file[deb_count]->package = (unsigned int) package_num;
-                       /* Add the package to the status hashtable */
-                       if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) {
-                               status_node = (status_node_t *) xmalloc(sizeof(status_node_t));
-                               status_node->package = deb_file[deb_count]->package;
-                               /* use reinstreq isnt changed to "ok" until the package control info
-                                * is written to the status file*/
-                               status_node->status = search_name_hashtable("install reinstreq not-installed");
-
-                               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               status_hashtable[status_num] = status_node;
-                       }
-               }
-               else if (dpkg_opt & dpkg_opt_package_name) {
-                       deb_file[deb_count]->filename = NULL;
-                       deb_file[deb_count]->control_file = NULL;
-                       deb_file[deb_count]->package = search_package_hashtable(
-                               search_name_hashtable(argv[optind]),
-                               search_name_hashtable("ANY"), VER_ANY);
-                       if (package_hashtable[deb_file[deb_count]->package] == NULL) {
-                               error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]);
-                       }
-                       state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3);
-
-                       /* check package status is "installed" */
-                       if (dpkg_opt & dpkg_opt_remove) {
-                               if ((strcmp(name_hashtable[state_status], "not-installed") == 0) ||
-                                       (strcmp(name_hashtable[state_status], "config-files") == 0)) {
-                                       error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               }
-                       }
-                       else if (dpkg_opt & dpkg_opt_purge) {
-                               /* if package status is "conf-files" then its ok */
-                               if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
-                                       error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               }
-                       }
-               }
-               deb_count++;
-               optind++;
-       }
-       deb_file[deb_count] = NULL;
-
-       /* Check that the deb file arguments are installable */
-       /* TODO: check dependencies before removing */
-       if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) {
-               if (!check_deps(deb_file, 0, deb_count)) {
-                       error_msg_and_die("Dependency check failed");
-               }
-       }
-
-       for (i = 0; i < deb_count; i++) {
-               /* Remove or purge packages */
-               if (dpkg_opt & dpkg_opt_remove) {
-                       remove_package(deb_file[i]->package);
-               }
-               else if (dpkg_opt & dpkg_opt_purge) {
-                       purge_package(deb_file[i]->package);
-               }
-               else if (dpkg_opt & dpkg_opt_unpack) {
-                       unpack_package(deb_file[i]);
-               }
-               else if (dpkg_opt & dpkg_opt_install) {
-                       unpack_package(deb_file[i]);
-                       configure_package(deb_file[i]);
-               }
-               else if (dpkg_opt & dpkg_opt_configure) {
-                       configure_package(deb_file[i]);
-               }
-       }
-
-       write_status_file(deb_file);
-
-       for (i = 0; i < deb_count; i++) {
-               free(deb_file[i]->control_file);
-               free(deb_file[i]->filename);
-               free(deb_file[i]);
-       }
-       free(deb_file);
-
-       for (i = 0; i < NAME_HASH_PRIME; i++) {
-               if (name_hashtable[i] != NULL) {
-                       free(name_hashtable[i]);
-               }
-       }
-
-       for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
-               free_package(package_hashtable[i]);
-       }
-
-       for (i = 0; i < STATUS_HASH_PRIME; i++) {
-               if (status_hashtable[i] != NULL) {
-                       free(status_hashtable[i]);
-               }
-       }
-
-       return(EXIT_FAILURE);
-}
-
diff --git a/busybox/archival/dpkg_deb.c b/busybox/archival/dpkg_deb.c
deleted file mode 100644 (file)
index a933c69..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int dpkg_deb_main(int argc, char **argv)
-{
-       char *prefix = NULL;
-       char *filename = NULL;
-       char *output_buffer = NULL;
-       int opt = 0;
-       int arg_type = 0;
-       int deb_extract_funct = extract_create_leading_dirs | extract_unconditional;    
-       
-       const int arg_type_prefix = 1;
-       const int arg_type_field = 2;
-       const int arg_type_filename = 4;
-//     const int arg_type_un_ar_gz = 8;
-
-       while ((opt = getopt(argc, argv, "ceftXxI")) != -1) {
-               switch (opt) {
-                       case 'c':
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_verbose_list;
-                               break;
-                       case 'e':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               break;
-                       case 'f':
-                               arg_type = arg_type_field;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_one_to_buffer;
-                               filename = xstrdup("./control");
-                               break;
-                       case 't': /* --fsys-tarfile, i just made up this short name */
-                               /* Integrate the functionality needed with some code from ar.c */
-                               error_msg_and_die("Option disabled");
-//                             arg_type = arg_type_un_ar_gz;
-                               break;
-                       case 'X':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               deb_extract_funct |= extract_list;
-                       case 'x':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               break;
-                       case 'I':
-                               arg_type = arg_type_filename;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_one_to_buffer;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)  {
-               show_usage();
-       }
-
-       /* Workout where to extract the files */
-       if (arg_type == arg_type_prefix) {
-               /* argument is a dir name */
-               if ((optind + 1) == argc ) {
-                       prefix = xstrdup("./DEBIAN/");
-               } else {
-                       prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2);
-                       strcpy(prefix, argv[optind + 1]);
-                       /* Make sure the directory has a trailing '/' */
-                       if (last_char_is(prefix, '/') == NULL) {
-                               strcat(prefix, "/");
-                       }
-               }
-               mkdir(prefix, 0777);
-       }
-
-       if (arg_type == arg_type_filename) {
-               if ((optind + 1) != argc) {
-                       filename = xstrdup(argv[optind + 1]);
-               } else {
-                       error_msg_and_die("-I currently requires a filename to be specified");
-               }
-       }
-
-       output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename);
-
-       if ((arg_type == arg_type_filename) && (output_buffer != NULL)) {
-               puts(output_buffer);
-       }
-       else if (arg_type == arg_type_field) {
-               char *field = NULL;
-               char *name;
-               char *value;
-               int field_start = 0;
-
-               while (1) {
-                       field_start += read_package_field(&output_buffer[field_start], &name, &value);
-                       if (name == NULL) {
-                               break;
-                       }
-                       if (strcmp(name, argv[optind + 1]) == 0) {
-                               puts(value);
-                       }
-                       free(field);
-               }
-       }
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/archival/gunzip.c b/busybox/archival/gunzip.c
deleted file mode 100644 (file)
index 430bc63..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Gzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
-       "   Copyright (C) 1992-1993 Jean-loup Gailly",
-       "   This program is free software; you can redistribute it and/or modify",
-       "   it under the terms of the GNU General Public License as published by",
-       "   the Free Software Foundation; either version 2, or (at your option)",
-       "   any later version.",
-       "",
-       "   This program is distributed in the hope that it will be useful,",
-       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
-       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
-       "   GNU General Public License for more details.",
-       "",
-       "   You should have received a copy of the GNU General Public License",
-       "   along with this program; if not, write to the Free Software",
-       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
-       0
-};
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int gunzip_main(int argc, char **argv)
-{
-       FILE *in_file = stdin;
-       FILE *out_file = NULL;
-       struct stat stat_buf;
-
-       char *if_name = NULL;
-       char *of_name = NULL;
-       char *delete_file_name = NULL;
-
-       const int gunzip_to_stdout = 1;
-       const int gunzip_force = 2;
-       const int gunzip_test = 4;
-
-       int flags = 0;
-       int opt = 0;
-       int delete_old_file = FALSE;
-
-       /* if called as zcat */
-       if (strcmp(applet_name, "zcat") == 0)
-               flags |= gunzip_to_stdout;
-
-       while ((opt = getopt(argc, argv, "ctfhdq")) != -1) {
-               switch (opt) {
-               case 'c':
-                       flags |= gunzip_to_stdout;
-                       break;
-               case 'f':
-                       flags |= gunzip_force;
-                       break;
-               case 't':
-                       flags |= gunzip_test;
-                       break;
-               case 'd': /* Used to convert gzip to gunzip. */
-                       break;
-               case 'q':
-                       error_msg("-q option not supported, ignored");
-                       break;
-               case 'h':
-               default:
-                       show_usage(); /* exit's inside usage */
-               }
-       }
-
-       /* Set input filename and number */
-       if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
-               flags |= gunzip_to_stdout;
-       } else {
-               if_name = strdup(argv[optind]);
-               /* Open input file */
-               in_file = xfopen(if_name, "r");
-
-               /* set the buffer size */
-               setvbuf(in_file, NULL, _IOFBF, 0x8000);
-
-               /* Get the time stamp on the input file. */
-               if (stat(if_name, &stat_buf) < 0) {
-                       error_msg_and_die("Couldn't stat file %s", if_name);
-               }
-       }
-
-       /* Check that the input is sane.  */
-       if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0)
-               error_msg_and_die("compressed data not read from terminal.  Use -f to force it.");
-
-       /* Set output filename and number */
-       if (flags & gunzip_test) {
-               out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
-       } else if (flags & gunzip_to_stdout) {
-               out_file = stdout;
-       } else {
-               char *extension;
-               int length = strlen(if_name);
-
-               delete_old_file = TRUE;
-               extension = strrchr(if_name, '.');
-               if (extension && strcmp(extension, ".gz") == 0) {
-                       length -= 3;
-               } else if (extension && strcmp(extension, ".tgz") == 0) {
-                       length -= 4;
-               } else {
-                       error_msg_and_die("Invalid extension");
-               }
-               of_name = (char *) xcalloc(sizeof(char), length + 1);
-               strncpy(of_name, if_name, length);
-
-               /* Open output file */
-               out_file = xfopen(of_name, "w");
-
-               /* Set permissions on the file */
-               chmod(of_name, stat_buf.st_mode);
-       }
-
-       /* do the decompression, and cleanup */
-       if (unzip(in_file, out_file) == 0) {
-               /* Success, remove .gz file */
-               delete_file_name = if_name;
-       } else {
-               /* remove failed attempt */
-               delete_file_name = of_name;
-       }
-
-       fclose(out_file);
-       fclose(in_file);
-
-       if (delete_old_file == TRUE) {
-               if (unlink(delete_file_name) < 0) {
-                       error_msg_and_die("Couldnt remove %s", delete_file_name);
-               }
-       }
-
-       free(of_name);
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/archival/gzip.c b/busybox/archival/gzip.c
deleted file mode 100644 (file)
index 54bb727..0000000
+++ /dev/null
@@ -1,2550 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Gzip implementation for busybox
- *
- * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
- *             "this is a stripped down version of gzip I put into busybox, it does
- *             only standard in to standard out with -9 compression.  It also requires
- *             the zcat module for some important functions."
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* These defines are very important for BusyBox.  Without these,
- * huge chunks of ram are pre-allocated making the BusyBox bss 
- * size Freaking Huge(tm), which is a bad thing.*/
-#define SMALL_MEM
-#define DYN_ALLOC
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <utime.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <time.h>
-#include "busybox.h"
-
-#define memzero(s, n)     memset ((void *)(s), 0, (n))
-
-#ifndef RETSIGTYPE
-#  define RETSIGTYPE void
-#endif
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-/* Return codes from gzip */
-#define OK      0
-#define ERROR   1
-#define WARNING 2
-
-/* Compression methods (see algorithm.doc) */
-/* Only STORED and DEFLATED are supported by this BusyBox module */
-#define STORED      0
-/* methods 4 to 7 reserved */
-#define DEFLATED    8
-static int method;                             /* compression method */
-
-/* To save memory for 16 bit systems, some arrays are overlaid between
- * the various modules:
- * deflate:  prev+head   window      d_buf  l_buf  outbuf
- * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
- * For compression, input is done in window[]. For decompression, output
- * is done in window except for unlzw.
- */
-
-#ifndef        INBUFSIZ
-#  ifdef SMALL_MEM
-#    define INBUFSIZ  0x2000   /* input buffer size */
-#  else
-#    define INBUFSIZ  0x8000   /* input buffer size */
-#  endif
-#endif
-#define INBUF_EXTRA  64                        /* required by unlzw() */
-
-#ifndef        OUTBUFSIZ
-#  ifdef SMALL_MEM
-#    define OUTBUFSIZ   8192   /* output buffer size */
-#  else
-#    define OUTBUFSIZ  16384   /* output buffer size */
-#  endif
-#endif
-#define OUTBUF_EXTRA 2048              /* required by unlzw() */
-
-#ifndef DIST_BUFSIZE
-#  ifdef SMALL_MEM
-#    define DIST_BUFSIZE 0x2000        /* buffer for distances, see trees.c */
-#  else
-#    define DIST_BUFSIZE 0x8000        /* buffer for distances, see trees.c */
-#  endif
-#endif
-
-#ifdef DYN_ALLOC
-#  define DECLARE(type, array, size)  static type * array
-#  define ALLOC(type, array, size) { \
-      array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
-      if (array == NULL) error_msg(memory_exhausted); \
-   }
-#  define FREE(array) {if (array != NULL) free(array), array=NULL;}
-#else
-#  define DECLARE(type, array, size)  static type array[size]
-#  define ALLOC(type, array, size)
-#  define FREE(array)
-#endif
-
-#define tab_suffix window
-#define tab_prefix prev                /* hash link (see deflate.c) */
-#define head (prev+WSIZE)              /* hash head (see deflate.c) */
-
-static long bytes_in;                  /* number of input bytes */
-
-#define isize bytes_in
-/* for compatibility with old zip sources (to be cleaned) */
-
-typedef int file_t;                            /* Do not use stdio */
-
-#define NO_FILE  (-1)                  /* in memory compression */
-
-
-#define        PACK_MAGIC     "\037\036"       /* Magic header for packed files */
-#define        GZIP_MAGIC     "\037\213"       /* Magic header for gzip files, 1F 8B */
-#define        OLD_GZIP_MAGIC "\037\236"       /* Magic header for gzip 0.5 = freeze 1.x */
-#define        LZH_MAGIC      "\037\240"       /* Magic header for SCO LZH Compress files */
-#define PKZIP_MAGIC    "\120\113\003\004"      /* Magic header for pkzip files */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01              /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02              /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04              /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08              /* bit 3 set: original file name present */
-#define COMMENT      0x10              /* bit 4 set: file comment present */
-#define RESERVED     0xC0              /* bit 6,7:   reserved */
-
-/* internal file attribute */
-#define UNKNOWN 0xffff
-#define BINARY  0
-#define ASCII   1
-
-#ifndef WSIZE
-#  define WSIZE 0x8000                 /* window size--must be a power of two, and */
-#endif                                                 /*  at least 32K for zip's deflate method */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-/* put_byte is used for the compressed output */
-#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
-   flush_outbuf();}
-
-/* Output a 16 bit value, lsb first */
-#define put_short(w) \
-{ if (outcnt < OUTBUFSIZ-2) { \
-    outbuf[outcnt++] = (uch) ((w) & 0xff); \
-    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
-  } else { \
-    put_byte((uch)((w) & 0xff)); \
-    put_byte((uch)((ush)(w) >> 8)); \
-  } \
-}
-
-/* Output a 32 bit value to the bit stream, lsb first */
-#define put_long(n) { \
-    put_short((n) & 0xffff); \
-    put_short(((ulg)(n)) >> 16); \
-}
-
-#define seekable()    0                        /* force sequential output */
-#define translate_eol 0                        /* no option -a yet */
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error_msg(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-#define WARN(msg) {if (!quiet) fprintf msg ; \
-                  if (exit_code == OK) exit_code = WARNING;}
-
-#ifndef MAX_PATH_LEN
-#  define MAX_PATH_LEN   1024  /* max pathname length */
-#endif
-
-
-
-       /* from zip.c: */
-static int zip (int in, int out);
-static int file_read (char *buf, unsigned size);
-
-       /* from gzip.c */
-static RETSIGTYPE abort_gzip (void);
-
-               /* from deflate.c */
-static void lm_init (ush * flags);
-static ulg deflate (void);
-
-               /* from trees.c */
-static void ct_init (ush * attr, int *methodp);
-static int ct_tally (int dist, int lc);
-static ulg flush_block (char *buf, ulg stored_len, int eof);
-
-               /* from bits.c */
-static void bi_init (file_t zipfile);
-static void send_bits (int value, int length);
-static unsigned bi_reverse (unsigned value, int length);
-static void bi_windup (void);
-static void copy_block (char *buf, unsigned len, int header);
-static int (*read_buf) (char *buf, unsigned size);
-
-       /* from util.c: */
-static void flush_outbuf (void);
-
-/* lzw.h -- define the lzw functions.
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if !defined(OF) && defined(lint)
-#  include "gzip.h"
-#endif
-
-#ifndef BITS
-#  define BITS 16
-#endif
-#define INIT_BITS 9                            /* Initial number of bits per code */
-
-#define BIT_MASK    0x1f               /* Mask for 'number of compression bits' */
-/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
- * It's a pity that old uncompress does not check bit 0x20. That makes
- * extension of the format actually undesirable because old compress
- * would just crash on the new format instead of giving a meaningful
- * error message. It does check the number of bits, but it's more
- * helpful to say "unsupported format, get a new version" than
- * "can only handle 16 bits".
- */
-
-/* tailor.h -- target dependent definitions
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/* The target dependent definitions should be defined here only.
- * The target dependent functions should be defined in tailor.c.
- */
-
-
-       /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03                        /* assume Unix */
-#endif
-
-#ifndef PATH_SEP
-#  define PATH_SEP '/'
-#endif
-
-#ifndef OPTIONS_VAR
-#  define OPTIONS_VAR "GZIP"
-#endif
-
-#ifndef Z_SUFFIX
-#  define Z_SUFFIX ".gz"
-#endif
-
-#ifdef MAX_EXT_CHARS
-#  define MAX_SUFFIX  MAX_EXT_CHARS
-#else
-#  define MAX_SUFFIX  30
-#endif
-
-               /* global buffers */
-
-DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
-DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
-DECLARE(ush, d_buf, DIST_BUFSIZE);
-DECLARE(uch, window, 2L * WSIZE);
-DECLARE(ush, tab_prefix, 1L << BITS);
-
-static int crc_table_empty = 1;
-
-static int foreground;                                 /* set if program run in foreground */
-static int method = DEFLATED;  /* compression method */
-static int exit_code = OK;             /* program exit code */
-static int part_nb;                                    /* number of parts in .gz file */
-static long time_stamp;                                /* original time stamp (modification time) */
-static long ifile_size;                                /* input file size, -1 for devices (debug only) */
-static char z_suffix[MAX_SUFFIX + 1];  /* default suffix (can be set with --suffix) */
-static int z_len;                                              /* strlen(z_suffix) */
-
-static char ifname[MAX_PATH_LEN];              /* input file name */
-static char ofname[MAX_PATH_LEN];              /* output file name */
-static int ifd;                                                /* input file descriptor */
-static int ofd;                                                /* output file descriptor */
-static unsigned insize;                                /* valid bytes in inbuf */
-static unsigned outcnt;                                /* bytes in output buffer */
-
-/* ========================================================================
- * Signal and error handler.
- */
-static void abort_gzip()
-{
-       exit(ERROR);
-}
-
-/* ===========================================================================
- * Clear input and output buffers
- */
-static void clear_bufs(void)
-{
-       outcnt = 0;
-       insize = 0;
-       bytes_in = 0L;
-}
-
-static void write_error_msg()
-{
-       fprintf(stderr, "\n");
-       perror("");
-       abort_gzip();
-}
-
-/* ===========================================================================
- * Does the same as write(), but also handles partial pipe writes and checks
- * for error return.
- */
-static void write_buf(int fd, void *buf, unsigned cnt)
-{
-       unsigned n;
-
-       while ((n = write(fd, buf, cnt)) != cnt) {
-               if (n == (unsigned) (-1)) {
-                       write_error_msg();
-               }
-               cnt -= n;
-               buf = (void *) ((char *) buf + n);
-       }
-}
-
-/* ===========================================================================
- * Run a set of bytes through the crc shift register.  If s is a NULL
- * pointer, then initialize the crc shift register contents instead.
- * Return the current crc in either case.
- */
-static ulg updcrc(uch *s, unsigned n)
-{
-       static ulg crc = (ulg) 0xffffffffL;     /* shift register contents */
-       register ulg c;                         /* temporary variable */
-       static unsigned long crc_32_tab[256];
-       if (crc_table_empty) {
-               unsigned long csr;      /* crc shift register */
-               unsigned long e=0;      /* polynomial exclusive-or pattern */
-               int i;                /* counter for all possible eight bit values */
-               int k;                /* byte being shifted into crc apparatus */
-
-               /* terms of polynomial defining this crc (except x^32): */
-               static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-               /* Make exclusive-or pattern from polynomial (0xedb88320) */
-               for (i = 0; i < sizeof(p)/sizeof(int); i++)
-                       e |= 1L << (31 - p[i]);
-
-               /* Compute and print table of CRC's, five per line */
-               crc_32_tab[0] = 0x00000000L;
-               for (i = 1; i < 256; i++) {
-                       csr = i;
-                  /* The idea to initialize the register with the byte instead of
-                    * zero was stolen from Haruhiko Okumura's ar002
-                    */
-                       for (k = 8; k; k--)
-                               csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1;
-                       crc_32_tab[i]=csr;
-               }
-       }
-
-       if (s == NULL) {
-               c = 0xffffffffL;
-       } else {
-               c = crc;
-               if (n)
-                       do {
-                               c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8);
-                       } while (--n);
-       }
-       crc = c;
-       return c ^ 0xffffffffL;         /* (instead of ~c for 64-bit machines) */
-}
-
-/* bits.c -- output variable-length bit strings
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-
-/*
- *  PURPOSE
- *
- *      Output variable-length bit strings. Compression can be done
- *      to a file or to memory. (The latter is not supported in this version.)
- *
- *  DISCUSSION
- *
- *      The PKZIP "deflate" file format interprets compressed file data
- *      as a sequence of bits.  Multi-bit strings in the file may cross
- *      byte boundaries without restriction.
- *
- *      The first bit of each byte is the low-order bit.
- *
- *      The routines in this file allow a variable-length bit value to
- *      be output right-to-left (useful for literal values). For
- *      left-to-right output (useful for code strings from the tree routines),
- *      the bits must have been reversed first with bi_reverse().
- *
- *      For in-memory compression, the compressed bit stream goes directly
- *      into the requested output buffer. The input data is read in blocks
- *      by the mem_read() function. The buffer is limited to 64K on 16 bit
- *      machines.
- *
- *  INTERFACE
- *
- *      void bi_init (FILE *zipfile)
- *          Initialize the bit string routines.
- *
- *      void send_bits (int value, int length)
- *          Write out a bit string, taking the source bits right to
- *          left.
- *
- *      int bi_reverse (int value, int length)
- *          Reverse the bits of a bit string, taking the source bits left to
- *          right and emitting them right to left.
- *
- *      void bi_windup (void)
- *          Write out any remaining bits in an incomplete byte.
- *
- *      void copy_block(char *buf, unsigned len, int header)
- *          Copy a stored block to the zip file, storing first the length and
- *          its one's complement if requested.
- *
- */
-
-/* ===========================================================================
- * Local data used by the "bit string" routines.
- */
-
-static file_t zfile;                           /* output gzip file */
-
-static unsigned short bi_buf;
-
-/* Output buffer. bits are inserted starting at the bottom (least significant
- * bits).
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-static int bi_valid;
-
-/* Current input function. Set to mem_read for in-memory compression */
-
-#ifdef DEBUG
-ulg bits_sent;                                 /* bit length of the compressed data */
-#endif
-
-/* ===========================================================================
- * Initialize the bit string routines.
- */
-static void bi_init(file_t zipfile)
-{
-       zfile = zipfile;
-       bi_buf = 0;
-       bi_valid = 0;
-#ifdef DEBUG
-       bits_sent = 0L;
-#endif
-
-       /* Set the defaults for file compression. They are set by memcompress
-        * for in-memory compression.
-        */
-       if (zfile != NO_FILE) {
-               read_buf = file_read;
-       }
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-static void send_bits(int value, int length)
-{
-#ifdef DEBUG
-       Tracev((stderr, " l %2d v %4x ", length, value));
-       Assert(length > 0 && length <= 15, "invalid length");
-       bits_sent += (ulg) length;
-#endif
-       /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-        * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-        * unused bits in value.
-        */
-       if (bi_valid > (int) Buf_size - length) {
-               bi_buf |= (value << bi_valid);
-               put_short(bi_buf);
-               bi_buf = (ush) value >> (Buf_size - bi_valid);
-               bi_valid += length - Buf_size;
-       } else {
-               bi_buf |= value << bi_valid;
-               bi_valid += length;
-       }
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-static unsigned bi_reverse(unsigned code, int len)
-{
-       register unsigned res = 0;
-
-       do {
-               res |= code & 1;
-               code >>= 1, res <<= 1;
-       } while (--len > 0);
-       return res >> 1;
-}
-
-/* ===========================================================================
- * Write out any remaining bits in an incomplete byte.
- */
-static void bi_windup()
-{
-       if (bi_valid > 8) {
-               put_short(bi_buf);
-       } else if (bi_valid > 0) {
-               put_byte(bi_buf);
-       }
-       bi_buf = 0;
-       bi_valid = 0;
-#ifdef DEBUG
-       bits_sent = (bits_sent + 7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block to the zip file, storing first the length and its
- * one's complement if requested.
- */
-static void copy_block(char *buf, unsigned len, int header)
-{
-       bi_windup();                            /* align on byte boundary */
-
-       if (header) {
-               put_short((ush) len);
-               put_short((ush) ~ len);
-#ifdef DEBUG
-               bits_sent += 2 * 16;
-#endif
-       }
-#ifdef DEBUG
-       bits_sent += (ulg) len << 3;
-#endif
-       while (len--) {
-               put_byte(*buf++);
-       }
-}
-
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/*
- *  PURPOSE
- *
- *      Identify new text as repetitions of old text within a fixed-
- *      length sliding window trailing behind the new text.
- *
- *  DISCUSSION
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many info-zippers for bug reports and testing.
- *
- *  REFERENCES
- *
- *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- *  INTERFACE
- *
- *      void lm_init (int pack_level, ush *flags)
- *          Initialize the "longest match" routines for a new file
- *
- *      ulg deflate (void)
- *          Processes a new input file and return its compressed length. Sets
- *          the compressed length, crc, deflate flags and internal file
- *          attributes.
- */
-
-
-/* ===========================================================================
- * Configuration parameters
- */
-
-/* Compile with MEDIUM_MEM to reduce the memory requirements or
- * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
- * entire input file can be held in memory (not possible on 16 bit systems).
- * Warning: defining these symbols affects HASH_BITS (see below) and thus
- * affects the compression ratio. The compressed output
- * is still correct, and might even be smaller in some cases.
- */
-
-#ifdef SMALL_MEM
-#   define HASH_BITS  13               /* Number of bits used to hash strings */
-#endif
-#ifdef MEDIUM_MEM
-#   define HASH_BITS  14
-#endif
-#ifndef HASH_BITS
-#   define HASH_BITS  15
-   /* For portability to 16 bit machines, do not use values above 15. */
-#endif
-
-/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
- * window with tab_suffix. Check that we can do this:
- */
-#if (WSIZE<<1) > (1<<BITS)
-#  error cannot overlay window with tab_suffix and prev with tab_prefix0
-#endif
-#if HASH_BITS > BITS-1
-#  error cannot overlay head with tab_prefix1
-#endif
-#define HASH_SIZE (unsigned)(1<<HASH_BITS)
-#define HASH_MASK (HASH_SIZE-1)
-#define WMASK     (WSIZE-1)
-/* HASH_SIZE and WSIZE must be powers of two */
-#define NIL 0
-/* Tail of hash chains */
-#define FAST 4
-#define SLOW 2
-/* speed options for the general purpose bit flag */
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-/* ===========================================================================
- * Local data used by the "longest match" routines.
- */
-typedef ush Pos;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-/* DECLARE(uch, window, 2L*WSIZE); */
-/* Sliding window. Input bytes are read into the second half of the window,
- * and move to the first half later to keep a dictionary of at least WSIZE
- * bytes. With this organization, matches are limited to a distance of
- * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
- * performed with a length multiple of the block size. Also, it limits
- * the window size to 64K, which is quite useful on MSDOS.
- * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
- * be less efficient).
- */
-
-/* DECLARE(Pos, prev, WSIZE); */
-/* Link to older string with same hash index. To limit the size of this
- * array to 64K, this link is maintained only for the last 32K strings.
- * An index in this array is thus a window index modulo 32K.
- */
-
-/* DECLARE(Pos, head, 1<<HASH_BITS); */
-/* Heads of the hash chains or NIL. */
-
-static const ulg window_size = (ulg) 2 * WSIZE;
-
-/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
- * input file length plus MIN_LOOKAHEAD.
- */
-
-static long block_start;
-
-/* window position at the beginning of the current output block. Gets
- * negative when the window is moved backwards.
- */
-
-static unsigned ins_h;                 /* hash index of string to be inserted */
-
-#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
-/* Number of bits by which ins_h and del_h must be shifted at each
- * input step. It must be such that after MIN_MATCH steps, the oldest
- * byte no longer takes part in the hash key, that is:
- *   H_SHIFT * MIN_MATCH >= HASH_BITS
- */
-
-static unsigned int prev_length;
-
-/* Length of the best match at previous step. Matches not greater than this
- * are discarded. This is used in the lazy match evaluation.
- */
-
-static unsigned strstart;                      /* start of string to insert */
-static unsigned match_start;           /* start of matching string */
-static int eofile;                             /* flag set at end of input file */
-static unsigned lookahead;             /* number of valid bytes ahead in window */
-
-static const unsigned max_chain_length=4096;
-
-/* To speed up deflation, hash chains are never searched beyond this length.
- * A higher limit improves compression ratio but degrades the speed.
- */
-
-static const unsigned int max_lazy_match=258;
-
-/* Attempt to find a better match only when the current match is strictly
- * smaller than this value. This mechanism is used only for compression
- * levels >= 4.
- */
-#define max_insert_length  max_lazy_match
-/* Insert new strings in the hash table only if the match length
- * is not greater than this length. This saves time but degrades compression.
- * max_insert_length is used only for compression levels <= 3.
- */
-
-static const unsigned good_match=32;
-
-/* Use a faster search when the previous match is longer than this */
-
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-
-static const int nice_match=258;                       /* Stop searching when current match exceeds this */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-/* ===========================================================================
- *  Prototypes for local functions.
- */
-static void fill_window (void);
-
-static int longest_match (IPos cur_match);
-
-#ifdef DEBUG
-static void check_match (IPos start, IPos match, int length);
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
-
-/* ===========================================================================
- * Insert string s in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of s are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, match_head) \
-   (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
-    prev[(s) & WMASK] = match_head = head[ins_h], \
-    head[ins_h] = (s))
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new file
- */
-static void lm_init(ush *flags)
-{
-       register unsigned j;
-
-       /* Initialize the hash table. */
-       memzero((char *) head, HASH_SIZE * sizeof(*head));
-       /* prev will be initialized on the fly */
-
-       *flags |= SLOW;
-       /* ??? reduce max_chain_length for binary files */
-
-       strstart = 0;
-       block_start = 0L;
-
-       lookahead = read_buf((char *) window,
-                                                sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
-
-       if (lookahead == 0 || lookahead == (unsigned) EOF) {
-               eofile = 1, lookahead = 0;
-               return;
-       }
-       eofile = 0;
-       /* Make sure that we always have enough lookahead. This is important
-        * if input comes from a device such as a tty.
-        */
-       while (lookahead < MIN_LOOKAHEAD && !eofile)
-               fill_window();
-
-       ins_h = 0;
-       for (j = 0; j < MIN_MATCH - 1; j++)
-               UPDATE_HASH(ins_h, window[j]);
-       /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
-        * not important since only literal bytes will be emitted.
-        */
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- */
-
-/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
- * match.s. The code is functionally equivalent, so you can use the C version
- * if desired.
- */
-static int longest_match(IPos cur_match)
-{
-       unsigned chain_length = max_chain_length;       /* max hash chain length */
-       register uch *scan = window + strstart; /* current string */
-       register uch *match;            /* matched string */
-       register int len;                       /* length of current match */
-       int best_len = prev_length;     /* best match length so far */
-       IPos limit =
-
-               strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL;
-       /* Stop when cur_match becomes <= limit. To simplify the code,
-        * we prevent matches with the string of window index 0.
-        */
-
-/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
- * It is easy to get rid of this optimization if necessary.
- */
-#if HASH_BITS < 8 || MAX_MATCH != 258
-#  error Code too clever
-#endif
-       register uch *strend = window + strstart + MAX_MATCH;
-       register uch scan_end1 = scan[best_len - 1];
-       register uch scan_end = scan[best_len];
-
-       /* Do not waste too much time if we already have a good match: */
-       if (prev_length >= good_match) {
-               chain_length >>= 2;
-       }
-       Assert(strstart <= window_size - MIN_LOOKAHEAD,
-                  "insufficient lookahead");
-
-       do {
-               Assert(cur_match < strstart, "no future");
-               match = window + cur_match;
-
-               /* Skip to next match if the match length cannot increase
-                * or if the match length is less than 2:
-                */
-               if (match[best_len] != scan_end ||
-                       match[best_len - 1] != scan_end1 ||
-                       *match != *scan || *++match != scan[1])
-                       continue;
-
-               /* The check at best_len-1 can be removed because it will be made
-                * again later. (This heuristic is not always a win.)
-                * It is not necessary to compare scan[2] and match[2] since they
-                * are always equal when the other bytes match, given that
-                * the hash keys are equal and that HASH_BITS >= 8.
-                */
-               scan += 2, match++;
-
-               /* We check for insufficient lookahead only every 8th comparison;
-                * the 256th check will be made at strstart+258.
-                */
-               do {
-               } while (*++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                scan < strend);
-
-               len = MAX_MATCH - (int) (strend - scan);
-               scan = strend - MAX_MATCH;
-
-               if (len > best_len) {
-                       match_start = cur_match;
-                       best_len = len;
-                       if (len >= nice_match)
-                               break;
-                       scan_end1 = scan[best_len - 1];
-                       scan_end = scan[best_len];
-               }
-       } while ((cur_match = prev[cur_match & WMASK]) > limit
-                        && --chain_length != 0);
-
-       return best_len;
-}
-
-#ifdef DEBUG
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-static void check_match(IPos start, IPos match, int length)
-{
-       /* check that the match is indeed a match */
-       if (memcmp((char *) window + match,
-                          (char *) window + start, length) != EQUAL) {
-               fprintf(stderr,
-                               " start %d, match %d, length %d\n", start, match, length);
-               error_msg("invalid match");
-       }
-       if (verbose > 1) {
-               fprintf(stderr, "\\[%d,%d]", start - match, length);
-               do {
-                       putc(window[start++], stderr);
-               } while (--length != 0);
-       }
-}
-#else
-#  define check_match(start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead, and sets eofile if end of input file.
- * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
- * OUT assertions: at least one byte has been read, or eofile is set;
- *    file reads are performed for at least two bytes (required for the
- *    translate_eol option).
- */
-static void fill_window()
-{
-       register unsigned n, m;
-       unsigned more =
-
-               (unsigned) (window_size - (ulg) lookahead - (ulg) strstart);
-       /* Amount of free space at the end of the window. */
-
-       /* If the window is almost full and there is insufficient lookahead,
-        * move the upper half to the lower one to make room in the upper half.
-        */
-       if (more == (unsigned) EOF) {
-               /* Very unlikely, but possible on 16 bit machine if strstart == 0
-                * and lookahead == 1 (input done one byte at time)
-                */
-               more--;
-       } else if (strstart >= WSIZE + MAX_DIST) {
-               /* By the IN assertion, the window is not empty so we can't confuse
-                * more == 0 with more == 64K on a 16 bit machine.
-                */
-               Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM");
-
-               memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE);
-               match_start -= WSIZE;
-               strstart -= WSIZE;              /* we now have strstart >= MAX_DIST: */
-
-               block_start -= (long) WSIZE;
-
-               for (n = 0; n < HASH_SIZE; n++) {
-                       m = head[n];
-                       head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
-               }
-               for (n = 0; n < WSIZE; n++) {
-                       m = prev[n];
-                       prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
-                       /* If n is not on any hash chain, prev[n] is garbage but
-                        * its value will never be used.
-                        */
-               }
-               more += WSIZE;
-       }
-       /* At this point, more >= 2 */
-       if (!eofile) {
-               n = read_buf((char *) window + strstart + lookahead, more);
-               if (n == 0 || n == (unsigned) EOF) {
-                       eofile = 1;
-               } else {
-                       lookahead += n;
-               }
-       }
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK(eof) \
-   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
-                (char*)NULL, (long)strstart - block_start, (eof))
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-static ulg deflate()
-{
-       IPos hash_head;                         /* head of hash chain */
-       IPos prev_match;                        /* previous match */
-       int flush;                                      /* set if current block must be flushed */
-       int match_available = 0;        /* set if previous match exists */
-       register unsigned match_length = MIN_MATCH - 1; /* length of best match */
-
-       /* Process the input block. */
-       while (lookahead != 0) {
-               /* Insert the string window[strstart .. strstart+2] in the
-                * dictionary, and set hash_head to the head of the hash chain:
-                */
-               INSERT_STRING(strstart, hash_head);
-
-               /* Find the longest match, discarding those <= prev_length.
-                */
-               prev_length = match_length, prev_match = match_start;
-               match_length = MIN_MATCH - 1;
-
-               if (hash_head != NIL && prev_length < max_lazy_match &&
-                       strstart - hash_head <= MAX_DIST) {
-                       /* To simplify the code, we prevent matches with the string
-                        * of window index 0 (in particular we have to avoid a match
-                        * of the string with itself at the start of the input file).
-                        */
-                       match_length = longest_match(hash_head);
-                       /* longest_match() sets match_start */
-                       if (match_length > lookahead)
-                               match_length = lookahead;
-
-                       /* Ignore a length 3 match if it is too distant: */
-                       if (match_length == MIN_MATCH
-                               && strstart - match_start > TOO_FAR) {
-                               /* If prev_match is also MIN_MATCH, match_start is garbage
-                                * but we will ignore the current match anyway.
-                                */
-                               match_length--;
-                       }
-               }
-               /* If there was a match at the previous step and the current
-                * match is not better, output the previous match:
-                */
-               if (prev_length >= MIN_MATCH && match_length <= prev_length) {
-
-                       check_match(strstart - 1, prev_match, prev_length);
-
-                       flush =
-                               ct_tally(strstart - 1 - prev_match,
-                                                prev_length - MIN_MATCH);
-
-                       /* Insert in hash table all strings up to the end of the match.
-                        * strstart-1 and strstart are already inserted.
-                        */
-                       lookahead -= prev_length - 1;
-                       prev_length -= 2;
-                       do {
-                               strstart++;
-                               INSERT_STRING(strstart, hash_head);
-                               /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                                * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
-                                * these bytes are garbage, but it does not matter since the
-                                * next lookahead bytes will always be emitted as literals.
-                                */
-                       } while (--prev_length != 0);
-                       match_available = 0;
-                       match_length = MIN_MATCH - 1;
-                       strstart++;
-                       if (flush)
-                               FLUSH_BLOCK(0), block_start = strstart;
-
-               } else if (match_available) {
-                       /* If there was no match at the previous position, output a
-                        * single literal. If there was a match but the current match
-                        * is longer, truncate the previous match to a single literal.
-                        */
-                       Tracevv((stderr, "%c", window[strstart - 1]));
-                       if (ct_tally(0, window[strstart - 1])) {
-                               FLUSH_BLOCK(0), block_start = strstart;
-                       }
-                       strstart++;
-                       lookahead--;
-               } else {
-                       /* There is no previous match to compare with, wait for
-                        * the next step to decide.
-                        */
-                       match_available = 1;
-                       strstart++;
-                       lookahead--;
-               }
-               Assert(strstart <= isize && lookahead <= isize, "a bit too far");
-
-               /* Make sure that we always have enough lookahead, except
-                * at the end of the input file. We need MAX_MATCH bytes
-                * for the next match, plus MIN_MATCH bytes to insert the
-                * string following the next match.
-                */
-               while (lookahead < MIN_LOOKAHEAD && !eofile)
-                       fill_window();
-       }
-       if (match_available)
-               ct_tally(0, window[strstart - 1]);
-
-       return FLUSH_BLOCK(1);          /* eof */
-}
-
-/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-/* Compress files with zip algorithm and 'compress' interface.
- * See usage() and help() functions below for all options.
- * Outputs:
- *        file.gz:   compressed file with same mode, owner, and utimes
- *     or stdout with -c option or if stdin used as input.
- * If the output file name had to be truncated, the original name is kept
- * in the compressed file.
- */
-
-               /* configuration */
-
-typedef struct dirent dir_type;
-
-typedef RETSIGTYPE(*sig_type) (int);
-
-
-/* ======================================================================== */
-// int main (argc, argv)
-//    int argc;
-//    char **argv;
-int gzip_main(int argc, char **argv)
-{
-       int result;
-       int inFileNum;
-       int outFileNum;
-       struct stat statBuf;
-       char *delFileName;
-       int tostdout = 0;
-       int fromstdin = 0;
-       int force = 0;
-       int opt;
-
-       while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) {
-               switch (opt) {
-               case 'c':
-                       tostdout = 1;
-                       break;
-               case 'f':
-                       force = 1;
-                       break;
-               /* Ignore 1-9 (compression level) options */
-               case '1': case '2': case '3': case '4': case '5':
-               case '6': case '7': case '8': case '9':
-                       break;
-               case 'q':
-                       break;
-#ifdef BB_GUNZIP
-               case 'd':
-                       optind = 1;
-                       return gunzip_main(argc, argv);
-#endif
-               default:
-                       show_usage();
-               }
-       }
-       if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) {
-               fromstdin = 1;
-               tostdout = 1;
-       }
-
-       if (isatty(fileno(stdout)) && tostdout==1 && force==0)
-               error_msg_and_die( "compressed data not written to terminal. Use -f to force it.");
-
-       foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
-       if (foreground) {
-               (void) signal(SIGINT, (sig_type) abort_gzip);
-       }
-#ifdef SIGTERM
-       if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGTERM, (sig_type) abort_gzip);
-       }
-#endif
-#ifdef SIGHUP
-       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGHUP, (sig_type) abort_gzip);
-       }
-#endif
-
-       strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1);
-       z_len = strlen(z_suffix);
-
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
-       ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
-       ALLOC(ush, d_buf, DIST_BUFSIZE);
-       ALLOC(uch, window, 2L * WSIZE);
-       ALLOC(ush, tab_prefix, 1L << BITS);
-
-       if (fromstdin == 1) {
-               strcpy(ofname, "stdin");
-
-               inFileNum = fileno(stdin);
-               time_stamp = 0;                 /* time unknown by default */
-               ifile_size = -1L;               /* convention for unknown size */
-       } else {
-               /* Open up the input file */
-               strncpy(ifname, argv[optind], MAX_PATH_LEN);
-
-               /* Open input file */
-               inFileNum = open(ifname, O_RDONLY);
-               if (inFileNum < 0)
-                       perror_msg_and_die("%s", ifname);
-               /* Get the time stamp on the input file. */
-               if (stat(ifname, &statBuf) < 0)
-                       perror_msg_and_die("%s", ifname);
-               time_stamp = statBuf.st_ctime;
-               ifile_size = statBuf.st_size;
-       }
-
-
-       if (tostdout == 1) {
-               /* And get to work */
-               strcpy(ofname, "stdout");
-               outFileNum = fileno(stdout);
-
-               clear_bufs();                   /* clear input and output buffers */
-               part_nb = 0;
-
-               /* Actually do the compression/decompression. */
-               zip(inFileNum, outFileNum);
-
-       } else {
-
-               /* And get to work */
-               strncpy(ofname, ifname, MAX_PATH_LEN - 4);
-               strcat(ofname, ".gz");
-
-
-               /* Open output fille */
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW);
-#else
-               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL);
-#endif
-               if (outFileNum < 0)
-                       perror_msg_and_die("%s", ofname);
-               /* Set permissions on the file */
-               fchmod(outFileNum, statBuf.st_mode);
-
-               clear_bufs();                   /* clear input and output buffers */
-               part_nb = 0;
-
-               /* Actually do the compression/decompression. */
-               result = zip(inFileNum, outFileNum);
-               close(outFileNum);
-               close(inFileNum);
-               /* Delete the original file */
-               if (result == OK)
-                       delFileName = ifname;
-               else
-                       delFileName = ofname;
-
-               if (unlink(delFileName) < 0)
-                       perror_msg_and_die("%s", delFileName);
-       }
-
-       return(exit_code);
-}
-
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/*
- *  PURPOSE
- *
- *      Encode various sets of source values using variable-length
- *      binary code trees.
- *
- *  DISCUSSION
- *
- *      The PKZIP "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in the ZIP file in a compressed form
- *      which is itself a Huffman encoding of the lengths of
- *      all the code strings (in ascending order by source values).
- *      The actual code strings are reconstructed from the lengths in
- *      the UNZIP process, as described in the "application note"
- *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
- *
- *  REFERENCES
- *
- *      Lynch, Thomas J.
- *          Data Compression:  Techniques and Applications, pp. 53-55.
- *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- *
- *  INTERFACE
- *
- *      void ct_init (ush *attr, int *methodp)
- *          Allocate the match buffer, initialize the various tables and save
- *          the location of the internal file attribute (ascii/binary) and
- *          method (DEFLATE/STORE)
- *
- *      void ct_tally (int dist, int lc);
- *          Save the match info and tally the frequency counts.
- *
- *      long flush_block (char *buf, ulg stored_len, int eof)
- *          Determine the best encoding for the current block: dynamic trees,
- *          static trees or store, and output the encoded block to the zip
- *          file. Returns the total compressed length for the file so far.
- *
- */
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-
-static const int extra_lbits[LENGTH_CODES]     /* extra bits for each length code */
-       = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
-               4, 4, 5, 5, 5, 5, 0 };
-
-static const int extra_dbits[D_CODES]  /* extra bits for each distance code */
-       = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
-               10, 10, 11, 11, 12, 12, 13, 13 };
-
-static const int extra_blbits[BL_CODES]        /* extra bits for each bit length code */
-= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#ifndef LIT_BUFSIZE
-#  ifdef SMALL_MEM
-#    define LIT_BUFSIZE  0x2000
-#  else
-#  ifdef MEDIUM_MEM
-#    define LIT_BUFSIZE  0x4000
-#  else
-#    define LIT_BUFSIZE  0x8000
-#  endif
-#  endif
-#endif
-#ifndef DIST_BUFSIZE
-#  define DIST_BUFSIZE  LIT_BUFSIZE
-#endif
-/* Sizes of match buffers for literals/lengths and distances.  There are
- * 4 reasons for limiting LIT_BUFSIZE to 64K:
- *   - frequencies can be kept in 16 bit counters
- *   - if compression is not successful for the first block, all input data is
- *     still in the window so we can still emit a stored block even when input
- *     comes from standard input.  (This can also be done for all blocks if
- *     LIT_BUFSIZE is not greater than 32K.)
- *   - if compression is not successful for a file smaller than 64K, we can
- *     even emit a stored file instead of a stored block (saving 5 bytes).
- *   - creating new Huffman trees less frequently may not provide fast
- *     adaptation to changes in the input data statistics. (Take for
- *     example a binary file with poorly compressible code followed by
- *     a highly compressible string table.) Smaller buffer sizes give
- *     fast adaptation but have of course the overhead of transmitting trees
- *     more frequently.
- *   - I can't count above 4
- * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
- * memory at the expense of compression). Some optimizations would be possible
- * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
- */
-#if LIT_BUFSIZE > INBUFSIZ
-error cannot overlay l_buf and inbuf
-#endif
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) *//* ===========================================================================
- * Local data
- *//* Data structure describing a single value and its code string. */ typedef struct ct_data {
-       union {
-               ush freq;                               /* frequency count */
-               ush code;                               /* bit string */
-       } fc;
-       union {
-               ush dad;                                /* father node in Huffman tree */
-               ush len;                                /* length of bit string */
-       } dl;
-} ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-static ct_data dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-static ct_data dyn_dtree[2 * D_CODES + 1];     /* distance tree */
-
-static ct_data static_ltree[L_CODES + 2];
-
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see ct_init
- * below).
- */
-
-static ct_data static_dtree[D_CODES];
-
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-static ct_data bl_tree[2 * BL_CODES + 1];
-
-/* Huffman tree for the bit lengths */
-
-typedef struct tree_desc {
-       ct_data *dyn_tree;              /* the dynamic tree */
-       ct_data *static_tree;   /* corresponding static tree or NULL */
-       const int *extra_bits;          /* extra bits for each code or NULL */
-       int extra_base;                         /* base index for extra_bits */
-       int elems;                                      /* max number of elements in the tree */
-       int max_length;                         /* max bit length for the codes */
-       int max_code;                           /* largest code with non zero frequency */
-} tree_desc;
-
-static tree_desc l_desc =
-       { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES,
-               MAX_BITS, 0 };
-
-static tree_desc d_desc =
-       { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 };
-
-static tree_desc bl_desc =
-       { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS,
-               0 };
-
-
-static ush bl_count[MAX_BITS + 1];
-
-/* number of codes at each bit length for an optimal tree */
-
-static const uch bl_order[BL_CODES]
-= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-static int heap[2 * L_CODES + 1];      /* heap used to build the Huffman trees */
-static int heap_len;                           /* number of elements in the heap */
-static int heap_max;                           /* element of largest frequency */
-
-/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
- * The same heap array is used to build all trees.
- */
-
-static uch depth[2 * L_CODES + 1];
-
-/* Depth of each subtree used as tie breaker for trees of equal frequency */
-
-static uch length_code[MAX_MATCH - MIN_MATCH + 1];
-
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-static uch dist_code[512];
-
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-static int base_length[LENGTH_CODES];
-
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-static int base_dist[D_CODES];
-
-/* First normalized distance for each code (0 = distance of 1) */
-
-#define l_buf inbuf
-/* DECLARE(uch, l_buf, LIT_BUFSIZE);  buffer for literals or lengths */
-
-/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
-
-static uch flag_buf[(LIT_BUFSIZE / 8)];
-
-/* flag_buf is a bit array distinguishing literals from lengths in
- * l_buf, thus indicating the presence or absence of a distance.
- */
-
-static unsigned last_lit;              /* running index in l_buf */
-static unsigned last_dist;             /* running index in d_buf */
-static unsigned last_flags;            /* running index in flag_buf */
-static uch flags;                              /* current flags not yet saved in flag_buf */
-static uch flag_bit;                           /* current bit used in flags */
-
-/* bits are filled in flags starting at bit 0 (least significant).
- * Note: these flags are overkill in the current code since we don't
- * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
- */
-
-static ulg opt_len;                            /* bit length of current block with optimal trees */
-static ulg static_len;                 /* bit length of current block with static trees */
-
-static ulg compressed_len;             /* total bit length of compressed file */
-
-
-static ush *file_type;                                 /* pointer to UNKNOWN, BINARY or ASCII */
-static int *file_method;                               /* pointer to DEFLATE or STORE */
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-static void init_block (void);
-static void pqdownheap (ct_data * tree, int k);
-static void gen_bitlen (tree_desc * desc);
-static void gen_codes (ct_data * tree, int max_code);
-static void build_tree (tree_desc * desc);
-static void scan_tree (ct_data * tree, int max_code);
-static void send_tree (ct_data * tree, int max_code);
-static int build_bl_tree (void);
-static void send_all_trees (int lcodes, int dcodes, int blcodes);
-static void compress_block (ct_data * ltree, ct_data * dtree);
-static void set_file_type (void);
-
-
-#ifndef DEBUG
-#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else                                                  /* DEBUG */
-#  define send_code(c, tree) \
-     { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Allocate the match buffer, initialize the various tables and save the
- * location of the internal file attribute (ascii/binary) and method
- * (DEFLATE/STORE).
- */
-static void ct_init(ush *attr, int *methodp)
-{
-       int n;                                          /* iterates over tree elements */
-       int bits;                                       /* bit counter */
-       int length;                                     /* length value */
-       int code;                                       /* code value */
-       int dist;                                       /* distance index */
-
-       file_type = attr;
-       file_method = methodp;
-       compressed_len = 0L;
-
-       if (static_dtree[0].Len != 0)
-               return;                                 /* ct_init already called */
-
-       /* Initialize the mapping length (0..255) -> length code (0..28) */
-       length = 0;
-       for (code = 0; code < LENGTH_CODES - 1; code++) {
-               base_length[code] = length;
-               for (n = 0; n < (1 << extra_lbits[code]); n++) {
-                       length_code[length++] = (uch) code;
-               }
-       }
-       Assert(length == 256, "ct_init: length != 256");
-       /* Note that the length 255 (match length 258) can be represented
-        * in two different ways: code 284 + 5 bits or code 285, so we
-        * overwrite length_code[255] to use the best encoding:
-        */
-       length_code[length - 1] = (uch) code;
-
-       /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-       dist = 0;
-       for (code = 0; code < 16; code++) {
-               base_dist[code] = dist;
-               for (n = 0; n < (1 << extra_dbits[code]); n++) {
-                       dist_code[dist++] = (uch) code;
-               }
-       }
-       Assert(dist == 256, "ct_init: dist != 256");
-       dist >>= 7;                                     /* from now on, all distances are divided by 128 */
-       for (; code < D_CODES; code++) {
-               base_dist[code] = dist << 7;
-               for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
-                       dist_code[256 + dist++] = (uch) code;
-               }
-       }
-       Assert(dist == 256, "ct_init: 256+dist != 512");
-
-       /* Construct the codes of the static literal tree */
-       for (bits = 0; bits <= MAX_BITS; bits++)
-               bl_count[bits] = 0;
-       n = 0;
-       while (n <= 143)
-               static_ltree[n++].Len = 8, bl_count[8]++;
-       while (n <= 255)
-               static_ltree[n++].Len = 9, bl_count[9]++;
-       while (n <= 279)
-               static_ltree[n++].Len = 7, bl_count[7]++;
-       while (n <= 287)
-               static_ltree[n++].Len = 8, bl_count[8]++;
-       /* Codes 286 and 287 do not exist, but we must include them in the
-        * tree construction to get a canonical Huffman tree (longest code
-        * all ones)
-        */
-       gen_codes((ct_data *) static_ltree, L_CODES + 1);
-
-       /* The static distance tree is trivial: */
-       for (n = 0; n < D_CODES; n++) {
-               static_dtree[n].Len = 5;
-               static_dtree[n].Code = bi_reverse(n, 5);
-       }
-
-       /* Initialize the first block of the first file: */
-       init_block();
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-static void init_block()
-{
-       int n;                                          /* iterates over tree elements */
-
-       /* Initialize the trees. */
-       for (n = 0; n < L_CODES; n++)
-               dyn_ltree[n].Freq = 0;
-       for (n = 0; n < D_CODES; n++)
-               dyn_dtree[n].Freq = 0;
-       for (n = 0; n < BL_CODES; n++)
-               bl_tree[n].Freq = 0;
-
-       dyn_ltree[END_BLOCK].Freq = 1;
-       opt_len = static_len = 0L;
-       last_lit = last_dist = last_flags = 0;
-       flags = 0;
-       flag_bit = 1;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(tree, top) \
-{\
-    top = heap[SMALLEST]; \
-    heap[SMALLEST] = heap[heap_len--]; \
-    pqdownheap(tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-static void pqdownheap(ct_data *tree, int k)
-{
-       int v = heap[k];
-       int j = k << 1;                         /* left son of k */
-
-       while (j <= heap_len) {
-               /* Set j to the smallest of the two sons: */
-               if (j < heap_len && smaller(tree, heap[j + 1], heap[j]))
-                       j++;
-
-               /* Exit if v is smaller than both sons */
-               if (smaller(tree, v, heap[j]))
-                       break;
-
-               /* Exchange v with the smallest son */
-               heap[k] = heap[j];
-               k = j;
-
-               /* And continue down the tree, setting j to the left son of k */
-               j <<= 1;
-       }
-       heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-static void gen_bitlen(tree_desc *desc)
-{
-       ct_data *tree = desc->dyn_tree;
-       const int *extra = desc->extra_bits;
-       int base = desc->extra_base;
-       int max_code = desc->max_code;
-       int max_length = desc->max_length;
-       ct_data *stree = desc->static_tree;
-       int h;                                          /* heap index */
-       int n, m;                                       /* iterate over the tree elements */
-       int bits;                                       /* bit length */
-       int xbits;                                      /* extra bits */
-       ush f;                                          /* frequency */
-       int overflow = 0;                       /* number of elements with bit length too large */
-
-       for (bits = 0; bits <= MAX_BITS; bits++)
-               bl_count[bits] = 0;
-
-       /* In a first pass, compute the optimal bit lengths (which may
-        * overflow in the case of the bit length tree).
-        */
-       tree[heap[heap_max]].Len = 0;   /* root of the heap */
-
-       for (h = heap_max + 1; h < HEAP_SIZE; h++) {
-               n = heap[h];
-               bits = tree[tree[n].Dad].Len + 1;
-               if (bits > max_length)
-                       bits = max_length, overflow++;
-               tree[n].Len = (ush) bits;
-               /* We overwrite tree[n].Dad which is no longer needed */
-
-               if (n > max_code)
-                       continue;                       /* not a leaf node */
-
-               bl_count[bits]++;
-               xbits = 0;
-               if (n >= base)
-                       xbits = extra[n - base];
-               f = tree[n].Freq;
-               opt_len += (ulg) f *(bits + xbits);
-
-               if (stree)
-                       static_len += (ulg) f *(stree[n].Len + xbits);
-       }
-       if (overflow == 0)
-               return;
-
-       Trace((stderr, "\nbit length overflow\n"));
-       /* This happens for example on obj2 and pic of the Calgary corpus */
-
-       /* Find the first bit length which could increase: */
-       do {
-               bits = max_length - 1;
-               while (bl_count[bits] == 0)
-                       bits--;
-               bl_count[bits]--;               /* move one leaf down the tree */
-               bl_count[bits + 1] += 2;        /* move one overflow item as its brother */
-               bl_count[max_length]--;
-               /* The brother of the overflow item also moves one step up,
-                * but this does not affect bl_count[max_length]
-                */
-               overflow -= 2;
-       } while (overflow > 0);
-
-       /* Now recompute all bit lengths, scanning in increasing frequency.
-        * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-        * lengths instead of fixing only the wrong ones. This idea is taken
-        * from 'ar' written by Haruhiko Okumura.)
-        */
-       for (bits = max_length; bits != 0; bits--) {
-               n = bl_count[bits];
-               while (n != 0) {
-                       m = heap[--h];
-                       if (m > max_code)
-                               continue;
-                       if (tree[m].Len != (unsigned) bits) {
-                               Trace(
-                                         (stderr, "code %d bits %d->%d\n", m, tree[m].Len,
-                                          bits));
-                               opt_len +=
-                                       ((long) bits -
-                                        (long) tree[m].Len) * (long) tree[m].Freq;
-                               tree[m].Len = (ush) bits;
-                       }
-                       n--;
-               }
-       }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-static void gen_codes(ct_data *tree, int max_code)
-{
-       ush next_code[MAX_BITS + 1];    /* next code value for each bit length */
-       ush code = 0;                           /* running code value */
-       int bits;                                       /* bit index */
-       int n;                                          /* code index */
-
-       /* The distribution counts are first used to generate the code values
-        * without bit reversal.
-        */
-       for (bits = 1; bits <= MAX_BITS; bits++) {
-               next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
-       }
-       /* Check that the bit counts in bl_count are consistent. The last code
-        * must be all ones.
-        */
-       Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
-                  "inconsistent bit counts");
-       Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
-
-       for (n = 0; n <= max_code; n++) {
-               int len = tree[n].Len;
-
-               if (len == 0)
-                       continue;
-               /* Now reverse the bits */
-               tree[n].Code = bi_reverse(next_code[len]++, len);
-
-               Tracec(tree != static_ltree,
-                          (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
-                               (isgraph(n) ? n : ' '), len, tree[n].Code,
-                               next_code[len] - 1));
-       }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-static void build_tree(tree_desc *desc)
-{
-       ct_data *tree = desc->dyn_tree;
-       ct_data *stree = desc->static_tree;
-       int elems = desc->elems;
-       int n, m;                                       /* iterate over heap elements */
-       int max_code = -1;                      /* largest code with non zero frequency */
-       int node = elems;                       /* next internal node of the tree */
-
-       /* Construct the initial heap, with least frequent element in
-        * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-        * heap[0] is not used.
-        */
-       heap_len = 0, heap_max = HEAP_SIZE;
-
-       for (n = 0; n < elems; n++) {
-               if (tree[n].Freq != 0) {
-                       heap[++heap_len] = max_code = n;
-                       depth[n] = 0;
-               } else {
-                       tree[n].Len = 0;
-               }
-       }
-
-       /* The pkzip format requires that at least one distance code exists,
-        * and that at least one bit should be sent even if there is only one
-        * possible code. So to avoid special checks later on we force at least
-        * two codes of non zero frequency.
-        */
-       while (heap_len < 2) {
-               int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
-
-               tree[new].Freq = 1;
-               depth[new] = 0;
-               opt_len--;
-               if (stree)
-                       static_len -= stree[new].Len;
-               /* new is 0 or 1 so it does not have extra bits */
-       }
-       desc->max_code = max_code;
-
-       /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-        * establish sub-heaps of increasing lengths:
-        */
-       for (n = heap_len / 2; n >= 1; n--)
-               pqdownheap(tree, n);
-
-       /* Construct the Huffman tree by repeatedly combining the least two
-        * frequent nodes.
-        */
-       do {
-               pqremove(tree, n);              /* n = node of least frequency */
-               m = heap[SMALLEST];             /* m = node of next least frequency */
-
-               heap[--heap_max] = n;   /* keep the nodes sorted by frequency */
-               heap[--heap_max] = m;
-
-               /* Create a new node father of n and m */
-               tree[node].Freq = tree[n].Freq + tree[m].Freq;
-               depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
-               tree[n].Dad = tree[m].Dad = (ush) node;
-#ifdef DUMP_BL_TREE
-               if (tree == bl_tree) {
-                       fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
-                                       node, tree[node].Freq, n, tree[n].Freq, m,
-                                       tree[m].Freq);
-               }
-#endif
-               /* and insert the new node in the heap */
-               heap[SMALLEST] = node++;
-               pqdownheap(tree, SMALLEST);
-
-       } while (heap_len >= 2);
-
-       heap[--heap_max] = heap[SMALLEST];
-
-       /* At this point, the fields freq and dad are set. We can now
-        * generate the bit lengths.
-        */
-       gen_bitlen((tree_desc *) desc);
-
-       /* The field len is now set, we can generate the bit codes */
-       gen_codes((ct_data *) tree, max_code);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree. Updates opt_len to take into account the repeat
- * counts. (The contribution of the bit length codes will be added later
- * during the construction of bl_tree.)
- */
-static void scan_tree(ct_data *tree, int max_code)
-{
-       int n;                                          /* iterates over all tree elements */
-       int prevlen = -1;                       /* last emitted length */
-       int curlen;                                     /* length of current code */
-       int nextlen = tree[0].Len;      /* length of next code */
-       int count = 0;                          /* repeat count of the current code */
-       int max_count = 7;                      /* max repeat count */
-       int min_count = 4;                      /* min repeat count */
-
-       if (nextlen == 0)
-               max_count = 138, min_count = 3;
-       tree[max_code + 1].Len = (ush) 0xffff;  /* guard */
-
-       for (n = 0; n <= max_code; n++) {
-               curlen = nextlen;
-               nextlen = tree[n + 1].Len;
-               if (++count < max_count && curlen == nextlen) {
-                       continue;
-               } else if (count < min_count) {
-                       bl_tree[curlen].Freq += count;
-               } else if (curlen != 0) {
-                       if (curlen != prevlen)
-                               bl_tree[curlen].Freq++;
-                       bl_tree[REP_3_6].Freq++;
-               } else if (count <= 10) {
-                       bl_tree[REPZ_3_10].Freq++;
-               } else {
-                       bl_tree[REPZ_11_138].Freq++;
-               }
-               count = 0;
-               prevlen = curlen;
-               if (nextlen == 0) {
-                       max_count = 138, min_count = 3;
-               } else if (curlen == nextlen) {
-                       max_count = 6, min_count = 3;
-               } else {
-                       max_count = 7, min_count = 4;
-               }
-       }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-static void send_tree(ct_data *tree, int max_code)
-{
-       int n;                                          /* iterates over all tree elements */
-       int prevlen = -1;                       /* last emitted length */
-       int curlen;                                     /* length of current code */
-       int nextlen = tree[0].Len;      /* length of next code */
-       int count = 0;                          /* repeat count of the current code */
-       int max_count = 7;                      /* max repeat count */
-       int min_count = 4;                      /* min repeat count */
-
-/* tree[max_code+1].Len = -1; *//* guard already set */
-       if (nextlen == 0)
-               max_count = 138, min_count = 3;
-
-       for (n = 0; n <= max_code; n++) {
-               curlen = nextlen;
-               nextlen = tree[n + 1].Len;
-               if (++count < max_count && curlen == nextlen) {
-                       continue;
-               } else if (count < min_count) {
-                       do {
-                               send_code(curlen, bl_tree);
-                       } while (--count != 0);
-
-               } else if (curlen != 0) {
-                       if (curlen != prevlen) {
-                               send_code(curlen, bl_tree);
-                               count--;
-                       }
-                       Assert(count >= 3 && count <= 6, " 3_6?");
-                       send_code(REP_3_6, bl_tree);
-                       send_bits(count - 3, 2);
-
-               } else if (count <= 10) {
-                       send_code(REPZ_3_10, bl_tree);
-                       send_bits(count - 3, 3);
-
-               } else {
-                       send_code(REPZ_11_138, bl_tree);
-                       send_bits(count - 11, 7);
-               }
-               count = 0;
-               prevlen = curlen;
-               if (nextlen == 0) {
-                       max_count = 138, min_count = 3;
-               } else if (curlen == nextlen) {
-                       max_count = 6, min_count = 3;
-               } else {
-                       max_count = 7, min_count = 4;
-               }
-       }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-static const int build_bl_tree()
-{
-       int max_blindex;                        /* index of last bit length code of non zero freq */
-
-       /* Determine the bit length frequencies for literal and distance trees */
-       scan_tree((ct_data *) dyn_ltree, l_desc.max_code);
-       scan_tree((ct_data *) dyn_dtree, d_desc.max_code);
-
-       /* Build the bit length tree: */
-       build_tree((tree_desc *) (&bl_desc));
-       /* opt_len now includes the length of the tree representations, except
-        * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-        */
-
-       /* Determine the number of bit length codes to send. The pkzip format
-        * requires that at least 4 bit length codes be sent. (appnote.txt says
-        * 3 but the actual value used is 4.)
-        */
-       for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
-               if (bl_tree[bl_order[max_blindex]].Len != 0)
-                       break;
-       }
-       /* Update opt_len to include the bit length tree and counts */
-       opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
-       Tracev(
-                  (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len,
-                       static_len));
-
-       return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-static void send_all_trees(int lcodes, int dcodes, int blcodes)
-{
-       int rank;                                       /* index in bl_order */
-
-       Assert(lcodes >= 257 && dcodes >= 1
-                  && blcodes >= 4, "not enough codes");
-       Assert(lcodes <= L_CODES && dcodes <= D_CODES
-                  && blcodes <= BL_CODES, "too many codes");
-       Tracev((stderr, "\nbl counts: "));
-       send_bits(lcodes - 257, 5);     /* not +255 as stated in appnote.txt */
-       send_bits(dcodes - 1, 5);
-       send_bits(blcodes - 4, 4);      /* not -3 as stated in appnote.txt */
-       for (rank = 0; rank < blcodes; rank++) {
-               Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-               send_bits(bl_tree[bl_order[rank]].Len, 3);
-       }
-       Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
-
-       send_tree((ct_data *) dyn_ltree, lcodes - 1);   /* send the literal tree */
-       Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
-
-       send_tree((ct_data *) dyn_dtree, dcodes - 1);   /* send the distance tree */
-       Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-static ulg flush_block(char *buf, ulg stored_len, int eof)
-{
-       ulg opt_lenb, static_lenb;      /* opt_len and static_len in bytes */
-       int max_blindex;                        /* index of last bit length code of non zero freq */
-
-       flag_buf[last_flags] = flags;   /* Save the flags for the last 8 items */
-
-       /* Check if the file is ascii or binary */
-       if (*file_type == (ush) UNKNOWN)
-               set_file_type();
-
-       /* Construct the literal and distance trees */
-       build_tree((tree_desc *) (&l_desc));
-       Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
-
-       build_tree((tree_desc *) (&d_desc));
-       Tracev(
-                  (stderr, "\ndist data: dyn %ld, stat %ld", opt_len,
-                       static_len));
-       /* At this point, opt_len and static_len are the total bit lengths of
-        * the compressed block data, excluding the tree representations.
-        */
-
-       /* Build the bit length tree for the above two trees, and get the index
-        * in bl_order of the last bit length code to send.
-        */
-       max_blindex = build_bl_tree();
-
-       /* Determine the best encoding. Compute first the block length in bytes */
-       opt_lenb = (opt_len + 3 + 7) >> 3;
-       static_lenb = (static_len + 3 + 7) >> 3;
-
-       Trace(
-                 (stderr,
-                  "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
-                  opt_lenb, opt_len, static_lenb, static_len, stored_len,
-                  last_lit, last_dist));
-
-       if (static_lenb <= opt_lenb)
-               opt_lenb = static_lenb;
-
-       /* If compression failed and this is the first and last block,
-        * and if the zip file can be seeked (to rewrite the local header),
-        * the whole file is transformed into a stored file:
-        */
-       if (stored_len <= opt_lenb && eof && compressed_len == 0L
-               && seekable()) {
-               /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-               if (buf == (char *) 0)
-                       error_msg("block vanished");
-
-               copy_block(buf, (unsigned) stored_len, 0);      /* without header */
-               compressed_len = stored_len << 3;
-               *file_method = STORED;
-
-       } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) {
-               /* 4: two words for the lengths */
-               /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-                * Otherwise we can't have processed more than WSIZE input bytes since
-                * the last block flush, because compression would have been
-                * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-                * transform a block into a stored block.
-                */
-               send_bits((STORED_BLOCK << 1) + eof, 3);        /* send block type */
-               compressed_len = (compressed_len + 3 + 7) & ~7L;
-               compressed_len += (stored_len + 4) << 3;
-
-               copy_block(buf, (unsigned) stored_len, 1);      /* with header */
-
-       } else if (static_lenb == opt_lenb) {
-               send_bits((STATIC_TREES << 1) + eof, 3);
-               compress_block((ct_data *) static_ltree,
-                                          (ct_data *) static_dtree);
-               compressed_len += 3 + static_len;
-       } else {
-               send_bits((DYN_TREES << 1) + eof, 3);
-               send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1,
-                                          max_blindex + 1);
-               compress_block((ct_data *) dyn_ltree,
-                                          (ct_data *) dyn_dtree);
-               compressed_len += 3 + opt_len;
-       }
-       Assert(compressed_len == bits_sent, "bad compressed size");
-       init_block();
-
-       if (eof) {
-               bi_windup();
-               compressed_len += 7;    /* align on byte boundary */
-       }
-       Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3,
-                       compressed_len - 7 * eof));
-
-       return compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-static int ct_tally(int dist, int lc)
-{
-       l_buf[last_lit++] = (uch) lc;
-       if (dist == 0) {
-               /* lc is the unmatched char */
-               dyn_ltree[lc].Freq++;
-       } else {
-               /* Here, lc is the match length - MIN_MATCH */
-               dist--;                                 /* dist = match distance - 1 */
-               Assert((ush) dist < (ush) MAX_DIST &&
-                          (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) &&
-                          (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match");
-
-               dyn_ltree[length_code[lc] + LITERALS + 1].Freq++;
-               dyn_dtree[d_code(dist)].Freq++;
-
-               d_buf[last_dist++] = (ush) dist;
-               flags |= flag_bit;
-       }
-       flag_bit <<= 1;
-
-       /* Output the flags if they fill a byte: */
-       if ((last_lit & 7) == 0) {
-               flag_buf[last_flags++] = flags;
-               flags = 0, flag_bit = 1;
-       }
-       /* Try to guess if it is profitable to stop the current block here */
-       if ((last_lit & 0xfff) == 0) {
-               /* Compute an upper bound for the compressed length */
-               ulg out_length = (ulg) last_lit * 8L;
-               ulg in_length = (ulg) strstart - block_start;
-               int dcode;
-
-               for (dcode = 0; dcode < D_CODES; dcode++) {
-                       out_length +=
-                               (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
-               }
-               out_length >>= 3;
-               Trace(
-                         (stderr,
-                          "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
-                          last_lit, last_dist, in_length, out_length,
-                          100L - out_length * 100L / in_length));
-               if (last_dist < last_lit / 2 && out_length < in_length / 2)
-                       return 1;
-       }
-       return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE);
-       /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
-        * on 16 bit machines and because stored blocks are restricted to
-        * 64K-1 bytes.
-        */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-static void compress_block(ct_data *ltree, ct_data *dtree)
-{
-       unsigned dist;                          /* distance of matched string */
-       int lc;                                         /* match length or unmatched char (if dist == 0) */
-       unsigned lx = 0;                        /* running index in l_buf */
-       unsigned dx = 0;                        /* running index in d_buf */
-       unsigned fx = 0;                        /* running index in flag_buf */
-       uch flag = 0;                           /* current flags */
-       unsigned code;                          /* the code to send */
-       int extra;                                      /* number of extra bits to send */
-
-       if (last_lit != 0)
-               do {
-                       if ((lx & 7) == 0)
-                               flag = flag_buf[fx++];
-                       lc = l_buf[lx++];
-                       if ((flag & 1) == 0) {
-                               send_code(lc, ltree);   /* send a literal byte */
-                               Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
-                       } else {
-                               /* Here, lc is the match length - MIN_MATCH */
-                               code = length_code[lc];
-                               send_code(code + LITERALS + 1, ltree);  /* send the length code */
-                               extra = extra_lbits[code];
-                               if (extra != 0) {
-                                       lc -= base_length[code];
-                                       send_bits(lc, extra);   /* send the extra length bits */
-                               }
-                               dist = d_buf[dx++];
-                               /* Here, dist is the match distance - 1 */
-                               code = d_code(dist);
-                               Assert(code < D_CODES, "bad d_code");
-
-                               send_code(code, dtree); /* send the distance code */
-                               extra = extra_dbits[code];
-                               if (extra != 0) {
-                                       dist -= base_dist[code];
-                                       send_bits(dist, extra); /* send the extra distance bits */
-                               }
-                       }                                       /* literal or match pair ? */
-                       flag >>= 1;
-               } while (lx < last_lit);
-
-       send_code(END_BLOCK, ltree);
-}
-
-/* ===========================================================================
- * Set the file type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-static void set_file_type()
-{
-       int n = 0;
-       unsigned ascii_freq = 0;
-       unsigned bin_freq = 0;
-
-       while (n < 7)
-               bin_freq += dyn_ltree[n++].Freq;
-       while (n < 128)
-               ascii_freq += dyn_ltree[n++].Freq;
-       while (n < LITERALS)
-               bin_freq += dyn_ltree[n++].Freq;
-       *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
-       if (*file_type == BINARY && translate_eol) {
-               error_msg("-l used on binary file");
-       }
-}
-
-/* zip.c -- compress files to the gzip or pkzip format
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-
-static ulg crc;                                        /* crc on uncompressed file data */
-static long header_bytes;                              /* number of bytes in gzip header */
-
-/* ===========================================================================
- * Deflate in to out.
- * IN assertions: the input and output buffers are cleared.
- *   The variables time_stamp and save_orig_name are initialized.
- */
-static int zip(int in, int out)
-{
-       uch my_flags = 0;                               /* general purpose bit flags */
-       ush attr = 0;                           /* ascii/binary flag */
-       ush deflate_flags = 0;          /* pkzip -es, -en or -ex equivalent */
-
-       ifd = in;
-       ofd = out;
-       outcnt = 0;
-
-       /* Write the header to the gzip file. See algorithm.doc for the format */
-
-
-       method = DEFLATED;
-       put_byte(GZIP_MAGIC[0]);        /* magic header */
-       put_byte(GZIP_MAGIC[1]);
-       put_byte(DEFLATED);                     /* compression method */
-
-       put_byte(my_flags);                     /* general flags */
-       put_long(time_stamp);
-
-       /* Write deflated file to zip file */
-       crc = updcrc(0, 0);
-
-       bi_init(out);
-       ct_init(&attr, &method);
-       lm_init(&deflate_flags);
-
-       put_byte((uch) deflate_flags);  /* extra flags */
-       put_byte(OS_CODE);                      /* OS identifier */
-
-       header_bytes = (long) outcnt;
-
-       (void) deflate();
-
-       /* Write the crc and uncompressed size */
-       put_long(crc);
-       put_long(isize);
-       header_bytes += 2 * sizeof(long);
-
-       flush_outbuf();
-       return OK;
-}
-
-
-/* ===========================================================================
- * Read a new buffer from the current input file, perform end-of-line
- * translation, and update the crc and input file size.
- * IN assertion: size >= 2 (for end-of-line translation)
- */
-static int file_read(char *buf, unsigned size)
-{
-       unsigned len;
-
-       Assert(insize == 0, "inbuf not empty");
-
-       len = read(ifd, buf, size);
-       if (len == (unsigned) (-1) || len == 0)
-               return (int) len;
-
-       crc = updcrc((uch *) buf, len);
-       isize += (ulg) len;
-       return (int) len;
-}
-
-/* ===========================================================================
- * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
- * (used for the compressed data only)
- */
-static void flush_outbuf()
-{
-       if (outcnt == 0)
-               return;
-
-       write_buf(ofd, (char *) outbuf, outcnt);
-       outcnt = 0;
-}
diff --git a/busybox/archival/libunarchive/decompress_unzip.c b/busybox/archival/libunarchive/decompress_unzip.c
deleted file mode 100644 (file)
index ee74621..0000000
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * gunzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
-       "   Copyright (C) 1992-1993 Jean-loup Gailly",
-       "   This program is free software; you can redistribute it and/or modify",
-       "   it under the terms of the GNU General Public License as published by",
-       "   the Free Software Foundation; either version 2, or (at your option)",
-       "   any later version.",
-       "",
-       "   This program is distributed in the hope that it will be useful,",
-       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
-       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
-       "   GNU General Public License for more details.",
-       "",
-       "   You should have received a copy of the GNU General Public License",
-       "   along with this program; if not, write to the Free Software",
-       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
-       0
-};
-#endif
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-static FILE *in_file, *out_file;
-
-/* these are freed by gz_close */
-static unsigned char *window;
-static unsigned long *crc_table;
-
-static unsigned long crc = 0xffffffffL;        /* shift register contents */
-
-/* Return codes from gzip */
-static const int ERROR = 1;
-
-/*
- * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
- */
-static const int WSIZE = 0x8000;
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-static const int BMAX = 16;            /* maximum bit length of any code (16 for explode) */
-static const int N_MAX = 288;          /* maximum number of codes in any set */
-
-static long bytes_out;         /* number of output bytes */
-static unsigned long outcnt;   /* bytes in output buffer */
-
-static unsigned hufts;         /* track memory usage */
-static unsigned long bb;                       /* bit buffer */
-static unsigned bk;            /* bits in bit buffer */
-
-typedef struct huft_s {
-       unsigned char e;                /* number of extra bits or operation */
-       unsigned char b;                /* number of bits in this code or subcode */
-       union {
-               unsigned short n;               /* literal, length base, or distance base */
-               struct huft_s *t;       /* pointer to next level of table */
-       } v;
-} huft_t;
-
-static const unsigned short mask_bits[] = {
-       0x0000,
-       0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-       0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-//static int error_number = 0;
-/* ========================================================================
- * Signal and error handler.
- */
-static void abort_gzip()
-{
-       error_msg("gzip aborted\n");
-       exit(ERROR);
-}
-
-static void make_crc_table()
-{
-       unsigned long table_entry;      /* crc shift register */
-       unsigned long poly = 0;      /* polynomial exclusive-or pattern */
-       int i;                /* counter for all possible eight bit values */
-       int k;                /* byte being shifted into crc apparatus */
-
-       /* terms of polynomial defining this crc (except x^32): */
-       static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-       crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long));
-
-       /* Make exclusive-or pattern from polynomial (0xedb88320) */
-       for (i = 0; i < sizeof(p)/sizeof(int); i++)
-               poly |= 1L << (31 - p[i]);
-
-       /* Compute and print table of CRC's, five per line */
-       for (i = 0; i < 256; i++) {
-               table_entry = i;
-          /* The idea to initialize the register with the byte instead of
-            * zero was stolen from Haruhiko Okumura's ar002
-            */
-               for (k = 8; k; k--) {
-                       table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
-               }
-               crc_table[i]=table_entry;
-       }
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-       int n;
-
-       if (outcnt == 0)
-               return;
-
-       for (n = 0; n < outcnt; n++) {
-               crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
-       }
-
-       if (fwrite(window, 1, outcnt, out_file) != outcnt) {
-               error_msg_and_die("Couldnt write");
-       }
-       bytes_out += (unsigned long) outcnt;
-       outcnt = 0;
-}
-
-/*
- * Free the malloc'ed tables built by huft_build(), which makes a linked
- * list of the tables it made, with the links in a dummy first entry of
- * each table. 
- * t: table to free
- */
-static int huft_free(huft_t *t)
-{
-       huft_t *p, *q;
-
-       /* Go through linked list, freeing from the malloced (t[-1]) address. */
-       p = t;
-       while (p != (huft_t *) NULL) {
-               q = (--p)->v.t;
-               free((char *) p);
-               p = q;
-       }
-       return 0;
-}
-
-/* Given a list of code lengths and a maximum table size, make a set of
- * tables to decode that set of codes.  Return zero on success, one if
- * the given code set is incomplete (the tables are still built in this
- * case), two if the input is invalid (all zero length codes or an
- * oversubscribed set of lengths), and three if not enough memory.
- *
- * b:  code lengths in bits (all assumed <= BMAX)
- * n:  number of codes (assumed <= N_MAX)
- * s:  number of simple-valued codes (0..s-1)
- * d:  list of base values for non-simple codes
- * e:  list of extra bits for non-simple codes
- * t:  result: starting table
- * m:  maximum lookup bits, returns actual
- */
-static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, 
-       const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
-{
-       unsigned a;             /* counter for codes of length k */
-       unsigned c[BMAX + 1];   /* bit length count table */
-       unsigned f;             /* i repeats in table every f entries */
-       int g;                  /* maximum code length */
-       int h;                  /* table level */
-       register unsigned i;    /* counter, current code */
-       register unsigned j;    /* counter */
-       register int k;         /* number of bits in current code */
-       int l;                  /* bits per table (returned in m) */
-       register unsigned *p;           /* pointer into c[], b[], or v[] */
-       register huft_t *q;     /* points to current table */
-       huft_t r;               /* table entry for structure assignment */
-       huft_t *u[BMAX];        /* table stack */
-       unsigned v[N_MAX];      /* values in order of bit length */
-       register int w;         /* bits before this table == (l * h) */
-       unsigned x[BMAX + 1];   /* bit offsets, then code stack */
-       unsigned *xp;           /* pointer into x */
-       int y;                  /* number of dummy codes added */
-       unsigned z;             /* number of entries in current table */
-
-       /* Generate counts for each bit length */
-       memset ((void *)(c), 0, sizeof(c));
-       p = b;
-       i = n;
-       do {
-               c[*p]++;        /* assume all entries <= BMAX */
-               p++;            /* Can't combine with above line (Solaris bug) */
-       } while (--i);
-       if (c[0] == n) {        /* null input--all zero length codes */
-               *t = (huft_t *) NULL;
-               *m = 0;
-               return 0;
-       }
-
-       /* Find minimum and maximum length, bound *m by those */
-       l = *m;
-       for (j = 1; j <= BMAX; j++)
-               if (c[j])
-                       break;
-       k = j;                          /* minimum code length */
-       if ((unsigned) l < j)
-               l = j;
-       for (i = BMAX; i; i--)
-               if (c[i])
-                       break;
-       g = i;                          /* maximum code length */
-       if ((unsigned) l > i)
-               l = i;
-       *m = l;
-
-       /* Adjust last length count to fill out codes, if needed */
-       for (y = 1 << j; j < i; j++, y <<= 1)
-               if ((y -= c[j]) < 0)
-                       return 2;       /* bad input: more codes than bits */
-       if ((y -= c[i]) < 0)
-               return 2;
-       c[i] += y;
-
-       /* Generate starting offsets into the value table for each length */
-       x[1] = j = 0;
-       p = c + 1;
-       xp = x + 2;
-       while (--i) {                   /* note that i == g from above */
-               *xp++ = (j += *p++);
-       }
-
-       /* Make a table of values in order of bit lengths */
-       p = b;
-       i = 0;
-       do {
-               if ((j = *p++) != 0)
-                       v[x[j]++] = i;
-       } while (++i < n);
-
-       /* Generate the Huffman codes and for each, make the table entries */
-       x[0] = i = 0;                   /* first Huffman code is zero */
-       p = v;                          /* grab values in bit order */
-       h = -1;                         /* no tables yet--level -1 */
-       w = -l;                         /* bits decoded == (l * h) */
-       u[0] = (huft_t *) NULL; /* just to keep compilers happy */
-       q = (huft_t *) NULL;    /* ditto */
-       z = 0;                          /* ditto */
-
-       /* go through the bit lengths (k already is bits in shortest code) */
-       for (; k <= g; k++) {
-               a = c[k];
-               while (a--) {
-                       /* here i is the Huffman code of length k bits for value *p */
-                       /* make tables up to required level */
-                       while (k > w + l) {
-                               h++;
-                               w += l;         /* previous table always l bits */
-
-                               /* compute minimum size table less than or equal to l bits */
-                               z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
-                               if ((f = 1 << (j = k - w)) > a + 1) {   /* try a k-w bit table *//* too few codes for k-w bit table */
-                                       f -= a + 1;     /* deduct codes from patterns left */
-                                       xp = c + k;
-                                       while (++j < z) {       /* try smaller tables up to z bits */
-                                               if ((f <<= 1) <= *++xp)
-                                                       break;  /* enough codes to use up j bits */
-                                               f -= *xp;       /* else deduct codes from patterns */
-                                       }
-                               }
-                               z = 1 << j;             /* table entries for j-bit table */
-
-                               /* allocate and link in new table */
-                               if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
-                                       if (h) {
-                                               huft_free(u[0]);
-                                       }
-                                       return 3;       /* not enough memory */
-                               }
-                               hufts += z + 1; /* track memory usage */
-                               *t = q + 1;             /* link to list for huft_free() */
-                               *(t = &(q->v.t)) = NULL;
-                               u[h] = ++q;             /* table starts after link */
-
-                               /* connect to last table, if there is one */
-                               if (h) {
-                                       x[h] = i;       /* save pattern for backing up */
-                                       r.b = (unsigned char) l;        /* bits to dump before this table */
-                                       r.e = (unsigned char) (16 + j); /* bits in this table */
-                                       r.v.t = q;      /* pointer to this table */
-                                       j = i >> (w - l);       /* (get around Turbo C bug) */
-                                       u[h - 1][j] = r;        /* connect to last table */
-                               }
-                       }
-
-                       /* set up table entry in r */
-                       r.b = (unsigned char) (k - w);
-                       if (p >= v + n)
-                               r.e = 99;               /* out of values--invalid code */
-                       else if (*p < s) {
-                               r.e = (unsigned char) (*p < 256 ? 16 : 15);     /* 256 is end-of-block code */
-                               r.v.n = (unsigned short) (*p);  /* simple code is just the value */
-                               p++;                    /* one compiler does not like *p++ */
-                       } else {
-                               r.e = (unsigned char) e[*p - s];        /* non-simple--look up in lists */
-                               r.v.n = d[*p++ - s];
-                       }
-
-                       /* fill code-like entries with r */
-                       f = 1 << (k - w);
-                       for (j = i >> w; j < z; j += f)
-                               q[j] = r;
-
-                       /* backwards increment the k-bit code i */
-                       for (j = 1 << (k - 1); i & j; j >>= 1)
-                               i ^= j;
-                       i ^= j;
-
-                       /* backup over finished tables */
-                       while ((i & ((1 << w) - 1)) != x[h]) {
-                               h--;                    /* don't need to update q */
-                               w -= l;
-                       }
-               }
-       }
-       /* Return true (1) if we were given an incomplete table */
-       return y != 0 && g != 1;
-}
-
-/*
- * inflate (decompress) the codes in a deflated (compressed) block.
- * Return an error code or zero if it all goes ok.
- *
- * tl, td: literal/length and distance decoder tables
- * bl, bd: number of bits decoded by tl[] and td[]
- */
-static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
-{
-       register unsigned long e;               /* table entry flag/number of extra bits */
-       unsigned long n, d;                             /* length and index for copy */
-       unsigned long w;                                /* current window position */
-       huft_t *t;                              /* pointer to table entry */
-       unsigned ml, md;                        /* masks for bl and bd bits */
-       register unsigned long b;                               /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-
-       /* make local copies of globals */
-       b = bb;                                 /* initialize bit buffer */
-       k = bk;
-       w = outcnt;                             /* initialize window position */
-
-       /* inflate the coded data */
-       ml = mask_bits[bl];                     /* precompute masks for speed */
-       md = mask_bits[bd];
-       for (;;) {                              /* do until end of block */
-               while (k < (unsigned) bl) {
-                       b |= ((unsigned long)fgetc(in_file)) << k;
-                       k += 8;
-               }
-               if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
-               do {
-                       if (e == 99) {
-                               return 1;
-                       }
-                       b >>= t->b;
-                       k -= t->b;
-                       e -= 16;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-               b >>= t->b;
-               k -= t->b;
-               if (e == 16) {          /* then it's a literal */
-                       window[w++] = (unsigned char) t->v.n;
-                       if (w == WSIZE) {
-                               outcnt=(w),
-                               flush_window();
-                               w = 0;
-                       }
-               } else {                                /* it's an EOB or a length */
-
-                       /* exit if end of block */
-                       if (e == 15) {
-                               break;
-                       }
-
-                       /* get length of block to copy */
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       n = t->v.n + ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* decode distance of block to copy */
-                       while (k < (unsigned) bd) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-
-                       if ((e = (t = td + ((unsigned) b & md))->e) > 16)
-                               do {
-                                       if (e == 99)
-                                               return 1;
-                                       b >>= t->b;
-                                       k -= t->b;
-                                       e -= 16;
-                                       while (k < e) {
-                                               b |= ((unsigned long)fgetc(in_file)) << k;
-                                               k += 8;
-                                       }
-                               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-                       b >>= t->b;
-                       k -= t->b;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       d = w - t->v.n - ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* do the copy */
-                       do {
-                               n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
-                               if (w - d >= e) {       /* (this test assumes unsigned comparison) */
-                                       memcpy(window + w, window + d, e);
-                                       w += e;
-                                       d += e;
-                               } else                  /* do it slow to avoid memcpy() overlap */
-#endif                                                 /* !NOMEMCPY */
-                                       do {
-                                               window[w++] = window[d++];
-                                       } while (--e);
-                               if (w == WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                       } while (n);
-               }
-       }
-
-       /* restore the globals from the locals */
-       outcnt = w;                     /* restore global window pointer */
-       bb = b;                         /* restore global bit buffer */
-       bk = k;
-
-       /* done */
-       return 0;
-}
-
-/*
- * decompress an inflated block
- * e: last block flag
- *
- * GLOBAL VARIABLES: bb, kk,
- */
-static int inflate_block(int *e)
-{
-       unsigned t;                     /* block type */
-       register unsigned long b;                       /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-       static unsigned short cplens[] = {              /* Copy lengths for literal codes 257..285 */
-               3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-               35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-       };
-       /* note: see note #13 above about the 258 in this list. */
-       static unsigned short cplext[] = {              /* Extra bits for literal codes 257..285 */
-               0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-               3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
-       };                              /* 99==invalid */
-       static unsigned short cpdist[] = {              /* Copy offsets for distance codes 0..29 */
-               1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-               257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-               8193, 12289, 16385, 24577
-       };
-       static unsigned short cpdext[] = {              /* Extra bits for distance codes */
-               0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-               7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-               12, 12, 13, 13
-       };
-
-       /* make local bit buffer */
-       b = bb;
-       k = bk;
-
-       /* read in last block bit */
-       while (k < 1) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       *e = (int) b & 1;
-       b >>= 1;
-       k -= 1;
-
-       /* read in block type */
-       while (k < 2) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       t = (unsigned) b & 3;
-       b >>= 2;
-       k -= 2;
-
-       /* restore the global bit buffer */
-       bb = b;
-       bk = k;
-
-       /* inflate that block type */
-       switch (t) {
-       case 0: /* Inflate stored */
-               {
-                       unsigned long n;                        /* number of bytes in block */
-                       unsigned long w;                        /* current window position */
-                       register unsigned long b_stored;                        /* bit buffer */
-                       register unsigned long k_stored;                /* number of bits in bit buffer */
-
-                       /* make local copies of globals */
-                       b_stored = bb;                          /* initialize bit buffer */
-                       k_stored = bk;
-                       w = outcnt;                     /* initialize window position */
-
-                       /* go to byte boundary */
-                       n = k_stored & 7;
-                       b_stored >>= n;
-                       k_stored -= n;
-
-                       /* get the length and its complement */
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       n = ((unsigned) b_stored & 0xffff);
-                       b_stored >>= 16;
-                       k_stored -= 16;
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       if (n != (unsigned) ((~b_stored) & 0xffff)) {
-                               return 1;               /* error in compressed data */
-                       }
-                       b_stored >>= 16;
-                       k_stored -= 16;
-
-                       /* read and output the compressed data */
-                       while (n--) {
-                               while (k_stored < 8) {
-                                       b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                                       k_stored += 8;
-                               }
-                               window[w++] = (unsigned char) b_stored;
-                               if (w == (unsigned long)WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                               b_stored >>= 8;
-                               k_stored -= 8;
-                       }
-
-                       /* restore the globals from the locals */
-                       outcnt = w;                     /* restore global window pointer */
-                       bb = b_stored;                          /* restore global bit buffer */
-                       bk = k_stored;
-                       return 0;
-               }
-       case 1: /* Inflate fixed 
-                        * decompress an inflated type 1 (fixed Huffman codes) block.  We should
-                        * either replace this with a custom decoder, or at least precompute the
-                        * Huffman tables.
-                        */
-               {
-                       int i;                                  /* temporary variable */
-                       huft_t *tl;                             /* literal/length code table */
-                       huft_t *td;                             /* distance code table */
-                       int bl;                                 /* lookup bits for tl */
-                       int bd;                                 /* lookup bits for td */
-                       unsigned int l[288];    /* length list for huft_build */
-
-                       /* set up literal table */
-                       for (i = 0; i < 144; i++) {
-                               l[i] = 8;
-                       }
-                       for (; i < 256; i++) {
-                               l[i] = 9;
-                       }
-                       for (; i < 280; i++) {
-                               l[i] = 7;
-                       }
-                       for (; i < 288; i++) {  /* make a complete, but wrong code set */
-                               l[i] = 8;
-                       }
-                       bl = 7;
-                       if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               return i;
-                       }
-
-                       /* set up distance table */
-                       for (i = 0; i < 30; i++) {      /* make an incomplete code set */
-                               l[i] = 5;
-                       }
-                       bd = 5;
-                       if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
-                               huft_free(tl);
-                               return i;
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       case 2: /* Inflate dynamic */
-               {
-                       /* Tables for deflate from PKZIP's appnote.txt. */
-                       static unsigned border[] = {    /* Order of the bit length code lengths */
-                               16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
-                       };
-                       int dbits = 6;                                  /* bits in base distance lookup table */
-                       int lbits = 9;                                  /* bits in base literal/length lookup table */
-
-                       int i;                                          /* temporary variables */
-                       unsigned j;
-                       unsigned l;                                     /* last length */
-                       unsigned m;                                     /* mask for bit lengths table */
-                       unsigned n;                                     /* number of lengths to get */
-                       huft_t *tl;                     /* literal/length code table */
-                       huft_t *td;                     /* distance code table */
-                       int bl;                                         /* lookup bits for tl */
-                       int bd;                                         /* lookup bits for td */
-                       unsigned nb;                            /* number of bit length codes */
-                       unsigned nl;                            /* number of literal/length codes */
-                       unsigned nd;                            /* number of distance codes */
-
-                       unsigned ll[286 + 30];          /* literal/length and distance code lengths */
-                       register unsigned long b_dynamic;       /* bit buffer */
-                       register unsigned k_dynamic;            /* number of bits in bit buffer */
-
-                       /* make local bit buffer */
-                       b_dynamic = bb;
-                       k_dynamic = bk;
-
-                       /* read in table lengths */
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nl = 257 + ((unsigned) b_dynamic & 0x1f);       /* number of literal/length codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 4) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nb = 4 + ((unsigned) b_dynamic & 0xf);  /* number of bit length codes */
-                       b_dynamic >>= 4;
-                       k_dynamic -= 4;
-                       if (nl > 286 || nd > 30) {
-                               return 1;       /* bad lengths */
-                       }
-
-                       /* read in bit-length-code lengths */
-                       for (j = 0; j < nb; j++) {
-                               while (k_dynamic < 3) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               ll[border[j]] = (unsigned) b_dynamic & 7;
-                               b_dynamic >>= 3;
-                               k_dynamic -= 3;
-                       }
-                       for (; j < 19; j++) {
-                               ll[border[j]] = 0;
-                       }
-
-                       /* build decoding table for trees--single level, 7 bit lookup */
-                       bl = 7;
-                       if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* read in literal and distance code lengths */
-                       n = nl + nd;
-                       m = mask_bits[bl];
-                       i = l = 0;
-                       while ((unsigned) i < n) {
-                               while (k_dynamic < (unsigned) bl) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               j = (td = tl + ((unsigned) b_dynamic & m))->b;
-                               b_dynamic >>= j;
-                               k_dynamic -= j;
-                               j = td->v.n;
-                               if (j < 16) {                   /* length of code in bits (0..15) */
-                                       ll[i++] = l = j;        /* save last length in l */
-                               }
-                               else if (j == 16) {             /* repeat last length 3 to 6 times */
-                                       while (k_dynamic < 2) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 3);
-                                       b_dynamic >>= 2;
-                                       k_dynamic -= 2;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = l;
-                                       }
-                               } else if (j == 17) {   /* 3 to 10 zero length codes */
-                                       while (k_dynamic < 3) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 7);
-                                       b_dynamic >>= 3;
-                                       k_dynamic -= 3;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               } else {                /* j == 18: 11 to 138 zero length codes */
-                                       while (k_dynamic < 7) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 11 + ((unsigned) b_dynamic & 0x7f);
-                                       b_dynamic >>= 7;
-                                       k_dynamic -= 7;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               }
-                       }
-
-                       /* free decoding table for trees */
-                       huft_free(tl);
-
-                       /* restore the global bit buffer */
-                       bb = b_dynamic;
-                       bk = k_dynamic;
-
-                       /* build the decoding tables for literal/length and distance codes */
-                       bl = lbits;
-                       if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       error_msg("Incomplete literal tree");
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-                       bd = dbits;
-                       if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
-                               if (i == 1) {
-                                       error_msg("incomplete distance tree");
-                                       huft_free(td);
-                               }
-                               huft_free(tl);
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       default:
-               /* bad block type */
-               return 2;
-       }
-}
-
-/*
- * decompress an inflated entry
- *
- * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
- */
-static int inflate()
-{
-       int e;                          /* last block flag */
-       int r;                          /* result code */
-       unsigned h = 0;         /* maximum struct huft's malloc'ed */
-
-       /* initialize window, bit buffer */
-       outcnt = 0;
-       bk = 0;
-       bb = 0;
-
-       /* decompress until the last block */
-       do {
-               hufts = 0;
-               if ((r = inflate_block(&e)) != 0) {
-                       return r;
-               }
-               if (hufts > h) {
-                       h = hufts;
-               }
-       } while (!e);
-
-       /* flush out window */
-       flush_window();
-
-       /* return success */
-       return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- *   the compressed data, from offsets inptr to insize-1 included.
- *   The magic header has already been checked. The output buffer is cleared.
- * in, out: input and output file descriptors
- */
-extern int unzip(FILE *l_in_file, FILE *l_out_file)
-{
-       const int extra_field = 0x04;   /* bit 2 set: extra field present */
-       const int orig_name = 0x08;     /* bit 3 set: original file name present */
-       const int comment = 0x10;       /* bit 4 set: file comment present */
-       unsigned char buf[8];   /* extended local header */
-       unsigned char flags;    /* compression flags */
-       char magic[2];                  /* magic header */
-       int method;
-       typedef void (*sig_type) (int);
-       int exit_code=0;        /* program exit code */
-       int i;
-
-       in_file = l_in_file;
-       out_file = l_out_file;
-
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGINT, (sig_type) abort_gzip);
-       }
-#ifdef SIGTERM
-//     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-//             (void) signal(SIGTERM, (sig_type) abort_gzip);
-//     }
-#endif
-#ifdef SIGHUP
-       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGHUP, (sig_type) abort_gzip);
-       }
-#endif
-
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
-       magic[0] = fgetc(in_file);
-       magic[1] = fgetc(in_file);
-
-       /* Magic header for gzip files, 1F 8B = \037\213 */
-       if (memcmp(magic, "\037\213", 2) != 0) {
-               error_msg("Invalid gzip magic");
-               return EXIT_FAILURE;
-       }
-
-       method = (int) fgetc(in_file);
-       if (method != 8) {
-               error_msg("unknown method %d -- get newer version of gzip", method);
-               exit_code = 1;
-               return -1;
-       }
-
-       flags = (unsigned char) fgetc(in_file);
-
-       /* Ignore time stamp(4), extra flags(1), OS type(1) */
-       for (i = 0; i < 6; i++)
-               fgetc(in_file);
-
-       if ((flags & extra_field) != 0) {
-               size_t extra;
-               extra = fgetc(in_file);
-               extra += fgetc(in_file) << 8;
-
-               for (i = 0; i < extra; i++)
-                       fgetc(in_file);
-       }
-
-       /* Discard original name if any */
-       if ((flags & orig_name) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       /* Discard file comment if any */
-       if ((flags & comment) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       if (method < 0) {
-               printf("it failed\n");
-               return(exit_code);              /* error message already emitted */
-       }
-
-       make_crc_table();
-
-       /* Decompress */
-       if (method == 8) {
-
-               int res = inflate();
-
-               if (res == 3) {
-                       error_msg(memory_exhausted);
-               } else if (res != 0) {
-                       error_msg("invalid compressed data--format violated");
-               }
-
-       } else {
-               error_msg("internal error, invalid method");
-       }
-
-       /* Get the crc and original length
-        * crc32  (see algorithm.doc)
-        * uncompressed input size modulo 2^32
-        */
-       fread(buf, 1, 8, in_file);
-
-       /* Validate decompression - crc */
-       if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
-               error_msg("invalid compressed data--crc error");
-       }
-       /* Validate decompression - size */
-       if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
-               error_msg("invalid compressed data--length error");
-       }
-
-       free(window);
-       free(crc_table);
-
-       return 0;
-}
-
-/*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
- */
-extern void gz_close(int gunzip_pid)
-{
-       if (kill(gunzip_pid, SIGTERM) == -1) {
-               error_msg_and_die("***  Couldnt kill old gunzip process *** aborting");
-       }
-
-       if (waitpid(gunzip_pid, NULL, 0) == -1) {
-               printf("Couldnt wait ?");
-       }
-               free(window);
-               free(crc_table);
-}
diff --git a/busybox/archival/libunarchive/unzip.c b/busybox/archival/libunarchive/unzip.c
deleted file mode 100644 (file)
index ee74621..0000000
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * gunzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
-       "   Copyright (C) 1992-1993 Jean-loup Gailly",
-       "   This program is free software; you can redistribute it and/or modify",
-       "   it under the terms of the GNU General Public License as published by",
-       "   the Free Software Foundation; either version 2, or (at your option)",
-       "   any later version.",
-       "",
-       "   This program is distributed in the hope that it will be useful,",
-       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
-       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
-       "   GNU General Public License for more details.",
-       "",
-       "   You should have received a copy of the GNU General Public License",
-       "   along with this program; if not, write to the Free Software",
-       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
-       0
-};
-#endif
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-static FILE *in_file, *out_file;
-
-/* these are freed by gz_close */
-static unsigned char *window;
-static unsigned long *crc_table;
-
-static unsigned long crc = 0xffffffffL;        /* shift register contents */
-
-/* Return codes from gzip */
-static const int ERROR = 1;
-
-/*
- * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
- */
-static const int WSIZE = 0x8000;
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-static const int BMAX = 16;            /* maximum bit length of any code (16 for explode) */
-static const int N_MAX = 288;          /* maximum number of codes in any set */
-
-static long bytes_out;         /* number of output bytes */
-static unsigned long outcnt;   /* bytes in output buffer */
-
-static unsigned hufts;         /* track memory usage */
-static unsigned long bb;                       /* bit buffer */
-static unsigned bk;            /* bits in bit buffer */
-
-typedef struct huft_s {
-       unsigned char e;                /* number of extra bits or operation */
-       unsigned char b;                /* number of bits in this code or subcode */
-       union {
-               unsigned short n;               /* literal, length base, or distance base */
-               struct huft_s *t;       /* pointer to next level of table */
-       } v;
-} huft_t;
-
-static const unsigned short mask_bits[] = {
-       0x0000,
-       0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-       0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-//static int error_number = 0;
-/* ========================================================================
- * Signal and error handler.
- */
-static void abort_gzip()
-{
-       error_msg("gzip aborted\n");
-       exit(ERROR);
-}
-
-static void make_crc_table()
-{
-       unsigned long table_entry;      /* crc shift register */
-       unsigned long poly = 0;      /* polynomial exclusive-or pattern */
-       int i;                /* counter for all possible eight bit values */
-       int k;                /* byte being shifted into crc apparatus */
-
-       /* terms of polynomial defining this crc (except x^32): */
-       static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-       crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long));
-
-       /* Make exclusive-or pattern from polynomial (0xedb88320) */
-       for (i = 0; i < sizeof(p)/sizeof(int); i++)
-               poly |= 1L << (31 - p[i]);
-
-       /* Compute and print table of CRC's, five per line */
-       for (i = 0; i < 256; i++) {
-               table_entry = i;
-          /* The idea to initialize the register with the byte instead of
-            * zero was stolen from Haruhiko Okumura's ar002
-            */
-               for (k = 8; k; k--) {
-                       table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
-               }
-               crc_table[i]=table_entry;
-       }
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-       int n;
-
-       if (outcnt == 0)
-               return;
-
-       for (n = 0; n < outcnt; n++) {
-               crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
-       }
-
-       if (fwrite(window, 1, outcnt, out_file) != outcnt) {
-               error_msg_and_die("Couldnt write");
-       }
-       bytes_out += (unsigned long) outcnt;
-       outcnt = 0;
-}
-
-/*
- * Free the malloc'ed tables built by huft_build(), which makes a linked
- * list of the tables it made, with the links in a dummy first entry of
- * each table. 
- * t: table to free
- */
-static int huft_free(huft_t *t)
-{
-       huft_t *p, *q;
-
-       /* Go through linked list, freeing from the malloced (t[-1]) address. */
-       p = t;
-       while (p != (huft_t *) NULL) {
-               q = (--p)->v.t;
-               free((char *) p);
-               p = q;
-       }
-       return 0;
-}
-
-/* Given a list of code lengths and a maximum table size, make a set of
- * tables to decode that set of codes.  Return zero on success, one if
- * the given code set is incomplete (the tables are still built in this
- * case), two if the input is invalid (all zero length codes or an
- * oversubscribed set of lengths), and three if not enough memory.
- *
- * b:  code lengths in bits (all assumed <= BMAX)
- * n:  number of codes (assumed <= N_MAX)
- * s:  number of simple-valued codes (0..s-1)
- * d:  list of base values for non-simple codes
- * e:  list of extra bits for non-simple codes
- * t:  result: starting table
- * m:  maximum lookup bits, returns actual
- */
-static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, 
-       const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
-{
-       unsigned a;             /* counter for codes of length k */
-       unsigned c[BMAX + 1];   /* bit length count table */
-       unsigned f;             /* i repeats in table every f entries */
-       int g;                  /* maximum code length */
-       int h;                  /* table level */
-       register unsigned i;    /* counter, current code */
-       register unsigned j;    /* counter */
-       register int k;         /* number of bits in current code */
-       int l;                  /* bits per table (returned in m) */
-       register unsigned *p;           /* pointer into c[], b[], or v[] */
-       register huft_t *q;     /* points to current table */
-       huft_t r;               /* table entry for structure assignment */
-       huft_t *u[BMAX];        /* table stack */
-       unsigned v[N_MAX];      /* values in order of bit length */
-       register int w;         /* bits before this table == (l * h) */
-       unsigned x[BMAX + 1];   /* bit offsets, then code stack */
-       unsigned *xp;           /* pointer into x */
-       int y;                  /* number of dummy codes added */
-       unsigned z;             /* number of entries in current table */
-
-       /* Generate counts for each bit length */
-       memset ((void *)(c), 0, sizeof(c));
-       p = b;
-       i = n;
-       do {
-               c[*p]++;        /* assume all entries <= BMAX */
-               p++;            /* Can't combine with above line (Solaris bug) */
-       } while (--i);
-       if (c[0] == n) {        /* null input--all zero length codes */
-               *t = (huft_t *) NULL;
-               *m = 0;
-               return 0;
-       }
-
-       /* Find minimum and maximum length, bound *m by those */
-       l = *m;
-       for (j = 1; j <= BMAX; j++)
-               if (c[j])
-                       break;
-       k = j;                          /* minimum code length */
-       if ((unsigned) l < j)
-               l = j;
-       for (i = BMAX; i; i--)
-               if (c[i])
-                       break;
-       g = i;                          /* maximum code length */
-       if ((unsigned) l > i)
-               l = i;
-       *m = l;
-
-       /* Adjust last length count to fill out codes, if needed */
-       for (y = 1 << j; j < i; j++, y <<= 1)
-               if ((y -= c[j]) < 0)
-                       return 2;       /* bad input: more codes than bits */
-       if ((y -= c[i]) < 0)
-               return 2;
-       c[i] += y;
-
-       /* Generate starting offsets into the value table for each length */
-       x[1] = j = 0;
-       p = c + 1;
-       xp = x + 2;
-       while (--i) {                   /* note that i == g from above */
-               *xp++ = (j += *p++);
-       }
-
-       /* Make a table of values in order of bit lengths */
-       p = b;
-       i = 0;
-       do {
-               if ((j = *p++) != 0)
-                       v[x[j]++] = i;
-       } while (++i < n);
-
-       /* Generate the Huffman codes and for each, make the table entries */
-       x[0] = i = 0;                   /* first Huffman code is zero */
-       p = v;                          /* grab values in bit order */
-       h = -1;                         /* no tables yet--level -1 */
-       w = -l;                         /* bits decoded == (l * h) */
-       u[0] = (huft_t *) NULL; /* just to keep compilers happy */
-       q = (huft_t *) NULL;    /* ditto */
-       z = 0;                          /* ditto */
-
-       /* go through the bit lengths (k already is bits in shortest code) */
-       for (; k <= g; k++) {
-               a = c[k];
-               while (a--) {
-                       /* here i is the Huffman code of length k bits for value *p */
-                       /* make tables up to required level */
-                       while (k > w + l) {
-                               h++;
-                               w += l;         /* previous table always l bits */
-
-                               /* compute minimum size table less than or equal to l bits */
-                               z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
-                               if ((f = 1 << (j = k - w)) > a + 1) {   /* try a k-w bit table *//* too few codes for k-w bit table */
-                                       f -= a + 1;     /* deduct codes from patterns left */
-                                       xp = c + k;
-                                       while (++j < z) {       /* try smaller tables up to z bits */
-                                               if ((f <<= 1) <= *++xp)
-                                                       break;  /* enough codes to use up j bits */
-                                               f -= *xp;       /* else deduct codes from patterns */
-                                       }
-                               }
-                               z = 1 << j;             /* table entries for j-bit table */
-
-                               /* allocate and link in new table */
-                               if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
-                                       if (h) {
-                                               huft_free(u[0]);
-                                       }
-                                       return 3;       /* not enough memory */
-                               }
-                               hufts += z + 1; /* track memory usage */
-                               *t = q + 1;             /* link to list for huft_free() */
-                               *(t = &(q->v.t)) = NULL;
-                               u[h] = ++q;             /* table starts after link */
-
-                               /* connect to last table, if there is one */
-                               if (h) {
-                                       x[h] = i;       /* save pattern for backing up */
-                                       r.b = (unsigned char) l;        /* bits to dump before this table */
-                                       r.e = (unsigned char) (16 + j); /* bits in this table */
-                                       r.v.t = q;      /* pointer to this table */
-                                       j = i >> (w - l);       /* (get around Turbo C bug) */
-                                       u[h - 1][j] = r;        /* connect to last table */
-                               }
-                       }
-
-                       /* set up table entry in r */
-                       r.b = (unsigned char) (k - w);
-                       if (p >= v + n)
-                               r.e = 99;               /* out of values--invalid code */
-                       else if (*p < s) {
-                               r.e = (unsigned char) (*p < 256 ? 16 : 15);     /* 256 is end-of-block code */
-                               r.v.n = (unsigned short) (*p);  /* simple code is just the value */
-                               p++;                    /* one compiler does not like *p++ */
-                       } else {
-                               r.e = (unsigned char) e[*p - s];        /* non-simple--look up in lists */
-                               r.v.n = d[*p++ - s];
-                       }
-
-                       /* fill code-like entries with r */
-                       f = 1 << (k - w);
-                       for (j = i >> w; j < z; j += f)
-                               q[j] = r;
-
-                       /* backwards increment the k-bit code i */
-                       for (j = 1 << (k - 1); i & j; j >>= 1)
-                               i ^= j;
-                       i ^= j;
-
-                       /* backup over finished tables */
-                       while ((i & ((1 << w) - 1)) != x[h]) {
-                               h--;                    /* don't need to update q */
-                               w -= l;
-                       }
-               }
-       }
-       /* Return true (1) if we were given an incomplete table */
-       return y != 0 && g != 1;
-}
-
-/*
- * inflate (decompress) the codes in a deflated (compressed) block.
- * Return an error code or zero if it all goes ok.
- *
- * tl, td: literal/length and distance decoder tables
- * bl, bd: number of bits decoded by tl[] and td[]
- */
-static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
-{
-       register unsigned long e;               /* table entry flag/number of extra bits */
-       unsigned long n, d;                             /* length and index for copy */
-       unsigned long w;                                /* current window position */
-       huft_t *t;                              /* pointer to table entry */
-       unsigned ml, md;                        /* masks for bl and bd bits */
-       register unsigned long b;                               /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-
-       /* make local copies of globals */
-       b = bb;                                 /* initialize bit buffer */
-       k = bk;
-       w = outcnt;                             /* initialize window position */
-
-       /* inflate the coded data */
-       ml = mask_bits[bl];                     /* precompute masks for speed */
-       md = mask_bits[bd];
-       for (;;) {                              /* do until end of block */
-               while (k < (unsigned) bl) {
-                       b |= ((unsigned long)fgetc(in_file)) << k;
-                       k += 8;
-               }
-               if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
-               do {
-                       if (e == 99) {
-                               return 1;
-                       }
-                       b >>= t->b;
-                       k -= t->b;
-                       e -= 16;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-               b >>= t->b;
-               k -= t->b;
-               if (e == 16) {          /* then it's a literal */
-                       window[w++] = (unsigned char) t->v.n;
-                       if (w == WSIZE) {
-                               outcnt=(w),
-                               flush_window();
-                               w = 0;
-                       }
-               } else {                                /* it's an EOB or a length */
-
-                       /* exit if end of block */
-                       if (e == 15) {
-                               break;
-                       }
-
-                       /* get length of block to copy */
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       n = t->v.n + ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* decode distance of block to copy */
-                       while (k < (unsigned) bd) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-
-                       if ((e = (t = td + ((unsigned) b & md))->e) > 16)
-                               do {
-                                       if (e == 99)
-                                               return 1;
-                                       b >>= t->b;
-                                       k -= t->b;
-                                       e -= 16;
-                                       while (k < e) {
-                                               b |= ((unsigned long)fgetc(in_file)) << k;
-                                               k += 8;
-                                       }
-                               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-                       b >>= t->b;
-                       k -= t->b;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       d = w - t->v.n - ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* do the copy */
-                       do {
-                               n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
-                               if (w - d >= e) {       /* (this test assumes unsigned comparison) */
-                                       memcpy(window + w, window + d, e);
-                                       w += e;
-                                       d += e;
-                               } else                  /* do it slow to avoid memcpy() overlap */
-#endif                                                 /* !NOMEMCPY */
-                                       do {
-                                               window[w++] = window[d++];
-                                       } while (--e);
-                               if (w == WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                       } while (n);
-               }
-       }
-
-       /* restore the globals from the locals */
-       outcnt = w;                     /* restore global window pointer */
-       bb = b;                         /* restore global bit buffer */
-       bk = k;
-
-       /* done */
-       return 0;
-}
-
-/*
- * decompress an inflated block
- * e: last block flag
- *
- * GLOBAL VARIABLES: bb, kk,
- */
-static int inflate_block(int *e)
-{
-       unsigned t;                     /* block type */
-       register unsigned long b;                       /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-       static unsigned short cplens[] = {              /* Copy lengths for literal codes 257..285 */
-               3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-               35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-       };
-       /* note: see note #13 above about the 258 in this list. */
-       static unsigned short cplext[] = {              /* Extra bits for literal codes 257..285 */
-               0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-               3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
-       };                              /* 99==invalid */
-       static unsigned short cpdist[] = {              /* Copy offsets for distance codes 0..29 */
-               1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-               257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-               8193, 12289, 16385, 24577
-       };
-       static unsigned short cpdext[] = {              /* Extra bits for distance codes */
-               0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-               7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-               12, 12, 13, 13
-       };
-
-       /* make local bit buffer */
-       b = bb;
-       k = bk;
-
-       /* read in last block bit */
-       while (k < 1) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       *e = (int) b & 1;
-       b >>= 1;
-       k -= 1;
-
-       /* read in block type */
-       while (k < 2) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       t = (unsigned) b & 3;
-       b >>= 2;
-       k -= 2;
-
-       /* restore the global bit buffer */
-       bb = b;
-       bk = k;
-
-       /* inflate that block type */
-       switch (t) {
-       case 0: /* Inflate stored */
-               {
-                       unsigned long n;                        /* number of bytes in block */
-                       unsigned long w;                        /* current window position */
-                       register unsigned long b_stored;                        /* bit buffer */
-                       register unsigned long k_stored;                /* number of bits in bit buffer */
-
-                       /* make local copies of globals */
-                       b_stored = bb;                          /* initialize bit buffer */
-                       k_stored = bk;
-                       w = outcnt;                     /* initialize window position */
-
-                       /* go to byte boundary */
-                       n = k_stored & 7;
-                       b_stored >>= n;
-                       k_stored -= n;
-
-                       /* get the length and its complement */
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       n = ((unsigned) b_stored & 0xffff);
-                       b_stored >>= 16;
-                       k_stored -= 16;
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       if (n != (unsigned) ((~b_stored) & 0xffff)) {
-                               return 1;               /* error in compressed data */
-                       }
-                       b_stored >>= 16;
-                       k_stored -= 16;
-
-                       /* read and output the compressed data */
-                       while (n--) {
-                               while (k_stored < 8) {
-                                       b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                                       k_stored += 8;
-                               }
-                               window[w++] = (unsigned char) b_stored;
-                               if (w == (unsigned long)WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                               b_stored >>= 8;
-                               k_stored -= 8;
-                       }
-
-                       /* restore the globals from the locals */
-                       outcnt = w;                     /* restore global window pointer */
-                       bb = b_stored;                          /* restore global bit buffer */
-                       bk = k_stored;
-                       return 0;
-               }
-       case 1: /* Inflate fixed 
-                        * decompress an inflated type 1 (fixed Huffman codes) block.  We should
-                        * either replace this with a custom decoder, or at least precompute the
-                        * Huffman tables.
-                        */
-               {
-                       int i;                                  /* temporary variable */
-                       huft_t *tl;                             /* literal/length code table */
-                       huft_t *td;                             /* distance code table */
-                       int bl;                                 /* lookup bits for tl */
-                       int bd;                                 /* lookup bits for td */
-                       unsigned int l[288];    /* length list for huft_build */
-
-                       /* set up literal table */
-                       for (i = 0; i < 144; i++) {
-                               l[i] = 8;
-                       }
-                       for (; i < 256; i++) {
-                               l[i] = 9;
-                       }
-                       for (; i < 280; i++) {
-                               l[i] = 7;
-                       }
-                       for (; i < 288; i++) {  /* make a complete, but wrong code set */
-                               l[i] = 8;
-                       }
-                       bl = 7;
-                       if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               return i;
-                       }
-
-                       /* set up distance table */
-                       for (i = 0; i < 30; i++) {      /* make an incomplete code set */
-                               l[i] = 5;
-                       }
-                       bd = 5;
-                       if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
-                               huft_free(tl);
-                               return i;
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       case 2: /* Inflate dynamic */
-               {
-                       /* Tables for deflate from PKZIP's appnote.txt. */
-                       static unsigned border[] = {    /* Order of the bit length code lengths */
-                               16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
-                       };
-                       int dbits = 6;                                  /* bits in base distance lookup table */
-                       int lbits = 9;                                  /* bits in base literal/length lookup table */
-
-                       int i;                                          /* temporary variables */
-                       unsigned j;
-                       unsigned l;                                     /* last length */
-                       unsigned m;                                     /* mask for bit lengths table */
-                       unsigned n;                                     /* number of lengths to get */
-                       huft_t *tl;                     /* literal/length code table */
-                       huft_t *td;                     /* distance code table */
-                       int bl;                                         /* lookup bits for tl */
-                       int bd;                                         /* lookup bits for td */
-                       unsigned nb;                            /* number of bit length codes */
-                       unsigned nl;                            /* number of literal/length codes */
-                       unsigned nd;                            /* number of distance codes */
-
-                       unsigned ll[286 + 30];          /* literal/length and distance code lengths */
-                       register unsigned long b_dynamic;       /* bit buffer */
-                       register unsigned k_dynamic;            /* number of bits in bit buffer */
-
-                       /* make local bit buffer */
-                       b_dynamic = bb;
-                       k_dynamic = bk;
-
-                       /* read in table lengths */
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nl = 257 + ((unsigned) b_dynamic & 0x1f);       /* number of literal/length codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 4) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nb = 4 + ((unsigned) b_dynamic & 0xf);  /* number of bit length codes */
-                       b_dynamic >>= 4;
-                       k_dynamic -= 4;
-                       if (nl > 286 || nd > 30) {
-                               return 1;       /* bad lengths */
-                       }
-
-                       /* read in bit-length-code lengths */
-                       for (j = 0; j < nb; j++) {
-                               while (k_dynamic < 3) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               ll[border[j]] = (unsigned) b_dynamic & 7;
-                               b_dynamic >>= 3;
-                               k_dynamic -= 3;
-                       }
-                       for (; j < 19; j++) {
-                               ll[border[j]] = 0;
-                       }
-
-                       /* build decoding table for trees--single level, 7 bit lookup */
-                       bl = 7;
-                       if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* read in literal and distance code lengths */
-                       n = nl + nd;
-                       m = mask_bits[bl];
-                       i = l = 0;
-                       while ((unsigned) i < n) {
-                               while (k_dynamic < (unsigned) bl) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               j = (td = tl + ((unsigned) b_dynamic & m))->b;
-                               b_dynamic >>= j;
-                               k_dynamic -= j;
-                               j = td->v.n;
-                               if (j < 16) {                   /* length of code in bits (0..15) */
-                                       ll[i++] = l = j;        /* save last length in l */
-                               }
-                               else if (j == 16) {             /* repeat last length 3 to 6 times */
-                                       while (k_dynamic < 2) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 3);
-                                       b_dynamic >>= 2;
-                                       k_dynamic -= 2;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = l;
-                                       }
-                               } else if (j == 17) {   /* 3 to 10 zero length codes */
-                                       while (k_dynamic < 3) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 7);
-                                       b_dynamic >>= 3;
-                                       k_dynamic -= 3;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               } else {                /* j == 18: 11 to 138 zero length codes */
-                                       while (k_dynamic < 7) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 11 + ((unsigned) b_dynamic & 0x7f);
-                                       b_dynamic >>= 7;
-                                       k_dynamic -= 7;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               }
-                       }
-
-                       /* free decoding table for trees */
-                       huft_free(tl);
-
-                       /* restore the global bit buffer */
-                       bb = b_dynamic;
-                       bk = k_dynamic;
-
-                       /* build the decoding tables for literal/length and distance codes */
-                       bl = lbits;
-                       if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       error_msg("Incomplete literal tree");
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-                       bd = dbits;
-                       if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
-                               if (i == 1) {
-                                       error_msg("incomplete distance tree");
-                                       huft_free(td);
-                               }
-                               huft_free(tl);
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       default:
-               /* bad block type */
-               return 2;
-       }
-}
-
-/*
- * decompress an inflated entry
- *
- * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
- */
-static int inflate()
-{
-       int e;                          /* last block flag */
-       int r;                          /* result code */
-       unsigned h = 0;         /* maximum struct huft's malloc'ed */
-
-       /* initialize window, bit buffer */
-       outcnt = 0;
-       bk = 0;
-       bb = 0;
-
-       /* decompress until the last block */
-       do {
-               hufts = 0;
-               if ((r = inflate_block(&e)) != 0) {
-                       return r;
-               }
-               if (hufts > h) {
-                       h = hufts;
-               }
-       } while (!e);
-
-       /* flush out window */
-       flush_window();
-
-       /* return success */
-       return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- *   the compressed data, from offsets inptr to insize-1 included.
- *   The magic header has already been checked. The output buffer is cleared.
- * in, out: input and output file descriptors
- */
-extern int unzip(FILE *l_in_file, FILE *l_out_file)
-{
-       const int extra_field = 0x04;   /* bit 2 set: extra field present */
-       const int orig_name = 0x08;     /* bit 3 set: original file name present */
-       const int comment = 0x10;       /* bit 4 set: file comment present */
-       unsigned char buf[8];   /* extended local header */
-       unsigned char flags;    /* compression flags */
-       char magic[2];                  /* magic header */
-       int method;
-       typedef void (*sig_type) (int);
-       int exit_code=0;        /* program exit code */
-       int i;
-
-       in_file = l_in_file;
-       out_file = l_out_file;
-
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGINT, (sig_type) abort_gzip);
-       }
-#ifdef SIGTERM
-//     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-//             (void) signal(SIGTERM, (sig_type) abort_gzip);
-//     }
-#endif
-#ifdef SIGHUP
-       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGHUP, (sig_type) abort_gzip);
-       }
-#endif
-
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
-       magic[0] = fgetc(in_file);
-       magic[1] = fgetc(in_file);
-
-       /* Magic header for gzip files, 1F 8B = \037\213 */
-       if (memcmp(magic, "\037\213", 2) != 0) {
-               error_msg("Invalid gzip magic");
-               return EXIT_FAILURE;
-       }
-
-       method = (int) fgetc(in_file);
-       if (method != 8) {
-               error_msg("unknown method %d -- get newer version of gzip", method);
-               exit_code = 1;
-               return -1;
-       }
-
-       flags = (unsigned char) fgetc(in_file);
-
-       /* Ignore time stamp(4), extra flags(1), OS type(1) */
-       for (i = 0; i < 6; i++)
-               fgetc(in_file);
-
-       if ((flags & extra_field) != 0) {
-               size_t extra;
-               extra = fgetc(in_file);
-               extra += fgetc(in_file) << 8;
-
-               for (i = 0; i < extra; i++)
-                       fgetc(in_file);
-       }
-
-       /* Discard original name if any */
-       if ((flags & orig_name) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       /* Discard file comment if any */
-       if ((flags & comment) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       if (method < 0) {
-               printf("it failed\n");
-               return(exit_code);              /* error message already emitted */
-       }
-
-       make_crc_table();
-
-       /* Decompress */
-       if (method == 8) {
-
-               int res = inflate();
-
-               if (res == 3) {
-                       error_msg(memory_exhausted);
-               } else if (res != 0) {
-                       error_msg("invalid compressed data--format violated");
-               }
-
-       } else {
-               error_msg("internal error, invalid method");
-       }
-
-       /* Get the crc and original length
-        * crc32  (see algorithm.doc)
-        * uncompressed input size modulo 2^32
-        */
-       fread(buf, 1, 8, in_file);
-
-       /* Validate decompression - crc */
-       if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
-               error_msg("invalid compressed data--crc error");
-       }
-       /* Validate decompression - size */
-       if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
-               error_msg("invalid compressed data--length error");
-       }
-
-       free(window);
-       free(crc_table);
-
-       return 0;
-}
-
-/*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
- */
-extern void gz_close(int gunzip_pid)
-{
-       if (kill(gunzip_pid, SIGTERM) == -1) {
-               error_msg_and_die("***  Couldnt kill old gunzip process *** aborting");
-       }
-
-       if (waitpid(gunzip_pid, NULL, 0) == -1) {
-               printf("Couldnt wait ?");
-       }
-               free(window);
-               free(crc_table);
-}
diff --git a/busybox/archival/rpm2cpio.c b/busybox/archival/rpm2cpio.c
deleted file mode 100644 (file)
index 8d639d6..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rpm2cpio implementation for busybox
- *
- * Copyright (C) 2001 by Laurence Anderson
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "busybox.h"
-#include <netinet/in.h> /* For ntohl & htonl function */
-#include <string.h>
-
-#define RPM_MAGIC "\355\253\356\333"
-#define RPM_HEADER_MAGIC "\216\255\350"
-
-struct rpm_lead {
-    unsigned char magic[4];
-    u_int8_t major, minor;
-    u_int16_t type;
-    u_int16_t archnum;
-    char name[66];
-    u_int16_t osnum;
-    u_int16_t signature_type;
-    char reserved[16];
-};
-
-struct rpm_header {
-       char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
-       u_int8_t version; /* 1 byte version number */
-       u_int32_t reserved; /* 4 bytes reserved */
-       u_int32_t entries; /* Number of entries in header (4 bytes) */
-       u_int32_t size; /* Size of store (4 bytes) */
-};
-
-void skip_header(FILE *rpmfile)
-{
-       struct rpm_header header;
-
-       fread(&header, sizeof(struct rpm_header), 1, rpmfile);
-       if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */
-       if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */
-       header.entries = ntohl(header.entries);
-       header.size = ntohl(header.size);
-       fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
-       fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */
-}
-
-/* No getopt required */
-extern int rpm2cpio_main(int argc, char **argv)
-{
-       struct rpm_lead lead;
-       int gunzip_pid;
-       FILE *rpmfile, *cpiofile;
-
-       if (argc == 1) {
-               rpmfile = stdin;
-       } else {
-               rpmfile = fopen(argv[1], "r");
-               if (!rpmfile) perror_msg_and_die("Can't open rpm file");
-               /* set the buffer size */
-               setvbuf(rpmfile, NULL, _IOFBF, 0x8000);
-       }
-
-       fread (&lead, sizeof(struct rpm_lead), 1, rpmfile);
-       if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
-       /* Skip the signature header */
-       skip_header(rpmfile);
-       fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */
-       /* Skip the main header */
-       skip_header(rpmfile);
-
-       cpiofile = gz_open(rpmfile, &gunzip_pid);
-
-       copyfd(fileno(cpiofile), fileno(stdout));
-       gz_close(gunzip_pid);
-       fclose(rpmfile);
-       return 0;
-}
diff --git a/busybox/archival/tar.c b/busybox/archival/tar.c
deleted file mode 100644 (file)
index 389d7f0..0000000
+++ /dev/null
@@ -1,1150 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tar implementation for busybox 
- *
- * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
- * ground up.  It still has remnents of the old code lying about, but it is
- * very different now (i.e., cleaner, less global variables, etc.)
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Based in part in the tar implementation in sash
- *  Copyright (c) 1999 by David I. Bell
- *  Permission is granted to use, distribute, or modify this source,
- *  provided that this copyright notice remains intact.
- *  Permission to distribute sash derived code under the GPL has been granted.
- *
- * Based in part on the tar implementation from busybox-0.28
- *  Copyright (C) 1995 Bruce Perens
- *  This is free software under the GNU General Public License.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <utime.h>
-#include <sys/types.h>
-#include <sys/sysmacros.h>
-#include <getopt.h>
-#include <fnmatch.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Tar file constants  */
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
-enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */
-
-/* POSIX tar Header Block, from POSIX 1003.1-1990  */
-struct TarHeader
-{
-                                /* byte offset */
-       char name[NAME_SIZE];         /*   0-99 */
-       char mode[8];                 /* 100-107 */
-       char uid[8];                  /* 108-115 */
-       char gid[8];                  /* 116-123 */
-       char size[12];                /* 124-135 */
-       char mtime[12];               /* 136-147 */
-       char chksum[8];               /* 148-155 */
-       char typeflag;                /* 156-156 */
-       char linkname[NAME_SIZE];     /* 157-256 */
-       char magic[6];                /* 257-262 */
-       char version[2];              /* 263-264 */
-       char uname[32];               /* 265-296 */
-       char gname[32];               /* 297-328 */
-       char devmajor[8];             /* 329-336 */
-       char devminor[8];             /* 337-344 */
-       char prefix[155];             /* 345-499 */
-       char padding[12];             /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
-};
-typedef struct TarHeader TarHeader;
-
-
-/* A few useful constants */
-#define TAR_MAGIC          "ustar"        /* ustar and a null */
-#define TAR_VERSION        "  "           /* Be compatable with GNU tar format */
-static const int TAR_MAGIC_LEN = 6;
-static const int TAR_VERSION_LEN = 2;
-static const int TAR_BLOCK_SIZE = 512;
-
-/* A nice enum with all the possible tar file content types */
-enum TarFileType 
-{
-       REGTYPE  = '0',            /* regular file */
-       REGTYPE0 = '\0',           /* regular file (ancient bug compat)*/
-       LNKTYPE  = '1',            /* hard link */
-       SYMTYPE  = '2',            /* symbolic link */
-       CHRTYPE  = '3',            /* character special */
-       BLKTYPE  = '4',            /* block special */
-       DIRTYPE  = '5',            /* directory */
-       FIFOTYPE = '6',            /* FIFO special */
-       CONTTYPE = '7',            /* reserved */
-       GNULONGLINK = 'K',         /* GNU long (>100 chars) link name */
-       GNULONGNAME = 'L',         /* GNU long (>100 chars) file name */
-};
-typedef enum TarFileType TarFileType;
-
-/* This struct ignores magic, non-numeric user name, 
- * non-numeric group name, and the checksum, since
- * these are all ignored by BusyBox tar. */ 
-struct TarInfo
-{
-       int              tarFd;          /* An open file descriptor for reading from the tarball */
-       char *           name;           /* File name */
-       mode_t           mode;           /* Unix mode, including device bits. */
-       uid_t            uid;            /* Numeric UID */
-       gid_t            gid;            /* Numeric GID */
-       size_t           size;           /* Size of file */
-       time_t           mtime;          /* Last-modified time */
-       enum TarFileType type;           /* Regular, directory, link, etc. */
-       char *           linkname;       /* Name for symbolic and hard links */
-       long             devmajor;       /* Major number for special device */
-       long             devminor;       /* Minor number for special device */
-};
-typedef struct TarInfo TarInfo;
-
-/* Local procedures to restore files from a tar file.  */
-static int readTarFile(int tarFd, int extractFlag, int listFlag, 
-               int tostdoutFlag, int verboseFlag, char** extractList,
-               char** excludeList);
-
-#ifdef BB_FEATURE_TAR_CREATE
-/* Local procedures to save files into a tar file.  */
-static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
-               char** excludeList);
-#endif
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-static struct option longopts[] = {
-       { "exclude", 1, NULL, 'e' },
-       { NULL, 0, NULL, 0 }
-};
-#endif
-
-extern int tar_main(int argc, char **argv)
-{
-       char** excludeList=NULL;
-       char** extractList=NULL;
-       const char *tarName="-";
-       const char *cwd=NULL;
-#if defined BB_FEATURE_TAR_EXCLUDE
-       int excludeListSize=0;
-       FILE *fileList;
-       char file[256];
-#endif
-#if defined BB_FEATURE_TAR_GZIP
-       FILE *comp_file = NULL;
-       int unzipFlag    = FALSE;
-#endif
-       int listFlag     = FALSE;
-       int extractFlag  = FALSE;
-       int createFlag   = FALSE;
-       int verboseFlag  = FALSE;
-       int tostdoutFlag = FALSE;
-       int status       = FALSE;
-       int opt;
-       pid_t pid;
-
-       if (argc <= 1)
-               show_usage();
-
-       if (argv[1][0] != '-') {
-               char *tmp = xmalloc(strlen(argv[1]) + 2);
-               tmp[0] = '-';
-               strcpy(tmp + 1, argv[1]);
-               argv[1] = tmp;
-       }
-
-       while (
-#ifndef BB_FEATURE_TAR_EXCLUDE
-                       (opt = getopt(argc, argv, "cxtzvOf:pC:"))
-#else
-                       (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL))
-#endif
-                       > 0) {
-               switch (opt) {
-                       case 'c':
-                               if (extractFlag == TRUE || listFlag == TRUE)
-                                       goto flagError;
-                               createFlag = TRUE;
-                               break;
-                       case 'x':
-                               if (listFlag == TRUE || createFlag == TRUE)
-                                       goto flagError;
-                               extractFlag = TRUE;
-                               break;
-                       case 't':
-                               if (extractFlag == TRUE || createFlag == TRUE)
-                                       goto flagError;
-                               listFlag = TRUE;
-                               break;
-#ifdef BB_FEATURE_TAR_GZIP
-                       case 'z':
-                               unzipFlag = TRUE;
-                               break;
-#endif
-                       case 'v':
-                               verboseFlag = TRUE;
-                               break;
-                       case 'O':
-                               tostdoutFlag = TRUE;
-                               break;
-                       case 'f':
-                               if (*tarName != '-')
-                                       error_msg_and_die( "Only one 'f' option allowed");
-                               tarName = optarg;
-                               break;
-#if defined BB_FEATURE_TAR_EXCLUDE
-                       case 'e':
-                               excludeList=xrealloc( excludeList,
-                                               sizeof(char *) * (excludeListSize+2));
-                               excludeList[excludeListSize] = optarg;
-                               /* Tack a NULL onto the end of the list */
-                               excludeList[++excludeListSize] = NULL;
-                       case 'X':
-                               fileList = xfopen(optarg, "r");
-                               while (fgets(file, sizeof(file), fileList) != NULL) {
-                                       excludeList = xrealloc(excludeList,
-                                                       sizeof(char *) * (excludeListSize+2));
-                                       chomp(file);
-                                       excludeList[excludeListSize] = xstrdup(file);
-                                       /* Tack a NULL onto the end of the list */
-                                       excludeList[++excludeListSize] = NULL;
-                               }
-                               fclose(fileList);
-                               break;
-#endif
-                       case 'p':
-                               break;
-                       case 'C':
-                               cwd = xgetcwd((char *)cwd);
-                               if (chdir(optarg)) {
-                                       printf("cd: %s: %s\n", optarg, strerror(errno));
-                                       return EXIT_FAILURE;
-                               }
-                               break;
-                       default:
-                                       show_usage();
-               }
-       }
-
-       /*
-        * Do the correct type of action supplying the rest of the
-        * command line arguments as the list of files to process.
-        */
-       if (createFlag == TRUE) {
-#ifndef BB_FEATURE_TAR_CREATE
-               error_msg_and_die( "This version of tar was not compiled with tar creation support.");
-#else
-#ifdef BB_FEATURE_TAR_GZIP
-               if (unzipFlag==TRUE)
-                       error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip");
-#endif
-               status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList);
-#endif
-       }
-       if (listFlag == TRUE || extractFlag == TRUE) {
-               int tarFd;
-               if (argv[optind])
-                       extractList = argv + optind;
-               /* Open the tar file for reading.  */
-               if (!strcmp(tarName, "-"))
-                       tarFd = fileno(stdin);
-               else
-                       tarFd = open(tarName, O_RDONLY);
-               if (tarFd < 0)
-                       perror_msg_and_die("Error opening '%s'", tarName);
-
-#ifdef BB_FEATURE_TAR_GZIP     
-               /* unzip tarFd in a seperate process */
-               if (unzipFlag == TRUE) {
-                       comp_file = fdopen(tarFd, "r");
-
-                       /* set the buffer size */
-                       setvbuf(comp_file, NULL, _IOFBF, 0x8000);
-
-                       if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) {
-                               error_msg_and_die("Couldnt unzip file");
-                       }
-               }
-#endif                 
-               status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag,
-                                       verboseFlag, extractList, excludeList);
-               close(tarFd);
-#ifdef BB_FEATURE_TAR_GZIP     
-               if (unzipFlag == TRUE) {
-                       gz_close(pid);
-                       fclose(comp_file);
-               }
-#endif                 
-       }
-
-       if (cwd)
-               chdir(cwd);
-       if (status == TRUE)
-               return EXIT_SUCCESS;
-       else
-               return EXIT_FAILURE;
-
-  flagError:
-       error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified");
-}
-                                       
-static void
-fixUpPermissions(TarInfo *header)
-{
-       struct utimbuf t;
-       /* Now set permissions etc. for the new file */
-       chown(header->name, header->uid, header->gid);
-       chmod(header->name, header->mode);
-       /* Reset the time */
-       t.actime = time(0);
-       t.modtime = header->mtime;
-       utime(header->name, &t);
-}
-                               
-static int
-tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       size_t  writeSize;
-       size_t  readSize;
-       size_t  actualWriteSz;
-       char    buffer[20 * TAR_BLOCK_SIZE];
-       size_t  size = header->size;
-       int outFd=fileno(stdout);
-
-       /* Open the file to be written, if a file is supposed to be written */
-       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
-               /* Create the path to the file, just in case it isn't there...
-                * This should not screw up path permissions or anything. */
-               char *buf, *dir;
-               buf = xstrdup (header->name);
-               dir = dirname (buf);
-               make_directory (dir, -1, FILEUTILS_RECUR);
-               free (buf);
-               if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, 
-                                               header->mode & ~S_IFMT)) < 0) {
-                       error_msg(io_error, header->name, strerror(errno)); 
-                       return( FALSE);
-               }
-       }
-
-       /* Write out the file, if we are supposed to be doing that */
-       while ( size > 0 ) {
-               actualWriteSz=0;
-               if ( size > sizeof(buffer) )
-                       writeSize = readSize = sizeof(buffer);
-               else {
-                       int mod = size % TAR_BLOCK_SIZE;
-                       if ( mod != 0 )
-                               readSize = size + (TAR_BLOCK_SIZE - mod);
-                       else
-                               readSize = size;
-                       writeSize = size;
-               }
-               if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) {
-                       /* Tarball seems to have a problem */
-                       error_msg("Unexpected EOF in archive"); 
-                       return( FALSE);
-               }
-               if ( readSize < writeSize )
-                       writeSize = readSize;
-
-               /* Write out the file, if we are supposed to be doing that */
-               if (extractFlag==TRUE) {
-
-                       if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) {
-                               /* Output file seems to have a problem */
-                               error_msg(io_error, header->name, strerror(errno)); 
-                               return( FALSE);
-                       }
-               } else {
-                       actualWriteSz=writeSize;
-               }
-
-               size -= actualWriteSz;
-       }
-
-       /* Now we are done writing the file out, so try 
-        * and fix up the permissions and whatnot */
-       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
-               close(outFd);
-               fixUpPermissions(header);
-       }
-       return( TRUE);
-}
-
-static int
-tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0)
-               return( FALSE);
-
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-static int
-tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (link(header->linkname, header->name) < 0) {
-               perror_msg("%s: Cannot create hard link to '%s'", header->name,
-                               header->linkname); 
-               return( FALSE);
-       }
-
-       /* Now set permissions etc. for the new directory */
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-static int
-tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-#ifdef S_ISLNK
-       if (symlink(header->linkname, header->name) < 0) {
-               perror_msg("%s: Cannot create symlink to '%s'", header->name,
-                               header->linkname); 
-               return( FALSE);
-       }
-       /* Try to change ownership of the symlink.
-        * If libs doesn't support that, don't bother.
-        * Changing the pointed-to-file is the Wrong Thing(tm).
-        */
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-       lchown(header->name, header->uid, header->gid);
-#endif
-
-       /* Do not change permissions or date on symlink,
-        * since it changes the pointed to file instead.  duh. */
-#else
-       error_msg("%s: Cannot create symlink to '%s': %s", 
-                       header->name, header->linkname, 
-                       "symlinks not supported"); 
-#endif
-       return( TRUE);
-}
-
-static int
-tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) {
-               if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) {
-                       perror_msg("%s: Cannot mknod", header->name); 
-                       return( FALSE);
-               }
-       } else if (S_ISFIFO(header->mode)) {
-               if (mkfifo(header->name, header->mode) < 0) {
-                       perror_msg("%s: Cannot mkfifo", header->name); 
-                       return( FALSE);
-               }
-       }
-
-       /* Now set permissions etc. for the new directory */
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-/* Parse the tar header and fill in the nice struct with the details */
-static int
-readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
-{
-       int i;
-       long chksum, sum=0;
-       unsigned char *s = (unsigned char *)rawHeader;
-
-       header->name  = rawHeader->name;
-       /* Check for and relativify any absolute paths */
-       if ( *(header->name) == '/' ) {
-               static int alreadyWarned=FALSE;
-
-               while (*(header->name) == '/')
-                       header->name++;
-
-               if (alreadyWarned == FALSE) {
-                       error_msg("Removing leading '/' from member names");
-                       alreadyWarned = TRUE;
-               }
-       }
-
-       header->mode  = strtol(rawHeader->mode, NULL, 8);
-       header->uid   = strtol(rawHeader->uid, NULL, 8);
-       header->gid   = strtol(rawHeader->gid, NULL, 8);
-       header->size  = strtol(rawHeader->size, NULL, 8);
-       header->mtime = strtol(rawHeader->mtime, NULL, 8);
-       chksum = strtol(rawHeader->chksum, NULL, 8);
-       header->type  = rawHeader->typeflag;
-       header->linkname  = rawHeader->linkname;
-       header->devmajor  = strtol(rawHeader->devmajor, NULL, 8);
-       header->devminor  = strtol(rawHeader->devminor, NULL, 8);
-
-       /* Check the checksum */
-       for (i = sizeof(*rawHeader); i-- != 0;) {
-               sum += *s++;
-       }
-       /* Remove the effects of the checksum field (replace 
-        * with blanks for the purposes of the checksum) */
-       s = rawHeader->chksum;
-       for (i = sizeof(rawHeader->chksum) ; i-- != 0;) {
-               sum -= *s++;
-       }
-       sum += ' ' * sizeof(rawHeader->chksum);
-       if (sum == chksum )
-               return ( TRUE);
-       return( FALSE);
-}
-
-static int exclude_file(char **excluded_files, const char *file)
-{
-       int i;
-
-       if (excluded_files == NULL)
-               return 0;
-
-       for (i = 0; excluded_files[i] != NULL; i++) {
-               if (excluded_files[i][0] == '/') {
-                       if (fnmatch(excluded_files[i], file,
-                                               FNM_PATHNAME | FNM_LEADING_DIR) == 0)
-                               return 1;
-               } else {
-                       const char *p;
-
-                       for (p = file; p[0] != '\0'; p++) {
-                               if ((p == file || p[-1] == '/') && p[0] != '/' &&
-                                               fnmatch(excluded_files[i], p,
-                                                       FNM_PATHNAME | FNM_LEADING_DIR) == 0)
-                                       return 1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int extract_file(char **extract_files, const char *file)
-{
-       int i;
-
-       if (extract_files == NULL)
-               return 1;
-
-       for (i = 0; extract_files[i] != NULL; i++) {
-               if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0)
-                       return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Read a tar file and extract or list the specified files within it.
- * If the list is empty than all files are extracted or listed.
- */
-static int readTarFile(int tarFd, int extractFlag, int listFlag, 
-               int tostdoutFlag, int verboseFlag, char** extractList,
-               char** excludeList)
-{
-       int status;
-       int errorFlag=FALSE;
-       int skipNextHeaderFlag=FALSE;
-       TarHeader rawHeader;
-       TarInfo header;
-
-       /* Read the tar file, and iterate over it one file at a time */
-       while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) {
-
-               /* Try to read the header */
-               if ( readTarHeader(&rawHeader, &header) == FALSE ) {
-                       if ( *(header.name) == '\0' ) {
-                               goto endgame;
-                       } else {
-                               errorFlag=TRUE;
-                               error_msg("Bad tar header, skipping");
-                               continue;
-                       }
-               }
-               if ( *(header.name) == '\0' )
-                       continue;
-               header.tarFd = tarFd;
-
-               /* Skip funky extra GNU headers that precede long files */
-               if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) {
-                       skipNextHeaderFlag=TRUE;
-                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                               errorFlag = TRUE;
-                       continue;
-               }
-               if ( skipNextHeaderFlag == TRUE ) { 
-                       skipNextHeaderFlag=FALSE;
-                       error_msg(name_longer_than_foo, NAME_SIZE); 
-                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                               errorFlag = TRUE;
-                       continue;
-               }
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-               if (exclude_file(excludeList, header.name)) {
-                       /* There are not the droids you're looking for, move along */
-                       /* If it is a regular file, pretend to extract it with
-                        * the extractFlag set to FALSE, so the junk in the tarball
-                        * is properly skipped over */
-                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
-                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                                       errorFlag = TRUE;
-                       }
-                       continue;
-               }
-#endif
-
-               if (!extract_file(extractList, header.name)) {
-                       /* There are not the droids you're looking for, move along */
-                       /* If it is a regular file, pretend to extract it with
-                        * the extractFlag set to FALSE, so the junk in the tarball
-                        * is properly skipped over */
-                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
-                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                                       errorFlag = TRUE;
-                       }
-                       continue;
-               }
-
-               if (listFlag == TRUE) {
-                       /* Special treatment if the list (-t) flag is on */
-                       if (verboseFlag == TRUE) {
-                               int len, len1;
-                               char buf[35];
-                               struct tm *tm = localtime (&(header.mtime));
-
-                               len=printf("%s ", mode_string(header.mode));
-                               my_getpwuid(buf, header.uid);
-                               if (! *buf)
-                                       len+=printf("%d", header.uid);
-                               else
-                                       len+=printf("%s", buf);
-                               my_getgrgid(buf, header.gid);
-                               if (! *buf)
-                                       len+=printf("/%-d ", header.gid);
-                               else
-                                       len+=printf("/%-s ", buf);
-
-                               if (header.type==CHRTYPE || header.type==BLKTYPE) {
-                                       len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", 
-                                                       header.devmajor, header.devminor);
-                               } else {
-                                       len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size);
-                               }
-                               /* Jump through some hoops to make the columns match up */
-                               for(;(len+len1)<31;len++)
-                                       printf(" ");
-                               printf(buf);
-
-                               /* Use ISO 8610 time format */
-                               if (tm) { 
-                                       printf ("%04d-%02d-%02d %02d:%02d:%02d ", 
-                                                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
-                                                       tm->tm_hour, tm->tm_min, tm->tm_sec);
-                               }
-                       }
-                       printf("%s", header.name);
-                       if (verboseFlag == TRUE) {
-                               if (header.type==LNKTYPE)       /* If this is a link, say so */
-                                       printf(" link to %s", header.linkname);
-                               else if (header.type==SYMTYPE)
-                                       printf(" -> %s", header.linkname);
-                       }
-                       printf("\n");
-               }
-
-               /* List contents if we are supposed to do that */
-               if (verboseFlag == TRUE && extractFlag == TRUE) {
-                       /* Now the normal listing */
-                       FILE *vbFd = stdout;
-                       if (tostdoutFlag == TRUE)       // If the archive goes to stdout, verbose to stderr
-                               vbFd = stderr;
-                       fprintf(vbFd, "%s\n", header.name);
-               }
-                       
-               /* Remove files if we would overwrite them */
-               if (extractFlag == TRUE && tostdoutFlag == FALSE)
-                       unlink(header.name);
-
-               /* If we got here, we can be certain we have a legitimate 
-                * header to work with.  So work with it.  */
-               switch ( header.type ) {
-                       case REGTYPE:
-                       case REGTYPE0:
-                               /* If the name ends in a '/' then assume it is
-                                * supposed to be a directory, and fall through */
-                               if (!last_char_is(header.name,'/')) {
-                                       if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE)
-                                               errorFlag=TRUE;
-                                       break;
-                               }
-                       case DIRTYPE:
-                               if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case LNKTYPE:
-                               if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case SYMTYPE:
-                               if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case CHRTYPE:
-                       case BLKTYPE:
-                       case FIFOTYPE:
-                               if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-#if 0
-                       /* Handled earlier */
-                       case GNULONGNAME:
-                       case GNULONGLINK:
-                               skipNextHeaderFlag=TRUE;
-                               break;
-#endif
-                       default:
-                               error_msg("Unknown file type '%c' in tar file", header.type);
-                               close( tarFd);
-                               return( FALSE);
-               }
-       }
-       close(tarFd);
-       if (status > 0) {
-               /* Bummer - we read a partial header */
-               perror_msg("Error reading tar file");
-               return ( FALSE);
-       }
-       else if (errorFlag==TRUE) {
-               error_msg( "Error exit delayed from previous errors");
-               return( FALSE);
-       } else 
-               return( status);
-
-       /* Stuff to do when we are done */
-endgame:
-       close( tarFd);
-       if ( *(header.name) == '\0' ) {
-               if (errorFlag==TRUE)
-                       error_msg( "Error exit delayed from previous errors");
-               else
-                       return( TRUE);
-       } 
-       return( FALSE);
-}
-
-
-#ifdef BB_FEATURE_TAR_CREATE
-
-/*
-** writeTarFile(),  writeFileToTarball(), and writeTarHeader() are
-** the only functions that deal with the HardLinkInfo structure.
-** Even these functions use the xxxHardLinkInfo() functions.
-*/
-typedef struct HardLinkInfo HardLinkInfo;
-struct HardLinkInfo
-{
-       HardLinkInfo *next;           /* Next entry in list */
-       dev_t dev;                    /* Device number */
-       ino_t ino;                    /* Inode number */
-       short linkCount;              /* (Hard) Link Count */
-       char name[1];                 /* Start of filename (must be last) */
-};
-
-/* Some info to be carried along when creating a new tarball */
-struct TarBallInfo
-{
-       char* fileName;               /* File name of the tarball */
-       int tarFd;                    /* Open-for-write file descriptor
-                                                                        for the tarball */
-       struct stat statBuf;          /* Stat info for the tarball, letting
-                                                                        us know the inode and device that the
-                                                                        tarball lives, so we can avoid trying 
-                                                                        to include the tarball into itself */
-       int verboseFlag;              /* Whether to print extra stuff or not */
-       char** excludeList;           /* List of files to not include */
-       HardLinkInfo *hlInfoHead;     /* Hard Link Tracking Information */
-       HardLinkInfo *hlInfo;         /* Hard Link Info for the current file */
-};
-typedef struct TarBallInfo TarBallInfo;
-
-
-/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static void
-addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
-               short linkCount, const char *name)
-{
-       /* Note: hlInfoHeadPtr can never be NULL! */
-       HardLinkInfo *hlInfo;
-
-       hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
-       if (hlInfo) {
-               hlInfo->next = *hlInfoHeadPtr;
-               *hlInfoHeadPtr = hlInfo;
-               hlInfo->dev = dev;
-               hlInfo->ino = ino;
-               hlInfo->linkCount = linkCount;
-               strcpy(hlInfo->name, name);
-       }
-       return;
-}
-
-static void
-freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
-{
-       HardLinkInfo *hlInfo = NULL;
-       HardLinkInfo *hlInfoNext = NULL;
-
-       if (hlInfoHeadPtr) {
-               hlInfo = *hlInfoHeadPtr;
-               while (hlInfo) {
-                       hlInfoNext = hlInfo->next;
-                       free(hlInfo);
-                       hlInfo = hlInfoNext;
-               }
-               *hlInfoHeadPtr = NULL;
-       }
-       return;
-}
-
-/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static HardLinkInfo *
-findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
-{
-       while(hlInfo) {
-               if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
-                       break;
-               hlInfo = hlInfo->next;
-       }
-       return(hlInfo);
-}
-
-/* Put an octal string into the specified buffer.
- * The number is zero and space padded and possibly null padded.
- * Returns TRUE if successful.  */ 
-static int putOctal (char *cp, int len, long value)
-{
-       int tempLength;
-       char tempBuffer[32];
-       char *tempString = tempBuffer;
-
-       /* Create a string of the specified length with an initial space,
-        * leading zeroes and the octal number, and a trailing null.  */
-       sprintf (tempString, "%0*lo", len - 1, value);
-
-       /* If the string is too large, suppress the leading space.  */
-       tempLength = strlen (tempString) + 1;
-       if (tempLength > len) {
-               tempLength--;
-               tempString++;
-       }
-
-       /* If the string is still too large, suppress the trailing null.  */
-       if (tempLength > len)
-               tempLength--;
-
-       /* If the string is still too large, fail.  */
-       if (tempLength > len)
-               return FALSE;
-
-       /* Copy the string to the field.  */
-       memcpy (cp, tempString, len);
-
-       return TRUE;
-}
-
-/* Write out a tar header for the specified file/directory/whatever */
-static int
-writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name,
-               const char *real_name, struct stat *statbuf)
-{
-       long chksum=0;
-       struct TarHeader header;
-       const unsigned char *cp = (const unsigned char *) &header;
-       ssize_t size = sizeof(struct TarHeader);
-               
-       memset( &header, 0, size);
-
-       strncpy(header.name, header_name, sizeof(header.name)); 
-
-       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
-       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
-       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
-       putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
-       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
-       strncpy(header.magic, TAR_MAGIC TAR_VERSION, 
-                       TAR_MAGIC_LEN + TAR_VERSION_LEN );
-
-       /* Enter the user and group names (default to root if it fails) */
-       my_getpwuid(header.uname, statbuf->st_uid);
-       if (! *header.uname)
-               strcpy(header.uname, "root");
-       my_getgrgid(header.gname, statbuf->st_gid);
-       if (! *header.uname)
-               strcpy(header.uname, "root");
-
-       if (tbInfo->hlInfo) {
-               /* This is a hard link */
-               header.typeflag = LNKTYPE;
-               strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               char *lpath = xreadlink(real_name);
-               if (!lpath) /* Already printed err msg inside xreadlink() */
-                       return ( FALSE);
-               header.typeflag  = SYMTYPE;
-               strncpy(header.linkname, lpath, sizeof(header.linkname)); 
-               free(lpath);
-       } else if (S_ISDIR(statbuf->st_mode)) {
-               header.typeflag  = DIRTYPE;
-               strncat(header.name, "/", sizeof(header.name)); 
-       } else if (S_ISCHR(statbuf->st_mode)) {
-               header.typeflag  = CHRTYPE;
-               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
-       } else if (S_ISBLK(statbuf->st_mode)) {
-               header.typeflag  = BLKTYPE;
-               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
-       } else if (S_ISFIFO(statbuf->st_mode)) {
-               header.typeflag  = FIFOTYPE;
-       } else if (S_ISREG(statbuf->st_mode)) {
-               header.typeflag  = REGTYPE;
-               putOctal(header.size, sizeof(header.size), statbuf->st_size);
-       } else {
-               error_msg("%s: Unknown file type", real_name);
-               return ( FALSE);
-       }
-
-       /* Calculate and store the checksum (i.e., the sum of all of the bytes of
-        * the header).  The checksum field must be filled with blanks for the
-        * calculation.  The checksum field is formatted differently from the
-        * other fields: it has [6] digits, a null, then a space -- rather than
-        * digits, followed by a null like the other fields... */
-       memset(header.chksum, ' ', sizeof(header.chksum));
-       cp = (const unsigned char *) &header;
-       while (size-- > 0)
-               chksum += *cp++;
-       putOctal(header.chksum, 7, chksum);
-       
-       /* Now write the header out to disk */
-       if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
-               error_msg(io_error, real_name, strerror(errno)); 
-               return ( FALSE);
-       }
-       /* Pad the header up to the tar block size */
-       for (; size<TAR_BLOCK_SIZE; size++) {
-               write(tbInfo->tarFd, "\0", 1);
-       }
-       /* Now do the verbose thing (or not) */
-       if (tbInfo->verboseFlag==TRUE) {
-               FILE *vbFd = stdout;
-               if (tbInfo->tarFd == fileno(stdout))    // If the archive goes to stdout, verbose to stderr
-                       vbFd = stderr;
-               fprintf(vbFd, "%s\n", header.name);
-       }
-
-       return ( TRUE);
-}
-
-
-static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
-{
-       struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
-       const char *header_name;
-
-       /*
-       ** Check to see if we are dealing with a hard link.
-       ** If so -
-       ** Treat the first occurance of a given dev/inode as a file while
-       ** treating any additional occurances as hard links.  This is done
-       ** by adding the file information to the HardLinkInfo linked list.
-       */
-       tbInfo->hlInfo = NULL;
-       if (statbuf->st_nlink > 1) {
-               tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, 
-                               statbuf->st_ino);
-               if (tbInfo->hlInfo == NULL)
-                       addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
-                                       statbuf->st_ino, statbuf->st_nlink, fileName);
-       }
-
-       /* It is against the rules to archive a socket */
-       if (S_ISSOCK(statbuf->st_mode)) {
-               error_msg("%s: socket ignored", fileName);
-               return( TRUE);
-       }
-
-       /* It is a bad idea to store the archive we are in the process of creating,
-        * so check the device and inode to be sure that this particular file isn't
-        * the new tarball */
-       if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
-                       tbInfo->statBuf.st_ino == statbuf->st_ino) {
-               error_msg("%s: file is the archive; skipping", fileName);
-               return( TRUE);
-       }
-
-       header_name = fileName;
-       while (header_name[0] == '/') {
-               static int alreadyWarned=FALSE;
-               if (alreadyWarned==FALSE) {
-                       error_msg("Removing leading '/' from member names");
-                       alreadyWarned=TRUE;
-               }
-               header_name++;
-       }
-
-       if (strlen(fileName) >= NAME_SIZE) {
-               error_msg(name_longer_than_foo, NAME_SIZE);
-               return ( TRUE);
-       }
-
-       if (header_name[0] == '\0')
-               return TRUE;
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-       if (exclude_file(tbInfo->excludeList, header_name)) {
-               return SKIP;
-       }
-#endif
-
-       if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) {
-               return( FALSE);
-       } 
-
-       /* Now, if the file is a regular file, copy it out to the tarball */
-       if ((tbInfo->hlInfo == NULL)
-       &&  (S_ISREG(statbuf->st_mode))) {
-               int  inputFileFd;
-               char buffer[BUFSIZ];
-               ssize_t size=0, readSize=0;
-
-               /* open the file we want to archive, and make sure all is well */
-               if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
-                       error_msg("%s: Cannot open: %s", fileName, strerror(errno));
-                       return( FALSE);
-               }
-               
-               /* write the file to the archive */
-               while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
-                       if (full_write(tbInfo->tarFd, buffer, size) != size ) {
-                               /* Output file seems to have a problem */
-                               error_msg(io_error, fileName, strerror(errno)); 
-                               return( FALSE);
-                       }
-                       readSize+=size;
-               }
-               if (size == -1) {
-                       error_msg(io_error, fileName, strerror(errno)); 
-                       return( FALSE);
-               }
-               /* Pad the file up to the tar block size */
-               for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
-                       write(tbInfo->tarFd, "\0", 1);
-               }
-               close( inputFileFd);
-       }
-
-       return( TRUE);
-}
-
-static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
-               char** excludeList)
-{
-       int tarFd=-1;
-       int errorFlag=FALSE;
-       ssize_t size;
-       struct TarBallInfo tbInfo;
-       tbInfo.verboseFlag = verboseFlag;
-       tbInfo.hlInfoHead = NULL;
-
-       /* Make sure there is at least one file to tar up.  */
-       if (*argv == NULL)
-               error_msg_and_die("Cowardly refusing to create an empty archive");
-
-       /* Open the tar file for writing.  */
-       if (!strcmp(tarName, "-"))
-               tbInfo.tarFd = fileno(stdout);
-       else
-               tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-       if (tbInfo.tarFd < 0) {
-               perror_msg( "Error opening '%s'", tarName);
-               freeHardLinkInfo(&tbInfo.hlInfoHead);
-               return ( FALSE);
-       }
-       tbInfo.excludeList=excludeList;
-       /* Store the stat info for the tarball's file, so
-        * can avoid including the tarball into itself....  */
-       if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
-               error_msg_and_die(io_error, tarName, strerror(errno)); 
-
-       /* Read the directory/files and iterate over them one at a time */
-       while (*argv != NULL) {
-               if (recursive_action(*argv++, TRUE, FALSE, FALSE,
-                                       writeFileToTarball, writeFileToTarball, 
-                                       (void*) &tbInfo) == FALSE) {
-                       errorFlag = TRUE;
-               }
-       }
-       /* Write two empty blocks to the end of the archive */
-       for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
-               write(tbInfo.tarFd, "\0", 1);
-       }
-
-       /* To be pedantically correct, we would check if the tarball
-        * is smaller than 20 tar blocks, and pad it if it was smaller,
-        * but that isn't necessary for GNU tar interoperability, and
-        * so is considered a waste of space */
-
-       /* Hang up the tools, close up shop, head home */
-       close(tarFd);
-       if (errorFlag == TRUE) {
-               error_msg("Error exit delayed from previous errors");
-               freeHardLinkInfo(&tbInfo.hlInfoHead);
-               return(FALSE);
-       }
-       freeHardLinkInfo(&tbInfo.hlInfoHead);
-       return( TRUE);
-}
-
-
-#endif
-
diff --git a/busybox/ash.c b/busybox/ash.c
deleted file mode 100644 (file)
index c0d4755..0000000
+++ /dev/null
@@ -1,12888 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * ash shell port for busybox
- *
- * Copyright (c) 1989, 1991, 1993, 1994
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This version of ash is adapted from the source in Debian's ash 0.3.8-5
- * package.
- *
- * Modified by Erik Andersen <andersee@debian.org> and
- * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
- *
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-
-/* These defines allow you to adjust the feature set to be compiled
- * into the ash shell.   As a rule, enabling these options will make
- * ash get bigger...   With all of these options off, ash adds about
- * 60k to busybox on an x86 system.*/
-
-
-/* Enable job control.  This allows you to run jobs in the background,
- * which is great when ash is being  used as an interactive shell, but
- * it completely useless for is all you are doing is running scripts.
- * This adds about 2.5k on an x86 system. */
-#undef JOBS
-
-/* This enables alias support in ash.  If you want to support things
- * like "alias ls='ls -l'" with ash, enable this.  This is only useful
- * when ash is used as an intractive shell.   This adds about 1.5k */
-#define ASH_ALIAS
-
-/* If you need ash to act as a full Posix shell, with full math
- * support, enable this.   This adds a bit over 2k an x86 system. */
-//#undef ASH_MATH_SUPPORT
-#define ASH_MATH_SUPPORT
-
-/* Getopts is used by shell procedures to parse positional parameters.
- * You probably want to leave this disabled, and use the busybox getopt
- * applet if you want to do this sort of thing.  There are some scripts
- * out there that use it, so if you need it, enable it.  Most people will
- * leave this disabled.  This adds 1k on an x86 system. */
-#undef ASH_GETOPTS
-
-/* This allows you to override shell builtins and use whatever is on
- * the filesystem.  This is most useful when ash is acting as a
- * standalone shell.   Adds about 272 bytes. */
-#undef ASH_CMDCMD
-
-
-/* Optimize size vs speed as size */
-#define ASH_OPTIMIZE_FOR_SIZE
-
-/* Enable this to compile in extra debugging noise.  When debugging is
- * on, debugging info will be written to $HOME/trace and a quit signal
- * will generate a core dump. */
-#undef DEBUG
-
-/* These are here to work with glibc -- Don't change these... */
-#undef FNMATCH_BROKEN
-#undef GLOB_BROKEN
-#define IFS_BROKEN
-
-#include <assert.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <paths.h>
-#include <pwd.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/cdefs.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-
-#if !defined(FNMATCH_BROKEN)
-#include <fnmatch.h>
-#endif
-#if !defined(GLOB_BROKEN)
-#include <glob.h>
-#endif
-
-#ifdef JOBS
-#include <termios.h>
-#endif
-
-#include "busybox.h"
-#include "cmdedit.h"
-
-/*
- * This file was generated by the mksyntax program.
- */
-
-/* Syntax classes */
-#define CWORD 0                 /* character is nothing special */
-#define CNL 1                   /* newline character */
-#define CBACK 2                 /* a backslash character */
-#define CSQUOTE 3               /* single quote */
-#define CDQUOTE 4               /* double quote */
-#define CENDQUOTE 5             /* a terminating quote */
-#define CBQUOTE 6               /* backwards single quote */
-#define CVAR 7                  /* a dollar sign */
-#define CENDVAR 8               /* a '}' character */
-#define CLP 9                   /* a left paren in arithmetic */
-#define CRP 10                  /* a right paren in arithmetic */
-#define CENDFILE 11             /* end of file */
-#define CCTL 12                 /* like CWORD, except it must be escaped */
-#define CSPCL 13                /* these terminate a word */
-#define CIGN 14                 /* character should be ignored */
-
-/* Syntax classes for is_ functions */
-#define ISDIGIT 01              /* a digit */
-#define ISUPPER 02              /* an upper case letter */
-#define ISLOWER 04              /* a lower case letter */
-#define ISUNDER 010             /* an underscore */
-#define ISSPECL 020             /* the name of a special parameter */
-
-#define SYNBASE 130
-#define PEOF -130
-
-#define PEOA -129
-
-#define TEOF 0
-#define TNL 1
-#define TSEMI 2
-#define TBACKGND 3
-#define TAND 4
-#define TOR 5
-#define TPIPE 6
-#define TLP 7
-#define TRP 8
-#define TENDCASE 9
-#define TENDBQUOTE 10
-#define TREDIR 11
-#define TWORD 12
-#define TASSIGN 13
-#define TNOT 14
-#define TCASE 15
-#define TDO 16
-#define TDONE 17
-#define TELIF 18
-#define TELSE 19
-#define TESAC 20
-#define TFI 21
-#define TFOR 22
-#define TIF 23
-#define TIN 24
-#define TTHEN 25
-#define TUNTIL 26
-#define TWHILE 27
-#define TBEGIN 28
-#define TEND 29
-
-
-#define BASESYNTAX (basesyntax + SYNBASE)
-#define DQSYNTAX (dqsyntax + SYNBASE)
-#define SQSYNTAX (sqsyntax + SYNBASE)
-#define ARISYNTAX (arisyntax + SYNBASE)
-
-/* control characters in argument strings */
-#define CTLESC '\201'
-#define CTLVAR '\202'
-#define CTLENDVAR '\203'
-#define CTLBACKQ '\204'
-#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
-/*      CTLBACKQ | CTLQUOTE == '\205' */
-#define CTLARI  '\206'
-#define CTLENDARI '\207'
-#define CTLQUOTEMARK '\210'
-
-#define is_digit(c)     ((c)>='0' && (c)<='9')
-#define is_alpha(c)     (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
-#define is_name(c)      (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
-#define is_in_name(c)   (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
-#define is_special(c)   ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
-#define digit_val(c)    ((c) - '0')
-
-
-#define _DIAGASSERT(x)
-
-
-
-#define S_DFL 1                 /* default signal handling (SIG_DFL) */
-#define S_CATCH 2               /* signal is caught */
-#define S_IGN 3                 /* signal is ignored (SIG_IGN) */
-#define S_HARD_IGN 4            /* signal is ignored permenantly */
-#define S_RESET 5               /* temporary - to reset a hard ignored sig */
-
-
-/* variable substitution byte (follows CTLVAR) */
-#define VSTYPE  0x0f            /* type of variable substitution */
-#define VSNUL   0x10            /* colon--treat the empty string as unset */
-#define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
-
-/* values of VSTYPE field */
-#define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
-#define VSMINUS         0x2             /* ${var-text} */
-#define VSPLUS          0x3             /* ${var+text} */
-#define VSQUESTION      0x4             /* ${var?message} */
-#define VSASSIGN        0x5             /* ${var=text} */
-#define VSTRIMLEFT      0x6             /* ${var#pattern} */
-#define VSTRIMLEFTMAX   0x7             /* ${var##pattern} */
-#define VSTRIMRIGHT     0x8             /* ${var%pattern} */
-#define VSTRIMRIGHTMAX  0x9             /* ${var%%pattern} */
-#define VSLENGTH        0xa             /* ${#var} */
-
-/* flags passed to redirect */
-#define REDIR_PUSH 01           /* save previous values of file descriptors */
-#define REDIR_BACKQ 02          /* save the command output to pipe */
-
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD)
-#define setjmp(jmploc)  _setjmp(jmploc)
-#define longjmp(jmploc, val)    _longjmp(jmploc, val)
-#endif
-
-/*
- * Most machines require the value returned from malloc to be aligned
- * in some way.  The following macro will get this right on many machines.
- */
-
-#ifndef ALIGN
-union align {
-       int i;
-       char *cp;
-};
-
-#define ALIGN(nbytes)   (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
-#endif
-
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-static void change_lc_all(const char *value);
-static void change_lc_ctype(const char *value);
-#endif
-
-/*
- * These macros allow the user to suspend the handling of interrupt signals
- * over a period of time.  This is similar to SIGHOLD to or sigblock, but
- * much more efficient and portable.  (But hacking the kernel is so much
- * more fun than worrying about efficiency and portability. :-))
- */
-
-static void onint (void);
-static volatile int suppressint;
-static volatile int intpending;
-
-#define INTOFF suppressint++
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define INTON { if (--suppressint == 0 && intpending) onint(); }
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
-#else
-static void __inton (void);
-static void forceinton (void);
-#define INTON __inton()
-#define FORCEINTON forceinton()
-#endif
-
-#define CLEAR_PENDING_INT intpending = 0
-#define int_pending() intpending
-
-
-typedef void *pointer;
-#ifndef NULL
-#define NULL (void *)0
-#endif
-
-static inline pointer  ckmalloc (int sz)          { return xmalloc(sz);     }
-static inline pointer  ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
-static inline char *   savestr  (const char *s)   { return xstrdup(s);      }
-
-static pointer stalloc (int);
-static void stunalloc (pointer);
-static void ungrabstackstr (char *, char *);
-static char * growstackstr(void);
-static char * makestrspace(size_t newlen);
-static char *sstrdup (const char *);
-
-/*
- * Parse trees for commands are allocated in lifo order, so we use a stack
- * to make this more efficient, and also to avoid all sorts of exception
- * handling code to handle interrupts in the middle of a parse.
- *
- * The size 504 was chosen because the Ultrix malloc handles that size
- * well.
- */
-
-#define MINSIZE 504             /* minimum size of a block */
-
-
-struct stack_block {
-       struct stack_block *prev;
-       char space[MINSIZE];
-};
-
-static struct stack_block stackbase;
-static struct stack_block *stackp = &stackbase;
-static struct stackmark *markp;
-static char *stacknxt = stackbase.space;
-static int stacknleft = MINSIZE;
-
-
-#define equal(s1, s2)   (strcmp(s1, s2) == 0)
-
-#define stackblock() stacknxt
-#define stackblocksize() stacknleft
-#define STARTSTACKSTR(p)        p = stackblock(), sstrnleft = stackblocksize()
-
-#define STPUTC(c, p)    (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
-#define CHECKSTRSPACE(n, p)     { if (sstrnleft < n) p = makestrspace(n); }
-#define STACKSTRNUL(p)  (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
-
-
-#define USTPUTC(c, p)   (--sstrnleft, *p++ = (c))
-#define STUNPUTC(p)     (++sstrnleft, --p)
-#define STTOPC(p)       p[-1]
-#define STADJUST(amount, p)     (p += (amount), sstrnleft -= (amount))
-#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
-
-#define ckfree(p)       free((pointer)(p))
-
-
-#ifdef DEBUG
-#define TRACE(param)    trace param
-static void trace (const char *, ...);
-static void trargs (char **);
-static void showtree (union node *);
-static void trputc (int);
-static void trputs (const char *);
-static void opentrace (void);
-#else
-#define TRACE(param)
-#endif
-
-#define NSEMI 0
-#define NCMD 1
-#define NPIPE 2
-#define NREDIR 3
-#define NBACKGND 4
-#define NSUBSHELL 5
-#define NAND 6
-#define NOR 7
-#define NIF 8
-#define NWHILE 9
-#define NUNTIL 10
-#define NFOR 11
-#define NCASE 12
-#define NCLIST 13
-#define NDEFUN 14
-#define NARG 15
-#define NTO 16
-#define NFROM 17
-#define NFROMTO 18
-#define NAPPEND 19
-#define NTOOV 20
-#define NTOFD 21
-#define NFROMFD 22
-#define NHERE 23
-#define NXHERE 24
-#define NNOT 25
-
-/*
- * expandarg() flags
- */
-#define EXP_FULL        0x1     /* perform word splitting & file globbing */
-#define EXP_TILDE       0x2     /* do normal tilde expansion */
-#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
-#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
-#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
-#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
-
-
-#define NOPTS   16
-
-static char optet_vals[NOPTS];
-
-static const char * const optlist[NOPTS] = {
-       "e" "errexit",
-       "f" "noglob",
-       "I" "ignoreeof",
-       "i" "interactive",
-       "m" "monitor",
-       "n" "noexec",
-       "s" "stdin",
-       "x" "xtrace",
-       "v" "verbose",
-       "V" "vi",
-       "E" "emacs",
-       "C" "noclobber",
-       "a" "allexport",
-       "b" "notify",
-       "u" "nounset",
-       "q" "quietprofile"
-};
-
-#define optent_name(optent) (optent+1)
-#define optent_letter(optent) optent[0]
-#define optent_val(optent) optet_vals[optent]
-
-#define eflag optent_val(0)
-#define fflag optent_val(1)
-#define Iflag optent_val(2)
-#define iflag optent_val(3)
-#define mflag optent_val(4)
-#define nflag optent_val(5)
-#define sflag optent_val(6)
-#define xflag optent_val(7)
-#define vflag optent_val(8)
-#define Vflag optent_val(9)
-#define Eflag optent_val(10)
-#define Cflag optent_val(11)
-#define aflag optent_val(12)
-#define bflag optent_val(13)
-#define uflag optent_val(14)
-#define qflag optent_val(15)
-
-
-/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
-#define FORK_FG 0
-#define FORK_BG 1
-#define FORK_NOJOB 2
-
-
-struct nbinary {
-      int type;
-      union node *ch1;
-      union node *ch2;
-};
-
-
-struct ncmd {
-      int type;
-      int backgnd;
-      union node *assign;
-      union node *args;
-      union node *redirect;
-};
-
-
-struct npipe {
-      int type;
-      int backgnd;
-      struct nodelist *cmdlist;
-};
-
-
-struct nredir {
-      int type;
-      union node *n;
-      union node *redirect;
-};
-
-
-struct nif {
-      int type;
-      union node *test;
-      union node *ifpart;
-      union node *elsepart;
-};
-
-
-struct nfor {
-      int type;
-      union node *args;
-      union node *body;
-      char *var;
-};
-
-
-struct ncase {
-      int type;
-      union node *expr;
-      union node *cases;
-};
-
-
-struct nclist {
-      int type;
-      union node *next;
-      union node *pattern;
-      union node *body;
-};
-
-
-struct narg {
-      int type;
-      union node *next;
-      char *text;
-      struct nodelist *backquote;
-};
-
-
-struct nfile {
-      int type;
-      union node *next;
-      int fd;
-      union node *fname;
-      char *expfname;
-};
-
-
-struct ndup {
-      int type;
-      union node *next;
-      int fd;
-      int dupfd;
-      union node *vname;
-};
-
-
-struct nhere {
-      int type;
-      union node *next;
-      int fd;
-      union node *doc;
-};
-
-
-struct nnot {
-      int type;
-      union node *com;
-};
-
-
-union node {
-      int type;
-      struct nbinary nbinary;
-      struct ncmd ncmd;
-      struct npipe npipe;
-      struct nredir nredir;
-      struct nif nif;
-      struct nfor nfor;
-      struct ncase ncase;
-      struct nclist nclist;
-      struct narg narg;
-      struct nfile nfile;
-      struct ndup ndup;
-      struct nhere nhere;
-      struct nnot nnot;
-};
-
-
-struct nodelist {
-       struct nodelist *next;
-       union node *n;
-};
-
-struct backcmd {                /* result of evalbackcmd */
-       int fd;                 /* file descriptor to read from */
-       char *buf;              /* buffer */
-       int nleft;              /* number of chars in buffer */
-       struct job *jp;         /* job structure for command */
-};
-
-struct cmdentry {
-       int cmdtype;
-       union param {
-               int index;
-               union node *func;
-               const struct builtincmd *cmd;
-       } u;
-};
-
-struct strlist {
-       struct strlist *next;
-       char *text;
-};
-
-
-struct arglist {
-       struct strlist *list;
-       struct strlist **lastp;
-};
-
-struct strpush {
-       struct strpush *prev;   /* preceding string on stack */
-       char *prevstring;
-       int prevnleft;
-#ifdef ASH_ALIAS
-       struct alias *ap;       /* if push was associated with an alias */
-#endif
-       char *string;           /* remember the string since it may change */
-};
-
-struct parsefile {
-       struct parsefile *prev; /* preceding file on stack */
-       int linno;              /* current line */
-       int fd;                 /* file descriptor (or -1 if string) */
-       int nleft;              /* number of chars left in this line */
-       int lleft;              /* number of chars left in this buffer */
-       char *nextc;            /* next char in buffer */
-       char *buf;              /* input buffer */
-       struct strpush *strpush; /* for pushing strings at this level */
-       struct strpush basestrpush; /* so pushing one is fast */
-};
-
-struct stackmark {
-       struct stack_block *stackp;
-       char *stacknxt;
-       int stacknleft;
-       struct stackmark *marknext;
-};
-
-struct shparam {
-       int nparam;             /* # of positional parameters (without $0) */
-       unsigned char malloc;   /* if parameter list dynamically allocated */
-       char **p;               /* parameter list */
-       int optind;             /* next parameter to be processed by getopts */
-       int optoff;             /* used by getopts */
-};
-
-/*
- * When commands are first encountered, they are entered in a hash table.
- * This ensures that a full path search will not have to be done for them
- * on each invocation.
- *
- * We should investigate converting to a linear search, even though that
- * would make the command name "hash" a misnomer.
- */
-#define CMDTABLESIZE 31         /* should be prime */
-#define ARB 1                   /* actual size determined at run time */
-
-
-
-struct tblentry {
-       struct tblentry *next;  /* next entry in hash chain */
-       union param param;      /* definition of builtin function */
-       short cmdtype;          /* index identifying command */
-       char rehash;            /* if set, cd done since entry created */
-       char cmdname[ARB];      /* name of command */
-};
-
-
-static struct tblentry *cmdtable[CMDTABLESIZE];
-static int builtinloc = -1;             /* index in path of %builtin, or -1 */
-static int exerrno = 0;                 /* Last exec error */
-
-
-static void tryexec (char *, char **, char **);
-static void printentry (struct tblentry *, int);
-static void clearcmdentry (int);
-static struct tblentry *cmdlookup (const char *, int);
-static void delete_cmd_entry (void);
-static int path_change (const char *, int *);
-
-
-static void flushall (void);
-static void out2fmt (const char *, ...)
-    __attribute__((__format__(__printf__,1,2)));
-static int xwrite (int, const char *, int);
-
-static void outstr (const char *p, FILE *file) { fputs(p, file); }
-static void out1str(const char *p) { outstr(p, stdout); }
-static void out2str(const char *p) { outstr(p, stderr); }
-
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define out2c(c)        putc((c), stderr)
-#else
-static void out2c(int c)           { putc(c, stderr); }
-#endif
-
-/* syntax table used when not in quotes */
-static const char basesyntax[257] = {
-      CENDFILE,   CSPCL,   CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CSPCL,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CSPCL,   CWORD,
-      CDQUOTE, CWORD,   CVAR,    CWORD,
-      CSPCL,   CSQUOTE, CSPCL,   CSPCL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CSPCL,   CSPCL,   CWORD,
-      CSPCL,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CBACK,   CWORD,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CSPCL,   CENDVAR,
-      CWORD
-};
-
-/* syntax table used when in double quotes */
-static const char dqsyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CCTL,
-      CENDQUOTE,CWORD,  CVAR,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CCTL,    CBACK,   CCTL,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CENDVAR,
-      CCTL
-};
-
-/* syntax table used when in single quotes */
-static const char sqsyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CCTL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CENDQUOTE,CWORD,  CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CCTL,    CCTL,    CCTL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL
-};
-
-/* syntax table used when in arithmetic */
-static const char arisyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CDQUOTE, CWORD,   CVAR,    CWORD,
-      CWORD,   CSQUOTE, CLP,     CRP,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CBACK,   CWORD,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CENDVAR,
-      CWORD
-};
-
-/* character classification table */
-static const char is_type[257] = {
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       ISSPECL,
-      0,       ISSPECL, ISSPECL, 0,
-      0,       0,       0,       0,
-      ISSPECL, 0,       0,       ISSPECL,
-      0,       0,       ISDIGIT, ISDIGIT,
-      ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
-      ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
-      0,       0,       0,       0,
-      0,       ISSPECL, ISSPECL, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, 0,       0,       0,
-      0,       ISUNDER, 0,       ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, 0,       0,       0,
-      0
-};
-
-/* Array indicating which tokens mark the end of a list */
-static const char tokendlist[] = {
-       1,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       1,
-       1,
-       1,
-       0,
-       0,
-       0,
-       0,
-       0,
-       1,
-       1,
-       1,
-       1,
-       1,
-       1,
-       0,
-       0,
-       0,
-       1,
-       0,
-       0,
-       0,
-       1,
-};
-
-static const char *const tokname[] = {
-       "end of file",
-       "newline",
-       "\";\"",
-       "\"&\"",
-       "\"&&\"",
-       "\"||\"",
-       "\"|\"",
-       "\"(\"",
-       "\")\"",
-       "\";;\"",
-       "\"`\"",
-       "redirection",
-       "word",
-       "assignment",
-       "\"!\"",
-       "\"case\"",
-       "\"do\"",
-       "\"done\"",
-       "\"elif\"",
-       "\"else\"",
-       "\"esac\"",
-       "\"fi\"",
-       "\"for\"",
-       "\"if\"",
-       "\"in\"",
-       "\"then\"",
-       "\"until\"",
-       "\"while\"",
-       "\"{\"",
-       "\"}\"",
-};
-
-#define KWDOFFSET 14
-
-static const char *const parsekwd[] = {
-       "!",
-       "case",
-       "do",
-       "done",
-       "elif",
-       "else",
-       "esac",
-       "fi",
-       "for",
-       "if",
-       "in",
-       "then",
-       "until",
-       "while",
-       "{",
-       "}"
-};
-
-
-static int plinno = 1;          /* input line number */
-
-static int parselleft;          /* copy of parsefile->lleft */
-
-static struct parsefile basepf; /* top level input file */
-static char basebuf[BUFSIZ];    /* buffer for top level input file */
-static struct parsefile *parsefile = &basepf;  /* current input file */
-
-/*
- * NEOF is returned by parsecmd when it encounters an end of file.  It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
-
-static int tokpushback;         /* last token pushed back */
-#define NEOF ((union node *)&tokpushback)
-static int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
-
-
-static void error (const char *, ...) __attribute__((__noreturn__));
-static void exerror (int, const char *, ...) __attribute__((__noreturn__));
-static void shellexec (char **, char **, const char *, int)
-    __attribute__((noreturn));
-static void exitshell (int) __attribute__((noreturn));
-
-static int  goodname(const char *);
-static void ignoresig (int);
-static void onsig (int);
-static void dotrap (void);
-static int  decode_signal (const char *, int);
-
-static void shprocvar(void);
-static void deletefuncs(void);
-static void setparam (char **);
-static void freeparam (volatile struct shparam *);
-
-/* reasons for skipping commands (see comment on breakcmd routine) */
-#define SKIPBREAK       1
-#define SKIPCONT        2
-#define SKIPFUNC        3
-#define SKIPFILE        4
-
-/* values of cmdtype */
-#define CMDUNKNOWN -1           /* no entry in table for command */
-#define CMDNORMAL 0             /* command is an executable program */
-#define CMDBUILTIN 1            /* command is a shell builtin */
-#define CMDFUNCTION 2           /* command is a shell function */
-
-#define DO_ERR  1               /* find_command prints errors */
-#define DO_ABS  2               /* find_command checks absolute paths */
-#define DO_NOFUN        4       /* find_command ignores functions */
-#define DO_BRUTE        8       /* find_command ignores hash table */
-
-/*
- * Shell variables.
- */
-
-/* flags */
-#define VEXPORT         0x01    /* variable is exported */
-#define VREADONLY       0x02    /* variable cannot be modified */
-#define VSTRFIXED       0x04    /* variable struct is staticly allocated */
-#define VTEXTFIXED      0x08    /* text is staticly allocated */
-#define VSTACK          0x10    /* text is allocated on the stack */
-#define VUNSET          0x20    /* the variable is not set */
-#define VNOFUNC         0x40    /* don't call the callback function */
-
-
-struct var {
-       struct var *next;               /* next entry in hash list */
-       int flags;                      /* flags are defined above */
-       char *text;                     /* name=value */
-       void (*func) (const char *);
-                                       /* function to be called when  */
-                                       /* the variable gets set/unset */
-};
-
-struct localvar {
-       struct localvar *next;          /* next local variable in list */
-       struct var *vp;                 /* the variable that was made local */
-       int flags;                      /* saved flags */
-       char *text;                     /* saved text */
-};
-
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-#define rmescapes(p) _rmescapes((p), 0)
-static char *_rmescapes (char *, int);
-#else
-static void rmescapes (char *);
-#endif
-
-static int  casematch (union node *, const char *);
-static void clearredir(void);
-static void popstring(void);
-static void readcmdfile (const char *);
-
-static int number (const char *);
-static int is_number (const char *, int *num);
-static char *single_quote (const char *);
-static int nextopt (const char *);
-
-static void redirect (union node *, int);
-static void popredir (void);
-static int dup_as_newfd (int, int);
-
-static void changepath(const char *newval);
-static void getoptsreset(const char *value);
-
-
-static int parsenleft;                  /* copy of parsefile->nleft */
-static char *parsenextc;                /* copy of parsefile->nextc */
-static int rootpid;     /* pid of main shell */
-static int rootshell;   /* true if we aren't a child of the main shell */
-
-static const char spcstr[] = " ";
-static const char snlfmt[] = "%s\n";
-
-static int sstrnleft;
-static int herefd = -1;
-
-static struct localvar *localvars;
-
-static struct var vifs;
-static struct var vmail;
-static struct var vmpath;
-static struct var vpath;
-static struct var vps1;
-static struct var vps2;
-static struct var voptind;
-#ifdef BB_LOCALE_SUPPORT
-static struct var vlc_all;
-static struct var vlc_ctype;
-#endif
-
-struct varinit {
-       struct var *var;
-       int flags;
-       const char *text;
-       void (*func) (const char *);
-};
-
-static const char defpathvar[] =
-       "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
-#define defpath (defpathvar + 5)
-
-#ifdef IFS_BROKEN
-static const char defifsvar[] = "IFS= \t\n";
-#define defifs (defifsvar + 4)
-#else
-static const char defifs[] = " \t\n";
-#endif
-
-static const struct varinit varinit[] = {
-#ifdef IFS_BROKEN
-       { &vifs,        VSTRFIXED|VTEXTFIXED,           defifsvar,
-#else
-       { &vifs,        VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS=",
-#endif
-         NULL },
-       { &vmail,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
-         NULL },
-       { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
-         NULL },
-       { &vpath,       VSTRFIXED|VTEXTFIXED,           defpathvar,
-         changepath },
-       /*
-        * vps1 depends on uid
-        */
-       { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
-         NULL },
-       { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
-         getoptsreset },
-#ifdef BB_LOCALE_SUPPORT
-       { &vlc_all,     VSTRFIXED|VTEXTFIXED|VUNSET,    "LC_ALL=",
-         change_lc_all },
-       { &vlc_ctype,   VSTRFIXED|VTEXTFIXED|VUNSET,    "LC_CTYPE=",
-         change_lc_ctype },
-#endif
-       { NULL, 0,                              NULL,
-         NULL }
-};
-
-#define VTABSIZE 39
-
-static struct var *vartab[VTABSIZE];
-
-/*
- * The following macros access the values of the above variables.
- * They have to skip over the name.  They return the null string
- * for unset variables.
- */
-
-#define ifsval()        (vifs.text + 4)
-#define ifsset()        ((vifs.flags & VUNSET) == 0)
-#define mailval()       (vmail.text + 5)
-#define mpathval()      (vmpath.text + 9)
-#define pathval()       (vpath.text + 5)
-#define ps1val()        (vps1.text + 4)
-#define ps2val()        (vps2.text + 4)
-#define optindval()     (voptind.text + 7)
-
-#define mpathset()      ((vmpath.flags & VUNSET) == 0)
-
-static void initvar (void);
-static void setvar (const char *, const char *, int);
-static void setvareq (char *, int);
-static void listsetvar (struct strlist *);
-static const char *lookupvar (const char *);
-static const char *bltinlookup (const char *);
-static char **environment (void);
-static int showvarscmd (int, char **);
-static void mklocal (char *);
-static void poplocalvars (void);
-static int unsetvar (const char *);
-static int varequal (const char *, const char *);
-
-
-static char *arg0;                      /* value of $0 */
-static struct shparam shellparam;       /* current positional parameters */
-static char **argptr;                   /* argument list for builtin commands */
-static char *optionarg;                 /* set by nextopt (like getopt) */
-static char *optptr;                    /* used by nextopt */
-static char *minusc;                    /* argument to -c option */
-
-
-#ifdef ASH_ALIAS
-
-#define ALIASINUSE      1
-#define ALIASDEAD       2
-
-#define ATABSIZE 39
-
-struct alias {
-       struct alias *next;
-       char *name;
-       char *val;
-       int flag;
-};
-
-static struct alias *atab[ATABSIZE];
-
-static void setalias (char *, char *);
-static struct alias **hashalias (const char *);
-static struct alias *freealias (struct alias *);
-static struct alias **__lookupalias (const char *);
-
-static void
-setalias(name, val)
-       char *name, *val;
-{
-       struct alias *ap, **app;
-
-       app = __lookupalias(name);
-       ap = *app;
-       INTOFF;
-       if (ap) {
-               if (!(ap->flag & ALIASINUSE)) {
-                       ckfree(ap->val);
-               }
-               ap->val = savestr(val);
-               ap->flag &= ~ALIASDEAD;
-       } else {
-               /* not found */
-               ap = ckmalloc(sizeof (struct alias));
-               ap->name = savestr(name);
-               ap->val = savestr(val);
-               ap->flag = 0;
-               ap->next = 0;
-               *app = ap;
-       }
-       INTON;
-}
-
-static int
-unalias(char *name)
-{
-       struct alias **app;
-
-       app = __lookupalias(name);
-
-       if (*app) {
-               INTOFF;
-               *app = freealias(*app);
-               INTON;
-               return (0);
-       }
-
-       return (1);
-}
-
-static void
-rmaliases(void)
-{
-       struct alias *ap, **app;
-       int i;
-
-       INTOFF;
-       for (i = 0; i < ATABSIZE; i++) {
-               app = &atab[i];
-               for (ap = *app; ap; ap = *app) {
-                       *app = freealias(*app);
-                       if (ap == *app) {
-                               app = &ap->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-static struct alias *
-lookupalias(const char *name, int check)
-{
-       struct alias *ap = *__lookupalias(name);
-
-       if (check && ap && (ap->flag & ALIASINUSE))
-               return (NULL);
-       return (ap);
-}
-
-static void
-printalias(const struct alias *ap) {
-       char *p;
-
-       p = single_quote(ap->val);
-       printf("alias %s=%s\n", ap->name, p);
-       stunalloc(p);
-}
-
-
-/*
- * TODO - sort output
- */
-static int
-aliascmd(int argc, char **argv)
-{
-       char *n, *v;
-       int ret = 0;
-       struct alias *ap;
-
-       if (argc == 1) {
-               int i;
-
-               for (i = 0; i < ATABSIZE; i++)
-                       for (ap = atab[i]; ap; ap = ap->next) {
-                               printalias(ap);
-                       }
-               return (0);
-       }
-       while ((n = *++argv) != NULL) {
-               if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
-                       if ((ap = *__lookupalias(n)) == NULL) {
-                               out2fmt("%s: %s not found\n", "alias", n);
-                               ret = 1;
-                       } else
-                               printalias(ap);
-               }
-               else {
-                       *v++ = '\0';
-                       setalias(n, v);
-               }
-       }
-
-       return (ret);
-}
-
-static int
-unaliascmd(int argc, char **argv)
-{
-       int i;
-
-       while ((i = nextopt("a")) != '\0') {
-               if (i == 'a') {
-                       rmaliases();
-                       return (0);
-               }
-       }
-       for (i = 0; *argptr; argptr++) {
-               if (unalias(*argptr)) {
-                       out2fmt("%s: %s not found\n", "unalias", *argptr);
-                       i = 1;
-               }
-       }
-
-       return (i);
-}
-
-static struct alias **
-hashalias(p)
-       const char *p;
-       {
-       unsigned int hashval;
-
-       hashval = *p << 4;
-       while (*p)
-               hashval+= *p++;
-       return &atab[hashval % ATABSIZE];
-}
-
-static struct alias *
-freealias(struct alias *ap) {
-       struct alias *next;
-
-       if (ap->flag & ALIASINUSE) {
-               ap->flag |= ALIASDEAD;
-               return ap;
-       }
-
-       next = ap->next;
-       ckfree(ap->name);
-       ckfree(ap->val);
-       ckfree(ap);
-       return next;
-}
-
-
-static struct alias **
-__lookupalias(const char *name) {
-       struct alias **app = hashalias(name);
-
-       for (; *app; app = &(*app)->next) {
-               if (equal(name, (*app)->name)) {
-                       break;
-               }
-       }
-
-       return app;
-}
-#endif
-
-#ifdef ASH_MATH_SUPPORT
-/* The generated file arith.c has been replaced with a custom hand
- * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.  
- * This is now part of libbb, so that it can be used by all the shells 
- * in busybox. */
-#define ARITH_NUM 257
-#define ARITH_LPAREN 258
-#define ARITH_RPAREN 259
-#define ARITH_OR 260
-#define ARITH_AND 261
-#define ARITH_BOR 262
-#define ARITH_BXOR 263
-#define ARITH_BAND 264
-#define ARITH_EQ 265
-#define ARITH_NE 266
-#define ARITH_LT 267
-#define ARITH_GT 268
-#define ARITH_GE 269
-#define ARITH_LE 270
-#define ARITH_LSHIFT 271
-#define ARITH_RSHIFT 272
-#define ARITH_ADD 273
-#define ARITH_SUB 274
-#define ARITH_MUL 275
-#define ARITH_DIV 276
-#define ARITH_REM 277
-#define ARITH_UNARYMINUS 278
-#define ARITH_UNARYPLUS 279
-#define ARITH_NOT 280
-#define ARITH_BNOT 281
-
-static void expari (int);
-#endif
-
-static char *trap[NSIG];                /* trap handler commands */
-static char sigmode[NSIG - 1];  /* current value of signal */
-static char gotsig[NSIG - 1];           /* indicates specified signal received */
-static int pendingsigs;                 /* indicates some signal received */
-
-/*
- * This file was generated by the mkbuiltins program.
- */
-
-#ifdef JOBS
-static int bgcmd (int, char **);
-static int fgcmd (int, char **);
-static int killcmd (int, char **);
-#endif
-static int bltincmd (int, char **);
-static int cdcmd (int, char **);
-static int breakcmd (int, char **);
-#ifdef ASH_CMDCMD
-static int commandcmd (int, char **);
-#endif
-static int dotcmd (int, char **);
-static int evalcmd (int, char **);
-static int execcmd (int, char **);
-static int exitcmd (int, char **);
-static int exportcmd (int, char **);
-static int histcmd (int, char **);
-static int hashcmd (int, char **);
-static int helpcmd (int, char **);
-static int jobscmd (int, char **);
-static int localcmd (int, char **);
-#ifndef BB_PWD
-static int pwdcmd (int, char **);
-#endif
-static int readcmd (int, char **);
-static int returncmd (int, char **);
-static int setcmd (int, char **);
-static int setvarcmd (int, char **);
-static int shiftcmd (int, char **);
-static int trapcmd (int, char **);
-static int umaskcmd (int, char **);
-#ifdef ASH_ALIAS
-static int aliascmd (int, char **);
-static int unaliascmd (int, char **);
-#endif
-static int unsetcmd (int, char **);
-static int waitcmd (int, char **);
-static int ulimitcmd (int, char **);
-static int timescmd (int, char **);
-#ifdef ASH_MATH_SUPPORT
-static int letcmd (int, char **);
-#endif
-static int typecmd (int, char **);
-#ifdef ASH_GETOPTS
-static int getoptscmd (int, char **);
-#endif
-
-#ifndef BB_TRUE_FALSE
-static int true_main (int, char **);
-static int false_main (int, char **);
-#endif
-
-static void     setpwd (const char *, int);
-
-
-#define BUILTIN_NOSPEC  "0"
-#define BUILTIN_SPECIAL "1"
-#define BUILTIN_REGULAR "2"
-#define BUILTIN_ASSIGN  "4"
-#define BUILTIN_SPEC_ASSG  "5"
-#define BUILTIN_REG_ASSG   "6"
-
-#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
-#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
-#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
-
-struct builtincmd {
-       const char *name;
-       int (*const builtinfunc) (int, char **);
-       //unsigned flags;
-};
-
-
-/* It is CRUCIAL that this listing be kept in ascii order, otherwise
- * the binary search in find_builtin() will stop working. If you value
- * your kneecaps, you'll be sure to *make sure* that any changes made
- * to this array result in the listing remaining in ascii order. You
- * have been warned.
- */
-static const struct builtincmd builtincmds[] = {
-       { BUILTIN_SPECIAL   ".", dotcmd },    /* first, see declare DOTCMD */
-       { BUILTIN_SPECIAL   ":", true_main },
-#ifdef ASH_ALIAS
-       { BUILTIN_REG_ASSG  "alias", aliascmd },
-#endif
-#ifdef JOBS
-       { BUILTIN_REGULAR   "bg", bgcmd },
-#endif
-       { BUILTIN_SPECIAL   "break", breakcmd },
-       { BUILTIN_SPECIAL   "builtin", bltincmd },
-       { BUILTIN_REGULAR   "cd", cdcmd },
-       { BUILTIN_NOSPEC    "chdir", cdcmd },
-#ifdef ASH_CMDCMD
-       { BUILTIN_REGULAR   "command", commandcmd },
-#endif
-       { BUILTIN_SPECIAL   "continue", breakcmd },
-       { BUILTIN_SPECIAL   "eval", evalcmd },
-       { BUILTIN_SPECIAL   "exec", execcmd },
-       { BUILTIN_SPECIAL   "exit", exitcmd },
-       { BUILTIN_SPEC_ASSG "export", exportcmd },
-       { BUILTIN_REGULAR   "false", false_main },
-       { BUILTIN_REGULAR   "fc", histcmd },
-#ifdef JOBS
-       { BUILTIN_REGULAR   "fg", fgcmd },
-#endif
-#ifdef ASH_GETOPTS
-       { BUILTIN_REGULAR   "getopts", getoptscmd },
-#endif
-       { BUILTIN_NOSPEC    "hash", hashcmd },
-       { BUILTIN_NOSPEC    "help", helpcmd },
-       { BUILTIN_REGULAR   "jobs", jobscmd },
-#ifdef JOBS
-       { BUILTIN_REGULAR   "kill", killcmd },
-#endif
-#ifdef ASH_MATH_SUPPORT
-       { BUILTIN_REGULAR    "let", letcmd },
-#endif
-       { BUILTIN_ASSIGN    "local", localcmd },
-#ifndef BB_PWD
-       { BUILTIN_NOSPEC    "pwd", pwdcmd },
-#endif
-       { BUILTIN_REGULAR   "read", readcmd },
-       { BUILTIN_SPEC_ASSG "readonly", exportcmd },
-       { BUILTIN_SPECIAL   "return", returncmd },
-       { BUILTIN_SPECIAL   "set", setcmd },
-       { BUILTIN_NOSPEC    "setvar", setvarcmd },
-       { BUILTIN_SPECIAL   "shift", shiftcmd },
-       { BUILTIN_SPECIAL   "times", timescmd },
-       { BUILTIN_SPECIAL   "trap", trapcmd },
-       { BUILTIN_REGULAR   "true", true_main },
-       { BUILTIN_NOSPEC    "type", typecmd },
-       { BUILTIN_NOSPEC    "ulimit", ulimitcmd },
-       { BUILTIN_REGULAR   "umask", umaskcmd },
-#ifdef ASH_ALIAS
-       { BUILTIN_REGULAR   "unalias", unaliascmd },
-#endif
-       { BUILTIN_SPECIAL   "unset", unsetcmd },
-       { BUILTIN_REGULAR   "wait", waitcmd },
-};
-#define NUMBUILTINS  (sizeof (builtincmds) / sizeof (struct builtincmd) )
-
-static const struct builtincmd *DOTCMD = &builtincmds[0];
-static struct builtincmd *BLTINCMD;
-static struct builtincmd *EXECCMD;
-static struct builtincmd *EVALCMD;
-
-/* states */
-#define JOBSTOPPED 1            /* all procs are stopped */
-#define JOBDONE 2               /* all procs are completed */
-
-/*
- * A job structure contains information about a job.  A job is either a
- * single process or a set of processes contained in a pipeline.  In the
- * latter case, pidlist will be non-NULL, and will point to a -1 terminated
- * array of pids.
- */
-
-struct procstat {
-       pid_t pid;              /* process id */
-       int status;             /* status flags (defined above) */
-       char *cmd;              /* text of command being run */
-};
-
-
-static int job_warning;         /* user was warned about stopped jobs */
-
-#ifdef JOBS
-static void setjobctl(int enable);
-#else
-#define setjobctl(on)   /* do nothing */
-#endif
-
-
-struct job {
-       struct procstat ps0;    /* status of process */
-       struct procstat *ps;    /* status or processes when more than one */
-       short nprocs;           /* number of processes */
-       short pgrp;             /* process group of this job */
-       char state;             /* true if job is finished */
-       char used;              /* true if this entry is in used */
-       char changed;           /* true if status has changed */
-#ifdef JOBS
-       char jobctl;            /* job running under job control */
-#endif
-};
-
-static struct job *jobtab;      /* array of jobs */
-static int njobs;               /* size of array */
-static int backgndpid = -1;     /* pid of last background process */
-#ifdef JOBS
-static int initialpgrp;         /* pgrp of shell on invocation */
-static int curjob;              /* current job */
-static int jobctl;
-#endif
-static int intreceived;
-
-static struct job *makejob (const union node *, int);
-static int forkshell (struct job *, const union node *, int);
-static int waitforjob (struct job *);
-
-static int docd (char *, int);
-static char *getcomponent (void);
-static void updatepwd (const char *);
-static void getpwd (void);
-
-static char *padvance (const char **, const char *);
-
-static char nullstr[1];         /* zero length string */
-static char *curdir = nullstr;          /* current working directory */
-static char *cdcomppath;
-
-static int
-cdcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       const char *dest;
-       const char *path;
-       char *p;
-       struct stat statb;
-       int print = 0;
-
-       nextopt(nullstr);
-       if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
-               error("HOME not set");
-       if (*dest == '\0')
-               dest = ".";
-       if (dest[0] == '-' && dest[1] == '\0') {
-               dest = bltinlookup("OLDPWD");
-               if (!dest || !*dest) {
-                       dest = curdir;
-               }
-               print = 1;
-               if (dest)
-                       print = 1;
-               else
-                       dest = ".";
-       }
-       if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
-               path = nullstr;
-       while ((p = padvance(&path, dest)) != NULL) {
-               if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
-                       if (!print) {
-                               /*
-                                * XXX - rethink
-                                */
-                               if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
-                                       p += 2;
-                               print = strcmp(p, dest);
-                       }
-                       if (docd(p, print) >= 0)
-                               return 0;
-
-               }
-       }
-       error("can't cd to %s", dest);
-       /* NOTREACHED */
-}
-
-
-/*
- * Actually do the chdir.  In an interactive shell, print the
- * directory name if "print" is nonzero.
- */
-
-static int
-docd(dest, print)
-       char *dest;
-       int print;
-{
-       char *p;
-       char *q;
-       char *component;
-       struct stat statb;
-       int first;
-       int badstat;
-
-       TRACE(("docd(\"%s\", %d) called\n", dest, print));
-
-       /*
-        *  Check each component of the path. If we find a symlink or
-        *  something we can't stat, clear curdir to force a getcwd()
-        *  next time we get the value of the current directory.
-        */
-       badstat = 0;
-       cdcomppath = sstrdup(dest);
-       STARTSTACKSTR(p);
-       if (*dest == '/') {
-               STPUTC('/', p);
-               cdcomppath++;
-       }
-       first = 1;
-       while ((q = getcomponent()) != NULL) {
-               if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
-                       continue;
-               if (! first)
-                       STPUTC('/', p);
-               first = 0;
-               component = q;
-               while (*q)
-                       STPUTC(*q++, p);
-               if (equal(component, ".."))
-                       continue;
-               STACKSTRNUL(p);
-               if ((lstat(stackblock(), &statb) < 0)
-                   || (S_ISLNK(statb.st_mode)))  {
-                       /* print = 1; */
-                       badstat = 1;
-                       break;
-               }
-       }
-
-       INTOFF;
-       if (chdir(dest) < 0) {
-               INTON;
-               return -1;
-       }
-       updatepwd(badstat ? NULL : dest);
-       INTON;
-       if (print && iflag)
-               printf(snlfmt, curdir);
-       return 0;
-}
-
-
-/*
- * Get the next component of the path name pointed to by cdcomppath.
- * This routine overwrites the string pointed to by cdcomppath.
- */
-
-static char *
-getcomponent() {
-       char *p;
-       char *start;
-
-       if ((p = cdcomppath) == NULL)
-               return NULL;
-       start = cdcomppath;
-       while (*p != '/' && *p != '\0')
-               p++;
-       if (*p == '\0') {
-               cdcomppath = NULL;
-       } else {
-               *p++ = '\0';
-               cdcomppath = p;
-       }
-       return start;
-}
-
-
-
-/*
- * Update curdir (the name of the current directory) in response to a
- * cd command.  We also call hashcd to let the routines in exec.c know
- * that the current directory has changed.
- */
-
-static void hashcd (void);
-
-static void
-updatepwd(const char *dir)
-{
-       char *new;
-       char *p;
-       size_t len;
-
-       hashcd();                               /* update command hash table */
-
-       /*
-        * If our argument is NULL, we don't know the current directory
-        * any more because we traversed a symbolic link or something
-        * we couldn't stat().
-        */
-       if (dir == NULL || curdir == nullstr)  {
-               setpwd(0, 1);
-               return;
-       }
-       len = strlen(dir);
-       cdcomppath = sstrdup(dir);
-       STARTSTACKSTR(new);
-       if (*dir != '/') {
-               p = curdir;
-               while (*p)
-                       STPUTC(*p++, new);
-               if (p[-1] == '/')
-                       STUNPUTC(new);
-       }
-       while ((p = getcomponent()) != NULL) {
-               if (equal(p, "..")) {
-                       while (new > stackblock() && (STUNPUTC(new), *new) != '/');
-               } else if (*p != '\0' && ! equal(p, ".")) {
-                       STPUTC('/', new);
-                       while (*p)
-                               STPUTC(*p++, new);
-               }
-       }
-       if (new == stackblock())
-               STPUTC('/', new);
-       STACKSTRNUL(new);
-       setpwd(stackblock(), 1);
-}
-
-
-#ifndef BB_PWD
-static int
-pwdcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       printf(snlfmt, curdir);
-       return 0;
-}
-#endif
-
-/*
- * Find out what the current directory is. If we already know the current
- * directory, this routine returns immediately.
- */
-static void
-getpwd(void)
-{
-       curdir = xgetcwd(0);
-       if(curdir==0)
-               curdir = nullstr;
-}
-
-static void
-setpwd(const char *val, int setold)
-{
-       if (setold) {
-               setvar("OLDPWD", curdir, VEXPORT);
-       }
-       INTOFF;
-       if (curdir != nullstr) {
-               free(curdir);
-               curdir = nullstr;
-       }
-       if (!val) {
-               getpwd();
-       } else {
-               curdir = savestr(val);
-       }
-       INTON;
-       setvar("PWD", curdir, VEXPORT);
-}
-
-/*
- * Errors and exceptions.
- */
-
-/*
- * Code to handle exceptions in C.
- */
-
-/*
- * We enclose jmp_buf in a structure so that we can declare pointers to
- * jump locations.  The global variable handler contains the location to
- * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exeception.  To implement nested
- * exception handlers, the user should save the value of handler on entry
- * to an inner scope, set handler to point to a jmploc structure for the
- * inner scope, and restore handler on exit from the scope.
- */
-
-struct jmploc {
-       jmp_buf loc;
-};
-
-/* exceptions */
-#define EXINT 0         /* SIGINT received */
-#define EXERROR 1       /* a generic error */
-#define EXSHELLPROC 2   /* execute a shell procedure */
-#define EXEXEC 3        /* command execution failed */
-
-static struct jmploc *handler;
-static int exception;
-
-static void exverror (int, const char *, va_list)
-    __attribute__((__noreturn__));
-
-/*
- * Called to raise an exception.  Since C doesn't include exceptions, we
- * just do a longjmp to the exception handler.  The type of exception is
- * stored in the global variable "exception".
- */
-
-static void exraise (int) __attribute__((__noreturn__));
-
-static void
-exraise(int e)
-{
-#ifdef DEBUG
-       if (handler == NULL)
-               abort();
-#endif
-       flushall();
-       exception = e;
-       longjmp(handler->loc, 1);
-}
-
-
-/*
- * Called from trap.c when a SIGINT is received.  (If the user specifies
- * that SIGINT is to be trapped or ignored using the trap builtin, then
- * this routine is not called.)  Suppressint is nonzero when interrupts
- * are held using the INTOFF macro.  The call to _exit is necessary because
- * there is a short period after a fork before the signal handlers are
- * set to the appropriate value for the child.  (The test for iflag is
- * just defensive programming.)
- */
-
-static void
-onint(void) {
-       sigset_t mysigset;
-
-       if (suppressint) {
-               intpending++;
-               return;
-       }
-       intpending = 0;
-       sigemptyset(&mysigset);
-       sigprocmask(SIG_SETMASK, &mysigset, NULL);
-       if (rootshell && iflag)
-               exraise(EXINT);
-       else {
-               signal(SIGINT, SIG_DFL);
-               raise(SIGINT);
-       }
-       /* NOTREACHED */
-}
-
-
-static char *commandname;       /* currently executing command */
-
-/*
- * Exverror is called to raise the error exception.  If the first argument
- * is not NULL then error prints an error message using printf style
- * formatting.  It then raises the error exception.
- */
-static void
-exverror(int cond, const char *msg, va_list ap)
-{
-       CLEAR_PENDING_INT;
-       INTOFF;
-
-#ifdef DEBUG
-       if (msg)
-               TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
-       else
-               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
-#endif
-       if (msg) {
-               if (commandname)
-                       out2fmt("%s: ", commandname);
-               vfprintf(stderr, msg, ap);
-               out2c('\n');
-       }
-       exraise(cond);
-       /* NOTREACHED */
-}
-
-
-static void 
-error(const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(EXERROR, msg, ap);
-       /* NOTREACHED */
-       va_end(ap);
-}
-
-
-static void
-exerror(int cond, const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(cond, msg, ap);
-       /* NOTREACHED */
-       va_end(ap);
-}
-
-
-
-/*
- * Table of error messages.
- */
-
-struct errname {
-       short errcode;          /* error number */
-       char  action;           /* operation which encountered the error */
-};
-
-/*
- * Types of operations (passed to the errmsg routine).
- */
-
-#define E_OPEN 01       /* opening a file */
-#define E_CREAT 02      /* creating a file */
-#define E_EXEC 04       /* executing a program */
-
-#define ALL (E_OPEN|E_CREAT|E_EXEC)
-
-static const struct errname errormsg[] = {
-       { EINTR,        ALL     },
-       { EACCES,       ALL     },
-       { EIO,          ALL     },
-       { ENOENT,       E_OPEN  },
-       { ENOENT,       E_CREAT },
-       { ENOENT,       E_EXEC  },
-       { ENOTDIR,      E_OPEN  },
-       { ENOTDIR,      E_CREAT },
-       { ENOTDIR,      E_EXEC  },
-       { EISDIR,       ALL     },
-       { EEXIST,       E_CREAT },
-#ifdef EMFILE
-       { EMFILE,       ALL     },
-#endif
-       { ENFILE,       ALL     },
-       { ENOSPC,       ALL     },
-#ifdef EDQUOT
-       { EDQUOT,       ALL     },
-#endif
-#ifdef ENOSR
-       { ENOSR,        ALL     },
-#endif
-       { ENXIO,        ALL     },
-       { EROFS,        ALL     },
-       { ETXTBSY,      ALL     },
-#ifdef EAGAIN
-       { EAGAIN,       E_EXEC  },
-#endif
-       { ENOMEM,       ALL     },
-#ifdef ENOLINK
-       { ENOLINK,      ALL     },
-#endif
-#ifdef EMULTIHOP
-       { EMULTIHOP,    ALL     },
-#endif
-#ifdef ECOMM
-       { ECOMM,        ALL     },
-#endif
-#ifdef ESTALE
-       { ESTALE,       ALL     },
-#endif
-#ifdef ETIMEDOUT
-       { ETIMEDOUT,    ALL     },
-#endif
-#ifdef ELOOP
-       { ELOOP,        ALL     },
-#endif
-       { E2BIG,        E_EXEC  },
-#ifdef ELIBACC
-       { ELIBACC,      E_EXEC  },
-#endif
-};
-
-#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
-
-/*
- * Return a string describing an error.  The returned string may be a
- * pointer to a static buffer that will be overwritten on the next call.
- * Action describes the operation that got the error.
- */
-
-static const char *
-errmsg(int e, int action)
-{
-       struct errname const *ep;
-       static char buf[12];
-
-       for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
-               if (ep->errcode == e && (ep->action & action) != 0)
-                       return strerror(e);
-       }
-
-       snprintf(buf, sizeof buf, "error %d", e);
-       return buf;
-}
-
-
-#ifdef ASH_OPTIMIZE_FOR_SIZE
-static void
-__inton() {
-       if (--suppressint == 0 && intpending) {
-               onint();
-       }
-}
-static void forceinton (void) {
-       suppressint = 0;
-       if (intpending)
-               onint();
-}
-#endif
-
-/* flags in argument to evaltree */
-#define EV_EXIT 01              /* exit after evaluating tree */
-#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
-#define EV_BACKCMD 04           /* command executing within back quotes */
-
-static int evalskip;                    /* set if we are skipping commands */
-static int skipcount;           /* number of levels to skip */
-static int loopnest;            /* current loop nesting level */
-static int funcnest;                    /* depth of function calls */
-
-
-static struct strlist *cmdenviron;      /* environment for builtin command */
-static int exitstatus;                  /* exit status of last command */
-static int oexitstatus;         /* saved exit status */
-
-static void evalsubshell (const union node *, int);
-static void expredir (union node *);
-static void prehash (union node *);
-static void eprintlist (struct strlist *);
-
-static union node *parsecmd(int);
-/*
- * Called to reset things after an exception.
- */
-
-/*
- * The eval commmand.
- */
-static void evalstring (char *, int);
-
-static int
-evalcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *p;
-       char *concat;
-       char **ap;
-
-       if (argc > 1) {
-               p = argv[1];
-               if (argc > 2) {
-                       STARTSTACKSTR(concat);
-                       ap = argv + 2;
-                       for (;;) {
-                               while (*p)
-                                       STPUTC(*p++, concat);
-                               if ((p = *ap++) == NULL)
-                                       break;
-                               STPUTC(' ', concat);
-                       }
-                       STPUTC('\0', concat);
-                       p = grabstackstr(concat);
-               }
-               evalstring(p, EV_TESTED);
-       }
-       return exitstatus;
-}
-
-/*
- * Execute a command or commands contained in a string.
- */
-
-static void evaltree (union node *, int);
-static void setinputstring (char *);
-static void popfile (void);
-static void setstackmark(struct stackmark *mark);
-static void popstackmark(struct stackmark *mark);
-
-
-static void
-evalstring(char *s, int flag)
-{
-       union node *n;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       setinputstring(s);
-       while ((n = parsecmd(0)) != NEOF) {
-               evaltree(n, flag);
-               popstackmark(&smark);
-       }
-       popfile();
-       popstackmark(&smark);
-}
-
-static struct builtincmd *find_builtin (const char *);
-static void expandarg (union node *, struct arglist *, int);
-static void calcsize (const union node *);
-static union node *copynode (const union node *);
-
-/*
- * Make a copy of a parse tree.
- */
-
-static int     funcblocksize;           /* size of structures in function */
-static int     funcstringsize;          /* size of strings in node */
-static pointer funcblock;              /* block to allocate function from */
-static char   *funcstring;              /* block to allocate strings from */
-
-
-static inline union node *
-copyfunc(union node *n)
-{
-       if (n == NULL)
-               return NULL;
-       funcblocksize = 0;
-       funcstringsize = 0;
-       calcsize(n);
-       funcblock = ckmalloc(funcblocksize + funcstringsize);
-       funcstring = (char *) funcblock + funcblocksize;
-       return copynode(n);
-}
-
-/*
- * Free a parse tree.
- */
-
-static void
-freefunc(union node *n)
-{
-       if (n)
-               ckfree(n);
-}
-
-
-/*
- * Add a new command entry, replacing any existing command entry for
- * the same name.
- */
-
-static inline void
-addcmdentry(char *name, struct cmdentry *entry)
-{
-       struct tblentry *cmdp;
-
-       INTOFF;
-       cmdp = cmdlookup(name, 1);
-       if (cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
-       }
-       cmdp->cmdtype = entry->cmdtype;
-       cmdp->param = entry->u;
-       INTON;
-}
-
-static inline void
-evalloop(const union node *n, int flags)
-{
-       int status;
-
-       loopnest++;
-       status = 0;
-       for (;;) {
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip) {
-skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
-                               evalskip = 0;
-                               continue;
-                       }
-                       if (evalskip == SKIPBREAK && --skipcount <= 0)
-                               evalskip = 0;
-                       break;
-               }
-               if (n->type == NWHILE) {
-                       if (exitstatus != 0)
-                               break;
-               } else {
-                       if (exitstatus == 0)
-                               break;
-               }
-               evaltree(n->nbinary.ch2, flags & EV_TESTED);
-               status = exitstatus;
-               if (evalskip)
-                       goto skipping;
-       }
-       loopnest--;
-       exitstatus = status;
-}
-
-static void
-evalfor(const union node *n, int flags)
-{
-       struct arglist arglist;
-       union node *argp;
-       struct strlist *sp;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
-               oexitstatus = exitstatus;
-               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
-               if (evalskip)
-                       goto out;
-       }
-       *arglist.lastp = NULL;
-
-       exitstatus = 0;
-       loopnest++;
-       for (sp = arglist.list ; sp ; sp = sp->next) {
-               setvar(n->nfor.var, sp->text, 0);
-               evaltree(n->nfor.body, flags & EV_TESTED);
-               if (evalskip) {
-                       if (evalskip == SKIPCONT && --skipcount <= 0) {
-                               evalskip = 0;
-                               continue;
-                       }
-                       if (evalskip == SKIPBREAK && --skipcount <= 0)
-                               evalskip = 0;
-                       break;
-               }
-       }
-       loopnest--;
-out:
-       popstackmark(&smark);
-}
-
-static inline void
-evalcase(const union node *n, int flags)
-{
-       union node *cp;
-       union node *patp;
-       struct arglist arglist;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       oexitstatus = exitstatus;
-       expandarg(n->ncase.expr, &arglist, EXP_TILDE);
-       for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
-               for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
-                       if (casematch(patp, arglist.list->text)) {
-                               if (evalskip == 0) {
-                                       evaltree(cp->nclist.body, flags);
-                               }
-                               goto out;
-                       }
-               }
-       }
-out:
-       popstackmark(&smark);
-}
-
-/*
- * Evaluate a pipeline.  All the processes in the pipeline are children
- * of the process creating the pipeline.  (This differs from some versions
- * of the shell, which make the last process in a pipeline the parent
- * of all the rest.)
- */
-
-static inline void
-evalpipe(n)
-       union node *n;
-{
-       struct job *jp;
-       struct nodelist *lp;
-       int pipelen;
-       int prevfd;
-       int pip[2];
-
-       TRACE(("evalpipe(0x%lx) called\n", (long)n));
-       pipelen = 0;
-       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
-               pipelen++;
-       INTOFF;
-       jp = makejob(n, pipelen);
-       prevfd = -1;
-       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-               prehash(lp->n);
-               pip[1] = -1;
-               if (lp->next) {
-                       if (pipe(pip) < 0) {
-                               close(prevfd);
-                               error("Pipe call failed");
-                       }
-               }
-               if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
-                       INTON;
-                       if (prevfd > 0) {
-                               close(0);
-                               dup_as_newfd(prevfd, 0);
-                               close(prevfd);
-                               if (pip[0] == 0) {
-                                       pip[0] = -1;
-                               }
-                       }
-                       if (pip[1] >= 0) {
-                               if (pip[0] >= 0) {
-                                       close(pip[0]);
-                               }
-                               if (pip[1] != 1) {
-                                       close(1);
-                                       dup_as_newfd(pip[1], 1);
-                                       close(pip[1]);
-                               }
-                       }
-                       evaltree(lp->n, EV_EXIT);
-               }
-               if (prevfd >= 0)
-                       close(prevfd);
-               prevfd = pip[0];
-               close(pip[1]);
-       }
-       INTON;
-       if (n->npipe.backgnd == 0) {
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
-               INTON;
-       }
-}
-
-static void find_command (const char *, struct cmdentry *, int, const char *);
-
-static int
-isassignment(const char *word) {
-       if (!is_name(*word)) {
-               return 0;
-       }
-       do {
-               word++;
-       } while (is_in_name(*word));
-       return *word == '=';
-}
-
-
-static void
-evalcommand(union node *cmd, int flags)
-{
-       struct stackmark smark;
-       union node *argp;
-       struct arglist arglist;
-       struct arglist varlist;
-       char **argv;
-       int argc;
-       char **envp;
-       struct strlist *sp;
-       int mode;
-       struct cmdentry cmdentry;
-       struct job *jp;
-       char *volatile savecmdname;
-       volatile struct shparam saveparam;
-       struct localvar *volatile savelocalvars;
-       volatile int e;
-       char *lastarg;
-       const char *path;
-       const struct builtincmd *firstbltin;
-       struct jmploc *volatile savehandler;
-       struct jmploc jmploc;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &argv;
-       (void) &argc;
-       (void) &lastarg;
-       (void) &flags;
-#endif
-
-       /* First expand the arguments. */
-       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       varlist.lastp = &varlist.list;
-       arglist.list = 0;
-       oexitstatus = exitstatus;
-       exitstatus = 0;
-       path = pathval();
-       for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
-               expandarg(argp, &varlist, EXP_VARTILDE);
-       }
-       for (
-               argp = cmd->ncmd.args; argp && !arglist.list;
-               argp = argp->narg.next
-       ) {
-               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-       }
-       if (argp) {
-               struct builtincmd *bcmd;
-               int pseudovarflag;
-               bcmd = find_builtin(arglist.list->text);
-               pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
-               for (; argp; argp = argp->narg.next) {
-                       if (pseudovarflag && isassignment(argp->narg.text)) {
-                               expandarg(argp, &arglist, EXP_VARTILDE);
-                               continue;
-                       }
-                       expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-               }
-       }
-       *arglist.lastp = NULL;
-       *varlist.lastp = NULL;
-       expredir(cmd->ncmd.redirect);
-       argc = 0;
-       for (sp = arglist.list ; sp ; sp = sp->next)
-               argc++;
-       argv = stalloc(sizeof (char *) * (argc + 1));
-
-       for (sp = arglist.list ; sp ; sp = sp->next) {
-               TRACE(("evalcommand arg: %s\n", sp->text));
-               *argv++ = sp->text;
-       }
-       *argv = NULL;
-       lastarg = NULL;
-       if (iflag && funcnest == 0 && argc > 0)
-               lastarg = argv[-1];
-       argv -= argc;
-
-       /* Print the command if xflag is set. */
-       if (xflag) {
-               out2c('+');
-               eprintlist(varlist.list);
-               eprintlist(arglist.list);
-               out2c('\n');
-       }
-
-       /* Now locate the command. */
-       if (argc == 0) {
-               cmdentry.cmdtype = CMDBUILTIN;
-               firstbltin = cmdentry.u.cmd = BLTINCMD;
-       } else {
-               const char *oldpath;
-               int findflag = DO_ERR;
-               int oldfindflag;
-
-               /*
-                * Modify the command lookup path, if a PATH= assignment
-                * is present
-                */
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       if (varequal(sp->text, defpathvar)) {
-                               path = sp->text + 5;
-                               findflag |= DO_BRUTE;
-                       }
-               oldpath = path;
-               oldfindflag = findflag;
-               firstbltin = 0;
-               for(;;) {
-                       find_command(argv[0], &cmdentry, findflag, path);
-                       if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
-                               exitstatus = 127;
-                               goto out;
-                       }
-                       /* implement bltin and command here */
-                       if (cmdentry.cmdtype != CMDBUILTIN) {
-                               break;
-                       }
-                       if (!firstbltin) {
-                               firstbltin = cmdentry.u.cmd;
-                       }
-                       if (cmdentry.u.cmd == BLTINCMD) {
-                               for(;;) {
-                                       struct builtincmd *bcmd;
-
-                                       argv++;
-                                       if (--argc == 0)
-                                               goto found;
-                                       if (!(bcmd = find_builtin(*argv))) {
-                                               out2fmt("%s: not found\n", *argv);
-                                               exitstatus = 127;
-                                               goto out;
-                                       }
-                                       cmdentry.u.cmd = bcmd;
-                                       if (bcmd != BLTINCMD)
-                                               break;
-                               }
-                       }
-                       if (cmdentry.u.cmd == find_builtin("command")) {
-                               argv++;
-                               if (--argc == 0) {
-                                       goto found;
-                               }
-                               if (*argv[0] == '-') {
-                                       if (!equal(argv[0], "-p")) {
-                                               argv--;
-                                               argc++;
-                                               break;
-                                       }
-                                       argv++;
-                                       if (--argc == 0) {
-                                               goto found;
-                                       }
-                                       path = defpath;
-                                       findflag |= DO_BRUTE;
-                               } else {
-                                       path = oldpath;
-                                       findflag = oldfindflag;
-                               }
-                               findflag |= DO_NOFUN;
-                               continue;
-                       }
-found:
-                       break;
-               }
-       }
-
-       /* Fork off a child process if necessary. */
-       if (cmd->ncmd.backgnd
-        || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
-       ) {
-               jp = makejob(cmd, 1);
-               mode = cmd->ncmd.backgnd;
-               if (forkshell(jp, cmd, mode) != 0)
-                       goto parent;    /* at end of routine */
-               flags |= EV_EXIT;
-       }
-
-       /* This is the child process if a fork occurred. */
-       /* Execute the command. */
-       if (cmdentry.cmdtype == CMDFUNCTION) {
-#ifdef DEBUG
-               trputs("Shell function:  ");  trargs(argv);
-#endif
-               exitstatus = oexitstatus;
-               redirect(cmd->ncmd.redirect, REDIR_PUSH);
-               saveparam = shellparam;
-               shellparam.malloc = 0;
-               shellparam.nparam = argc - 1;
-               shellparam.p = argv + 1;
-               INTOFF;
-               savelocalvars = localvars;
-               localvars = NULL;
-               INTON;
-               if (setjmp(jmploc.loc)) {
-                       if (exception == EXSHELLPROC) {
-                               freeparam((volatile struct shparam *)
-                                   &saveparam);
-                       } else {
-                               saveparam.optind = shellparam.optind;
-                               saveparam.optoff = shellparam.optoff;
-                               freeparam(&shellparam);
-                               shellparam = saveparam;
-                       }
-                       poplocalvars();
-                       localvars = savelocalvars;
-                       handler = savehandler;
-                       longjmp(handler->loc, 1);
-               }
-               savehandler = handler;
-               handler = &jmploc;
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       mklocal(sp->text);
-               funcnest++;
-               evaltree(cmdentry.u.func, flags & EV_TESTED);
-               funcnest--;
-               INTOFF;
-               poplocalvars();
-               localvars = savelocalvars;
-               saveparam.optind = shellparam.optind;
-               saveparam.optoff = shellparam.optoff;
-               freeparam(&shellparam);
-               shellparam = saveparam;
-               handler = savehandler;
-               popredir();
-               INTON;
-               if (evalskip == SKIPFUNC) {
-                       evalskip = 0;
-                       skipcount = 0;
-               }
-               if (flags & EV_EXIT)
-                       exitshell(exitstatus);
-       } else if (cmdentry.cmdtype == CMDBUILTIN) {
-#ifdef DEBUG
-               trputs("builtin command:  ");  trargs(argv);
-#endif
-               mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-               redirect(cmd->ncmd.redirect, mode);
-               savecmdname = commandname;
-               if (IS_BUILTIN_SPECIAL(firstbltin)) {
-                       listsetvar(varlist.list);
-               } else {
-                       cmdenviron = varlist.list;
-               }
-               e = -1;
-               if (setjmp(jmploc.loc)) {
-                       e = exception;
-                       exitstatus = (e == EXINT)? SIGINT+128 : 2;
-                       goto cmddone;
-               }
-               savehandler = handler;
-               handler = &jmploc;
-               commandname = argv[0];
-               argptr = argv + 1;
-               optptr = NULL;                  /* initialize nextopt */
-               exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
-               flushall();
-cmddone:
-               cmdenviron = NULL;
-               if (e != EXSHELLPROC) {
-                       commandname = savecmdname;
-                       if (flags & EV_EXIT)
-                               exitshell(exitstatus);
-               }
-               handler = savehandler;
-               if (e != -1) {
-                       if ((e != EXERROR && e != EXEXEC)
-                          || cmdentry.u.cmd == BLTINCMD
-                          || cmdentry.u.cmd == DOTCMD
-                          || cmdentry.u.cmd == EVALCMD
-                          || cmdentry.u.cmd == EXECCMD)
-                               exraise(e);
-                       FORCEINTON;
-               }
-               if (cmdentry.u.cmd != EXECCMD)
-                       popredir();
-       } else {
-#ifdef DEBUG
-               trputs("normal command:  ");  trargs(argv);
-#endif
-               redirect(cmd->ncmd.redirect, 0);
-               clearredir();
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
-               envp = environment();
-               shellexec(argv, envp, path, cmdentry.u.index);
-       }
-       goto out;
-
-parent: /* parent process gets here (if we forked) */
-       if (mode == 0) {        /* argument to fork */
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               INTON;
-       }
-
-out:
-       if (lastarg)
-               setvar("_", lastarg, 0);
-       popstackmark(&smark);
-}
-
-/*
- * Evaluate a parse tree.  The value is left in the global variable
- * exitstatus.
- */
-static void
-evaltree(n, flags)
-       union node *n;
-       int flags;
-{
-       int checkexit = 0;
-       if (n == NULL) {
-               TRACE(("evaltree(NULL) called\n"));
-               goto out;
-       }
-       TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
-       switch (n->type) {
-       case NSEMI:
-               evaltree(n->nbinary.ch1, flags & EV_TESTED);
-               if (evalskip)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NAND:
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus != 0)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NOR:
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus == 0)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NREDIR:
-               expredir(n->nredir.redirect);
-               redirect(n->nredir.redirect, REDIR_PUSH);
-               evaltree(n->nredir.n, flags);
-               popredir();
-               break;
-       case NSUBSHELL:
-               evalsubshell(n, flags);
-               break;
-       case NBACKGND:
-               evalsubshell(n, flags);
-               break;
-       case NIF: {
-               evaltree(n->nif.test, EV_TESTED);
-               if (evalskip)
-                       goto out;
-               if (exitstatus == 0)
-                       evaltree(n->nif.ifpart, flags);
-               else if (n->nif.elsepart)
-                       evaltree(n->nif.elsepart, flags);
-               else
-                       exitstatus = 0;
-               break;
-       }
-       case NWHILE:
-       case NUNTIL:
-               evalloop(n, flags);
-               break;
-       case NFOR:
-               evalfor(n, flags);
-               break;
-       case NCASE:
-               evalcase(n, flags);
-               break;
-       case NDEFUN: {
-               struct builtincmd *bcmd;
-               struct cmdentry entry;
-               if (
-                       (bcmd = find_builtin(n->narg.text)) &&
-                       IS_BUILTIN_SPECIAL(bcmd)
-               ) {
-                       out2fmt("%s is a special built-in\n", n->narg.text);
-                       exitstatus = 1;
-                       break;
-               }
-               entry.cmdtype = CMDFUNCTION;
-               entry.u.func = copyfunc(n->narg.next);
-               addcmdentry(n->narg.text, &entry);
-               exitstatus = 0;
-               break;
-       }
-       case NNOT:
-               evaltree(n->nnot.com, EV_TESTED);
-               exitstatus = !exitstatus;
-               break;
-
-       case NPIPE:
-               evalpipe(n);
-               checkexit = 1;
-               break;
-       case NCMD:
-               evalcommand(n, flags);
-               checkexit = 1;
-               break;
-#ifdef DEBUG
-       default:
-               printf("Node type = %d\n", n->type);
-               break;
-#endif
-       }
-out:
-       if (pendingsigs)
-               dotrap();
-       if (
-               flags & EV_EXIT ||
-               (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
-       )
-               exitshell(exitstatus);
-}
-
-/*
- * Kick off a subshell to evaluate a tree.
- */
-
-static void
-evalsubshell(const union node *n, int flags)
-{
-       struct job *jp;
-       int backgnd = (n->type == NBACKGND);
-
-       expredir(n->nredir.redirect);
-       jp = makejob(n, 1);
-       if (forkshell(jp, n, backgnd) == 0) {
-               if (backgnd)
-                       flags &=~ EV_TESTED;
-               redirect(n->nredir.redirect, 0);
-               evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
-       }
-       if (! backgnd) {
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               INTON;
-       }
-}
-
-/*
- * Compute the names of the files in a redirection list.
- */
-
-static void fixredir(union node *n, const char *text, int err);
-
-static void
-expredir(union node *n)
-{
-       union node *redir;
-
-       for (redir = n ; redir ; redir = redir->nfile.next) {
-               struct arglist fn;
-               fn.lastp = &fn.list;
-               oexitstatus = exitstatus;
-               switch (redir->type) {
-               case NFROMTO:
-               case NFROM:
-               case NTO:
-               case NAPPEND:
-               case NTOOV:
-                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
-                       redir->nfile.expfname = fn.list->text;
-                       break;
-               case NFROMFD:
-               case NTOFD:
-                       if (redir->ndup.vname) {
-                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
-                               fixredir(redir, fn.list->text, 1);
-                       }
-                       break;
-               }
-       }
-}
-
-
-/*
- * Execute a command inside back quotes.  If it's a builtin command, we
- * want to save its output in a block obtained from malloc.  Otherwise
- * we fork off a subprocess and get the output of the command via a pipe.
- * Should be called with interrupts off.
- */
-
-static void
-evalbackcmd(union node *n, struct backcmd *result)
-{
-       int pip[2];
-       struct job *jp;
-       struct stackmark smark;         /* unnecessary */
-
-       setstackmark(&smark);
-       result->fd = -1;
-       result->buf = NULL;
-       result->nleft = 0;
-       result->jp = NULL;
-       if (n == NULL) {
-               exitstatus = 0;
-               goto out;
-       }
-       exitstatus = 0;
-       if (pipe(pip) < 0)
-               error("Pipe call failed");
-       jp = makejob(n, 1);
-       if (forkshell(jp, n, FORK_NOJOB) == 0) {
-               FORCEINTON;
-               close(pip[0]);
-               if (pip[1] != 1) {
-                       close(1);
-                       dup_as_newfd(pip[1], 1);
-                       close(pip[1]);
-               }
-               eflag = 0;
-               evaltree(n, EV_EXIT);
-       }
-       close(pip[1]);
-       result->fd = pip[0];
-       result->jp = jp;
-out:
-       popstackmark(&smark);
-       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
-               result->fd, result->buf, result->nleft, result->jp));
-}
-
-
-/*
- * Execute a simple command.
- */
-
-/*
- * Search for a command.  This is called before we fork so that the
- * location of the command will be available in the parent as well as
- * the child.  The check for "goodname" is an overly conservative
- * check that the name will not be subject to expansion.
- */
-
-static void
-prehash(n)
-       union node *n;
-{
-       struct cmdentry entry;
-
-       if (n->type == NCMD && n->ncmd.args)
-               if (goodname(n->ncmd.args->narg.text))
-                       find_command(n->ncmd.args->narg.text, &entry, 0,
-                                    pathval());
-}
-
-
-/*
- * Builtin commands.  Builtin commands whose functions are closely
- * tied to evaluation are implemented here.
- */
-
-/*
- * No command given, or a bltin command with no arguments.  Set the
- * specified variables.
- */
-
-int
-bltincmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       /*
-        * Preserve exitstatus of a previous possible redirection
-        * as POSIX mandates
-        */
-       return exitstatus;
-}
-
-
-/*
- * Handle break and continue commands.  Break, continue, and return are
- * all handled by setting the evalskip flag.  The evaluation routines
- * above all check this flag, and if it is set they start skipping
- * commands rather than executing them.  The variable skipcount is
- * the number of loops to break/continue, or the number of function
- * levels to return.  (The latter is always 1.)  It should probably
- * be an error to break out of more loops than exist, but it isn't
- * in the standard shell so we don't make it one here.
- */
-
-static int
-breakcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int n = argc > 1 ? number(argv[1]) : 1;
-
-       if (n > loopnest)
-               n = loopnest;
-       if (n > 0) {
-               evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
-               skipcount = n;
-       }
-       return 0;
-}
-
-
-/*
- * The return command.
- */
-
-static int
-returncmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int ret = argc > 1 ? number(argv[1]) : oexitstatus;
-
-       if (funcnest) {
-               evalskip = SKIPFUNC;
-               skipcount = 1;
-               return ret;
-       }
-       else {
-               /* Do what ksh does; skip the rest of the file */
-               evalskip = SKIPFILE;
-               skipcount = 1;
-               return ret;
-       }
-}
-
-
-#ifndef BB_TRUE_FALSE
-static int
-false_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       return 1;
-}
-
-
-static int
-true_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       return 0;
-}
-#endif
-
-/*
- * Controls whether the shell is interactive or not.
- */
-
-static void setsignal(int signo);
-static void chkmail(int silent);
-
-
-static void
-setinteractive(int on)
-{
-       static int is_interactive;
-       static int do_banner=0;
-
-       if (on == is_interactive)
-               return;
-       setsignal(SIGINT);
-       setsignal(SIGQUIT);
-       setsignal(SIGTERM);
-       chkmail(1);
-       is_interactive = on;
-       if (do_banner==0 && is_interactive) {
-               /* Looks like they want an interactive shell */
-               printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
-               printf( "Enter 'help' for a list of built-in commands.\n\n");
-               do_banner=1;
-       }
-}
-
-static void
-optschanged(void)
-{
-       setinteractive(iflag);
-       setjobctl(mflag);
-}
-
-
-static int
-execcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc > 1) {
-               struct strlist *sp;
-
-               iflag = 0;              /* exit on error */
-               mflag = 0;
-               optschanged();
-               for (sp = cmdenviron; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
-               shellexec(argv + 1, environment(), pathval(), 0);
-       }
-       return 0;
-}
-
-static void
-eprintlist(struct strlist *sp)
-{
-       for (; sp; sp = sp->next) {
-               out2fmt(" %s",sp->text);
-       }
-}
-
-/*
- * Exec a program.  Never returns.  If you change this routine, you may
- * have to change the find_command routine as well.
- */
-
-static const char *pathopt;     /* set by padvance */
-
-static void
-shellexec(argv, envp, path, idx)
-       char **argv, **envp;
-       const char *path;
-       int idx;
-{
-       char *cmdname;
-       int e;
-
-       if (strchr(argv[0], '/') != NULL) {
-               tryexec(argv[0], argv, envp);
-               e = errno;
-       } else {
-               e = ENOENT;
-               while ((cmdname = padvance(&path, argv[0])) != NULL) {
-                       if (--idx < 0 && pathopt == NULL) {
-                               tryexec(cmdname, argv, envp);
-                               if (errno != ENOENT && errno != ENOTDIR)
-                                       e = errno;
-                       }
-                       stunalloc(cmdname);
-               }
-       }
-
-       /* Map to POSIX errors */
-       switch (e) {
-       case EACCES:
-               exerrno = 126;
-               break;
-       case ENOENT:
-               exerrno = 127;
-               break;
-       default:
-               exerrno = 2;
-               break;
-       }
-       exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
-       /* NOTREACHED */
-}
-
-/*
- * Clear traps on a fork.
- */
-static void
-clear_traps(void) {
-       char **tp;
-
-       for (tp = trap ; tp < &trap[NSIG] ; tp++) {
-               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
-                       INTOFF;
-                       ckfree(*tp);
-                       *tp = NULL;
-                       if (tp != &trap[0])
-                               setsignal(tp - trap);
-                       INTON;
-               }
-       }
-}
-
-
-static void
-initshellproc(void) {
-
-#ifdef ASH_ALIAS
-      /* from alias.c: */
-      {
-             rmaliases();
-      }
-#endif
-      /* from eval.c: */
-      {
-             exitstatus = 0;
-      }
-
-      /* from exec.c: */
-      {
-             deletefuncs();
-      }
-
-      /* from jobs.c: */
-      {
-             backgndpid = -1;
-#ifdef JOBS
-             jobctl = 0;
-#endif
-      }
-
-      /* from options.c: */
-      {
-             int i;
-
-             for (i = 0; i < NOPTS; i++)
-                     optent_val(i) = 0;
-             optschanged();
-
-      }
-
-      /* from redir.c: */
-      {
-             clearredir();
-      }
-
-      /* from trap.c: */
-      {
-             char *sm;
-
-             clear_traps();
-             for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
-                     if (*sm == S_IGN)
-                             *sm = S_HARD_IGN;
-             }
-      }
-
-      /* from var.c: */
-      {
-             shprocvar();
-      }
-}
-
-static int preadbuffer(void);
-static void pushfile (void);
-
-/*
- * Read a character from the script, returning PEOF on end of file.
- * Nul characters in the input are silently discarded.
- */
-
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define pgetc_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
-static int
-pgetc(void)
-{
-       return pgetc_macro();
-}
-#else
-static int
-pgetc_macro(void)
-{
-       return --parsenleft >= 0? *parsenextc++ : preadbuffer();
-}
-
-static inline int
-pgetc(void)
-{
-       return pgetc_macro();
-}
-#endif
-
-
-/*
- * Undo the last call to pgetc.  Only one character may be pushed back.
- * PEOF may be pushed back.
- */
-
-static void
-pungetc() {
-       parsenleft++;
-       parsenextc--;
-}
-
-
-static void
-popfile(void) {
-       struct parsefile *pf = parsefile;
-
-       INTOFF;
-       if (pf->fd >= 0)
-               close(pf->fd);
-       if (pf->buf)
-               ckfree(pf->buf);
-       while (pf->strpush)
-               popstring();
-       parsefile = pf->prev;
-       ckfree(pf);
-       parsenleft = parsefile->nleft;
-       parselleft = parsefile->lleft;
-       parsenextc = parsefile->nextc;
-       plinno = parsefile->linno;
-       INTON;
-}
-
-
-/*
- * Return to top level.
- */
-
-static void
-popallfiles(void) {
-       while (parsefile != &basepf)
-               popfile();
-}
-
-/*
- * Close the file(s) that the shell is reading commands from.  Called
- * after a fork is done.
- */
-
-static void
-closescript() {
-       popallfiles();
-       if (parsefile->fd > 0) {
-               close(parsefile->fd);
-               parsefile->fd = 0;
-       }
-}
-
-
-/*
- * Like setinputfile, but takes an open file descriptor.  Call this with
- * interrupts off.
- */
-
-static void
-setinputfd(fd, push)
-       int fd, push;
-{
-       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-       if (push) {
-               pushfile();
-               parsefile->buf = 0;
-       } else {
-               closescript();
-               while (parsefile->strpush)
-                       popstring();
-       }
-       parsefile->fd = fd;
-       if (parsefile->buf == NULL)
-               parsefile->buf = ckmalloc(BUFSIZ);
-       parselleft = parsenleft = 0;
-       plinno = 1;
-}
-
-
-/*
- * Set the input to take input from a file.  If push is set, push the
- * old input onto the stack first.
- */
-
-static void
-setinputfile(const char *fname, int push)
-{
-       int fd;
-       int myfileno2;
-
-       INTOFF;
-       if ((fd = open(fname, O_RDONLY)) < 0)
-               error("Can't open %s", fname);
-       if (fd < 10) {
-               myfileno2 = dup_as_newfd(fd, 10);
-               close(fd);
-               if (myfileno2 < 0)
-                       error("Out of file descriptors");
-               fd = myfileno2;
-       }
-       setinputfd(fd, push);
-       INTON;
-}
-
-
-static void
-tryexec(char *cmd, char **argv, char **envp)
-{
-       int e;
-
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name = cmd;
-       char** argv_l=argv;
-       int argc_l;
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       name = get_last_path_component(name);
-#endif
-       argv_l=envp;
-       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
-               putenv(*argv_l);
-       argv_l=argv;
-       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
-       optind = 1;
-       run_applet_by_name(name, argc_l, argv);
-#endif
-       execve(cmd, argv, envp);
-       e = errno;
-       if (e == ENOEXEC) {
-               INTOFF;
-               initshellproc();
-               setinputfile(cmd, 0);
-               commandname = arg0 = savestr(argv[0]);
-               setparam(argv + 1);
-               exraise(EXSHELLPROC);
-       }
-       errno = e;
-}
-
-static char *commandtext (const union node *);
-
-/*
- * Do a path search.  The variable path (passed by reference) should be
- * set to the start of the path before the first call; padvance will update
- * this value as it proceeds.  Successive calls to padvance will return
- * the possible path expansions in sequence.  If an option (indicated by
- * a percent sign) appears in the path entry then the global variable
- * pathopt will be set to point to it; otherwise pathopt will be set to
- * NULL.
- */
-
-static const char *pathopt;
-
-static void growstackblock(void);
-
-
-static char *
-padvance(const char **path, const char *name)
-{
-       const char *p;
-       char *q;
-       const char *start;
-       int len;
-
-       if (*path == NULL)
-               return NULL;
-       start = *path;
-       for (p = start ; *p && *p != ':' && *p != '%' ; p++);
-       len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
-       while (stackblocksize() < len)
-               growstackblock();
-       q = stackblock();
-       if (p != start) {
-               memcpy(q, start, p - start);
-               q += p - start;
-               *q++ = '/';
-       }
-       strcpy(q, name);
-       pathopt = NULL;
-       if (*p == '%') {
-               pathopt = ++p;
-               while (*p && *p != ':')  p++;
-       }
-       if (*p == ':')
-               *path = p + 1;
-       else
-               *path = NULL;
-       return stalloc(len);
-}
-
-/*
- * Wrapper around strcmp for qsort/bsearch/...
- */
-static int
-pstrcmp(const void *a, const void *b)
-{
-       return strcmp((const char *) a, *(const char *const *) b);
-}
-
-/*
- * Find a keyword is in a sorted array.
- */
-
-static const char *const *
-findkwd(const char *s)
-{
-       return  bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
-                       sizeof(const char *), pstrcmp);
-}
-
-
-/*** Command hashing code ***/
-
-
-static int
-hashcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-       int c;
-       int verbose;
-       struct cmdentry entry;
-       char *name;
-#ifdef ASH_ALIAS
-       const struct alias *ap;
-#endif
-
-       verbose = 0;
-       while ((c = nextopt("rvV")) != '\0') {
-               if (c == 'r') {
-                       clearcmdentry(0);
-                       return 0;
-               } else if (c == 'v' || c == 'V') {
-                       verbose = c;
-               }
-       }
-       if (*argptr == NULL) {
-               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                               if (cmdp->cmdtype != CMDBUILTIN) {
-                                       printentry(cmdp, verbose);
-                               }
-                       }
-               }
-               return 0;
-       }
-       c = 0;
-       while ((name = *argptr++) != NULL) {
-               if ((cmdp = cmdlookup(name, 0)) != NULL
-                && (cmdp->cmdtype == CMDNORMAL
-                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
-                       delete_cmd_entry();
-#ifdef ASH_ALIAS
-       /* Then look at the aliases */
-               if ((ap = lookupalias(name, 0)) != NULL) {
-                       if (verbose=='v')
-                               printf("%s is an alias for %s\n", name, ap->val);
-                       else
-                               printalias(ap);
-                       continue;
-               }
-#endif
-                       /* First look at the keywords */
-               if (findkwd(name)!=0) {
-                       if (verbose=='v')
-                               printf("%s is a shell keyword\n", name);
-                       else
-                               printf(snlfmt, name);
-                       continue;
-               }
-
-               find_command(name, &entry, DO_ERR, pathval());
-               if (entry.cmdtype == CMDUNKNOWN) c = 1;
-               else if (verbose) {
-                       cmdp = cmdlookup(name, 0);
-                       if (cmdp) printentry(cmdp, verbose=='v');
-                       flushall();
-               }
-       }
-       return c;
-}
-
-static void
-printentry(cmdp, verbose)
-       struct tblentry *cmdp;
-       int verbose;
-       {
-       int idx;
-       const char *path;
-       char *name;
-
-       printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
-       if (cmdp->cmdtype == CMDNORMAL) {
-               idx = cmdp->param.index;
-               path = pathval();
-               do {
-                       name = padvance(&path, cmdp->cmdname);
-                       stunalloc(name);
-               } while (--idx >= 0);
-               if(verbose)
-                       out1str(name);
-       } else if (cmdp->cmdtype == CMDBUILTIN) {
-               if(verbose)
-                       out1str("a shell builtin");
-       } else if (cmdp->cmdtype == CMDFUNCTION) {
-               if (verbose) {
-                       INTOFF;
-                       out1str("a function\n");
-                       name = commandtext(cmdp->param.func);
-                       printf("%s() {\n %s\n}", cmdp->cmdname, name);
-                       ckfree(name);
-                       INTON;
-               }
-#ifdef DEBUG
-       } else {
-               error("internal error: cmdtype %d", cmdp->cmdtype);
-#endif
-       }
-       printf(snlfmt, cmdp->rehash ? "*" : nullstr);
-}
-
-
-
-/*** List the available builtins ***/
-
-
-static int helpcmd(int argc, char** argv)
-{
-       int col, i;
-
-       printf("\nBuilt-in commands:\n-------------------\n");
-       for (col=0, i=0; i < NUMBUILTINS; i++) {
-               col += printf("%c%s", ((col == 0) ? '\t' : ' '),
-                               builtincmds[i].name+1);
-               if (col > 60) {
-                       printf("\n");
-                       col = 0;
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       {
-               extern const struct BB_applet applets[];
-               extern const size_t NUM_APPLETS;
-
-               for (i=0; i < NUM_APPLETS; i++) {
-
-                       col += printf("%c%s", ((col == 0) ? '\t' : ' '),
-                                       applets[i].name);
-                       if (col > 60) {
-                               printf("\n");
-                               col = 0;
-                       }
-               }
-       }
-#endif
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/*
- * Resolve a command name.  If you change this routine, you may have to
- * change the shellexec routine as well.
- */
-
-static int prefix (const char *, const char *);
-
-static void
-find_command(const char *name, struct cmdentry *entry, int act, const char *path)
-{
-       struct tblentry *cmdp;
-       int idx;
-       int prev;
-       char *fullname;
-       struct stat statb;
-       int e;
-       int bltin;
-       int firstchange;
-       int updatetbl;
-       int regular;
-       struct builtincmd *bcmd;
-
-       /* If name contains a slash, don't use the hash table */
-       if (strchr(name, '/') != NULL) {
-               if (act & DO_ABS) {
-                       while (stat(name, &statb) < 0) {
-                               if (errno != ENOENT && errno != ENOTDIR)
-                                       e = errno;
-                               entry->cmdtype = CMDUNKNOWN;
-                               entry->u.index = -1;
-                               return;
-                       }
-                       entry->cmdtype = CMDNORMAL;
-                       entry->u.index = -1;
-                       return;
-               }
-               entry->cmdtype = CMDNORMAL;
-               entry->u.index = 0;
-               return;
-       }
-
-       updatetbl = 1;
-       if (act & DO_BRUTE) {
-               firstchange = path_change(path, &bltin);
-       } else {
-               bltin = builtinloc;
-               firstchange = 9999;
-       }
-
-       /* If name is in the table, and not invalidated by cd, we're done */
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
-               if (cmdp->cmdtype == CMDFUNCTION) {
-                       if (act & DO_NOFUN) {
-                               updatetbl = 0;
-                       } else {
-                               goto success;
-                       }
-               } else if (act & DO_BRUTE) {
-                       if ((cmdp->cmdtype == CMDNORMAL &&
-                            cmdp->param.index >= firstchange) ||
-                           (cmdp->cmdtype == CMDBUILTIN &&
-                            ((builtinloc < 0 && bltin >= 0) ?
-                             bltin : builtinloc) >= firstchange)) {
-                               /* need to recompute the entry */
-                       } else {
-                               goto success;
-                       }
-               } else {
-                       goto success;
-               }
-       }
-
-       bcmd = find_builtin(name);
-       regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
-
-       if (regular) {
-               if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
-                       goto success;
-               }
-       } else if (act & DO_BRUTE) {
-               if (firstchange == 0) {
-                       updatetbl = 0;
-               }
-       }
-
-       /* If %builtin not in path, check for builtin next */
-       if (regular || (bltin < 0 && bcmd)) {
-builtin:
-               if (!updatetbl) {
-                       entry->cmdtype = CMDBUILTIN;
-                       entry->u.cmd = bcmd;
-                       return;
-               }
-               INTOFF;
-               cmdp = cmdlookup(name, 1);
-               cmdp->cmdtype = CMDBUILTIN;
-               cmdp->param.cmd = bcmd;
-               INTON;
-               goto success;
-       }
-
-       /* We have to search path. */
-       prev = -1;              /* where to start */
-       if (cmdp && cmdp->rehash) {     /* doing a rehash */
-               if (cmdp->cmdtype == CMDBUILTIN)
-                       prev = builtinloc;
-               else
-                       prev = cmdp->param.index;
-       }
-
-       e = ENOENT;
-       idx = -1;
-loop:
-       while ((fullname = padvance(&path, name)) != NULL) {
-               stunalloc(fullname);
-               idx++;
-               if (idx >= firstchange) {
-                       updatetbl = 0;
-               }
-               if (pathopt) {
-                       if (prefix("builtin", pathopt)) {
-                               if ((bcmd = find_builtin(name))) {
-                                       goto builtin;
-                               }
-                               continue;
-                       } else if (!(act & DO_NOFUN) &&
-                                  prefix("func", pathopt)) {
-                               /* handled below */
-                       } else {
-                               continue;       /* ignore unimplemented options */
-                       }
-               }
-               /* if rehash, don't redo absolute path names */
-               if (fullname[0] == '/' && idx <= prev &&
-                   idx < firstchange) {
-                       if (idx < prev)
-                               continue;
-                       TRACE(("searchexec \"%s\": no change\n", name));
-                       goto success;
-               }
-               while (stat(fullname, &statb) < 0) {
-                       if (errno != ENOENT && errno != ENOTDIR)
-                               e = errno;
-                       goto loop;
-               }
-               e = EACCES;     /* if we fail, this will be the error */
-               if (!S_ISREG(statb.st_mode))
-                       continue;
-               if (pathopt) {          /* this is a %func directory */
-                       stalloc(strlen(fullname) + 1);
-                       readcmdfile(fullname);
-                       if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
-                               error("%s not defined in %s", name, fullname);
-                       stunalloc(fullname);
-                       goto success;
-               }
-               TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
-               /* If we aren't called with DO_BRUTE and cmdp is set, it must
-                  be a function and we're being called with DO_NOFUN */
-               if (!updatetbl) {
-                       entry->cmdtype = CMDNORMAL;
-                       entry->u.index = idx;
-                       return;
-               }
-               INTOFF;
-               cmdp = cmdlookup(name, 1);
-               cmdp->cmdtype = CMDNORMAL;
-               cmdp->param.index = idx;
-               INTON;
-               goto success;
-       }
-
-       /* We failed.  If there was an entry for this command, delete it */
-       if (cmdp && updatetbl)
-               delete_cmd_entry();
-       if (act & DO_ERR)
-               out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
-       entry->cmdtype = CMDUNKNOWN;
-       return;
-
-success:
-       cmdp->rehash = 0;
-       entry->cmdtype = cmdp->cmdtype;
-       entry->u = cmdp->param;
-}
-
-
-
-/*
- * Search the table of builtin commands.
- */
-
-static int
-bstrcmp(const void *name, const void *b)
-{
-       return strcmp((const char *)name, (*(const char *const *) b)+1);
-}
-
-static struct builtincmd *
-find_builtin(const char *name)
-{
-       struct builtincmd *bp;
-
-       bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
-               bstrcmp
-       );
-       return bp;
-}
-
-
-/*
- * Called when a cd is done.  Marks all commands so the next time they
- * are executed they will be rehashed.
- */
-
-static void
-hashcd(void) {
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-               for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                       if (cmdp->cmdtype == CMDNORMAL
-                        || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
-                               cmdp->rehash = 1;
-               }
-       }
-}
-
-
-
-/*
- * Called before PATH is changed.  The argument is the new value of PATH;
- * pathval() still returns the old value at this point.  Called with
- * interrupts off.
- */
-
-static void
-changepath(const char *newval)
-{
-       int firstchange;
-       int bltin;
-
-       firstchange = path_change(newval, &bltin);
-       if (builtinloc < 0 && bltin >= 0)
-               builtinloc = bltin;             /* zap builtins */
-       clearcmdentry(firstchange);
-       builtinloc = bltin;
-}
-
-
-/*
- * Clear out command entries.  The argument specifies the first entry in
- * PATH which has changed.
- */
-
-static void
-clearcmdentry(firstchange)
-       int firstchange;
-{
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INTOFF;
-       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if ((cmdp->cmdtype == CMDNORMAL &&
-                            cmdp->param.index >= firstchange)
-                        || (cmdp->cmdtype == CMDBUILTIN &&
-                            builtinloc >= firstchange)) {
-                               *pp = cmdp->next;
-                               ckfree(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-
-/*
- * Delete all functions.
- */
-
-static void
-deletefuncs(void) {
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INTOFF;
-       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if (cmdp->cmdtype == CMDFUNCTION) {
-                               *pp = cmdp->next;
-                               freefunc(cmdp->param.func);
-                               ckfree(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-
-
-/*
- * Locate a command in the command hash table.  If "add" is nonzero,
- * add the command to the table if it is not already present.  The
- * variable "lastcmdentry" is set to point to the address of the link
- * pointing to the entry, so that delete_cmd_entry can delete the
- * entry.
- */
-
-static struct tblentry **lastcmdentry;
-
-static struct tblentry *
-cmdlookup(const char *name, int add)
-{
-       int hashval;
-       const char *p;
-       struct tblentry *cmdp;
-       struct tblentry **pp;
-
-       p = name;
-       hashval = *p << 4;
-       while (*p)
-               hashval += *p++;
-       hashval &= 0x7FFF;
-       pp = &cmdtable[hashval % CMDTABLESIZE];
-       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-               if (equal(cmdp->cmdname, name))
-                       break;
-               pp = &cmdp->next;
-       }
-       if (add && cmdp == NULL) {
-               INTOFF;
-               cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
-                                       + strlen(name) + 1);
-               cmdp->next = NULL;
-               cmdp->cmdtype = CMDUNKNOWN;
-               cmdp->rehash = 0;
-               strcpy(cmdp->cmdname, name);
-               INTON;
-       }
-       lastcmdentry = pp;
-       return cmdp;
-}
-
-/*
- * Delete the command entry returned on the last lookup.
- */
-
-static void
-delete_cmd_entry() {
-       struct tblentry *cmdp;
-
-       INTOFF;
-       cmdp = *lastcmdentry;
-       *lastcmdentry = cmdp->next;
-       ckfree(cmdp);
-       INTON;
-}
-
-
-
-
-
-static const short nodesize[26] = {
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct ncmd)),
-      ALIGN(sizeof (struct npipe)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nif)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nfor)),
-      ALIGN(sizeof (struct ncase)),
-      ALIGN(sizeof (struct nclist)),
-      ALIGN(sizeof (struct narg)),
-      ALIGN(sizeof (struct narg)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct ndup)),
-      ALIGN(sizeof (struct ndup)),
-      ALIGN(sizeof (struct nhere)),
-      ALIGN(sizeof (struct nhere)),
-      ALIGN(sizeof (struct nnot)),
-};
-
-
-
-/*
- * Delete a function if it exists.
- */
-
-static void
-unsetfunc(char *name)
-{
-       struct tblentry *cmdp;
-
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
-               delete_cmd_entry();
-       }
-}
-
-
-/*
- * Locate and print what a word is...
- */
-
-static int
-typecmd(int argc, char **argv)
-{
-       int i;
-       int err = 0;
-       char *argv_a[2];
-
-       argv_a[1] = 0;
-
-       for (i = 1; i < argc; i++) {
-               argv_a[0] = argv[i];
-               argptr = argv_a;
-               optptr = "v";
-               err |= hashcmd(argc, argv);
-       }
-       return err;
-}
-
-#ifdef ASH_CMDCMD
-static int
-commandcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int c;
-       int default_path = 0;
-       int verify_only = 0;
-       int verbose_verify_only = 0;
-
-       while ((c = nextopt("pvV")) != '\0')
-               switch (c) {
-               case 'p':
-                       default_path = 1;
-                       break;
-               case 'v':
-                       verify_only = 1;
-                       break;
-               case 'V':
-                       verbose_verify_only = 1;
-                       break;
-               }
-
-       if (default_path + verify_only + verbose_verify_only > 1 ||
-           !*argptr) {
-                       out2str(
-                               "command [-p] command [arg ...]\n"
-                               "command {-v|-V} command\n");
-                       return EX_USAGE;
-       }
-
-       if (verify_only || verbose_verify_only) {
-               char *argv_a[2];
-
-               argv_a[1] = 0;
-               argv_a[0] = *argptr;
-               argptr = argv_a;
-               optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
-               return hashcmd(argc, argv);
-       }
-
-       return 0;
-}
-#endif
-
-static int
-path_change(newval, bltin)
-       const char *newval;
-       int *bltin;
-{
-       const char *old, *new;
-       int idx;
-       int firstchange;
-
-       old = pathval();
-       new = newval;
-       firstchange = 9999;     /* assume no change */
-       idx = 0;
-       *bltin = -1;
-       for (;;) {
-               if (*old != *new) {
-                       firstchange = idx;
-                       if ((*old == '\0' && *new == ':')
-                        || (*old == ':' && *new == '\0'))
-                               firstchange++;
-                       old = new;      /* ignore subsequent differences */
-               }
-               if (*new == '\0')
-                       break;
-               if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
-                       *bltin = idx;
-               if (*new == ':') {
-                       idx++;
-               }
-               new++, old++;
-       }
-       if (builtinloc >= 0 && *bltin < 0)
-               firstchange = 0;
-       return firstchange;
-}
-/*
- * Routines to expand arguments to commands.  We have to deal with
- * backquotes, shell variables, and file metacharacters.
- */
-/*
- * _rmescape() flags
- */
-#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
-#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
-
-/*
- * Structure specifying which parts of the string should be searched
- * for IFS characters.
- */
-
-struct ifsregion {
-       struct ifsregion *next; /* next region in list */
-       int begoff;             /* offset of start of region */
-       int endoff;             /* offset of end of region */
-       int nulonly;            /* search for nul bytes only */
-};
-
-
-static char *expdest;                   /* output of current string */
-static struct nodelist *argbackq;      /* list of back quote expressions */
-static struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
-static struct ifsregion *ifslastp;     /* last struct in list */
-static struct arglist exparg;          /* holds expanded arg list */
-
-static void argstr (char *, int);
-static char *exptilde (char *, int);
-static void expbackq (union node *, int, int);
-static int subevalvar (char *, char *, int, int, int, int, int);
-static int varisset (char *, int);
-static void strtodest (const char *, const char *, int);
-static void varvalue (char *, int, int);
-static void recordregion (int, int, int);
-static void removerecordregions (int);
-static void ifsbreakup (char *, struct arglist *);
-static void ifsfree (void);
-static void expandmeta (struct strlist *, int);
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
-#if !defined(GLOB_BROKEN)
-static void addglob (const glob_t *);
-#endif
-#endif
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-static void expmeta (char *, char *);
-#endif
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-static struct strlist *expsort (struct strlist *);
-static struct strlist *msort (struct strlist *, int);
-#endif
-static int patmatch (char *, char *, int);
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-static int patmatch2 (char *, char *, int);
-#else
-static int pmatch (char *, char *, int);
-#define patmatch2 patmatch
-#endif
-static char *cvtnum (int, char *);
-
-/*
- * Expand shell variables and backquotes inside a here document.
- */
-
-/* arg: the document, fd: where to write the expanded version */
-static inline void
-expandhere(union node *arg, int fd)
-{
-       herefd = fd;
-       expandarg(arg, (struct arglist *)NULL, 0);
-       xwrite(fd, stackblock(), expdest - stackblock());
-}
-
-
-/*
- * Perform variable substitution and command substitution on an argument,
- * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
- * perform splitting and file name expansion.  When arglist is NULL, perform
- * here document expansion.
- */
-
-static void
-expandarg(arg, arglist, flag)
-       union node *arg;
-       struct arglist *arglist;
-       int flag;
-{
-       struct strlist *sp;
-       char *p;
-
-       argbackq = arg->narg.backquote;
-       STARTSTACKSTR(expdest);
-       ifsfirst.next = NULL;
-       ifslastp = NULL;
-       argstr(arg->narg.text, flag);
-       if (arglist == NULL) {
-               return;                 /* here document expanded */
-       }
-       STPUTC('\0', expdest);
-       p = grabstackstr(expdest);
-       exparg.lastp = &exparg.list;
-       /*
-        * TODO - EXP_REDIR
-        */
-       if (flag & EXP_FULL) {
-               ifsbreakup(p, &exparg);
-               *exparg.lastp = NULL;
-               exparg.lastp = &exparg.list;
-               expandmeta(exparg.list, flag);
-       } else {
-               if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
-                       rmescapes(p);
-               sp = (struct strlist *)stalloc(sizeof (struct strlist));
-               sp->text = p;
-               *exparg.lastp = sp;
-               exparg.lastp = &sp->next;
-       }
-       ifsfree();
-       *exparg.lastp = NULL;
-       if (exparg.list) {
-               *arglist->lastp = exparg.list;
-               arglist->lastp = exparg.lastp;
-       }
-}
-
-
-/*
- * Expand a variable, and return a pointer to the next character in the
- * input string.
- */
-
-static inline char *
-evalvar(p, flag)
-       char *p;
-       int flag;
-{
-       int subtype;
-       int varflags;
-       char *var;
-       const char *val;
-       int patloc;
-       int c;
-       int set;
-       int special;
-       int startloc;
-       int varlen;
-       int easy;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-
-       varflags = *p++;
-       subtype = varflags & VSTYPE;
-       var = p;
-       special = 0;
-       if (! is_name(*p))
-               special = 1;
-       p = strchr(p, '=') + 1;
-again: /* jump here after setting a variable with ${var=text} */
-       if (special) {
-               set = varisset(var, varflags & VSNUL);
-               val = NULL;
-       } else {
-               val = lookupvar(var);
-               if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
-                       val = NULL;
-                       set = 0;
-               } else
-                       set = 1;
-       }
-       varlen = 0;
-       startloc = expdest - stackblock();
-       if (set && subtype != VSPLUS) {
-               /* insert the value of the variable */
-               if (special) {
-                       varvalue(var, varflags & VSQUOTE, flag);
-                       if (subtype == VSLENGTH) {
-                               varlen = expdest - stackblock() - startloc;
-                               STADJUST(-varlen, expdest);
-                       }
-               } else {
-                       if (subtype == VSLENGTH) {
-                               varlen = strlen(val);
-                       } else {
-                               strtodest(
-                                       val,
-                                       varflags & VSQUOTE ?
-                                               DQSYNTAX : BASESYNTAX,
-                                       quotes
-                               );
-                       }
-               }
-       }
-
-       if (subtype == VSPLUS)
-               set = ! set;
-
-       easy = ((varflags & VSQUOTE) == 0 ||
-               (*var == '@' && shellparam.nparam != 1));
-
-
-       switch (subtype) {
-       case VSLENGTH:
-               expdest = cvtnum(varlen, expdest);
-               goto record;
-
-       case VSNORMAL:
-               if (!easy)
-                       break;
-record:
-               recordregion(startloc, expdest - stackblock(),
-                            varflags & VSQUOTE);
-               break;
-
-       case VSPLUS:
-       case VSMINUS:
-               if (!set) {
-                       argstr(p, flag);
-                       break;
-               }
-               if (easy)
-                       goto record;
-               break;
-
-       case VSTRIMLEFT:
-       case VSTRIMLEFTMAX:
-       case VSTRIMRIGHT:
-       case VSTRIMRIGHTMAX:
-               if (!set)
-                       break;
-               /*
-                * Terminate the string and start recording the pattern
-                * right after it
-                */
-               STPUTC('\0', expdest);
-               patloc = expdest - stackblock();
-               if (subevalvar(p, NULL, patloc, subtype,
-                              startloc, varflags, quotes) == 0) {
-                       int amount = (expdest - stackblock() - patloc) + 1;
-                       STADJUST(-amount, expdest);
-               }
-               /* Remove any recorded regions beyond start of variable */
-               removerecordregions(startloc);
-               goto record;
-
-       case VSASSIGN:
-       case VSQUESTION:
-               if (!set) {
-                       if (subevalvar(p, var, 0, subtype, startloc,
-                                      varflags, quotes)) {
-                               varflags &= ~VSNUL;
-                               /*
-                                * Remove any recorded regions beyond
-                                * start of variable
-                                */
-                               removerecordregions(startloc);
-                               goto again;
-                       }
-                       break;
-               }
-               if (easy)
-                       goto record;
-               break;
-
-#ifdef DEBUG
-       default:
-               abort();
-#endif
-       }
-
-       if (subtype != VSNORMAL) {      /* skip to end of alternative */
-               int nesting = 1;
-               for (;;) {
-                       if ((c = *p++) == CTLESC)
-                               p++;
-                       else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
-                               if (set)
-                                       argbackq = argbackq->next;
-                       } else if (c == CTLVAR) {
-                               if ((*p++ & VSTYPE) != VSNORMAL)
-                                       nesting++;
-                       } else if (c == CTLENDVAR) {
-                               if (--nesting == 0)
-                                       break;
-                       }
-               }
-       }
-       return p;
-}
-
-
-/*
- * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
- * characters to allow for further processing.  Otherwise treat
- * $@ like $* since no splitting will be performed.
- */
-
-static void
-argstr(p, flag)
-       char *p;
-       int flag;
-{
-       char c;
-       int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
-       int firsteq = 1;
-
-       if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
-               p = exptilde(p, flag);
-       for (;;) {
-               switch (c = *p++) {
-               case '\0':
-               case CTLENDVAR: /* ??? */
-                       goto breakloop;
-               case CTLQUOTEMARK:
-                       /* "$@" syntax adherence hack */
-                       if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
-                               break;
-                       if ((flag & EXP_FULL) != 0)
-                               STPUTC(c, expdest);
-                       break;
-               case CTLESC:
-                       if (quotes)
-                               STPUTC(c, expdest);
-                       c = *p++;
-                       STPUTC(c, expdest);
-                       break;
-               case CTLVAR:
-                       p = evalvar(p, flag);
-                       break;
-               case CTLBACKQ:
-               case CTLBACKQ|CTLQUOTE:
-                       expbackq(argbackq->n, c & CTLQUOTE, flag);
-                       argbackq = argbackq->next;
-                       break;
-#ifdef ASH_MATH_SUPPORT
-               case CTLENDARI:
-                       expari(flag);
-                       break;
-#endif
-               case ':':
-               case '=':
-                       /*
-                        * sort of a hack - expand tildes in variable
-                        * assignments (after the first '=' and after ':'s).
-                        */
-                       STPUTC(c, expdest);
-                       if (flag & EXP_VARTILDE && *p == '~') {
-                               if (c == '=') {
-                                       if (firsteq)
-                                               firsteq = 0;
-                                       else
-                                               break;
-                               }
-                               p = exptilde(p, flag);
-                       }
-                       break;
-               default:
-                       STPUTC(c, expdest);
-               }
-       }
-breakloop:;
-       return;
-}
-
-static char *
-exptilde(p, flag)
-       char *p;
-       int flag;
-{
-       char c, *startp = p;
-       struct passwd *pw;
-       const char *home;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-
-       while ((c = *p) != '\0') {
-               switch(c) {
-               case CTLESC:
-                       return (startp);
-               case CTLQUOTEMARK:
-                       return (startp);
-               case ':':
-                       if (flag & EXP_VARTILDE)
-                               goto done;
-                       break;
-               case '/':
-                       goto done;
-               }
-               p++;
-       }
-done:
-       *p = '\0';
-       if (*(startp+1) == '\0') {
-               if ((home = lookupvar("HOME")) == NULL)
-                       goto lose;
-       } else {
-               if ((pw = getpwnam(startp+1)) == NULL)
-                       goto lose;
-               home = pw->pw_dir;
-       }
-       if (*home == '\0')
-               goto lose;
-       *p = c;
-       strtodest(home, SQSYNTAX, quotes);
-       return (p);
-lose:
-       *p = c;
-       return (startp);
-}
-
-
-static void
-removerecordregions(int endoff)
-{
-       if (ifslastp == NULL)
-               return;
-
-       if (ifsfirst.endoff > endoff) {
-               while (ifsfirst.next != NULL) {
-                       struct ifsregion *ifsp;
-                       INTOFF;
-                       ifsp = ifsfirst.next->next;
-                       ckfree(ifsfirst.next);
-                       ifsfirst.next = ifsp;
-                       INTON;
-               }
-               if (ifsfirst.begoff > endoff)
-                       ifslastp = NULL;
-               else {
-                       ifslastp = &ifsfirst;
-                       ifsfirst.endoff = endoff;
-               }
-               return;
-       }
-
-       ifslastp = &ifsfirst;
-       while (ifslastp->next && ifslastp->next->begoff < endoff)
-               ifslastp=ifslastp->next;
-       while (ifslastp->next != NULL) {
-               struct ifsregion *ifsp;
-               INTOFF;
-               ifsp = ifslastp->next->next;
-               ckfree(ifslastp->next);
-               ifslastp->next = ifsp;
-               INTON;
-       }
-       if (ifslastp->endoff > endoff)
-               ifslastp->endoff = endoff;
-}
-
-
-#ifdef ASH_MATH_SUPPORT
-/*
- * Expand arithmetic expression.  Backup to start of expression,
- * evaluate, place result in (backed up) result, adjust string position.
- */
-static void
-expari(int flag)
-{
-       char *p, *start;
-       int errcode;
-       int result;
-       int begoff;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-       int quoted;
-
-       /*      ifsfree(); */
-
-       /*
-        * This routine is slightly over-complicated for
-        * efficiency.  First we make sure there is
-        * enough space for the result, which may be bigger
-        * than the expression if we add exponentation.  Next we
-        * scan backwards looking for the start of arithmetic.  If the
-        * next previous character is a CTLESC character, then we
-        * have to rescan starting from the beginning since CTLESC
-        * characters have to be processed left to right.
-        */
-       CHECKSTRSPACE(10, expdest);
-       USTPUTC('\0', expdest);
-       start = stackblock();
-       p = expdest - 1;
-       while (*p != CTLARI && p >= start)
-               --p;
-       if (*p != CTLARI)
-               error("missing CTLARI (shouldn't happen)");
-       if (p > start && *(p-1) == CTLESC)
-               for (p = start; *p != CTLARI; p++)
-                       if (*p == CTLESC)
-                               p++;
-
-       if (p[1] == '"')
-               quoted=1;
-       else
-               quoted=0;
-       begoff = p - start;
-       removerecordregions(begoff);
-       if (quotes)
-               rmescapes(p+2);
-       result = arith(p+2, &errcode);
-       if (errcode < 0) {
-               if(errcode == -2)
-                       error("divide by zero");
-               else
-                       error("syntax error: \"%s\"\n", p+2);
-       }
-       snprintf(p, 12, "%d", result);
-
-       while (*p++)
-               ;
-
-       if (quoted == 0)
-               recordregion(begoff, p - 1 - start, 0);
-       result = expdest - p + 1;
-       STADJUST(-result, expdest);
-}
-#endif
-
-/*
- * Expand stuff in backwards quotes.
- */
-
-static void
-expbackq(cmd, quoted, flag)
-       union node *cmd;
-       int quoted;
-       int flag;
-{
-       volatile struct backcmd in;
-       int i;
-       char buf[128];
-       char *p;
-       char *dest = expdest;
-       volatile struct ifsregion saveifs;
-       struct ifsregion *volatile savelastp;
-       struct nodelist *volatile saveargbackq;
-       char lastc;
-       int startloc = dest - stackblock();
-       char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
-       volatile int saveherefd;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
-       int ex;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &dest;
-       (void) &syntax;
-#endif
-
-       in.fd = -1;
-       in.buf = 0;
-       in.jp = 0;
-
-       INTOFF;
-       saveifs = ifsfirst;
-       savelastp = ifslastp;
-       saveargbackq = argbackq;
-       saveherefd = herefd;
-       herefd = -1;
-       if ((ex = setjmp(jmploc.loc))) {
-               goto err1;
-       }
-       savehandler = handler;
-       handler = &jmploc;
-       INTON;
-       p = grabstackstr(dest);
-       evalbackcmd(cmd, (struct backcmd *) &in);
-       ungrabstackstr(p, dest);
-err1:
-       INTOFF;
-       ifsfirst = saveifs;
-       ifslastp = savelastp;
-       argbackq = saveargbackq;
-       herefd = saveherefd;
-       if (ex) {
-               goto err2;
-       }
-
-       p = in.buf;
-       lastc = '\0';
-       for (;;) {
-               if (--in.nleft < 0) {
-                       if (in.fd < 0)
-                               break;
-                       i = safe_read(in.fd, buf, sizeof buf);
-                       TRACE(("expbackq: read returns %d\n", i));
-                       if (i <= 0)
-                               break;
-                       p = buf;
-                       in.nleft = i - 1;
-               }
-               lastc = *p++;
-               if (lastc != '\0') {
-                       if (quotes && syntax[(int)lastc] == CCTL)
-                               STPUTC(CTLESC, dest);
-                       STPUTC(lastc, dest);
-               }
-       }
-
-       /* Eat all trailing newlines */
-       for (; dest > stackblock() && dest[-1] == '\n';)
-               STUNPUTC(dest);
-
-err2:
-       if (in.fd >= 0)
-               close(in.fd);
-       if (in.buf)
-               ckfree(in.buf);
-       if (in.jp)
-               exitstatus = waitforjob(in.jp);
-       handler = savehandler;
-       if (ex) {
-               longjmp(handler->loc, 1);
-       }
-       if (quoted == 0)
-               recordregion(startloc, dest - stackblock(), 0);
-       TRACE(("evalbackq: size=%d: \"%.*s\"\n",
-               (dest - stackblock()) - startloc,
-               (dest - stackblock()) - startloc,
-               stackblock() + startloc));
-       expdest = dest;
-       INTON;
-}
-
-static int
-subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
-       char *p;
-       char *str;
-       int strloc;
-       int subtype;
-       int startloc;
-       int varflags;
-       int quotes;
-{
-       char *startp;
-       char *loc = NULL;
-       char *q;
-       int c = 0;
-       int saveherefd = herefd;
-       struct nodelist *saveargbackq = argbackq;
-       int amount;
-
-       herefd = -1;
-       argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
-       STACKSTRNUL(expdest);
-       herefd = saveherefd;
-       argbackq = saveargbackq;
-       startp = stackblock() + startloc;
-       if (str == NULL)
-           str = stackblock() + strloc;
-
-       switch (subtype) {
-       case VSASSIGN:
-               setvar(str, startp, 0);
-               amount = startp - expdest;
-               STADJUST(amount, expdest);
-               varflags &= ~VSNUL;
-               if (c != 0)
-                       *loc = c;
-               return 1;
-
-       case VSQUESTION:
-               if (*p != CTLENDVAR) {
-                       out2fmt(snlfmt, startp);
-                       error((char *)NULL);
-               }
-               error("%.*s: parameter %snot set", p - str - 1,
-                     str, (varflags & VSNUL) ? "null or "
-                                             : nullstr);
-               /* NOTREACHED */
-
-       case VSTRIMLEFT:
-               for (loc = startp; loc < str; loc++) {
-                       c = *loc;
-                       *loc = '\0';
-                       if (patmatch2(str, startp, quotes))
-                               goto recordleft;
-                       *loc = c;
-                       if (quotes && *loc == CTLESC)
-                               loc++;
-               }
-               return 0;
-
-       case VSTRIMLEFTMAX:
-               for (loc = str - 1; loc >= startp;) {
-                       c = *loc;
-                       *loc = '\0';
-                       if (patmatch2(str, startp, quotes))
-                               goto recordleft;
-                       *loc = c;
-                       loc--;
-                       if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-                               for (q = startp; q < loc; q++)
-                                       if (*q == CTLESC)
-                                               q++;
-                               if (q > loc)
-                                       loc--;
-                       }
-               }
-               return 0;
-
-       case VSTRIMRIGHT:
-               for (loc = str - 1; loc >= startp;) {
-                       if (patmatch2(str, loc, quotes))
-                               goto recordright;
-                       loc--;
-                       if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-                               for (q = startp; q < loc; q++)
-                                       if (*q == CTLESC)
-                                               q++;
-                               if (q > loc)
-                                       loc--;
-                       }
-               }
-               return 0;
-
-       case VSTRIMRIGHTMAX:
-               for (loc = startp; loc < str - 1; loc++) {
-                       if (patmatch2(str, loc, quotes))
-                               goto recordright;
-                       if (quotes && *loc == CTLESC)
-                               loc++;
-               }
-               return 0;
-
-#ifdef DEBUG
-       default:
-               abort();
-#endif
-       }
-
-recordleft:
-       *loc = c;
-       amount = ((str - 1) - (loc - startp)) - expdest;
-       STADJUST(amount, expdest);
-       while (loc != str - 1)
-               *startp++ = *loc++;
-       return 1;
-
-recordright:
-       amount = loc - expdest;
-       STADJUST(amount, expdest);
-       STPUTC('\0', expdest);
-       STADJUST(-1, expdest);
-       return 1;
-}
-
-
-/*
- * Test whether a specialized variable is set.
- */
-
-static int
-varisset(name, nulok)
-       char *name;
-       int nulok;
-{
-       if (*name == '!')
-               return backgndpid != -1;
-       else if (*name == '@' || *name == '*') {
-               if (*shellparam.p == NULL)
-                       return 0;
-
-               if (nulok) {
-                       char **av;
-
-                       for (av = shellparam.p; *av; av++)
-                               if (**av != '\0')
-                                       return 1;
-                       return 0;
-               }
-       } else if (is_digit(*name)) {
-               char *ap;
-               int num = atoi(name);
-
-               if (num > shellparam.nparam)
-                       return 0;
-
-               if (num == 0)
-                       ap = arg0;
-               else
-                       ap = shellparam.p[num - 1];
-
-               if (nulok && (ap == NULL || *ap == '\0'))
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Put a string on the stack.
- */
-
-static void
-strtodest(p, syntax, quotes)
-       const char *p;
-       const char *syntax;
-       int quotes;
-{
-       while (*p) {
-               if (quotes && syntax[(int) *p] == CCTL)
-                       STPUTC(CTLESC, expdest);
-               STPUTC(*p++, expdest);
-       }
-}
-
-/*
- * Add the value of a specialized variable to the stack string.
- */
-
-static void
-varvalue(name, quoted, flags)
-       char *name;
-       int quoted;
-       int flags;
-{
-       int num;
-       char *p;
-       int i;
-       int sep;
-       int sepq = 0;
-       char **ap;
-       char const *syntax;
-       int allow_split = flags & EXP_FULL;
-       int quotes = flags & (EXP_FULL | EXP_CASE);
-
-       syntax = quoted ? DQSYNTAX : BASESYNTAX;
-       switch (*name) {
-       case '$':
-               num = rootpid;
-               goto numvar;
-       case '?':
-               num = oexitstatus;
-               goto numvar;
-       case '#':
-               num = shellparam.nparam;
-               goto numvar;
-       case '!':
-               num = backgndpid;
-numvar:
-               expdest = cvtnum(num, expdest);
-               break;
-       case '-':
-               for (i = 0 ; i < NOPTS ; i++) {
-                       if (optent_val(i))
-                               STPUTC(optent_letter(optlist[i]), expdest);
-               }
-               break;
-       case '@':
-               if (allow_split && quoted) {
-                       sep = 1 << CHAR_BIT;
-                       goto param;
-               }
-               /* fall through */
-       case '*':
-               sep = ifsset() ? ifsval()[0] : ' ';
-               if (quotes) {
-                       sepq = syntax[(int) sep] == CCTL;
-               }
-param:
-               for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
-                       strtodest(p, syntax, quotes);
-                       if (*ap && sep) {
-                               if (sepq)
-                                       STPUTC(CTLESC, expdest);
-                               STPUTC(sep, expdest);
-                       }
-               }
-               break;
-       case '0':
-               strtodest(arg0, syntax, quotes);
-               break;
-       default:
-               num = atoi(name);
-               if (num > 0 && num <= shellparam.nparam) {
-                       strtodest(shellparam.p[num - 1], syntax, quotes);
-               }
-               break;
-       }
-}
-
-
-/*
- * Record the fact that we have to scan this region of the
- * string for IFS characters.
- */
-
-static void
-recordregion(start, end, nulonly)
-       int start;
-       int end;
-       int nulonly;
-{
-       struct ifsregion *ifsp;
-
-       if (ifslastp == NULL) {
-               ifsp = &ifsfirst;
-       } else {
-               INTOFF;
-               ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
-               ifsp->next = NULL;
-               ifslastp->next = ifsp;
-               INTON;
-       }
-       ifslastp = ifsp;
-       ifslastp->begoff = start;
-       ifslastp->endoff = end;
-       ifslastp->nulonly = nulonly;
-}
-
-
-
-/*
- * Break the argument string into pieces based upon IFS and add the
- * strings to the argument list.  The regions of the string to be
- * searched for IFS characters have been stored by recordregion.
- */
-static void
-ifsbreakup(string, arglist)
-       char *string;
-       struct arglist *arglist;
-       {
-       struct ifsregion *ifsp;
-       struct strlist *sp;
-       char *start;
-       char *p;
-       char *q;
-       const char *ifs, *realifs;
-       int ifsspc;
-       int nulonly;
-
-
-       start = string;
-       ifsspc = 0;
-       nulonly = 0;
-       realifs = ifsset() ? ifsval() : defifs;
-       if (ifslastp != NULL) {
-               ifsp = &ifsfirst;
-               do {
-                       p = string + ifsp->begoff;
-                       nulonly = ifsp->nulonly;
-                       ifs = nulonly ? nullstr : realifs;
-                       ifsspc = 0;
-                       while (p < string + ifsp->endoff) {
-                               q = p;
-                               if (*p == CTLESC)
-                                       p++;
-                               if (strchr(ifs, *p)) {
-                                       if (!nulonly)
-                                               ifsspc = (strchr(defifs, *p) != NULL);
-                                       /* Ignore IFS whitespace at start */
-                                       if (q == start && ifsspc) {
-                                               p++;
-                                               start = p;
-                                               continue;
-                                       }
-                                       *q = '\0';
-                                       sp = (struct strlist *)stalloc(sizeof *sp);
-                                       sp->text = start;
-                                       *arglist->lastp = sp;
-                                       arglist->lastp = &sp->next;
-                                       p++;
-                                       if (!nulonly) {
-                                               for (;;) {
-                                                       if (p >= string + ifsp->endoff) {
-                                                               break;
-                                                       }
-                                                       q = p;
-                                                       if (*p == CTLESC)
-                                                               p++;
-                                                       if (strchr(ifs, *p) == NULL ) {
-                                                               p = q;
-                                                               break;
-                                                       } else if (strchr(defifs, *p) == NULL) {
-                                                               if (ifsspc) {
-                                                                       p++;
-                                                                       ifsspc = 0;
-                                                               } else {
-                                                                       p = q;
-                                                                       break;
-                                                               }
-                                                       } else
-                                                               p++;
-                                               }
-                                       }
-                                       start = p;
-                               } else
-                                       p++;
-                       }
-               } while ((ifsp = ifsp->next) != NULL);
-               if (!(*start || (!ifsspc && start > string && nulonly))) {
-                       return;
-               }
-       }
-
-       sp = (struct strlist *)stalloc(sizeof *sp);
-       sp->text = start;
-       *arglist->lastp = sp;
-       arglist->lastp = &sp->next;
-}
-
-static void
-ifsfree()
-{
-       while (ifsfirst.next != NULL) {
-               struct ifsregion *ifsp;
-               INTOFF;
-               ifsp = ifsfirst.next->next;
-               ckfree(ifsfirst.next);
-               ifsfirst.next = ifsp;
-               INTON;
-       }
-       ifslastp = NULL;
-       ifsfirst.next = NULL;
-}
-
-/*
- * Add a file name to the list.
- */
-
-static void
-addfname(const char *name)
-{
-       char *p;
-       struct strlist *sp;
-
-       p = sstrdup(name);
-       sp = (struct strlist *)stalloc(sizeof *sp);
-       sp->text = p;
-       *exparg.lastp = sp;
-       exparg.lastp = &sp->next;
-}
-
-/*
- * Expand shell metacharacters.  At this point, the only control characters
- * should be escapes.  The results are stored in the list exparg.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
-static void
-expandmeta(str, flag)
-       struct strlist *str;
-       int flag;
-{
-       const char *p;
-       glob_t pglob;
-       /* TODO - EXP_REDIR */
-
-       while (str) {
-               if (fflag)
-                       goto nometa;
-               p = preglob(str->text);
-               INTOFF;
-               switch (glob(p, 0, 0, &pglob)) {
-               case 0:
-                       if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
-                               goto nometa2;
-                       addglob(&pglob);
-                       globfree(&pglob);
-                       INTON;
-                       break;
-               case GLOB_NOMATCH:
-nometa2:
-                       globfree(&pglob);
-                       INTON;
-nometa:
-                       *exparg.lastp = str;
-                       rmescapes(str->text);
-                       exparg.lastp = &str->next;
-                       break;
-               default:        /* GLOB_NOSPACE */
-                       error("Out of space");
-               }
-               str = str->next;
-       }
-}
-
-
-/*
- * Add the result of glob(3) to the list.
- */
-
-static void
-addglob(pglob)
-       const glob_t *pglob;
-{
-       char **p = pglob->gl_pathv;
-
-       do {
-               addfname(*p);
-       } while (*++p);
-}
-
-
-#else   /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
-static char *expdir;
-
-
-static void
-expandmeta(str, flag)
-       struct strlist *str;
-       int flag;
-{
-       char *p;
-       struct strlist **savelastp;
-       struct strlist *sp;
-       char c;
-       /* TODO - EXP_REDIR */
-
-       while (str) {
-               if (fflag)
-                       goto nometa;
-               p = str->text;
-               for (;;) {                      /* fast check for meta chars */
-                       if ((c = *p++) == '\0')
-                               goto nometa;
-                       if (c == '*' || c == '?' || c == '[' || c == '!')
-                               break;
-               }
-               savelastp = exparg.lastp;
-               INTOFF;
-               if (expdir == NULL) {
-                       int i = strlen(str->text);
-                       expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
-               }
-
-               expmeta(expdir, str->text);
-               ckfree(expdir);
-               expdir = NULL;
-               INTON;
-               if (exparg.lastp == savelastp) {
-                       /*
-                        * no matches
-                        */
-nometa:
-                       *exparg.lastp = str;
-                       rmescapes(str->text);
-                       exparg.lastp = &str->next;
-               } else {
-                       *exparg.lastp = NULL;
-                       *savelastp = sp = expsort(*savelastp);
-                       while (sp->next != NULL)
-                               sp = sp->next;
-                       exparg.lastp = &sp->next;
-               }
-               str = str->next;
-       }
-}
-
-
-/*
- * Do metacharacter (i.e. *, ?, [...]) expansion.
- */
-
-static void
-expmeta(enddir, name)
-       char *enddir;
-       char *name;
-       {
-       char *p;
-       const char *cp;
-       char *q;
-       char *start;
-       char *endname;
-       int metaflag;
-       struct stat statb;
-       DIR *dirp;
-       struct dirent *dp;
-       int atend;
-       int matchdot;
-
-       metaflag = 0;
-       start = name;
-       for (p = name ; ; p++) {
-               if (*p == '*' || *p == '?')
-                       metaflag = 1;
-               else if (*p == '[') {
-                       q = p + 1;
-                       if (*q == '!')
-                               q++;
-                       for (;;) {
-                               while (*q == CTLQUOTEMARK)
-                                       q++;
-                               if (*q == CTLESC)
-                                       q++;
-                               if (*q == '/' || *q == '\0')
-                                       break;
-                               if (*++q == ']') {
-                                       metaflag = 1;
-                                       break;
-                               }
-                       }
-               } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
-                       metaflag = 1;
-               } else if (*p == '\0')
-                       break;
-               else if (*p == CTLQUOTEMARK)
-                       continue;
-               else if (*p == CTLESC)
-                       p++;
-               if (*p == '/') {
-                       if (metaflag)
-                               break;
-                       start = p + 1;
-               }
-       }
-       if (metaflag == 0) {    /* we've reached the end of the file name */
-               if (enddir != expdir)
-                       metaflag++;
-               for (p = name ; ; p++) {
-                       if (*p == CTLQUOTEMARK)
-                               continue;
-                       if (*p == CTLESC)
-                               p++;
-                       *enddir++ = *p;
-                       if (*p == '\0')
-                               break;
-               }
-               if (metaflag == 0 || lstat(expdir, &statb) >= 0)
-                       addfname(expdir);
-               return;
-       }
-       endname = p;
-       if (start != name) {
-               p = name;
-               while (p < start) {
-                       while (*p == CTLQUOTEMARK)
-                               p++;
-                       if (*p == CTLESC)
-                               p++;
-                       *enddir++ = *p++;
-               }
-       }
-       if (enddir == expdir) {
-               cp = ".";
-       } else if (enddir == expdir + 1 && *expdir == '/') {
-               cp = "/";
-       } else {
-               cp = expdir;
-               enddir[-1] = '\0';
-       }
-       if ((dirp = opendir(cp)) == NULL)
-               return;
-       if (enddir != expdir)
-               enddir[-1] = '/';
-       if (*endname == 0) {
-               atend = 1;
-       } else {
-               atend = 0;
-               *endname++ = '\0';
-       }
-       matchdot = 0;
-       p = start;
-       while (*p == CTLQUOTEMARK)
-               p++;
-       if (*p == CTLESC)
-               p++;
-       if (*p == '.')
-               matchdot++;
-       while (! int_pending() && (dp = readdir(dirp)) != NULL) {
-               if (dp->d_name[0] == '.' && ! matchdot)
-                       continue;
-               if (patmatch(start, dp->d_name, 0)) {
-                       if (atend) {
-                               strcpy(enddir, dp->d_name);
-                               addfname(expdir);
-                       } else {
-                               for (p = enddir, cp = dp->d_name;
-                                    (*p++ = *cp++) != '\0';)
-                                       continue;
-                               p[-1] = '/';
-                               expmeta(p, endname);
-                       }
-               }
-       }
-       closedir(dirp);
-       if (! atend)
-               endname[-1] = '/';
-}
-#endif  /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
-
-
-
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-/*
- * Sort the results of file name expansion.  It calculates the number of
- * strings to sort and then calls msort (short for merge sort) to do the
- * work.
- */
-
-static struct strlist *
-expsort(str)
-       struct strlist *str;
-       {
-       int len;
-       struct strlist *sp;
-
-       len = 0;
-       for (sp = str ; sp ; sp = sp->next)
-               len++;
-       return msort(str, len);
-}
-
-
-static struct strlist *
-msort(list, len)
-       struct strlist *list;
-       int len;
-{
-       struct strlist *p, *q = NULL;
-       struct strlist **lpp;
-       int half;
-       int n;
-
-       if (len <= 1)
-               return list;
-       half = len >> 1;
-       p = list;
-       for (n = half ; --n >= 0 ; ) {
-               q = p;
-               p = p->next;
-       }
-       q->next = NULL;                 /* terminate first half of list */
-       q = msort(list, half);          /* sort first half of list */
-       p = msort(p, len - half);               /* sort second half */
-       lpp = &list;
-       for (;;) {
-               if (strcmp(p->text, q->text) < 0) {
-                       *lpp = p;
-                       lpp = &p->next;
-                       if ((p = *lpp) == NULL) {
-                               *lpp = q;
-                               break;
-                       }
-               } else {
-                       *lpp = q;
-                       lpp = &q->next;
-                       if ((q = *lpp) == NULL) {
-                               *lpp = p;
-                               break;
-                       }
-               }
-       }
-       return list;
-}
-#endif
-
-
-
-/*
- * Returns true if the pattern matches the string.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-/* squoted: string might have quote chars */
-static int
-patmatch(char *pattern, char *string, int squoted)
-{
-       const char *p;
-       char *q;
-
-       p = preglob(pattern);
-       q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
-
-       return !fnmatch(p, q, 0);
-}
-
-
-static int
-patmatch2(char *pattern, char *string, int squoted)
-{
-       char *p;
-       int res;
-
-       sstrnleft--;
-       p = grabstackstr(expdest);
-       res = patmatch(pattern, string, squoted);
-       ungrabstackstr(p, expdest);
-       return res;
-}
-#else
-static int
-patmatch(char *pattern, char *string, int squoted) {
-       return pmatch(pattern, string, squoted);
-}
-
-
-static int
-pmatch(char *pattern, char *string, int squoted)
-{
-       char *p, *q;
-       char c;
-
-       p = pattern;
-       q = string;
-       for (;;) {
-               switch (c = *p++) {
-               case '\0':
-                       goto breakloop;
-               case CTLESC:
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ != *p++)
-                               return 0;
-                       break;
-               case CTLQUOTEMARK:
-                       continue;
-               case '?':
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ == '\0')
-                               return 0;
-                       break;
-               case '*':
-                       c = *p;
-                       while (c == CTLQUOTEMARK || c == '*')
-                               c = *++p;
-                       if (c != CTLESC &&  c != CTLQUOTEMARK &&
-                           c != '?' && c != '*' && c != '[') {
-                               while (*q != c) {
-                                       if (squoted && *q == CTLESC &&
-                                           q[1] == c)
-                                               break;
-                                       if (*q == '\0')
-                                               return 0;
-                                       if (squoted && *q == CTLESC)
-                                               q++;
-                                       q++;
-                               }
-                       }
-                       do {
-                               if (pmatch(p, q, squoted))
-                                       return 1;
-                               if (squoted && *q == CTLESC)
-                                       q++;
-                       } while (*q++ != '\0');
-                       return 0;
-               case '[': {
-                       char *endp;
-                       int invert, found;
-                       char chr;
-
-                       endp = p;
-                       if (*endp == '!')
-                               endp++;
-                       for (;;) {
-                               while (*endp == CTLQUOTEMARK)
-                                       endp++;
-                               if (*endp == '\0')
-                                       goto dft;               /* no matching ] */
-                               if (*endp == CTLESC)
-                                       endp++;
-                               if (*++endp == ']')
-                                       break;
-                       }
-                       invert = 0;
-                       if (*p == '!') {
-                               invert++;
-                               p++;
-                       }
-                       found = 0;
-                       chr = *q++;
-                       if (squoted && chr == CTLESC)
-                               chr = *q++;
-                       if (chr == '\0')
-                               return 0;
-                       c = *p++;
-                       do {
-                               if (c == CTLQUOTEMARK)
-                                       continue;
-                               if (c == CTLESC)
-                                       c = *p++;
-                               if (*p == '-' && p[1] != ']') {
-                                       p++;
-                                       while (*p == CTLQUOTEMARK)
-                                               p++;
-                                       if (*p == CTLESC)
-                                               p++;
-                                       if (chr >= c && chr <= *p)
-                                               found = 1;
-                                       p++;
-                               } else {
-                                       if (chr == c)
-                                               found = 1;
-                               }
-                       } while ((c = *p++) != ']');
-                       if (found == invert)
-                               return 0;
-                       break;
-               }
-dft:            default:
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ != c)
-                               return 0;
-                       break;
-               }
-       }
-breakloop:
-       if (*q != '\0')
-               return 0;
-       return 1;
-}
-#endif
-
-
-
-/*
- * Remove any CTLESC characters from a string.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-static char *
-_rmescapes(char *str, int flag)
-{
-       char *p, *q, *r;
-       static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
-
-       p = strpbrk(str, qchars);
-       if (!p) {
-               return str;
-       }
-       q = p;
-       r = str;
-       if (flag & RMESCAPE_ALLOC) {
-               size_t len = p - str;
-               q = r = stalloc(strlen(p) + len + 1);
-               if (len > 0) {
-                       memcpy(q, str, len);
-                       q += len;
-               }
-       }
-       while (*p) {
-               if (*p == CTLQUOTEMARK) {
-                       p++;
-                       continue;
-               }
-               if (*p == CTLESC) {
-                       p++;
-                       if (flag & RMESCAPE_GLOB && *p != '/') {
-                               *q++ = '\\';
-                       }
-               }
-               *q++ = *p++;
-       }
-       *q = '\0';
-       return r;
-}
-#else
-static void
-rmescapes(str)
-       char *str;
-{
-       char *p, *q;
-
-       p = str;
-       while (*p != CTLESC && *p != CTLQUOTEMARK) {
-               if (*p++ == '\0')
-                       return;
-       }
-       q = p;
-       while (*p) {
-               if (*p == CTLQUOTEMARK) {
-                       p++;
-                       continue;
-               }
-               if (*p == CTLESC)
-                       p++;
-               *q++ = *p++;
-       }
-       *q = '\0';
-}
-#endif
-
-
-
-/*
- * See if a pattern matches in a case statement.
- */
-
-static int
-casematch(union node *pattern, const char *val)
-{
-       struct stackmark smark;
-       int result;
-       char *p;
-
-       setstackmark(&smark);
-       argbackq = pattern->narg.backquote;
-       STARTSTACKSTR(expdest);
-       ifslastp = NULL;
-       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
-       STPUTC('\0', expdest);
-       p = grabstackstr(expdest);
-       result = patmatch(p, (char *)val, 0);
-       popstackmark(&smark);
-       return result;
-}
-
-/*
- * Our own itoa().
- */
-
-static char *
-cvtnum(num, buf)
-       int num;
-       char *buf;
-       {
-       int len;
-
-       CHECKSTRSPACE(32, buf);
-       len = sprintf(buf, "%d", num);
-       STADJUST(len, buf);
-       return buf;
-}
-/*
- * Editline and history functions (and glue).
- */
-static int histcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       error("not compiled with history support");
-       /* NOTREACHED */
-}
-
-
-struct redirtab {
-       struct redirtab *next;
-       short renamed[10]; /* Current ash support only 0-9 descriptors */
-       /* char on arm (and others) can't be negative */
-};
-
-static struct redirtab *redirlist;
-
-extern char **environ;
-
-
-
-/*
- * Initialization code.
- */
-
-static void
-init(void) {
-
-      /* from cd.c: */
-      {
-             setpwd(0, 0);
-      }
-
-      /* from input.c: */
-      {
-             basepf.nextc = basepf.buf = basebuf;
-      }
-
-      /* from var.c: */
-      {
-             char **envp;
-             char ppid[32];
-
-             initvar();
-             for (envp = environ ; *envp ; envp++) {
-                     if (strchr(*envp, '=')) {
-                             setvareq(*envp, VEXPORT|VTEXTFIXED);
-                     }
-             }
-
-             snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
-             setvar("PPID", ppid, 0);
-      }
-}
-
-
-
-/*
- * This routine is called when an error or an interrupt occurs in an
- * interactive shell and control is returned to the main command loop.
- */
-
-/* 1 == check for aliases, 2 == also check for assignments */
-static int checkalias;  /* also used in no alias mode for check assignments */
-
-static void
-reset(void) {
-
-      /* from eval.c: */
-      {
-             evalskip = 0;
-             loopnest = 0;
-             funcnest = 0;
-      }
-
-      /* from input.c: */
-      {
-             if (exception != EXSHELLPROC)
-                     parselleft = parsenleft = 0;      /* clear input buffer */
-             popallfiles();
-      }
-
-      /* from parser.c: */
-      {
-             tokpushback = 0;
-             checkkwd = 0;
-             checkalias = 0;
-      }
-
-      /* from redir.c: */
-      {
-             while (redirlist)
-                     popredir();
-      }
-
-}
-
-
-
-/*
- * This file implements the input routines used by the parser.
- */
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-static const char * cmdedit_prompt;
-static inline void putprompt(const char *s) {
-    cmdedit_prompt = s;
-}
-#else
-static inline void putprompt(const char *s) {
-    out2str(s);
-}
-#endif
-
-#define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
-
-
-
-/*
- * Same as pgetc(), but ignores PEOA.
- */
-
-#ifdef ASH_ALIAS
-static int
-pgetc2()
-{
-       int c;
-       do {
-               c = pgetc_macro();
-       } while (c == PEOA);
-       return c;
-}
-#else
-static inline int pgetc2() { return pgetc_macro(); }
-#endif
-
-/*
- * Read a line from the script.
- */
-
-static inline char *
-pfgets(char *line, int len)
-{
-       char *p = line;
-       int nleft = len;
-       int c;
-
-       while (--nleft > 0) {
-               c = pgetc2();
-               if (c == PEOF) {
-                       if (p == line)
-                               return NULL;
-                       break;
-               }
-               *p++ = c;
-               if (c == '\n')
-                       break;
-       }
-       *p = '\0';
-       return line;
-}
-
-static inline int
-preadfd(void)
-{
-    int nr;
-    char *buf =  parsefile->buf;
-    parsenextc = buf;
-
-retry:
-#ifdef BB_FEATURE_COMMAND_EDITING
-       {
-           if (!iflag || parsefile->fd)
-                   nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
-           else {
-                   nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
-           }
-       }
-#else
-       nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
-#endif
-
-       if (nr < 0) {
-               if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
-                       int flags = fcntl(0, F_GETFL, 0);
-                       if (flags >= 0 && flags & O_NONBLOCK) {
-                               flags &=~ O_NONBLOCK;
-                               if (fcntl(0, F_SETFL, flags) >= 0) {
-                                       out2str("sh: turning off NDELAY mode\n");
-                                       goto retry;
-                               }
-                       }
-               }
-       }
-       return nr;
-}
-
-static void
-popstring(void)
-{
-       struct strpush *sp = parsefile->strpush;
-
-       INTOFF;
-#ifdef ASH_ALIAS
-       if (sp->ap) {
-               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
-                       if (!checkalias) {
-                               checkalias = 1;
-                       }
-               }
-               if (sp->string != sp->ap->val) {
-                       ckfree(sp->string);
-               }
-
-               sp->ap->flag &= ~ALIASINUSE;
-               if (sp->ap->flag & ALIASDEAD) {
-                       unalias(sp->ap->name);
-               }
-       }
-#endif
-       parsenextc = sp->prevstring;
-       parsenleft = sp->prevnleft;
-/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
-       parsefile->strpush = sp->prev;
-       if (sp != &(parsefile->basestrpush))
-               ckfree(sp);
-       INTON;
-}
-
-
-/*
- * Refill the input buffer and return the next input character:
- *
- * 1) If a string was pushed back on the input, pop it;
- * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
- *    from a string so we can't refill the buffer, return EOF.
- * 3) If the is more stuff in this buffer, use it else call read to fill it.
- * 4) Process input up to the next newline, deleting nul characters.
- */
-
-static int
-preadbuffer(void)
-{
-       char *p, *q;
-       int more;
-       char savec;
-
-       while (parsefile->strpush) {
-#ifdef ASH_ALIAS
-               if (parsenleft == -1 && parsefile->strpush->ap &&
-                       parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
-                       return PEOA;
-               }
-#endif
-               popstring();
-               if (--parsenleft >= 0)
-                       return (*parsenextc++);
-       }
-       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
-               return PEOF;
-       flushall();
-
-again:
-       if (parselleft <= 0) {
-               if ((parselleft = preadfd()) <= 0) {
-                       parselleft = parsenleft = EOF_NLEFT;
-                       return PEOF;
-               }
-       }
-
-       q = p = parsenextc;
-
-       /* delete nul characters */
-       for (more = 1; more;) {
-               switch (*p) {
-               case '\0':
-                       p++;    /* Skip nul */
-                       goto check;
-
-
-               case '\n':
-                       parsenleft = q - parsenextc;
-                       more = 0; /* Stop processing here */
-                       break;
-               }
-
-               *q++ = *p++;
-check:
-               if (--parselleft <= 0 && more) {
-                       parsenleft = q - parsenextc - 1;
-                       if (parsenleft < 0)
-                               goto again;
-                       more = 0;
-               }
-       }
-
-       savec = *q;
-       *q = '\0';
-
-       if (vflag) {
-               out2str(parsenextc);
-       }
-
-       *q = savec;
-
-       return *parsenextc++;
-}
-
-
-/*
- * Push a string back onto the input at this current parsefile level.
- * We handle aliases this way.
- */
-static void
-pushstring(char *s, int len, void *ap)
-{
-       struct strpush *sp;
-
-       INTOFF;
-/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
-       if (parsefile->strpush) {
-               sp = ckmalloc(sizeof (struct strpush));
-               sp->prev = parsefile->strpush;
-               parsefile->strpush = sp;
-       } else
-               sp = parsefile->strpush = &(parsefile->basestrpush);
-       sp->prevstring = parsenextc;
-       sp->prevnleft = parsenleft;
-#ifdef ASH_ALIAS
-       sp->ap = (struct alias *)ap;
-       if (ap) {
-               ((struct alias *)ap)->flag |= ALIASINUSE;
-               sp->string = s;
-       }
-#endif
-       parsenextc = s;
-       parsenleft = len;
-       INTON;
-}
-
-
-/*
- * Like setinputfile, but takes input from a string.
- */
-
-static void
-setinputstring(char *string)
-{
-       INTOFF;
-       pushfile();
-       parsenextc = string;
-       parsenleft = strlen(string);
-       parsefile->buf = NULL;
-       plinno = 1;
-       INTON;
-}
-
-
-
-/*
- * To handle the "." command, a stack of input files is used.  Pushfile
- * adds a new entry to the stack and popfile restores the previous level.
- */
-
-static void
-pushfile(void) {
-       struct parsefile *pf;
-
-       parsefile->nleft = parsenleft;
-       parsefile->lleft = parselleft;
-       parsefile->nextc = parsenextc;
-       parsefile->linno = plinno;
-       pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
-       pf->prev = parsefile;
-       pf->fd = -1;
-       pf->strpush = NULL;
-       pf->basestrpush.prev = NULL;
-       parsefile = pf;
-}
-
-#ifdef JOBS
-static void restartjob (struct job *);
-#endif
-static void freejob (struct job *);
-static struct job *getjob (const char *);
-static int dowait (int, struct job *);
-static void waitonint(int);
-
-
-/*
- * We keep track of whether or not fd0 has been redirected.  This is for
- * background commands, where we want to redirect fd0 to /dev/null only
- * if it hasn't already been redirected.
-*/
-static int fd0_redirected = 0;
-
-/* Return true if fd 0 has already been redirected at least once.  */
-static inline int
-fd0_redirected_p () {
-       return fd0_redirected != 0;
-}
-
-static void dupredirect (const union node *, int, int fd1dup);
-
-#ifdef JOBS
-/*
- * Turn job control on and off.
- *
- * Note:  This code assumes that the third arg to ioctl is a character
- * pointer, which is true on Berkeley systems but not System V.  Since
- * System V doesn't have job control yet, this isn't a problem now.
- */
-
-
-
-static void setjobctl(int enable)
-{
-#ifdef OLD_TTY_DRIVER
-       int ldisc;
-#endif
-
-       if (enable == jobctl || rootshell == 0)
-               return;
-       if (enable) {
-               do { /* while we are in the background */
-#ifdef OLD_TTY_DRIVER
-                       if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
-#else
-                       initialpgrp = tcgetpgrp(2);
-                       if (initialpgrp < 0) {
-#endif
-                               out2str("sh: can't access tty; job control turned off\n");
-                               mflag = 0;
-                               return;
-                       }
-                       if (initialpgrp == -1)
-                               initialpgrp = getpgrp();
-                       else if (initialpgrp != getpgrp()) {
-                               killpg(initialpgrp, SIGTTIN);
-                               continue;
-                       }
-               } while (0);
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
-                       out2str("sh: need new tty driver to run job control; job control turned off\n");
-                       mflag = 0;
-                       return;
-               }
-#endif
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-               setpgid(0, rootpid);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *)&rootpid);
-#else
-               tcsetpgrp(2, rootpid);
-#endif
-       } else { /* turning job control off */
-               setpgid(0, initialpgrp);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
-#else
-               tcsetpgrp(2, initialpgrp);
-#endif
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-       }
-       jobctl = enable;
-}
-#endif
-
-
-#ifdef JOBS
-static int
-killcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int signo = -1;
-       int list = 0;
-       int i;
-       pid_t pid;
-       struct job *jp;
-
-       if (argc <= 1) {
-usage:
-               error(
-"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
-"kill -l [exitstatus]"
-               );
-       }
-
-       if (*argv[1] == '-') {
-               signo = decode_signal(argv[1] + 1, 1);
-               if (signo < 0) {
-                       int c;
-
-                       while ((c = nextopt("ls:")) != '\0')
-                               switch (c) {
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 's':
-                                       signo = decode_signal(optionarg, 1);
-                                       if (signo < 0) {
-                                               error(
-                                                       "invalid signal number or name: %s",
-                                                       optionarg
-                                               );
-                                       }
-                                       break;
-#ifdef DEBUG
-                               default:
-                                       error(
-       "nextopt returned character code 0%o", c);
-#endif
-                       }
-               } else
-                       argptr++;
-       }
-
-       if (!list && signo < 0)
-               signo = SIGTERM;
-
-       if ((signo < 0 || !*argptr) ^ list) {
-               goto usage;
-       }
-
-       if (list) {
-               const char *name;
-
-               if (!*argptr) {
-                       out1str("0\n");
-                       for (i = 1; i < NSIG; i++) {
-                               name = u_signal_names(0, &i, 1);
-                               if(name)
-                                       printf(snlfmt, name);
-                       }
-                       return 0;
-               }
-               name = u_signal_names(*argptr, &signo, -1);
-               if (name)
-                       printf(snlfmt, name);
-               else
-                       error("invalid signal number or exit status: %s",
-                             *argptr);
-               return 0;
-       }
-
-       do {
-               if (**argptr == '%') {
-                       jp = getjob(*argptr);
-                       if (jp->jobctl == 0)
-                               error("job %s not created under job control",
-                                     *argptr);
-                       pid = -jp->ps[0].pid;
-               } else
-                       pid = atoi(*argptr);
-               if (kill(pid, signo) != 0)
-                       error("%s: %m", *argptr);
-       } while (*++argptr);
-
-       return 0;
-}
-
-static int
-fgcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *jp;
-       int pgrp;
-       int status;
-
-       jp = getjob(argv[1]);
-       if (jp->jobctl == 0)
-               error("job not created under job control");
-       pgrp = jp->ps[0].pid;
-#ifdef OLD_TTY_DRIVER
-       ioctl(2, TIOCSPGRP, (char *)&pgrp);
-#else
-       tcsetpgrp(2, pgrp);
-#endif
-       restartjob(jp);
-       INTOFF;
-       status = waitforjob(jp);
-       INTON;
-       return status;
-}
-
-
-static int
-bgcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *jp;
-
-       do {
-               jp = getjob(*++argv);
-               if (jp->jobctl == 0)
-                       error("job not created under job control");
-               restartjob(jp);
-       } while (--argc > 1);
-       return 0;
-}
-
-
-static void
-restartjob(jp)
-       struct job *jp;
-{
-       struct procstat *ps;
-       int i;
-
-       if (jp->state == JOBDONE)
-               return;
-       INTOFF;
-       killpg(jp->ps[0].pid, SIGCONT);
-       for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
-               if (WIFSTOPPED(ps->status)) {
-                       ps->status = -1;
-                       jp->state = 0;
-               }
-       }
-       INTON;
-}
-#endif
-
-static void showjobs(int change);
-
-
-static int
-jobscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       showjobs(0);
-       return 0;
-}
-
-
-/*
- * Print a list of jobs.  If "change" is nonzero, only print jobs whose
- * statuses have changed since the last call to showjobs.
- *
- * If the shell is interrupted in the process of creating a job, the
- * result may be a job structure containing zero processes.  Such structures
- * will be freed here.
- */
-
-static void
-showjobs(change)
-       int change;
-{
-       int jobno;
-       int procno;
-       int i;
-       struct job *jp;
-       struct procstat *ps;
-       int col;
-       char s[64];
-
-       TRACE(("showjobs(%d) called\n", change));
-       while (dowait(0, (struct job *)NULL) > 0);
-       for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
-               if (! jp->used)
-                       continue;
-               if (jp->nprocs == 0) {
-                       freejob(jp);
-                       continue;
-               }
-               if (change && ! jp->changed)
-                       continue;
-               procno = jp->nprocs;
-               for (ps = jp->ps ; ; ps++) {    /* for each process */
-                       if (ps == jp->ps)
-                               snprintf(s, 64, "[%d] %ld ", jobno,
-                                   (long)ps->pid);
-                       else
-                               snprintf(s, 64, "    %ld ",
-                                   (long)ps->pid);
-                       out1str(s);
-                       col = strlen(s);
-                       s[0] = '\0';
-                       if (ps->status == -1) {
-                               /* don't print anything */
-                       } else if (WIFEXITED(ps->status)) {
-                               snprintf(s, 64, "Exit %d",
-                                      WEXITSTATUS(ps->status));
-                       } else {
-#ifdef JOBS
-                               if (WIFSTOPPED(ps->status))
-                                       i = WSTOPSIG(ps->status);
-                               else /* WIFSIGNALED(ps->status) */
-#endif
-                                       i = WTERMSIG(ps->status);
-                               if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
-                                       strcpy(s, sys_siglist[i & 0x7F]);
-                               else
-                                       snprintf(s, 64, "Signal %d", i & 0x7F);
-                               if (WCOREDUMP(ps->status))
-                                       strcat(s, " (core dumped)");
-                       }
-                       out1str(s);
-                       col += strlen(s);
-                       printf(
-                               "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
-                               ps->cmd
-                       );
-                       if (--procno <= 0)
-                               break;
-               }
-               jp->changed = 0;
-               if (jp->state == JOBDONE) {
-                       freejob(jp);
-               }
-       }
-}
-
-
-/*
- * Mark a job structure as unused.
- */
-
-static void
-freejob(struct job *jp)
-{
-       const struct procstat *ps;
-       int i;
-
-       INTOFF;
-       for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
-               if (ps->cmd != nullstr)
-                       ckfree(ps->cmd);
-       }
-       if (jp->ps != &jp->ps0)
-               ckfree(jp->ps);
-       jp->used = 0;
-#ifdef JOBS
-       if (curjob == jp - jobtab + 1)
-               curjob = 0;
-#endif
-       INTON;
-}
-
-
-
-static int
-waitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *job;
-       int status, retval;
-       struct job *jp;
-
-       if (--argc > 0) {
-start:
-               job = getjob(*++argv);
-       } else {
-               job = NULL;
-       }
-       for (;;) {      /* loop until process terminated or stopped */
-               if (job != NULL) {
-                       if (job->state) {
-                               status = job->ps[job->nprocs - 1].status;
-                               if (! iflag)
-                                       freejob(job);
-                               if (--argc) {
-                                       goto start;
-                               }
-                               if (WIFEXITED(status))
-                                       retval = WEXITSTATUS(status);
-#ifdef JOBS
-                               else if (WIFSTOPPED(status))
-                                       retval = WSTOPSIG(status) + 128;
-#endif
-                               else {
-                                       /* XXX: limits number of signals */
-                                       retval = WTERMSIG(status) + 128;
-                               }
-                               return retval;
-                       }
-               } else {
-                       for (jp = jobtab ; ; jp++) {
-                               if (jp >= jobtab + njobs) {     /* no running procs */
-                                       return 0;
-                               }
-                               if (jp->used && jp->state == 0)
-                                       break;
-                       }
-               }
-               if (dowait(2, 0) < 0 && errno == EINTR) {
-                       return 129;
-               }
-       }
-}
-
-
-
-/*
- * Convert a job name to a job structure.
- */
-
-static struct job *
-getjob(const char *name)
-{
-       int jobno;
-       struct job *jp;
-       int pid;
-       int i;
-
-       if (name == NULL) {
-#ifdef JOBS
-currentjob:
-               if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
-                       error("No current job");
-               return &jobtab[jobno - 1];
-#else
-               error("No current job");
-#endif
-       } else if (name[0] == '%') {
-               if (is_digit(name[1])) {
-                       jobno = number(name + 1);
-                       if (jobno > 0 && jobno <= njobs
-                        && jobtab[jobno - 1].used != 0)
-                               return &jobtab[jobno - 1];
-#ifdef JOBS
-               } else if (name[1] == '%' && name[2] == '\0') {
-                       goto currentjob;
-#endif
-               } else {
-                       struct job *found = NULL;
-                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                               if (jp->used && jp->nprocs > 0
-                                && prefix(name + 1, jp->ps[0].cmd)) {
-                                       if (found)
-                                               error("%s: ambiguous", name);
-                                       found = jp;
-                               }
-                       }
-                       if (found)
-                               return found;
-               }
-       } else if (is_number(name, &pid)) {
-               for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                       if (jp->used && jp->nprocs > 0
-                        && jp->ps[jp->nprocs - 1].pid == pid)
-                               return jp;
-               }
-       }
-       error("No such job: %s", name);
-       /* NOTREACHED */
-}
-
-
-
-/*
- * Return a new job structure,
- */
-
-static struct job *
-makejob(const union node *node, int nprocs)
-{
-       int i;
-       struct job *jp;
-
-       for (i = njobs, jp = jobtab ; ; jp++) {
-               if (--i < 0) {
-                       INTOFF;
-                       if (njobs == 0) {
-                               jobtab = ckmalloc(4 * sizeof jobtab[0]);
-                       } else {
-                               jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
-                               memcpy(jp, jobtab, njobs * sizeof jp[0]);
-                               /* Relocate `ps' pointers */
-                               for (i = 0; i < njobs; i++)
-                                       if (jp[i].ps == &jobtab[i].ps0)
-                                               jp[i].ps = &jp[i].ps0;
-                               ckfree(jobtab);
-                               jobtab = jp;
-                       }
-                       jp = jobtab + njobs;
-                       for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
-                       INTON;
-                       break;
-               }
-               if (jp->used == 0)
-                       break;
-       }
-       INTOFF;
-       jp->state = 0;
-       jp->used = 1;
-       jp->changed = 0;
-       jp->nprocs = 0;
-#ifdef JOBS
-       jp->jobctl = jobctl;
-#endif
-       if (nprocs > 1) {
-               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
-       } else {
-               jp->ps = &jp->ps0;
-       }
-       INTON;
-       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
-           jp - jobtab + 1));
-       return jp;
-}
-
-
-/*
- * Fork of a subshell.  If we are doing job control, give the subshell its
- * own process group.  Jp is a job structure that the job is to be added to.
- * N is the command that will be evaluated by the child.  Both jp and n may
- * be NULL.  The mode parameter can be one of the following:
- *      FORK_FG - Fork off a foreground process.
- *      FORK_BG - Fork off a background process.
- *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
- *                   process group even if job control is on.
- *
- * When job control is turned off, background processes have their standard
- * input redirected to /dev/null (except for the second and later processes
- * in a pipeline).
- */
-
-
-
-static int
-forkshell(struct job *jp, const union node *n, int mode)
-{
-       int pid;
-#ifdef JOBS
-       int pgrp;
-#endif
-       const char *devnull = _PATH_DEVNULL;
-       const char *nullerr = "Can't open %s";
-
-       TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
-           mode));
-       INTOFF;
-       pid = fork();
-       if (pid == -1) {
-               TRACE(("Fork failed, errno=%d\n", errno));
-               INTON;
-               error("Cannot fork");
-       }
-       if (pid == 0) {
-               struct job *p;
-               int wasroot;
-               int i;
-
-               TRACE(("Child shell %d\n", getpid()));
-               wasroot = rootshell;
-               rootshell = 0;
-               closescript();
-               INTON;
-               clear_traps();
-#ifdef JOBS
-               jobctl = 0;             /* do job control only in root shell */
-               if (wasroot && mode != FORK_NOJOB && mflag) {
-                       if (jp == NULL || jp->nprocs == 0)
-                               pgrp = getpid();
-                       else
-                               pgrp = jp->ps[0].pid;
-                       setpgid(0, pgrp);
-                       if (mode == FORK_FG) {
-                               /*** this causes superfluous TIOCSPGRPS ***/
-#ifdef OLD_TTY_DRIVER
-                               if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
-                                       error("TIOCSPGRP failed, errno=%d", errno);
-#else
-                               if (tcsetpgrp(2, pgrp) < 0)
-                                       error("tcsetpgrp failed, errno=%d", errno);
-#endif
-                       }
-                       setsignal(SIGTSTP);
-                       setsignal(SIGTTOU);
-               } else if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(devnull, O_RDONLY) != 0)
-                                       error(nullerr, devnull);
-                       }
-               }
-#else
-               if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(devnull, O_RDONLY) != 0)
-                                       error(nullerr, devnull);
-                       }
-               }
-#endif
-               for (i = njobs, p = jobtab ; --i >= 0 ; p++)
-                       if (p->used)
-                               freejob(p);
-               if (wasroot && iflag) {
-                       setsignal(SIGINT);
-                       setsignal(SIGQUIT);
-                       setsignal(SIGTERM);
-               }
-               return pid;
-       }
-#ifdef JOBS
-       if (rootshell && mode != FORK_NOJOB && mflag) {
-               if (jp == NULL || jp->nprocs == 0)
-                       pgrp = pid;
-               else
-                       pgrp = jp->ps[0].pid;
-               setpgid(pid, pgrp);
-       }
-#endif
-       if (mode == FORK_BG)
-               backgndpid = pid;               /* set $! */
-       if (jp) {
-               struct procstat *ps = &jp->ps[jp->nprocs++];
-               ps->pid = pid;
-               ps->status = -1;
-               ps->cmd = nullstr;
-               if (iflag && rootshell && n)
-                       ps->cmd = commandtext(n);
-       }
-       INTON;
-       TRACE(("In parent shell:  child = %d\n", pid));
-       return pid;
-}
-
-
-
-/*
- * Wait for job to finish.
- *
- * Under job control we have the problem that while a child process is
- * running interrupts generated by the user are sent to the child but not
- * to the shell.  This means that an infinite loop started by an inter-
- * active user may be hard to kill.  With job control turned off, an
- * interactive user may place an interactive program inside a loop.  If
- * the interactive program catches interrupts, the user doesn't want
- * these interrupts to also abort the loop.  The approach we take here
- * is to have the shell ignore interrupt signals while waiting for a
- * forground process to terminate, and then send itself an interrupt
- * signal if the child process was terminated by an interrupt signal.
- * Unfortunately, some programs want to do a bit of cleanup and then
- * exit on interrupt; unless these processes terminate themselves by
- * sending a signal to themselves (instead of calling exit) they will
- * confuse this approach.
- */
-
-static int
-waitforjob(struct job *jp)
-{
-#ifdef JOBS
-       int mypgrp = getpgrp();
-#endif
-       int status;
-       int st;
-       struct sigaction act, oact;
-
-       INTOFF;
-       intreceived = 0;
-#ifdef JOBS
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, 0, &act);
-               act.sa_handler = waitonint;
-               sigaction(SIGINT, &act, &oact);
-       }
-       TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
-       while (jp->state == 0) {
-               dowait(1, jp);
-       }
-#ifdef JOBS
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, &oact, 0);
-               if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
-       }
-#ifdef JOBS
-       if (jp->jobctl) {
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
-                       error("TIOCSPGRP failed, errno=%d\n", errno);
-#else
-               if (tcsetpgrp(2, mypgrp) < 0)
-                       error("tcsetpgrp failed, errno=%d\n", errno);
-#endif
-       }
-       if (jp->state == JOBSTOPPED)
-               curjob = jp - jobtab + 1;
-#endif
-       status = jp->ps[jp->nprocs - 1].status;
-       /* convert to 8 bits */
-       if (WIFEXITED(status))
-               st = WEXITSTATUS(status);
-#ifdef JOBS
-       else if (WIFSTOPPED(status))
-               st = WSTOPSIG(status) + 128;
-#endif
-       else
-               st = WTERMSIG(status) + 128;
-#ifdef JOBS
-       if (jp->jobctl) {
-               /*
-                * This is truly gross.
-                * If we're doing job control, then we did a TIOCSPGRP which
-                * caused us (the shell) to no longer be in the controlling
-                * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
-                * intuit from the subprocess exit status whether a SIGINT
-                * occured, and if so interrupt ourselves.  Yuck.  - mycroft
-                */
-               if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
-                       raise(SIGINT);
-       }
-       if (jp->state == JOBDONE)
-
-#endif
-               freejob(jp);
-       INTON;
-       return st;
-}
-
-
-
-/*
- * Wait for a process to terminate.
- */
-
-/*
- * Do a wait system call.  If job control is compiled in, we accept
- * stopped processes.  If block is zero, we return a value of zero
- * rather than blocking.
- *
- * System V doesn't have a non-blocking wait system call.  It does
- * have a SIGCLD signal that is sent to a process when one of it's
- * children dies.  The obvious way to use SIGCLD would be to install
- * a handler for SIGCLD which simply bumped a counter when a SIGCLD
- * was received, and have waitproc bump another counter when it got
- * the status of a process.  Waitproc would then know that a wait
- * system call would not block if the two counters were different.
- * This approach doesn't work because if a process has children that
- * have not been waited for, System V will send it a SIGCLD when it
- * installs a signal handler for SIGCLD.  What this means is that when
- * a child exits, the shell will be sent SIGCLD signals continuously
- * until is runs out of stack space, unless it does a wait call before
- * restoring the signal handler.  The code below takes advantage of
- * this (mis)feature by installing a signal handler for SIGCLD and
- * then checking to see whether it was called.  If there are any
- * children to be waited for, it will be.
- *
- */
-
-static inline int
-waitproc(int block, int *status)
-{
-       int flags;
-
-       flags = 0;
-#ifdef JOBS
-       if (jobctl)
-               flags |= WUNTRACED;
-#endif
-       if (block == 0)
-               flags |= WNOHANG;
-       return wait3(status, flags, (struct rusage *)NULL);
-}
-
-static int
-dowait(int block, struct job *job)
-{
-       int pid;
-       int status;
-       struct procstat *sp;
-       struct job *jp;
-       struct job *thisjob;
-       int done;
-       int stopped;
-       int core;
-       int sig;
-
-       TRACE(("dowait(%d) called\n", block));
-       do {
-               pid = waitproc(block, &status);
-               TRACE(("wait returns %d, status=%d\n", pid, status));
-       } while (!(block & 2) && pid == -1 && errno == EINTR);
-       if (pid <= 0)
-               return pid;
-       INTOFF;
-       thisjob = NULL;
-       for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
-               if (jp->used) {
-                       done = 1;
-                       stopped = 1;
-                       for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
-                               if (sp->pid == -1)
-                                       continue;
-                               if (sp->pid == pid) {
-                                       TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
-                                       sp->status = status;
-                                       thisjob = jp;
-                               }
-                               if (sp->status == -1)
-                                       stopped = 0;
-                               else if (WIFSTOPPED(sp->status))
-                                       done = 0;
-                       }
-                       if (stopped) {          /* stopped or done */
-                               int state = done? JOBDONE : JOBSTOPPED;
-                               if (jp->state != state) {
-                                       TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
-                                       jp->state = state;
-#ifdef JOBS
-                                       if (done && curjob == jp - jobtab + 1)
-                                               curjob = 0;             /* no current job */
-#endif
-                               }
-                       }
-               }
-       }
-       INTON;
-       if (! rootshell || ! iflag || (job && thisjob == job)) {
-               core = WCOREDUMP(status);
-#ifdef JOBS
-               if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
-               else
-#endif
-               if (WIFEXITED(status)) sig = 0;
-               else sig = WTERMSIG(status);
-
-               if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
-                       if (thisjob != job)
-                               out2fmt("%d: ", pid);
-#ifdef JOBS
-                       if (sig == SIGTSTP && rootshell && iflag)
-                               out2fmt("%%%ld ",
-                                   (long)(job - jobtab + 1));
-#endif
-                       if (sig < NSIG && sys_siglist[sig])
-                               out2str(sys_siglist[sig]);
-                       else
-                               out2fmt("Signal %d", sig);
-                       if (core)
-                               out2str(" - core dumped");
-                       out2c('\n');
-               } else {
-                       TRACE(("Not printing status: status=%d, sig=%d\n",
-                              status, sig));
-               }
-       } else {
-               TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
-               if (thisjob)
-                       thisjob->changed = 1;
-       }
-       return pid;
-}
-
-
-
-
-/*
- * return 1 if there are stopped jobs, otherwise 0
- */
-static int
-stoppedjobs(void)
-{
-       int jobno;
-       struct job *jp;
-
-       if (job_warning)
-               return (0);
-       for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
-               if (jp->used == 0)
-                       continue;
-               if (jp->state == JOBSTOPPED) {
-                       out2str("You have stopped jobs.\n");
-                       job_warning = 2;
-                       return (1);
-               }
-       }
-
-       return (0);
-}
-
-/*
- * Return a string identifying a command (to be printed by the
- * jobs command.
- */
-
-static char *cmdnextc;
-static int cmdnleft;
-#define MAXCMDTEXT      200
-
-static void
-cmdputs(const char *s)
-{
-       const char *p;
-       char *q;
-       char c;
-       int subtype = 0;
-
-       if (cmdnleft <= 0)
-               return;
-       p = s;
-       q = cmdnextc;
-       while ((c = *p++) != '\0') {
-               if (c == CTLESC)
-                       *q++ = *p++;
-               else if (c == CTLVAR) {
-                       *q++ = '$';
-                       if (--cmdnleft > 0)
-                               *q++ = '{';
-                       subtype = *p++;
-               } else if (c == '=' && subtype != 0) {
-                       *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
-                       subtype = 0;
-               } else if (c == CTLENDVAR) {
-                       *q++ = '}';
-               } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
-                       cmdnleft++;             /* ignore it */
-               else
-                       *q++ = c;
-               if (--cmdnleft <= 0) {
-                       *q++ = '.';
-                       *q++ = '.';
-                       *q++ = '.';
-                       break;
-               }
-       }
-       cmdnextc = q;
-}
-
-
-static void
-cmdtxt(const union node *n)
-{
-       union node *np;
-       struct nodelist *lp;
-       const char *p;
-       int i;
-       char s[2];
-
-       if (n == NULL)
-               return;
-       switch (n->type) {
-       case NSEMI:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NAND:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" && ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NOR:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" || ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NPIPE:
-               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-                       cmdtxt(lp->n);
-                       if (lp->next)
-                               cmdputs(" | ");
-               }
-               break;
-       case NSUBSHELL:
-               cmdputs("(");
-               cmdtxt(n->nredir.n);
-               cmdputs(")");
-               break;
-       case NREDIR:
-       case NBACKGND:
-               cmdtxt(n->nredir.n);
-               break;
-       case NIF:
-               cmdputs("if ");
-               cmdtxt(n->nif.test);
-               cmdputs("; then ");
-               cmdtxt(n->nif.ifpart);
-               cmdputs("...");
-               break;
-       case NWHILE:
-               cmdputs("while ");
-               goto until;
-       case NUNTIL:
-               cmdputs("until ");
-until:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; do ");
-               cmdtxt(n->nbinary.ch2);
-               cmdputs("; done");
-               break;
-       case NFOR:
-               cmdputs("for ");
-               cmdputs(n->nfor.var);
-               cmdputs(" in ...");
-               break;
-       case NCASE:
-               cmdputs("case ");
-               cmdputs(n->ncase.expr->narg.text);
-               cmdputs(" in ...");
-               break;
-       case NDEFUN:
-               cmdputs(n->narg.text);
-               cmdputs("() ...");
-               break;
-       case NCMD:
-               for (np = n->ncmd.args ; np ; np = np->narg.next) {
-                       cmdtxt(np);
-                       if (np->narg.next)
-                               cmdputs(spcstr);
-               }
-               for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
-                       cmdputs(spcstr);
-                       cmdtxt(np);
-               }
-               break;
-       case NARG:
-               cmdputs(n->narg.text);
-               break;
-       case NTO:
-               p = ">";  i = 1;  goto redir;
-       case NAPPEND:
-               p = ">>";  i = 1;  goto redir;
-       case NTOFD:
-               p = ">&";  i = 1;  goto redir;
-       case NTOOV:
-               p = ">|";  i = 1;  goto redir;
-       case NFROM:
-               p = "<";  i = 0;  goto redir;
-       case NFROMFD:
-               p = "<&";  i = 0;  goto redir;
-       case NFROMTO:
-               p = "<>";  i = 0;  goto redir;
-redir:
-               if (n->nfile.fd != i) {
-                       s[0] = n->nfile.fd + '0';
-                       s[1] = '\0';
-                       cmdputs(s);
-               }
-               cmdputs(p);
-               if (n->type == NTOFD || n->type == NFROMFD) {
-                       s[0] = n->ndup.dupfd + '0';
-                       s[1] = '\0';
-                       cmdputs(s);
-               } else {
-                       cmdtxt(n->nfile.fname);
-               }
-               break;
-       case NHERE:
-       case NXHERE:
-               cmdputs("<<...");
-               break;
-       default:
-               cmdputs("???");
-               break;
-       }
-}
-
-
-static char *
-commandtext(const union node *n)
-{
-       char *name;
-
-       cmdnextc = name = ckmalloc(MAXCMDTEXT);
-       cmdnleft = MAXCMDTEXT - 4;
-       cmdtxt(n);
-       *cmdnextc = '\0';
-       return name;
-}
-
-
-static void waitonint(int sig) {
-       intreceived = 1;
-       return;
-}
-/*
- * Routines to check for mail.  (Perhaps make part of main.c?)
- */
-
-
-#define MAXMBOXES 10
-
-
-static int nmboxes;                     /* number of mailboxes */
-static time_t mailtime[MAXMBOXES];      /* times of mailboxes */
-
-
-
-/*
- * Print appropriate message(s) if mail has arrived.  If the argument is
- * nozero, then the value of MAIL has changed, so we just update the
- * values.
- */
-
-static void
-chkmail(int silent)
-{
-       int i;
-       const char *mpath;
-       char *p;
-       char *q;
-       struct stackmark smark;
-       struct stat statb;
-
-       if (silent)
-               nmboxes = 10;
-       if (nmboxes == 0)
-               return;
-       setstackmark(&smark);
-       mpath = mpathset()? mpathval() : mailval();
-       for (i = 0 ; i < nmboxes ; i++) {
-               p = padvance(&mpath, nullstr);
-               if (p == NULL)
-                       break;
-               if (*p == '\0')
-                       continue;
-               for (q = p ; *q ; q++);
-#ifdef DEBUG
-               if (q[-1] != '/')
-                       abort();
-#endif
-               q[-1] = '\0';                   /* delete trailing '/' */
-               if (stat(p, &statb) < 0)
-                       statb.st_size = 0;
-               if (statb.st_size > mailtime[i] && ! silent) {
-                       out2fmt(snlfmt,
-                               pathopt? pathopt : "you have mail");
-               }
-               mailtime[i] = statb.st_size;
-       }
-       nmboxes = i;
-       popstackmark(&smark);
-}
-
-#define PROFILE 0
-
-#if PROFILE
-static short profile_buf[16384];
-extern int etext();
-#endif
-
-static void read_profile (const char *);
-static void cmdloop (int);
-static void options (int);
-static void setoption (int, int);
-static void procargs (int, char **);
-
-
-/*
- * Main routine.  We initialize things, parse the arguments, execute
- * profiles if we're a login shell, and then call cmdloop to execute
- * commands.  The setjmp call sets up the location to jump to when an
- * exception occurs.  When an exception occurs the variable "state"
- * is used to figure out how far we had gotten.
- */
-
-int
-ash_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct jmploc jmploc;
-       struct stackmark smark;
-       volatile int state;
-       const char *shinit;
-
-       BLTINCMD = find_builtin("builtin");
-       EXECCMD = find_builtin("exec");
-       EVALCMD = find_builtin("eval");
-
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       unsetenv("PS1");
-       unsetenv("PS2");
-#endif
-
-#if PROFILE
-       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
-#endif
-#if defined(linux) || defined(__GNU__)
-       signal(SIGCHLD, SIG_DFL);
-#endif
-       state = 0;
-       if (setjmp(jmploc.loc)) {
-               INTOFF;
-               /*
-                * When a shell procedure is executed, we raise the
-                * exception EXSHELLPROC to clean up before executing
-                * the shell procedure.
-                */
-               switch (exception) {
-               case EXSHELLPROC:
-                       rootpid = getpid();
-                       rootshell = 1;
-                       minusc = NULL;
-                       state = 3;
-                       break;
-
-               case EXEXEC:
-                       exitstatus = exerrno;
-                       break;
-
-               case EXERROR:
-                       exitstatus = 2;
-                       break;
-
-               default:
-                       break;
-               }
-
-               if (exception != EXSHELLPROC) {
-                   if (state == 0 || iflag == 0 || ! rootshell)
-                           exitshell(exitstatus);
-               }
-               reset();
-               if (exception == EXINT) {
-                       out2c('\n');
-               }
-               popstackmark(&smark);
-               FORCEINTON;                             /* enable interrupts */
-               if (state == 1)
-                       goto state1;
-               else if (state == 2)
-                       goto state2;
-               else if (state == 3)
-                       goto state3;
-               else
-                       goto state4;
-       }
-       handler = &jmploc;
-#ifdef DEBUG
-       opentrace();
-       trputs("Shell args:  ");  trargs(argv);
-#endif
-       rootpid = getpid();
-       rootshell = 1;
-       init();
-       setstackmark(&smark);
-       procargs(argc, argv);
-       if (argv[0] && argv[0][0] == '-') {
-               state = 1;
-               read_profile("/etc/profile");
-state1:
-               state = 2;
-               read_profile(".profile");
-       }
-state2:
-       state = 3;
-#ifndef linux
-       if (getuid() == geteuid() && getgid() == getegid()) {
-#endif
-               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
-                       state = 3;
-                       read_profile(shinit);
-               }
-#ifndef linux
-       }
-#endif
-state3:
-       state = 4;
-       if (sflag == 0 || minusc) {
-               static int sigs[] =  {
-                   SIGINT, SIGQUIT, SIGHUP,
-#ifdef SIGTSTP
-                   SIGTSTP,
-#endif
-                   SIGPIPE
-               };
-#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
-               int i;
-
-               for (i = 0; i < SIGSSIZE; i++)
-                   setsignal(sigs[i]);
-       }
-
-       if (minusc)
-               evalstring(minusc, 0);
-
-       if (sflag || minusc == NULL) {
-state4: /* XXX ??? - why isn't this before the "if" statement */
-               cmdloop(1);
-       }
-#if PROFILE
-       monitor(0);
-#endif
-       exitshell(exitstatus);
-       /* NOTREACHED */
-}
-
-
-/*
- * Read and execute commands.  "Top" is nonzero for the top level command
- * loop; it turns on prompting if the shell is interactive.
- */
-
-static void
-cmdloop(int top)
-{
-       union node *n;
-       struct stackmark smark;
-       int inter;
-       int numeof = 0;
-
-       TRACE(("cmdloop(%d) called\n", top));
-       setstackmark(&smark);
-       for (;;) {
-               if (pendingsigs)
-                       dotrap();
-               inter = 0;
-               if (iflag && top) {
-                       inter++;
-                       showjobs(1);
-                       chkmail(0);
-                       flushall();
-               }
-               n = parsecmd(inter);
-               /* showtree(n); DEBUG */
-               if (n == NEOF) {
-                       if (!top || numeof >= 50)
-                               break;
-                       if (!stoppedjobs()) {
-                               if (!Iflag)
-                                       break;
-                               out2str("\nUse \"exit\" to leave shell.\n");
-                       }
-                       numeof++;
-               } else if (n != NULL && nflag == 0) {
-                       job_warning = (job_warning == 2) ? 1 : 0;
-                       numeof = 0;
-                       evaltree(n, 0);
-               }
-               popstackmark(&smark);
-               setstackmark(&smark);
-               if (evalskip == SKIPFILE) {
-                       evalskip = 0;
-                       break;
-               }
-       }
-       popstackmark(&smark);
-}
-
-
-
-/*
- * Read /etc/profile or .profile.  Return on error.
- */
-
-static void
-read_profile(name)
-       const char *name;
-{
-       int fd;
-       int xflag_set = 0;
-       int vflag_set = 0;
-
-       INTOFF;
-       if ((fd = open(name, O_RDONLY)) >= 0)
-               setinputfd(fd, 1);
-       INTON;
-       if (fd < 0)
-               return;
-       /* -q turns off -x and -v just when executing init files */
-       if (qflag)  {
-           if (xflag)
-                   xflag = 0, xflag_set = 1;
-           if (vflag)
-                   vflag = 0, vflag_set = 1;
-       }
-       cmdloop(0);
-       if (qflag)  {
-           if (xflag_set)
-                   xflag = 1;
-           if (vflag_set)
-                   vflag = 1;
-       }
-       popfile();
-}
-
-
-
-/*
- * Read a file containing shell functions.
- */
-
-static void
-readcmdfile(const char *name)
-{
-       int fd;
-
-       INTOFF;
-       if ((fd = open(name, O_RDONLY)) >= 0)
-               setinputfd(fd, 1);
-       else
-               error("Can't open %s", name);
-       INTON;
-       cmdloop(0);
-       popfile();
-}
-
-
-
-/*
- * Take commands from a file.  To be compatable we should do a path
- * search for the file, which is necessary to find sub-commands.
- */
-
-
-static inline char *
-find_dot_file(mybasename)
-       char *mybasename;
-{
-       char *fullname;
-       const char *path = pathval();
-       struct stat statb;
-
-       /* don't try this for absolute or relative paths */
-       if (strchr(mybasename, '/'))
-               return mybasename;
-
-       while ((fullname = padvance(&path, mybasename)) != NULL) {
-               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
-                       /*
-                        * Don't bother freeing here, since it will
-                        * be freed by the caller.
-                        */
-                       return fullname;
-               }
-               stunalloc(fullname);
-       }
-
-       /* not found in the PATH */
-       error("%s: not found", mybasename);
-       /* NOTREACHED */
-}
-
-static int
-dotcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct strlist *sp;
-       exitstatus = 0;
-
-       for (sp = cmdenviron; sp ; sp = sp->next)
-               setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
-
-       if (argc >= 2) {                /* That's what SVR2 does */
-               char *fullname;
-               struct stackmark smark;
-
-               setstackmark(&smark);
-               fullname = find_dot_file(argv[1]);
-               setinputfile(fullname, 1);
-               commandname = fullname;
-               cmdloop(0);
-               popfile();
-               popstackmark(&smark);
-       }
-       return exitstatus;
-}
-
-
-static int
-exitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (stoppedjobs())
-               return 0;
-       if (argc > 1)
-               exitstatus = number(argv[1]);
-       else
-               exitstatus = oexitstatus;
-       exitshell(exitstatus);
-       /* NOTREACHED */
-}
-
-static pointer
-stalloc(int nbytes)
-{
-       char *p;
-
-       nbytes = ALIGN(nbytes);
-       if (nbytes > stacknleft) {
-               int blocksize;
-               struct stack_block *sp;
-
-               blocksize = nbytes;
-               if (blocksize < MINSIZE)
-                       blocksize = MINSIZE;
-               INTOFF;
-               sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
-               sp->prev = stackp;
-               stacknxt = sp->space;
-               stacknleft = blocksize;
-               stackp = sp;
-               INTON;
-       }
-       p = stacknxt;
-       stacknxt += nbytes;
-       stacknleft -= nbytes;
-       return p;
-}
-
-
-static void
-stunalloc(pointer p)
-{
-#ifdef DEBUG
-       if (p == NULL) {                /*DEBUG */
-               write(2, "stunalloc\n", 10);
-               abort();
-       }
-#endif
-       if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
-               p = stackp->space;
-       }
-       stacknleft += stacknxt - (char *)p;
-       stacknxt = p;
-}
-
-
-static void
-setstackmark(struct stackmark *mark)
-{
-       mark->stackp = stackp;
-       mark->stacknxt = stacknxt;
-       mark->stacknleft = stacknleft;
-       mark->marknext = markp;
-       markp = mark;
-}
-
-
-static void
-popstackmark(struct stackmark *mark)
-{
-       struct stack_block *sp;
-
-       INTOFF;
-       markp = mark->marknext;
-       while (stackp != mark->stackp) {
-               sp = stackp;
-               stackp = sp->prev;
-               ckfree(sp);
-       }
-       stacknxt = mark->stacknxt;
-       stacknleft = mark->stacknleft;
-       INTON;
-}
-
-
-/*
- * When the parser reads in a string, it wants to stick the string on the
- * stack and only adjust the stack pointer when it knows how big the
- * string is.  Stackblock (defined in stack.h) returns a pointer to a block
- * of space on top of the stack and stackblocklen returns the length of
- * this block.  Growstackblock will grow this space by at least one byte,
- * possibly moving it (like realloc).  Grabstackblock actually allocates the
- * part of the block that has been used.
- */
-
-static void
-growstackblock(void) {
-       char *p;
-       int newlen = ALIGN(stacknleft * 2 + 100);
-       char *oldspace = stacknxt;
-       int oldlen = stacknleft;
-       struct stack_block *sp;
-       struct stack_block *oldstackp;
-
-       if (stacknxt == stackp->space && stackp != &stackbase) {
-               INTOFF;
-               oldstackp = stackp;
-               sp = stackp;
-               stackp = sp->prev;
-               sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
-               sp->prev = stackp;
-               stackp = sp;
-               stacknxt = sp->space;
-               stacknleft = newlen;
-               {
-                 /* Stack marks pointing to the start of the old block
-                  * must be relocated to point to the new block
-                  */
-                 struct stackmark *xmark;
-                 xmark = markp;
-                 while (xmark != NULL && xmark->stackp == oldstackp) {
-                   xmark->stackp = stackp;
-                   xmark->stacknxt = stacknxt;
-                   xmark->stacknleft = stacknleft;
-                   xmark = xmark->marknext;
-                 }
-               }
-               INTON;
-       } else {
-               p = stalloc(newlen);
-               memcpy(p, oldspace, oldlen);
-               stacknxt = p;                   /* free the space */
-               stacknleft += newlen;           /* we just allocated */
-       }
-}
-
-
-
-static inline void
-grabstackblock(int len)
-{
-       len = ALIGN(len);
-       stacknxt += len;
-       stacknleft -= len;
-}
-
-
-
-/*
- * The following routines are somewhat easier to use that the above.
- * The user declares a variable of type STACKSTR, which may be declared
- * to be a register.  The macro STARTSTACKSTR initializes things.  Then
- * the user uses the macro STPUTC to add characters to the string.  In
- * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
- * grown as necessary.  When the user is done, she can just leave the
- * string there and refer to it using stackblock().  Or she can allocate
- * the space for it using grabstackstr().  If it is necessary to allow
- * someone else to use the stack temporarily and then continue to grow
- * the string, the user should use grabstack to allocate the space, and
- * then call ungrabstr(p) to return to the previous mode of operation.
- *
- * USTPUTC is like STPUTC except that it doesn't check for overflow.
- * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
- * is space for at least one character.
- */
-
-
-static char *
-growstackstr(void) {
-       int len = stackblocksize();
-       if (herefd >= 0 && len >= 1024) {
-               xwrite(herefd, stackblock(), len);
-               sstrnleft = len - 1;
-               return stackblock();
-       }
-       growstackblock();
-       sstrnleft = stackblocksize() - len - 1;
-       return stackblock() + len;
-}
-
-
-/*
- * Called from CHECKSTRSPACE.
- */
-
-static char *
-makestrspace(size_t newlen) {
-       int len = stackblocksize() - sstrnleft;
-       do {
-               growstackblock();
-               sstrnleft = stackblocksize() - len;
-       } while (sstrnleft < newlen);
-       return stackblock() + len;
-}
-
-
-
-static void
-ungrabstackstr(char *s, char *p)
-{
-       stacknleft += stacknxt - s;
-       stacknxt = s;
-       sstrnleft = stacknleft - (p - s);
-}
-/*
- * Miscelaneous builtins.
- */
-
-
-#undef rflag
-
-//#ifdef __GLIBC__
-static mode_t getmode(const void *, mode_t);
-static void *setmode(const char *);
-//#endif
-
-#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
-typedef long rlim_t;
-#endif
-
-
-
-/*
- * The read builtin.  The -e option causes backslashes to escape the
- * following character.
- *
- * This uses unbuffered input, which may be avoidable in some cases.
- */
-
-static int
-readcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **ap;
-       int backslash;
-       char c;
-       int rflag;
-       char *prompt;
-       const char *ifs;
-       char *p;
-       int startword;
-       int status;
-       int i;
-
-       rflag = 0;
-       prompt = NULL;
-       while ((i = nextopt("p:r")) != '\0') {
-               if (i == 'p')
-                       prompt = optionarg;
-               else
-                       rflag = 1;
-       }
-       if (prompt && isatty(0)) {
-               putprompt(prompt);
-               flushall();
-       }
-       if (*(ap = argptr) == NULL)
-               error("arg count");
-       if ((ifs = bltinlookup("IFS")) == NULL)
-               ifs = defifs;
-       status = 0;
-       startword = 1;
-       backslash = 0;
-       STARTSTACKSTR(p);
-       for (;;) {
-               if (read(0, &c, 1) != 1) {
-                       status = 1;
-                       break;
-               }
-               if (c == '\0')
-                       continue;
-               if (backslash) {
-                       backslash = 0;
-                       if (c != '\n')
-                               STPUTC(c, p);
-                       continue;
-               }
-               if (!rflag && c == '\\') {
-                       backslash++;
-                       continue;
-               }
-               if (c == '\n')
-                       break;
-               if (startword && *ifs == ' ' && strchr(ifs, c)) {
-                       continue;
-               }
-               startword = 0;
-               if (backslash && c == '\\') {
-                       if (read(0, &c, 1) != 1) {
-                               status = 1;
-                               break;
-                       }
-                       STPUTC(c, p);
-               } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
-                       STACKSTRNUL(p);
-                       setvar(*ap, stackblock(), 0);
-                       ap++;
-                       startword = 1;
-                       STARTSTACKSTR(p);
-               } else {
-                       STPUTC(c, p);
-               }
-       }
-       STACKSTRNUL(p);
-       /* Remove trailing blanks */
-       while (stackblock() <= --p && strchr(ifs, *p) != NULL)
-               *p = '\0';
-       setvar(*ap, stackblock(), 0);
-       while (*++ap != NULL)
-               setvar(*ap, nullstr, 0);
-       return status;
-}
-
-
-
-static int
-umaskcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *ap;
-       int mask;
-       int i;
-       int symbolic_mode = 0;
-
-       while (nextopt("S") != '\0') {
-               symbolic_mode = 1;
-       }
-
-       INTOFF;
-       mask = umask(0);
-       umask(mask);
-       INTON;
-
-       if ((ap = *argptr) == NULL) {
-               if (symbolic_mode) {
-                       char u[4], g[4], o[4];
-
-                       i = 0;
-                       if ((mask & S_IRUSR) == 0)
-                               u[i++] = 'r';
-                       if ((mask & S_IWUSR) == 0)
-                               u[i++] = 'w';
-                       if ((mask & S_IXUSR) == 0)
-                               u[i++] = 'x';
-                       u[i] = '\0';
-
-                       i = 0;
-                       if ((mask & S_IRGRP) == 0)
-                               g[i++] = 'r';
-                       if ((mask & S_IWGRP) == 0)
-                               g[i++] = 'w';
-                       if ((mask & S_IXGRP) == 0)
-                               g[i++] = 'x';
-                       g[i] = '\0';
-
-                       i = 0;
-                       if ((mask & S_IROTH) == 0)
-                               o[i++] = 'r';
-                       if ((mask & S_IWOTH) == 0)
-                               o[i++] = 'w';
-                       if ((mask & S_IXOTH) == 0)
-                               o[i++] = 'x';
-                       o[i] = '\0';
-
-                       printf("u=%s,g=%s,o=%s\n", u, g, o);
-               } else {
-                       printf("%.4o\n", mask);
-               }
-       } else {
-               if (is_digit((unsigned char)*ap)) {
-                       mask = 0;
-                       do {
-                               if (*ap >= '8' || *ap < '0')
-                                       error("Illegal number: %s", argv[1]);
-                               mask = (mask << 3) + (*ap - '0');
-                       } while (*++ap != '\0');
-                       umask(mask);
-               } else {
-                       void *set;
-
-                       INTOFF;
-                       if ((set = setmode(ap)) != 0) {
-                               mask = getmode(set, ~mask & 0777);
-                               ckfree(set);
-                       }
-                       INTON;
-                       if (!set)
-                               error("Illegal mode: %s", ap);
-
-                       umask(~mask & 0777);
-               }
-       }
-       return 0;
-}
-
-/*
- * ulimit builtin
- *
- * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
- * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
- * ash by J.T. Conklin.
- *
- * Public domain.
- */
-
-struct limits {
-       const char *name;
-       int     cmd;
-       int     factor; /* multiply by to get rlim_{cur,max} values */
-       char    option;
-};
-
-static const struct limits limits[] = {
-#ifdef RLIMIT_CPU
-       { "time(seconds)",              RLIMIT_CPU,        1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
-       { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
-#endif
-#ifdef RLIMIT_DATA
-       { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
-       { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
-#endif
-#ifdef  RLIMIT_CORE
-       { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
-#endif
-#ifdef RLIMIT_RSS
-       { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
-#endif
-#ifdef RLIMIT_MEMLOCK
-       { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_NPROC
-       { "process(processes)",         RLIMIT_NPROC,      1, 'p' },
-#endif
-#ifdef RLIMIT_NOFILE
-       { "nofiles(descriptors)",       RLIMIT_NOFILE,     1, 'n' },
-#endif
-#ifdef RLIMIT_VMEM
-       { "vmemory(kbytes)",            RLIMIT_VMEM,    1024, 'v' },
-#endif
-#ifdef RLIMIT_SWAP
-       { "swap(kbytes)",               RLIMIT_SWAP,    1024, 'w' },
-#endif
-       { (char *) 0,                   0,                 0,  '\0' }
-};
-
-static int
-ulimitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int     c;
-       rlim_t val = 0;
-       enum { SOFT = 0x1, HARD = 0x2 }
-                       how = SOFT | HARD;
-       const struct limits     *l;
-       int             set, all = 0;
-       int             optc, what;
-       struct rlimit   limit;
-
-       what = 'f';
-       while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
-               switch (optc) {
-               case 'H':
-                       how = HARD;
-                       break;
-               case 'S':
-                       how = SOFT;
-                       break;
-               case 'a':
-                       all = 1;
-                       break;
-               default:
-                       what = optc;
-               }
-
-       for (l = limits; l->name && l->option != what; l++)
-               ;
-       if (!l->name)
-               error("internal error (%c)", what);
-
-       set = *argptr ? 1 : 0;
-       if (set) {
-               char *p = *argptr;
-
-               if (all || argptr[1])
-                       error("too many arguments");
-               if (strcmp(p, "unlimited") == 0)
-                       val = RLIM_INFINITY;
-               else {
-                       val = (rlim_t) 0;
-
-                       while ((c = *p++) >= '0' && c <= '9')
-                       {
-                               val = (val * 10) + (long)(c - '0');
-                               if (val < (rlim_t) 0)
-                                       break;
-                       }
-                       if (c)
-                               error("bad number");
-                       val *= l->factor;
-               }
-       }
-       if (all) {
-               for (l = limits; l->name; l++) {
-                       getrlimit(l->cmd, &limit);
-                       if (how & SOFT)
-                               val = limit.rlim_cur;
-                       else if (how & HARD)
-                               val = limit.rlim_max;
-
-                       printf("%-20s ", l->name);
-                       if (val == RLIM_INFINITY)
-                               printf("unlimited\n");
-                       else
-                       {
-                               val /= l->factor;
-                               printf("%lld\n", (long long) val);
-                       }
-               }
-               return 0;
-       }
-
-       getrlimit(l->cmd, &limit);
-       if (set) {
-               if (how & HARD)
-                       limit.rlim_max = val;
-               if (how & SOFT)
-                       limit.rlim_cur = val;
-               if (setrlimit(l->cmd, &limit) < 0)
-                       error("error setting limit (%m)");
-       } else {
-               if (how & SOFT)
-                       val = limit.rlim_cur;
-               else if (how & HARD)
-                       val = limit.rlim_max;
-
-               if (val == RLIM_INFINITY)
-                       printf("unlimited\n");
-               else
-               {
-                       val /= l->factor;
-                       printf("%lld\n", (long long) val);
-               }
-       }
-       return 0;
-}
-/*
- * prefix -- see if pfx is a prefix of string.
- */
-
-static int
-prefix(char const *pfx, char const *string)
-{
-       while (*pfx) {
-               if (*pfx++ != *string++)
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Return true if s is a string of digits, and save munber in intptr
- * nagative is bad
- */
-
-static int
-is_number(const char *p, int *intptr)
-{
-       int ret = 0;
-
-       do {
-               if (! is_digit(*p))
-                       return 0;
-               ret *= 10;
-               ret += digit_val(*p);
-               p++;
-       } while (*p != '\0');
-
-       *intptr = ret;
-       return 1;
-}
-
-/*
- * Convert a string of digits to an integer, printing an error message on
- * failure.
- */
-
-static int
-number(const char *s)
-{
-       int i;
-       if (! is_number(s, &i))
-               error("Illegal number: %s", s);
-       return i;
-}
-
-/*
- * Produce a possibly single quoted string suitable as input to the shell.
- * The return string is allocated on the stack.
- */
-
-static char *
-single_quote(const char *s) {
-       char *p;
-
-       STARTSTACKSTR(p);
-
-       do {
-               char *q = p;
-               size_t len1, len1p, len2, len2p;
-
-               len1 = strcspn(s, "'");
-               len2 = strspn(s + len1, "'");
-
-               len1p = len1 ? len1 + 2 : len1;
-               switch (len2) {
-               case 0:
-                       len2p = 0;
-                       break;
-               case 1:
-                       len2p = 2;
-                       break;
-               default:
-                       len2p = len2 + 2;
-               }
-
-               CHECKSTRSPACE(len1p + len2p + 1, p);
-
-               if (len1) {
-                       *p = '\'';
-                       q = p + 1 + len1;
-                       memcpy(p + 1, s, len1);
-                       *q++ = '\'';
-                       s += len1;
-               }
-
-               switch (len2) {
-               case 0:
-                       break;
-               case 1:
-                       *q++ = '\\';
-                       *q = '\'';
-                       s++;
-                       break;
-               default:
-                       *q = '"';
-                       q += 1 + len2;
-                       memcpy(q + 1, s, len2);
-                       *q = '"';
-                       s += len2;
-               }
-
-               STADJUST(len1p + len2p, p);
-       } while (*s);
-
-       USTPUTC(0, p);
-
-       return grabstackstr(p);
-}
-
-/*
- * Like strdup but works with the ash stack.
- */
-
-static char *
-sstrdup(const char *p)
-{
-       size_t len = strlen(p) + 1;
-       return memcpy(stalloc(len), p, len);
-}
-
-
-/*
- * Routine for dealing with parsed shell commands.
- */
-
-
-static void sizenodelist (const struct nodelist *);
-static struct nodelist *copynodelist (const struct nodelist *);
-static char *nodesavestr (const char *);
-
-static void
-calcsize(const union node *n)
-{
-      if (n == NULL)
-           return;
-      funcblocksize += nodesize[n->type];
-      switch (n->type) {
-      case NSEMI:
-      case NAND:
-      case NOR:
-      case NWHILE:
-      case NUNTIL:
-           calcsize(n->nbinary.ch2);
-           calcsize(n->nbinary.ch1);
-           break;
-      case NCMD:
-           calcsize(n->ncmd.redirect);
-           calcsize(n->ncmd.args);
-           calcsize(n->ncmd.assign);
-           break;
-      case NPIPE:
-           sizenodelist(n->npipe.cmdlist);
-           break;
-      case NREDIR:
-      case NBACKGND:
-      case NSUBSHELL:
-           calcsize(n->nredir.redirect);
-           calcsize(n->nredir.n);
-           break;
-      case NIF:
-           calcsize(n->nif.elsepart);
-           calcsize(n->nif.ifpart);
-           calcsize(n->nif.test);
-           break;
-      case NFOR:
-           funcstringsize += strlen(n->nfor.var) + 1;
-           calcsize(n->nfor.body);
-           calcsize(n->nfor.args);
-           break;
-      case NCASE:
-           calcsize(n->ncase.cases);
-           calcsize(n->ncase.expr);
-           break;
-      case NCLIST:
-           calcsize(n->nclist.body);
-           calcsize(n->nclist.pattern);
-           calcsize(n->nclist.next);
-           break;
-      case NDEFUN:
-      case NARG:
-           sizenodelist(n->narg.backquote);
-           funcstringsize += strlen(n->narg.text) + 1;
-           calcsize(n->narg.next);
-           break;
-      case NTO:
-      case NFROM:
-      case NFROMTO:
-      case NAPPEND:
-      case NTOOV:
-           calcsize(n->nfile.fname);
-           calcsize(n->nfile.next);
-           break;
-      case NTOFD:
-      case NFROMFD:
-           calcsize(n->ndup.vname);
-           calcsize(n->ndup.next);
-           break;
-      case NHERE:
-      case NXHERE:
-           calcsize(n->nhere.doc);
-           calcsize(n->nhere.next);
-           break;
-      case NNOT:
-           calcsize(n->nnot.com);
-           break;
-      };
-}
-
-static void
-sizenodelist(const struct nodelist *lp)
-{
-       while (lp) {
-               funcblocksize += ALIGN(sizeof(struct nodelist));
-               calcsize(lp->n);
-               lp = lp->next;
-       }
-}
-
-
-static union node *
-copynode(const union node *n)
-{
-      union node *new;
-
-      if (n == NULL)
-           return NULL;
-      new = funcblock;
-      funcblock = (char *) funcblock + nodesize[n->type];
-      switch (n->type) {
-      case NSEMI:
-      case NAND:
-      case NOR:
-      case NWHILE:
-      case NUNTIL:
-           new->nbinary.ch2 = copynode(n->nbinary.ch2);
-           new->nbinary.ch1 = copynode(n->nbinary.ch1);
-           break;
-      case NCMD:
-           new->ncmd.redirect = copynode(n->ncmd.redirect);
-           new->ncmd.args = copynode(n->ncmd.args);
-           new->ncmd.assign = copynode(n->ncmd.assign);
-           new->ncmd.backgnd = n->ncmd.backgnd;
-           break;
-      case NPIPE:
-           new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
-           new->npipe.backgnd = n->npipe.backgnd;
-           break;
-      case NREDIR:
-      case NBACKGND:
-      case NSUBSHELL:
-           new->nredir.redirect = copynode(n->nredir.redirect);
-           new->nredir.n = copynode(n->nredir.n);
-           break;
-      case NIF:
-           new->nif.elsepart = copynode(n->nif.elsepart);
-           new->nif.ifpart = copynode(n->nif.ifpart);
-           new->nif.test = copynode(n->nif.test);
-           break;
-      case NFOR:
-           new->nfor.var = nodesavestr(n->nfor.var);
-           new->nfor.body = copynode(n->nfor.body);
-           new->nfor.args = copynode(n->nfor.args);
-           break;
-      case NCASE:
-           new->ncase.cases = copynode(n->ncase.cases);
-           new->ncase.expr = copynode(n->ncase.expr);
-           break;
-      case NCLIST:
-           new->nclist.body = copynode(n->nclist.body);
-           new->nclist.pattern = copynode(n->nclist.pattern);
-           new->nclist.next = copynode(n->nclist.next);
-           break;
-      case NDEFUN:
-      case NARG:
-           new->narg.backquote = copynodelist(n->narg.backquote);
-           new->narg.text = nodesavestr(n->narg.text);
-           new->narg.next = copynode(n->narg.next);
-           break;
-      case NTO:
-      case NFROM:
-      case NFROMTO:
-      case NAPPEND:
-      case NTOOV:
-           new->nfile.fname = copynode(n->nfile.fname);
-           new->nfile.fd = n->nfile.fd;
-           new->nfile.next = copynode(n->nfile.next);
-           break;
-      case NTOFD:
-      case NFROMFD:
-           new->ndup.vname = copynode(n->ndup.vname);
-           new->ndup.dupfd = n->ndup.dupfd;
-           new->ndup.fd = n->ndup.fd;
-           new->ndup.next = copynode(n->ndup.next);
-           break;
-      case NHERE:
-      case NXHERE:
-           new->nhere.doc = copynode(n->nhere.doc);
-           new->nhere.fd = n->nhere.fd;
-           new->nhere.next = copynode(n->nhere.next);
-           break;
-      case NNOT:
-           new->nnot.com = copynode(n->nnot.com);
-           break;
-      };
-      new->type = n->type;
-      return new;
-}
-
-
-static struct nodelist *
-copynodelist(const struct nodelist *lp)
-{
-       struct nodelist *start;
-       struct nodelist **lpp;
-
-       lpp = &start;
-       while (lp) {
-               *lpp = funcblock;
-               funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
-               (*lpp)->n = copynode(lp->n);
-               lp = lp->next;
-               lpp = &(*lpp)->next;
-       }
-       *lpp = NULL;
-       return start;
-}
-
-
-static char *
-nodesavestr(const char *s)
-{
-       const char *p = s;
-       char *q = funcstring;
-       char   *rtn = funcstring;
-
-       while ((*q++ = *p++) != '\0')
-               continue;
-       funcstring = q;
-       return rtn;
-}
-
-#ifdef ASH_GETOPTS
-static int getopts (char *, char *, char **, int *, int *);
-#endif
-
-
-/*
- * Process the shell command line arguments.
- */
-
-static void
-procargs(argc, argv)
-       int argc;
-       char **argv;
-{
-       int i;
-
-       argptr = argv;
-       if (argc > 0)
-               argptr++;
-       for (i = 0; i < NOPTS; i++)
-               optent_val(i) = 2;
-       options(1);
-       if (*argptr == NULL && minusc == NULL)
-               sflag = 1;
-       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
-               iflag = 1;
-       if (mflag == 2)
-               mflag = iflag;
-       for (i = 0; i < NOPTS; i++)
-               if (optent_val(i) == 2)
-                       optent_val(i) = 0;
-       arg0 = argv[0];
-       if (sflag == 0 && minusc == NULL) {
-               commandname = argv[0];
-               arg0 = *argptr++;
-               setinputfile(arg0, 0);
-               commandname = arg0;
-       }
-       /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
-       if (argptr && minusc && *argptr)
-               arg0 = *argptr++;
-
-       shellparam.p = argptr;
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
-       while (*argptr) {
-               shellparam.nparam++;
-               argptr++;
-       }
-       optschanged();
-}
-
-
-
-/*
- * Process shell options.  The global variable argptr contains a pointer
- * to the argument list; we advance it past the options.
- */
-
-static inline void
-minus_o(const char *name, int val)
-{
-       int i;
-
-       if (name == NULL) {
-               out1str("Current option settings\n");
-               for (i = 0; i < NOPTS; i++)
-                       printf("%-16s%s\n", optent_name(optlist[i]),
-                               optent_val(i) ? "on" : "off");
-       } else {
-               for (i = 0; i < NOPTS; i++)
-                       if (equal(name, optent_name(optlist[i]))) {
-                               setoption(optent_letter(optlist[i]), val);
-                               return;
-                       }
-               error("Illegal option -o %s", name);
-       }
-}
-
-
-static void
-options(int cmdline)
-{
-       char *p;
-       int val;
-       int c;
-
-       if (cmdline)
-               minusc = NULL;
-       while ((p = *argptr) != NULL) {
-               argptr++;
-               if ((c = *p++) == '-') {
-                       val = 1;
-                       if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
-                               if (!cmdline) {
-                                       /* "-" means turn off -x and -v */
-                                       if (p[0] == '\0')
-                                               xflag = vflag = 0;
-                                       /* "--" means reset params */
-                                       else if (*argptr == NULL)
-                                               setparam(argptr);
-                               }
-                               break;    /* "-" or  "--" terminates options */
-                       }
-               } else if (c == '+') {
-                       val = 0;
-               } else {
-                       argptr--;
-                       break;
-               }
-               while ((c = *p++) != '\0') {
-                       if (c == 'c' && cmdline) {
-                               char *q;
-#ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
-                               if (*p == '\0')
-#endif
-                                       q = *argptr++;
-                               if (q == NULL || minusc != NULL)
-                                       error("Bad -c option");
-                               minusc = q;
-#ifdef NOHACK
-                               break;
-#endif
-                       } else if (c == 'o') {
-                               minus_o(*argptr, val);
-                               if (*argptr)
-                                       argptr++;
-                       } else {
-                               setoption(c, val);
-                       }
-               }
-       }
-}
-
-
-static void
-setoption(int flag, int val)
-{
-       int i;
-
-       for (i = 0; i < NOPTS; i++)
-               if (optent_letter(optlist[i]) == flag) {
-                       optent_val(i) = val;
-                       if (val) {
-                               /* #%$ hack for ksh semantics */
-                               if (flag == 'V')
-                                       Eflag = 0;
-                               else if (flag == 'E')
-                                       Vflag = 0;
-                       }
-                       return;
-               }
-       error("Illegal option -%c", flag);
-       /* NOTREACHED */
-}
-
-
-
-/*
- * Set the shell parameters.
- */
-
-static void
-setparam(char **argv)
-{
-       char **newparam;
-       char **ap;
-       int nparam;
-
-       for (nparam = 0 ; argv[nparam] ; nparam++);
-       ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
-       while (*argv) {
-               *ap++ = savestr(*argv++);
-       }
-       *ap = NULL;
-       freeparam(&shellparam);
-       shellparam.malloc = 1;
-       shellparam.nparam = nparam;
-       shellparam.p = newparam;
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-}
-
-
-/*
- * Free the list of positional parameters.
- */
-
-static void
-freeparam(volatile struct shparam *param)
-{
-       char **ap;
-
-       if (param->malloc) {
-               for (ap = param->p ; *ap ; ap++)
-                       ckfree(*ap);
-               ckfree(param->p);
-       }
-}
-
-
-
-/*
- * The shift builtin command.
- */
-
-static int
-shiftcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int n;
-       char **ap1, **ap2;
-
-       n = 1;
-       if (argc > 1)
-               n = number(argv[1]);
-       if (n > shellparam.nparam)
-               error("can't shift that many");
-       INTOFF;
-       shellparam.nparam -= n;
-       for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
-               if (shellparam.malloc)
-                       ckfree(*ap1);
-       }
-       ap2 = shellparam.p;
-       while ((*ap2++ = *ap1++) != NULL);
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-       INTON;
-       return 0;
-}
-
-
-
-/*
- * The set command builtin.
- */
-
-static int
-setcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc == 1)
-               return showvarscmd(argc, argv);
-       INTOFF;
-       options(0);
-       optschanged();
-       if (*argptr != NULL) {
-               setparam(argptr);
-       }
-       INTON;
-       return 0;
-}
-
-
-static void
-getoptsreset(const char *value)
-{
-       shellparam.optind = number(value);
-       shellparam.optoff = -1;
-}
-
-#ifdef BB_LOCALE_SUPPORT
-static void change_lc_all(const char *value)
-{
-       if(value != 0 && *value != 0)
-               setlocale(LC_ALL, value);
-}
-
-static void change_lc_ctype(const char *value)
-{
-       if(value != 0 && *value != 0)
-               setlocale(LC_CTYPE, value);
-}
-
-#endif
-
-#ifdef ASH_GETOPTS
-/*
- * The getopts builtin.  Shellparam.optnext points to the next argument
- * to be processed.  Shellparam.optptr points to the next character to
- * be processed in the current argument.  If shellparam.optnext is NULL,
- * then it's the first time getopts has been called.
- */
-
-static int
-getoptscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **optbase;
-
-       if (argc < 3)
-               error("Usage: getopts optstring var [arg]");
-       else if (argc == 3) {
-               optbase = shellparam.p;
-               if (shellparam.optind > shellparam.nparam + 1) {
-                       shellparam.optind = 1;
-                       shellparam.optoff = -1;
-               }
-       }
-       else {
-               optbase = &argv[3];
-               if (shellparam.optind > argc - 2) {
-                       shellparam.optind = 1;
-                       shellparam.optoff = -1;
-               }
-       }
-
-       return getopts(argv[1], argv[2], optbase, &shellparam.optind,
-                      &shellparam.optoff);
-}
-
-/*
- * Safe version of setvar, returns 1 on success 0 on failure.
- */
-
-static int
-setvarsafe(name, val, flags)
-       const char *name, *val;
-       int flags;
-{
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler = handler;
-       int err = 0;
-#ifdef __GNUC__
-       (void) &err;
-#endif
-
-       if (setjmp(jmploc.loc))
-               err = 1;
-       else {
-               handler = &jmploc;
-               setvar(name, val, flags);
-       }
-       handler = savehandler;
-       return err;
-}
-
-static int
-getopts(optstr, optvar, optfirst, myoptind, optoff)
-       char *optstr;
-       char *optvar;
-       char **optfirst;
-       int *myoptind;
-       int *optoff;
-{
-       char *p, *q;
-       char c = '?';
-       int done = 0;
-       int err = 0;
-       char s[10];
-       char **optnext = optfirst + *myoptind - 1;
-
-       if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
-           strlen(*(optnext - 1)) < *optoff)
-               p = NULL;
-       else
-               p = *(optnext - 1) + *optoff;
-       if (p == NULL || *p == '\0') {
-               /* Current word is done, advance */
-               if (optnext == NULL)
-                       return 1;
-               p = *optnext;
-               if (p == NULL || *p != '-' || *++p == '\0') {
-atend:
-                       *myoptind = optnext - optfirst + 1;
-                       p = NULL;
-                       done = 1;
-                       goto out;
-               }
-               optnext++;
-               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
-                       goto atend;
-       }
-
-       c = *p++;
-       for (q = optstr; *q != c; ) {
-               if (*q == '\0') {
-                       if (optstr[0] == ':') {
-                               s[0] = c;
-                               s[1] = '\0';
-                               err |= setvarsafe("OPTARG", s, 0);
-                       }
-                       else {
-                               out2fmt("Illegal option -%c\n", c);
-                               (void) unsetvar("OPTARG");
-                       }
-                       c = '?';
-                       goto bad;
-               }
-               if (*++q == ':')
-                       q++;
-       }
-
-       if (*++q == ':') {
-               if (*p == '\0' && (p = *optnext) == NULL) {
-                       if (optstr[0] == ':') {
-                               s[0] = c;
-                               s[1] = '\0';
-                               err |= setvarsafe("OPTARG", s, 0);
-                               c = ':';
-                       }
-                       else {
-                               out2fmt("No arg for -%c option\n", c);
-                               (void) unsetvar("OPTARG");
-                               c = '?';
-                       }
-                       goto bad;
-               }
-
-               if (p == *optnext)
-                       optnext++;
-               setvarsafe("OPTARG", p, 0);
-               p = NULL;
-       }
-       else
-               setvarsafe("OPTARG", "", 0);
-       *myoptind = optnext - optfirst + 1;
-       goto out;
-
-bad:
-       *myoptind = 1;
-       p = NULL;
-out:
-       *optoff = p ? p - *(optnext - 1) : -1;
-       snprintf(s, sizeof(s), "%d", *myoptind);
-       err |= setvarsafe("OPTIND", s, VNOFUNC);
-       s[0] = c;
-       s[1] = '\0';
-       err |= setvarsafe(optvar, s, 0);
-       if (err) {
-               *myoptind = 1;
-               *optoff = -1;
-               exraise(EXERROR);
-       }
-       return done;
-}
-#endif
-
-/*
- * XXX - should get rid of.  have all builtins use getopt(3).  the
- * library getopt must have the BSD extension static variable "optreset"
- * otherwise it can't be used within the shell safely.
- *
- * Standard option processing (a la getopt) for builtin routines.  The
- * only argument that is passed to nextopt is the option string; the
- * other arguments are unnecessary.  It return the character, or '\0' on
- * end of input.
- */
-
-static int
-nextopt(const char *optstring)
-{
-       char *p;
-       const char *q;
-       char c;
-
-       if ((p = optptr) == NULL || *p == '\0') {
-               p = *argptr;
-               if (p == NULL || *p != '-' || *++p == '\0')
-                       return '\0';
-               argptr++;
-               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
-                       return '\0';
-       }
-       c = *p++;
-       for (q = optstring ; *q != c ; ) {
-               if (*q == '\0')
-                       error("Illegal option -%c", c);
-               if (*++q == ':')
-                       q++;
-       }
-       if (*++q == ':') {
-               if (*p == '\0' && (p = *argptr++) == NULL)
-                       error("No arg for -%c option", c);
-               optionarg = p;
-               p = NULL;
-       }
-       optptr = p;
-       return c;
-}
-
-static void
-flushall() {
-       INTOFF;
-       fflush(stdout);
-       INTON;
-}
-
-
-static void
-out2fmt(const char *fmt, ...)
-{
-       va_list ap;
-       va_start(ap, fmt);
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-}
-
-/*
- * Version of write which resumes after a signal is caught.
- */
-
-static int
-xwrite(int fd, const char *buf, int nbytes)
-{
-       int ntry;
-       int i;
-       int n;
-
-       n = nbytes;
-       ntry = 0;
-       for (;;) {
-               i = write(fd, buf, n);
-               if (i > 0) {
-                       if ((n -= i) <= 0)
-                               return nbytes;
-                       buf += i;
-                       ntry = 0;
-               } else if (i == 0) {
-                       if (++ntry > 10)
-                               return nbytes - n;
-               } else if (errno != EINTR) {
-                       return -1;
-               }
-       }
-}
-
-
-/*
- * Shell command parser.
- */
-
-#define EOFMARKLEN 79
-
-
-
-struct heredoc {
-       struct heredoc *next;   /* next here document in list */
-       union node *here;               /* redirection node */
-       char *eofmark;          /* string indicating end of input */
-       int striptabs;          /* if set, strip leading tabs */
-};
-
-static struct heredoc *heredoclist;     /* list of here documents to read */
-static int parsebackquote;              /* nonzero if we are inside backquotes */
-static int doprompt;                    /* if set, prompt the user */
-static int needprompt;                  /* true if interactive and at start of line */
-static int lasttoken;                   /* last token read */
-
-static char *wordtext;                  /* text of last word returned by readtoken */
-
-static struct nodelist *backquotelist;
-static union node *redirnode;
-static struct heredoc *heredoc;
-static int quoteflag;                   /* set if (part of) last token was quoted */
-static int startlinno;                  /* line # where last token started */
-
-
-static union node *list (int);
-static union node *andor (void);
-static union node *pipeline (void);
-static union node *command (void);
-static union node *simplecmd (void);
-static void parsefname (void);
-static void parseheredoc (void);
-static int peektoken (void);
-static int readtoken (void);
-static int xxreadtoken (void);
-static int readtoken1 (int, char const *, char *, int);
-static int noexpand (char *);
-static void synexpect (int) __attribute__((noreturn));
-static void synerror (const char *) __attribute__((noreturn));
-static void setprompt (int);
-
-
-/*
- * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
- * valid parse tree indicating a blank line.)
- */
-
-static union node *
-parsecmd(int interact)
-{
-       int t;
-
-       tokpushback = 0;
-       doprompt = interact;
-       if (doprompt)
-               setprompt(1);
-       else
-               setprompt(0);
-       needprompt = 0;
-       t = readtoken();
-       if (t == TEOF)
-               return NEOF;
-       if (t == TNL)
-               return NULL;
-       tokpushback++;
-       return list(1);
-}
-
-
-static union node *
-list(nlflag)
-       int nlflag;
-{
-       union node *n1, *n2, *n3;
-       int tok;
-
-       checkkwd = 2;
-       if (nlflag == 0 && tokendlist[peektoken()])
-               return NULL;
-       n1 = NULL;
-       for (;;) {
-               n2 = andor();
-               tok = readtoken();
-               if (tok == TBACKGND) {
-                       if (n2->type == NCMD || n2->type == NPIPE) {
-                               n2->ncmd.backgnd = 1;
-                       } else if (n2->type == NREDIR) {
-                               n2->type = NBACKGND;
-                       } else {
-                               n3 = (union node *)stalloc(sizeof (struct nredir));
-                               n3->type = NBACKGND;
-                               n3->nredir.n = n2;
-                               n3->nredir.redirect = NULL;
-                               n2 = n3;
-                       }
-               }
-               if (n1 == NULL) {
-                       n1 = n2;
-               }
-               else {
-                       n3 = (union node *)stalloc(sizeof (struct nbinary));
-                       n3->type = NSEMI;
-                       n3->nbinary.ch1 = n1;
-                       n3->nbinary.ch2 = n2;
-                       n1 = n3;
-               }
-               switch (tok) {
-               case TBACKGND:
-               case TSEMI:
-                       tok = readtoken();
-                       /* fall through */
-               case TNL:
-                       if (tok == TNL) {
-                               parseheredoc();
-                               if (nlflag)
-                                       return n1;
-                       } else {
-                               tokpushback++;
-                       }
-                       checkkwd = 2;
-                       if (tokendlist[peektoken()])
-                               return n1;
-                       break;
-               case TEOF:
-                       if (heredoclist)
-                               parseheredoc();
-                       else
-                               pungetc();              /* push back EOF on input */
-                       return n1;
-               default:
-                       if (nlflag)
-                               synexpect(-1);
-                       tokpushback++;
-                       return n1;
-               }
-       }
-}
-
-
-
-static union node *
-andor() {
-       union node *n1, *n2, *n3;
-       int t;
-
-       checkkwd = 1;
-       n1 = pipeline();
-       for (;;) {
-               if ((t = readtoken()) == TAND) {
-                       t = NAND;
-               } else if (t == TOR) {
-                       t = NOR;
-               } else {
-                       tokpushback++;
-                       return n1;
-               }
-               checkkwd = 2;
-               n2 = pipeline();
-               n3 = (union node *)stalloc(sizeof (struct nbinary));
-               n3->type = t;
-               n3->nbinary.ch1 = n1;
-               n3->nbinary.ch2 = n2;
-               n1 = n3;
-       }
-}
-
-
-
-static union node *
-pipeline() {
-       union node *n1, *n2, *pipenode;
-       struct nodelist *lp, *prev;
-       int negate;
-
-       negate = 0;
-       TRACE(("pipeline: entered\n"));
-       if (readtoken() == TNOT) {
-               negate = !negate;
-               checkkwd = 1;
-       } else
-               tokpushback++;
-       n1 = command();
-       if (readtoken() == TPIPE) {
-               pipenode = (union node *)stalloc(sizeof (struct npipe));
-               pipenode->type = NPIPE;
-               pipenode->npipe.backgnd = 0;
-               lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-               pipenode->npipe.cmdlist = lp;
-               lp->n = n1;
-               do {
-                       prev = lp;
-                       lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-                       checkkwd = 2;
-                       lp->n = command();
-                       prev->next = lp;
-               } while (readtoken() == TPIPE);
-               lp->next = NULL;
-               n1 = pipenode;
-       }
-       tokpushback++;
-       if (negate) {
-               n2 = (union node *)stalloc(sizeof (struct nnot));
-               n2->type = NNOT;
-               n2->nnot.com = n1;
-               return n2;
-       } else
-               return n1;
-}
-
-
-
-static union node *
-command() {
-       union node *n1, *n2;
-       union node *ap, **app;
-       union node *cp, **cpp;
-       union node *redir, **rpp;
-       int t;
-
-       redir = NULL;
-       n1 = NULL;
-       rpp = &redir;
-
-       /* Check for redirection which may precede command */
-       while (readtoken() == TREDIR) {
-               *rpp = n2 = redirnode;
-               rpp = &n2->nfile.next;
-               parsefname();
-       }
-       tokpushback++;
-
-       switch (readtoken()) {
-       case TIF:
-               n1 = (union node *)stalloc(sizeof (struct nif));
-               n1->type = NIF;
-               n1->nif.test = list(0);
-               if (readtoken() != TTHEN)
-                       synexpect(TTHEN);
-               n1->nif.ifpart = list(0);
-               n2 = n1;
-               while (readtoken() == TELIF) {
-                       n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
-                       n2 = n2->nif.elsepart;
-                       n2->type = NIF;
-                       n2->nif.test = list(0);
-                       if (readtoken() != TTHEN)
-                               synexpect(TTHEN);
-                       n2->nif.ifpart = list(0);
-               }
-               if (lasttoken == TELSE)
-                       n2->nif.elsepart = list(0);
-               else {
-                       n2->nif.elsepart = NULL;
-                       tokpushback++;
-               }
-               if (readtoken() != TFI)
-                       synexpect(TFI);
-               checkkwd = 1;
-               break;
-       case TWHILE:
-       case TUNTIL: {
-               int got;
-               n1 = (union node *)stalloc(sizeof (struct nbinary));
-               n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
-               n1->nbinary.ch1 = list(0);
-               if ((got=readtoken()) != TDO) {
-TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
-                       synexpect(TDO);
-               }
-               n1->nbinary.ch2 = list(0);
-               if (readtoken() != TDONE)
-                       synexpect(TDONE);
-               checkkwd = 1;
-               break;
-       }
-       case TFOR:
-               if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
-                       synerror("Bad for loop variable");
-               n1 = (union node *)stalloc(sizeof (struct nfor));
-               n1->type = NFOR;
-               n1->nfor.var = wordtext;
-               checkkwd = 1;
-               if (readtoken() == TIN) {
-                       app = &ap;
-                       while (readtoken() == TWORD) {
-                               n2 = (union node *)stalloc(sizeof (struct narg));
-                               n2->type = NARG;
-                               n2->narg.text = wordtext;
-                               n2->narg.backquote = backquotelist;
-                               *app = n2;
-                               app = &n2->narg.next;
-                       }
-                       *app = NULL;
-                       n1->nfor.args = ap;
-                       if (lasttoken != TNL && lasttoken != TSEMI)
-                               synexpect(-1);
-               } else {
-                       static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
-                                                                  '@', '=', '\0'};
-                       n2 = (union node *)stalloc(sizeof (struct narg));
-                       n2->type = NARG;
-                       n2->narg.text = argvars;
-                       n2->narg.backquote = NULL;
-                       n2->narg.next = NULL;
-                       n1->nfor.args = n2;
-                       /*
-                        * Newline or semicolon here is optional (but note
-                        * that the original Bourne shell only allowed NL).
-                        */
-                       if (lasttoken != TNL && lasttoken != TSEMI)
-                               tokpushback++;
-               }
-               checkkwd = 2;
-               if (readtoken() != TDO)
-                       synexpect(TDO);
-               n1->nfor.body = list(0);
-               if (readtoken() != TDONE)
-                       synexpect(TDONE);
-               checkkwd = 1;
-               break;
-       case TCASE:
-               n1 = (union node *)stalloc(sizeof (struct ncase));
-               n1->type = NCASE;
-               if (readtoken() != TWORD)
-                       synexpect(TWORD);
-               n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
-               n2->type = NARG;
-               n2->narg.text = wordtext;
-               n2->narg.backquote = backquotelist;
-               n2->narg.next = NULL;
-               do {
-                       checkkwd = 1;
-               } while (readtoken() == TNL);
-               if (lasttoken != TIN)
-                       synerror("expecting \"in\"");
-               cpp = &n1->ncase.cases;
-               checkkwd = 2, readtoken();
-               do {
-                       if (lasttoken == TLP)
-                               readtoken();
-                       *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
-                       cp->type = NCLIST;
-                       app = &cp->nclist.pattern;
-                       for (;;) {
-                               *app = ap = (union node *)stalloc(sizeof (struct narg));
-                               ap->type = NARG;
-                               ap->narg.text = wordtext;
-                               ap->narg.backquote = backquotelist;
-                               if (checkkwd = 2, readtoken() != TPIPE)
-                                       break;
-                               app = &ap->narg.next;
-                               readtoken();
-                       }
-                       ap->narg.next = NULL;
-                       if (lasttoken != TRP)
-                               synexpect(TRP);
-                       cp->nclist.body = list(0);
-
-                       checkkwd = 2;
-                       if ((t = readtoken()) != TESAC) {
-                               if (t != TENDCASE)
-                                       synexpect(TENDCASE);
-                               else
-                                       checkkwd = 2, readtoken();
-                       }
-                       cpp = &cp->nclist.next;
-               } while(lasttoken != TESAC);
-               *cpp = NULL;
-               checkkwd = 1;
-               break;
-       case TLP:
-               n1 = (union node *)stalloc(sizeof (struct nredir));
-               n1->type = NSUBSHELL;
-               n1->nredir.n = list(0);
-               n1->nredir.redirect = NULL;
-               if (readtoken() != TRP)
-                       synexpect(TRP);
-               checkkwd = 1;
-               break;
-       case TBEGIN:
-               n1 = list(0);
-               if (readtoken() != TEND)
-                       synexpect(TEND);
-               checkkwd = 1;
-               break;
-       /* Handle an empty command like other simple commands.  */
-       case TSEMI:
-       case TAND:
-       case TOR:
-       case TNL:
-       case TEOF:
-       case TRP:
-       case TBACKGND:
-               /*
-                * An empty command before a ; doesn't make much sense, and
-                * should certainly be disallowed in the case of `if ;'.
-                */
-               if (!redir)
-                       synexpect(-1);
-       case TWORD:
-               tokpushback++;
-               n1 = simplecmd();
-               return n1;
-       default:
-               synexpect(-1);
-               /* NOTREACHED */
-       }
-
-       /* Now check for redirection which may follow command */
-       while (readtoken() == TREDIR) {
-               *rpp = n2 = redirnode;
-               rpp = &n2->nfile.next;
-               parsefname();
-       }
-       tokpushback++;
-       *rpp = NULL;
-       if (redir) {
-               if (n1->type != NSUBSHELL) {
-                       n2 = (union node *)stalloc(sizeof (struct nredir));
-                       n2->type = NREDIR;
-                       n2->nredir.n = n1;
-                       n1 = n2;
-               }
-               n1->nredir.redirect = redir;
-       }
-
-       return n1;
-}
-
-
-static union node *
-simplecmd() {
-       union node *args, **app;
-       union node *n = NULL;
-       union node *vars, **vpp;
-       union node **rpp, *redir;
-
-       args = NULL;
-       app = &args;
-       vars = NULL;
-       vpp = &vars;
-       redir = NULL;
-       rpp = &redir;
-
-       checkalias = 2;
-       for (;;) {
-               switch (readtoken()) {
-               case TWORD:
-               case TASSIGN:
-                       n = (union node *)stalloc(sizeof (struct narg));
-                       n->type = NARG;
-                       n->narg.text = wordtext;
-                       n->narg.backquote = backquotelist;
-                       if (lasttoken == TWORD) {
-                               *app = n;
-                               app = &n->narg.next;
-                       } else {
-                               *vpp = n;
-                               vpp = &n->narg.next;
-                       }
-                       break;
-               case TREDIR:
-                       *rpp = n = redirnode;
-                       rpp = &n->nfile.next;
-                       parsefname();   /* read name of redirection file */
-                       break;
-               case TLP:
-                       if (
-                               args && app == &args->narg.next &&
-                               !vars && !redir
-                       ) {
-                               /* We have a function */
-                               if (readtoken() != TRP)
-                                       synexpect(TRP);
-                               n->type = NDEFUN;
-                               checkkwd = 2;
-                               n->narg.next = command();
-                               return n;
-                       }
-                       /* fall through */
-               default:
-                       tokpushback++;
-                       goto out;
-               }
-       }
-out:
-       *app = NULL;
-       *vpp = NULL;
-       *rpp = NULL;
-       n = (union node *)stalloc(sizeof (struct ncmd));
-       n->type = NCMD;
-       n->ncmd.backgnd = 0;
-       n->ncmd.args = args;
-       n->ncmd.assign = vars;
-       n->ncmd.redirect = redir;
-       return n;
-}
-
-static union node *
-makename(void) {
-       union node *n;
-
-       n = (union node *)stalloc(sizeof (struct narg));
-       n->type = NARG;
-       n->narg.next = NULL;
-       n->narg.text = wordtext;
-       n->narg.backquote = backquotelist;
-       return n;
-}
-
-static void fixredir(union node *n, const char *text, int err)
-{
-       TRACE(("Fix redir %s %d\n", text, err));
-       if (!err)
-               n->ndup.vname = NULL;
-
-       if (is_digit(text[0]) && text[1] == '\0')
-               n->ndup.dupfd = digit_val(text[0]);
-       else if (text[0] == '-' && text[1] == '\0')
-               n->ndup.dupfd = -1;
-       else {
-
-               if (err)
-                       synerror("Bad fd number");
-               else
-                       n->ndup.vname = makename();
-       }
-}
-
-
-static void
-parsefname(void) {
-       union node *n = redirnode;
-
-       if (readtoken() != TWORD)
-               synexpect(-1);
-       if (n->type == NHERE) {
-               struct heredoc *here = heredoc;
-               struct heredoc *p;
-               int i;
-
-               if (quoteflag == 0)
-                       n->type = NXHERE;
-               TRACE(("Here document %d\n", n->type));
-               if (here->striptabs) {
-                       while (*wordtext == '\t')
-                               wordtext++;
-               }
-               if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
-                       synerror("Illegal eof marker for << redirection");
-               rmescapes(wordtext);
-               here->eofmark = wordtext;
-               here->next = NULL;
-               if (heredoclist == NULL)
-                       heredoclist = here;
-               else {
-                       for (p = heredoclist ; p->next ; p = p->next);
-                       p->next = here;
-               }
-       } else if (n->type == NTOFD || n->type == NFROMFD) {
-               fixredir(n, wordtext, 0);
-       } else {
-               n->nfile.fname = makename();
-       }
-}
-
-
-/*
- * Input any here documents.
- */
-
-static void
-parseheredoc() {
-       struct heredoc *here;
-       union node *n;
-
-       while (heredoclist) {
-               here = heredoclist;
-               heredoclist = here->next;
-               if (needprompt) {
-                       setprompt(2);
-                       needprompt = 0;
-               }
-               readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
-                               here->eofmark, here->striptabs);
-               n = (union node *)stalloc(sizeof (struct narg));
-               n->narg.type = NARG;
-               n->narg.next = NULL;
-               n->narg.text = wordtext;
-               n->narg.backquote = backquotelist;
-               here->here->nhere.doc = n;
-       }
-}
-
-static int
-peektoken() {
-       int t;
-
-       t = readtoken();
-       tokpushback++;
-       return (t);
-}
-
-static int
-readtoken() {
-       int t;
-
-#ifdef ASH_ALIAS
-       int savecheckalias = checkalias;
-       int savecheckkwd = checkkwd;
-       struct alias *ap;
-#endif
-
-#ifdef DEBUG
-       int alreadyseen = tokpushback;
-#endif
-
-#ifdef ASH_ALIAS
-top:
-#endif
-
-       t = xxreadtoken();
-
-#ifdef ASH_ALIAS
-       checkalias = savecheckalias;
-#endif
-
-       if (checkkwd) {
-               /*
-                * eat newlines
-                */
-               if (checkkwd == 2) {
-                       checkkwd = 0;
-                       while (t == TNL) {
-                               parseheredoc();
-                               t = xxreadtoken();
-                       }
-               }
-               checkkwd = 0;
-               /*
-                * check for keywords
-                */
-               if (t == TWORD && !quoteflag)
-               {
-                       const char *const *pp;
-
-                       if ((pp = findkwd(wordtext))) {
-                               lasttoken = t = pp - parsekwd + KWDOFFSET;
-                               TRACE(("keyword %s recognized\n", tokname[t]));
-                               goto out;
-                       }
-               }
-       }
-
-
-       if (t != TWORD) {
-               if (t != TREDIR) {
-                       checkalias = 0;
-               }
-       } else if (checkalias == 2 && isassignment(wordtext)) {
-               lasttoken = t = TASSIGN;
-#ifdef ASH_ALIAS
-       } else if (checkalias) {
-               if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
-                       if (*ap->val) {
-                               pushstring(ap->val, strlen(ap->val), ap);
-                       }
-                       checkkwd = savecheckkwd;
-                       goto top;
-               }
-               checkalias = 0;
-#endif
-       }
-out:
-#ifdef DEBUG
-       if (!alreadyseen)
-           TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
-       else
-           TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
-#endif
-       return (t);
-}
-
-
-/*
- * Read the next input token.
- * If the token is a word, we set backquotelist to the list of cmds in
- *      backquotes.  We set quoteflag to true if any part of the word was
- *      quoted.
- * If the token is TREDIR, then we set redirnode to a structure containing
- *      the redirection.
- * In all cases, the variable startlinno is set to the number of the line
- *      on which the token starts.
- *
- * [Change comment:  here documents and internal procedures]
- * [Readtoken shouldn't have any arguments.  Perhaps we should make the
- *  word parsing code into a separate routine.  In this case, readtoken
- *  doesn't need to have any internal procedures, but parseword does.
- *  We could also make parseoperator in essence the main routine, and
- *  have parseword (readtoken1?) handle both words and redirection.]
- */
-
-#define RETURN(token)   return lasttoken = token
-
-static int
-xxreadtoken() {
-       int c;
-
-       if (tokpushback) {
-               tokpushback = 0;
-               return lasttoken;
-       }
-       if (needprompt) {
-               setprompt(2);
-               needprompt = 0;
-       }
-       startlinno = plinno;
-       for (;;) {      /* until token or start of word found */
-               c = pgetc_macro();
-               switch (c) {
-               case ' ': case '\t':
-#ifdef ASH_ALIAS
-               case PEOA:
-#endif
-                       continue;
-               case '#':
-                       while ((c = pgetc()) != '\n' && c != PEOF);
-                       pungetc();
-                       continue;
-               case '\\':
-                       if (pgetc() == '\n') {
-                               startlinno = ++plinno;
-                               if (doprompt)
-                                       setprompt(2);
-                               else
-                                       setprompt(0);
-                               continue;
-                       }
-                       pungetc();
-                       goto breakloop;
-               case '\n':
-                       plinno++;
-                       needprompt = doprompt;
-                       RETURN(TNL);
-               case PEOF:
-                       RETURN(TEOF);
-               case '&':
-                       if (pgetc() == '&')
-                               RETURN(TAND);
-                       pungetc();
-                       RETURN(TBACKGND);
-               case '|':
-                       if (pgetc() == '|')
-                               RETURN(TOR);
-                       pungetc();
-                       RETURN(TPIPE);
-               case ';':
-                       if (pgetc() == ';')
-                               RETURN(TENDCASE);
-                       pungetc();
-                       RETURN(TSEMI);
-               case '(':
-                       RETURN(TLP);
-               case ')':
-                       RETURN(TRP);
-               default:
-                       goto breakloop;
-               }
-       }
-breakloop:
-       return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
-#undef RETURN
-}
-
-
-
-/*
- * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
- * is not NULL, read a here document.  In the latter case, eofmark is the
- * word which marks the end of the document and striptabs is true if
- * leading tabs should be stripped from the document.  The argument firstc
- * is the first character of the input token or document.
- *
- * Because C does not have internal subroutines, I have simulated them
- * using goto's to implement the subroutine linkage.  The following macros
- * will run code that appears at the end of readtoken1.
- */
-
-#define CHECKEND()      {goto checkend; checkend_return:;}
-#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
-#define PARSESUB()      {goto parsesub; parsesub_return:;}
-#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
-#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
-#define PARSEARITH()    {goto parsearith; parsearith_return:;}
-
-static int
-readtoken1(firstc, syntax, eofmark, striptabs)
-       int firstc;
-       char const *syntax;
-       char *eofmark;
-       int striptabs;
-       {
-       int c = firstc;
-       char *out;
-       int len;
-       char line[EOFMARKLEN + 1];
-       struct nodelist *bqlist;
-       int quotef;
-       int dblquote;
-       int varnest;    /* levels of variables expansion */
-       int arinest;    /* levels of arithmetic expansion */
-       int parenlevel; /* levels of parens in arithmetic */
-       int dqvarnest;  /* levels of variables expansion within double quotes */
-       int oldstyle;
-       char const *prevsyntax; /* syntax before arithmetic */
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &out;
-       (void) &quotef;
-       (void) &dblquote;
-       (void) &varnest;
-       (void) &arinest;
-       (void) &parenlevel;
-       (void) &dqvarnest;
-       (void) &oldstyle;
-       (void) &prevsyntax;
-       (void) &syntax;
-#endif
-
-       startlinno = plinno;
-       dblquote = 0;
-       if (syntax == DQSYNTAX)
-               dblquote = 1;
-       quotef = 0;
-       bqlist = NULL;
-       varnest = 0;
-       arinest = 0;
-       parenlevel = 0;
-       dqvarnest = 0;
-
-       STARTSTACKSTR(out);
-       loop: { /* for each line, until end of word */
-               CHECKEND();     /* set c to PEOF if at end of here document */
-               for (;;) {      /* until end of line or end of word */
-                       CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
-                       switch(syntax[c]) {
-                       case CNL:       /* '\n' */
-                               if (syntax == BASESYNTAX)
-                                       goto endword;   /* exit outer loop */
-                               USTPUTC(c, out);
-                               plinno++;
-                               if (doprompt)
-                                       setprompt(2);
-                               else
-                                       setprompt(0);
-                               c = pgetc();
-                               goto loop;              /* continue outer loop */
-                       case CWORD:
-                               USTPUTC(c, out);
-                               break;
-                       case CCTL:
-                               if ((eofmark == NULL || dblquote) &&
-                                   dqvarnest == 0)
-                                       USTPUTC(CTLESC, out);
-                               USTPUTC(c, out);
-                               break;
-                       case CBACK:     /* backslash */
-                               c = pgetc2();
-                               if (c == PEOF) {
-                                       USTPUTC('\\', out);
-                                       pungetc();
-                               } else if (c == '\n') {
-                                       if (doprompt)
-                                               setprompt(2);
-                                       else
-                                               setprompt(0);
-                               } else {
-                                       if (dblquote && c != '\\' && c != '`' && c != '$'
-                                                        && (c != '"' || eofmark != NULL))
-                                               USTPUTC('\\', out);
-                                       if (SQSYNTAX[c] == CCTL)
-                                               USTPUTC(CTLESC, out);
-                                       else if (eofmark == NULL)
-                                               USTPUTC(CTLQUOTEMARK, out);
-                                       USTPUTC(c, out);
-                                       quotef++;
-                               }
-                               break;
-                       case CSQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = SQSYNTAX;
-                               break;
-                       case CDQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = DQSYNTAX;
-                               dblquote = 1;
-                               break;
-                       case CENDQUOTE:
-                               if (eofmark != NULL && arinest == 0 &&
-                                   varnest == 0) {
-                                       USTPUTC(c, out);
-                               } else {
-                                       if (arinest) {
-                                               syntax = ARISYNTAX;
-                                               dblquote = 0;
-                                       } else if (eofmark == NULL &&
-                                                  dqvarnest == 0) {
-                                               syntax = BASESYNTAX;
-                                               dblquote = 0;
-                                       }
-                                       quotef++;
-                               }
-                               break;
-                       case CVAR:      /* '$' */
-                               PARSESUB();             /* parse substitution */
-                               break;
-                       case CENDVAR:   /* '}' */
-                               if (varnest > 0) {
-                                       varnest--;
-                                       if (dqvarnest > 0) {
-                                               dqvarnest--;
-                                       }
-                                       USTPUTC(CTLENDVAR, out);
-                               } else {
-                                       USTPUTC(c, out);
-                               }
-                               break;
-#ifdef ASH_MATH_SUPPORT
-                       case CLP:       /* '(' in arithmetic */
-                               parenlevel++;
-                               USTPUTC(c, out);
-                               break;
-                       case CRP:       /* ')' in arithmetic */
-                               if (parenlevel > 0) {
-                                       USTPUTC(c, out);
-                                       --parenlevel;
-                               } else {
-                                       if (pgetc() == ')') {
-                                               if (--arinest == 0) {
-                                                       USTPUTC(CTLENDARI, out);
-                                                       syntax = prevsyntax;
-                                                       if (syntax == DQSYNTAX)
-                                                               dblquote = 1;
-                                                       else
-                                                               dblquote = 0;
-                                               } else
-                                                       USTPUTC(')', out);
-                                       } else {
-                                               /*
-                                                * unbalanced parens
-                                                *  (don't 2nd guess - no error)
-                                                */
-                                               pungetc();
-                                               USTPUTC(')', out);
-                                       }
-                               }
-                               break;
-#endif
-                       case CBQUOTE:   /* '`' */
-                               PARSEBACKQOLD();
-                               break;
-                       case CENDFILE:
-                               goto endword;           /* exit outer loop */
-                       case CIGN:
-                               break;
-                       default:
-                               if (varnest == 0)
-                                       goto endword;   /* exit outer loop */
-#ifdef ASH_ALIAS
-                               if (c != PEOA)
-#endif
-                                       USTPUTC(c, out);
-
-                       }
-                       c = pgetc_macro();
-               }
-       }
-endword:
-       if (syntax == ARISYNTAX)
-               synerror("Missing '))'");
-       if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
-               synerror("Unterminated quoted string");
-       if (varnest != 0) {
-               startlinno = plinno;
-               synerror("Missing '}'");
-       }
-       USTPUTC('\0', out);
-       len = out - stackblock();
-       out = stackblock();
-       if (eofmark == NULL) {
-               if ((c == '>' || c == '<')
-                && quotef == 0
-                && len <= 2
-                && (*out == '\0' || is_digit(*out))) {
-                       PARSEREDIR();
-                       return lasttoken = TREDIR;
-               } else {
-                       pungetc();
-               }
-       }
-       quoteflag = quotef;
-       backquotelist = bqlist;
-       grabstackblock(len);
-       wordtext = out;
-       return lasttoken = TWORD;
-/* end of readtoken routine */
-
-
-
-/*
- * Check to see whether we are at the end of the here document.  When this
- * is called, c is set to the first character of the next input line.  If
- * we are at the end of the here document, this routine sets the c to PEOF.
- */
-
-checkend: {
-       if (eofmark) {
-#ifdef ASH_ALIAS
-               if (c == PEOA) {
-                       c = pgetc2();
-               }
-#endif
-               if (striptabs) {
-                       while (c == '\t') {
-                               c = pgetc2();
-                       }
-               }
-               if (c == *eofmark) {
-                       if (pfgets(line, sizeof line) != NULL) {
-                               char *p, *q;
-
-                               p = line;
-                               for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
-                               if (*p == '\n' && *q == '\0') {
-                                       c = PEOF;
-                                       plinno++;
-                                       needprompt = doprompt;
-                               } else {
-                                       pushstring(line, strlen(line), NULL);
-                               }
-                       }
-               }
-       }
-       goto checkend_return;
-}
-
-
-/*
- * Parse a redirection operator.  The variable "out" points to a string
- * specifying the fd to be redirected.  The variable "c" contains the
- * first character of the redirection operator.
- */
-
-parseredir: {
-       char fd = *out;
-       union node *np;
-
-       np = (union node *)stalloc(sizeof (struct nfile));
-       if (c == '>') {
-               np->nfile.fd = 1;
-               c = pgetc();
-               if (c == '>')
-                       np->type = NAPPEND;
-               else if (c == '&')
-                       np->type = NTOFD;
-               else if (c == '|')
-                       np->type = NTOOV;
-               else {
-                       np->type = NTO;
-                       pungetc();
-               }
-       } else {        /* c == '<' */
-               np->nfile.fd = 0;
-               switch (c = pgetc()) {
-               case '<':
-                       if (sizeof (struct nfile) != sizeof (struct nhere)) {
-                               np = (union node *)stalloc(sizeof (struct nhere));
-                               np->nfile.fd = 0;
-                       }
-                       np->type = NHERE;
-                       heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
-                       heredoc->here = np;
-                       if ((c = pgetc()) == '-') {
-                               heredoc->striptabs = 1;
-                       } else {
-                               heredoc->striptabs = 0;
-                               pungetc();
-                       }
-                       break;
-
-               case '&':
-                       np->type = NFROMFD;
-                       break;
-
-               case '>':
-                       np->type = NFROMTO;
-                       break;
-
-               default:
-                       np->type = NFROM;
-                       pungetc();
-                       break;
-               }
-       }
-       if (fd != '\0')
-               np->nfile.fd = digit_val(fd);
-       redirnode = np;
-       goto parseredir_return;
-}
-
-
-/*
- * Parse a substitution.  At this point, we have read the dollar sign
- * and nothing else.
- */
-
-parsesub: {
-       int subtype;
-       int typeloc;
-       int flags;
-       char *p;
-       static const char types[] = "}-+?=";
-
-       c = pgetc();
-       if (
-               c <= PEOA  ||
-               (c != '(' && c != '{' && !is_name(c) && !is_special(c))
-       ) {
-               USTPUTC('$', out);
-               pungetc();
-       } else if (c == '(') {  /* $(command) or $((arith)) */
-               if (pgetc() == '(') {
-                       PARSEARITH();
-               } else {
-                       pungetc();
-                       PARSEBACKQNEW();
-               }
-       } else {
-               USTPUTC(CTLVAR, out);
-               typeloc = out - stackblock();
-               USTPUTC(VSNORMAL, out);
-               subtype = VSNORMAL;
-               if (c == '{') {
-                       c = pgetc();
-                       if (c == '#') {
-                               if ((c = pgetc()) == '}')
-                                       c = '#';
-                               else
-                                       subtype = VSLENGTH;
-                       }
-                       else
-                               subtype = 0;
-               }
-               if (c > PEOA && is_name(c)) {
-                       do {
-                               STPUTC(c, out);
-                               c = pgetc();
-                       } while (c > PEOA && is_in_name(c));
-               } else if (is_digit(c)) {
-                       do {
-                               USTPUTC(c, out);
-                               c = pgetc();
-                       } while (is_digit(c));
-               }
-               else if (is_special(c)) {
-                       USTPUTC(c, out);
-                       c = pgetc();
-               }
-               else
-badsub:                 synerror("Bad substitution");
-
-               STPUTC('=', out);
-               flags = 0;
-               if (subtype == 0) {
-                       switch (c) {
-                       case ':':
-                               flags = VSNUL;
-                               c = pgetc();
-                               /*FALLTHROUGH*/
-                       default:
-                               p = strchr(types, c);
-                               if (p == NULL)
-                                       goto badsub;
-                               subtype = p - types + VSNORMAL;
-                               break;
-                       case '%':
-                       case '#':
-                               {
-                                       int cc = c;
-                                       subtype = c == '#' ? VSTRIMLEFT :
-                                                            VSTRIMRIGHT;
-                                       c = pgetc();
-                                       if (c == cc)
-                                               subtype++;
-                                       else
-                                               pungetc();
-                                       break;
-                               }
-                       }
-               } else {
-                       pungetc();
-               }
-               if (dblquote || arinest)
-                       flags |= VSQUOTE;
-               *(stackblock() + typeloc) = subtype | flags;
-               if (subtype != VSNORMAL) {
-                       varnest++;
-                       if (dblquote) {
-                               dqvarnest++;
-                       }
-               }
-       }
-       goto parsesub_return;
-}
-
-
-/*
- * Called to parse command substitutions.  Newstyle is set if the command
- * is enclosed inside $(...); nlpp is a pointer to the head of the linked
- * list of commands (passed by reference), and savelen is the number of
- * characters on the top of the stack which must be preserved.
- */
-
-parsebackq: {
-       struct nodelist **nlpp;
-       int savepbq;
-       union node *n;
-       char *volatile str;
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
-       int savelen;
-       int saveprompt;
-#ifdef __GNUC__
-       (void) &saveprompt;
-#endif
-
-       savepbq = parsebackquote;
-       if (setjmp(jmploc.loc)) {
-               if (str)
-                       ckfree(str);
-               parsebackquote = 0;
-               handler = savehandler;
-               longjmp(handler->loc, 1);
-       }
-       INTOFF;
-       str = NULL;
-       savelen = out - stackblock();
-       if (savelen > 0) {
-               str = ckmalloc(savelen);
-               memcpy(str, stackblock(), savelen);
-       }
-       savehandler = handler;
-       handler = &jmploc;
-       INTON;
-       if (oldstyle) {
-               /* We must read until the closing backquote, giving special
-                  treatment to some slashes, and then push the string and
-                  reread it as input, interpreting it normally.  */
-               char *pout;
-               int pc;
-               int psavelen;
-               char *pstr;
-
-
-               STARTSTACKSTR(pout);
-               for (;;) {
-                       if (needprompt) {
-                               setprompt(2);
-                               needprompt = 0;
-                       }
-                       switch (pc = pgetc()) {
-                       case '`':
-                               goto done;
-
-                       case '\\':
-                               if ((pc = pgetc()) == '\n') {
-                                       plinno++;
-                                       if (doprompt)
-                                               setprompt(2);
-                                       else
-                                               setprompt(0);
-                                       /*
-                                        * If eating a newline, avoid putting
-                                        * the newline into the new character
-                                        * stream (via the STPUTC after the
-                                        * switch).
-                                        */
-                                       continue;
-                               }
-                               if (pc != '\\' && pc != '`' && pc != '$'
-                                   && (!dblquote || pc != '"'))
-                                       STPUTC('\\', pout);
-                               if (pc > PEOA) {
-                                       break;
-                               }
-                               /* fall through */
-
-                       case PEOF:
-#ifdef ASH_ALIAS
-                       case PEOA:
-#endif
-                               startlinno = plinno;
-                               synerror("EOF in backquote substitution");
-
-                       case '\n':
-                               plinno++;
-                               needprompt = doprompt;
-                               break;
-
-                       default:
-                               break;
-                       }
-                       STPUTC(pc, pout);
-               }
-done:
-               STPUTC('\0', pout);
-               psavelen = pout - stackblock();
-               if (psavelen > 0) {
-                       pstr = grabstackstr(pout);
-                       setinputstring(pstr);
-               }
-       }
-       nlpp = &bqlist;
-       while (*nlpp)
-               nlpp = &(*nlpp)->next;
-       *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-       (*nlpp)->next = NULL;
-       parsebackquote = oldstyle;
-
-       if (oldstyle) {
-               saveprompt = doprompt;
-               doprompt = 0;
-       }
-
-       n = list(0);
-
-       if (oldstyle)
-               doprompt = saveprompt;
-       else {
-               if (readtoken() != TRP)
-                       synexpect(TRP);
-       }
-
-       (*nlpp)->n = n;
-       if (oldstyle) {
-               /*
-                * Start reading from old file again, ignoring any pushed back
-                * tokens left from the backquote parsing
-                */
-               popfile();
-               tokpushback = 0;
-       }
-       while (stackblocksize() <= savelen)
-               growstackblock();
-       STARTSTACKSTR(out);
-       if (str) {
-               memcpy(out, str, savelen);
-               STADJUST(savelen, out);
-               INTOFF;
-               ckfree(str);
-               str = NULL;
-               INTON;
-       }
-       parsebackquote = savepbq;
-       handler = savehandler;
-       if (arinest || dblquote)
-               USTPUTC(CTLBACKQ | CTLQUOTE, out);
-       else
-               USTPUTC(CTLBACKQ, out);
-       if (oldstyle)
-               goto parsebackq_oldreturn;
-       else
-               goto parsebackq_newreturn;
-}
-
-/*
- * Parse an arithmetic expansion (indicate start of one and set state)
- */
-parsearith: {
-
-       if (++arinest == 1) {
-               prevsyntax = syntax;
-               syntax = ARISYNTAX;
-               USTPUTC(CTLARI, out);
-               if (dblquote)
-                       USTPUTC('"',out);
-               else
-                       USTPUTC(' ',out);
-       } else {
-               /*
-                * we collapse embedded arithmetic expansion to
-                * parenthesis, which should be equivalent
-                */
-               USTPUTC('(', out);
-       }
-       goto parsearith_return;
-}
-
-} /* end of readtoken */
-
-
-/*
- * Returns true if the text contains nothing to expand (no dollar signs
- * or backquotes).
- */
-
-static int
-noexpand(text)
-       char *text;
-       {
-       char *p;
-       char c;
-
-       p = text;
-       while ((c = *p++) != '\0') {
-               if (c == CTLQUOTEMARK)
-                       continue;
-               if (c == CTLESC)
-                       p++;
-               else if (BASESYNTAX[(int)c] == CCTL)
-                       return 0;
-       }
-       return 1;
-}
-
-
-/*
- * Return true if the argument is a legal variable name (a letter or
- * underscore followed by zero or more letters, underscores, and digits).
- */
-
-static int
-goodname(const char *name)
-{
-       const char *p;
-
-       p = name;
-       if (! is_name(*p))
-               return 0;
-       while (*++p) {
-               if (! is_in_name(*p))
-                       return 0;
-       }
-       return 1;
-}
-
-
-/*
- * Called when an unexpected token is read during the parse.  The argument
- * is the token that is expected, or -1 if more than one type of token can
- * occur at this point.
- */
-
-static void
-synexpect(token)
-       int token;
-{
-       char msg[64];
-
-       if (token >= 0) {
-               snprintf(msg, 64, "%s unexpected (expecting %s)",
-                       tokname[lasttoken], tokname[token]);
-       } else {
-               snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
-       }
-       synerror(msg);
-       /* NOTREACHED */
-}
-
-
-static void
-synerror(const char *msg)
-{
-       if (commandname)
-               out2fmt("%s: %d: ", commandname, startlinno);
-       out2fmt("Syntax error: %s\n", msg);
-       error((char *)NULL);
-       /* NOTREACHED */
-}
-
-
-/*
- * called by editline -- any expansions to the prompt
- *    should be added here.
- */
-static void
-setprompt(int whichprompt)
-{
-    char *prompt;
-    switch (whichprompt) {
-       case 1:
-               prompt = ps1val();
-               break;
-       case 2:
-               prompt = ps2val();
-               break;
-       default:                /* 0 */
-               prompt = "";
-    }
-    putprompt(prompt);
-}
-
-
-/*
- * Code for dealing with input/output redirection.
- */
-
-#define EMPTY -2                /* marks an unused slot in redirtab */
-#ifndef PIPE_BUF
-# define PIPESIZE 4096          /* amount of buffering in a pipe */
-#else
-# define PIPESIZE PIPE_BUF
-#endif
-
-
-/*
- * Open a file in noclobber mode.
- * The code was copied from bash.
- */
-static inline int
-noclobberopen(const char *fname)
-{
-       int r, fd;
-       struct stat finfo, finfo2;
-
-       /*
-        * If the file exists and is a regular file, return an error
-        * immediately.
-        */
-       r = stat(fname, &finfo);
-       if (r == 0 && S_ISREG(finfo.st_mode)) {
-               errno = EEXIST;
-               return -1;
-       }
-
-       /*
-        * If the file was not present (r != 0), make sure we open it
-        * exclusively so that if it is created before we open it, our open
-        * will fail.  Make sure that we do not truncate an existing file.
-        * Note that we don't turn on O_EXCL unless the stat failed -- if the
-        * file was not a regular file, we leave O_EXCL off.
-        */
-       if (r != 0)
-               return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
-       fd = open(fname, O_WRONLY|O_CREAT, 0666);
-
-       /* If the open failed, return the file descriptor right away. */
-       if (fd < 0)
-               return fd;
-
-       /*
-        * OK, the open succeeded, but the file may have been changed from a
-        * non-regular file to a regular file between the stat and the open.
-        * We are assuming that the O_EXCL open handles the case where FILENAME
-        * did not exist and is symlinked to an existing file between the stat
-        * and open.
-        */
-
-       /*
-        * If we can open it and fstat the file descriptor, and neither check
-        * revealed that it was a regular file, and the file has not been
-        * replaced, return the file descriptor.
-        */
-        if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
-            finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
-               return fd;
-
-       /* The file has been replaced.  badness. */
-       close(fd);
-       errno = EEXIST;
-       return -1;
-}
-
-/*
- * Handle here documents.  Normally we fork off a process to write the
- * data to a pipe.  If the document is short, we can stuff the data in
- * the pipe without forking.
- */
-
-static inline int
-openhere(const union node *redir)
-{
-       int pip[2];
-       int len = 0;
-
-       if (pipe(pip) < 0)
-               error("Pipe call failed");
-       if (redir->type == NHERE) {
-               len = strlen(redir->nhere.doc->narg.text);
-               if (len <= PIPESIZE) {
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
-                       goto out;
-               }
-       }
-       if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
-               close(pip[0]);
-               signal(SIGINT, SIG_IGN);
-               signal(SIGQUIT, SIG_IGN);
-               signal(SIGHUP, SIG_IGN);
-#ifdef SIGTSTP
-               signal(SIGTSTP, SIG_IGN);
-#endif
-               signal(SIGPIPE, SIG_DFL);
-               if (redir->type == NHERE)
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
-               else
-                       expandhere(redir->nhere.doc, pip[1]);
-               _exit(0);
-       }
-out:
-       close(pip[1]);
-       return pip[0];
-}
-
-
-static inline int
-openredirect(const union node *redir)
-{
-       char *fname;
-       int f;
-
-       switch (redir->nfile.type) {
-       case NFROM:
-               fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDONLY)) < 0)
-                       goto eopen;
-               break;
-       case NFROMTO:
-               fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
-                       goto ecreate;
-               break;
-       case NTO:
-               /* Take care of noclobber mode. */
-               if (Cflag) {
-                       fname = redir->nfile.expfname;
-                       if ((f = noclobberopen(fname)) < 0)
-                               goto ecreate;
-                       break;
-               }
-       case NTOOV:
-               fname = redir->nfile.expfname;
-#ifdef O_CREAT
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
-                       goto ecreate;
-#else
-               if ((f = creat(fname, 0666)) < 0)
-                       goto ecreate;
-#endif
-               break;
-       case NAPPEND:
-               fname = redir->nfile.expfname;
-#ifdef O_APPEND
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
-                       goto ecreate;
-#else
-               if ((f = open(fname, O_WRONLY)) < 0
-                && (f = creat(fname, 0666)) < 0)
-                       goto ecreate;
-               lseek(f, (off_t)0, 2);
-#endif
-               break;
-       default:
-#ifdef DEBUG
-               abort();
-#endif
-               /* Fall through to eliminate warning. */
-       case NTOFD:
-       case NFROMFD:
-               f = -1;
-               break;
-       case NHERE:
-       case NXHERE:
-               f = openhere(redir);
-               break;
-       }
-
-       return f;
-ecreate:
-       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-eopen:
-       error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
-}
-
-
-/*
- * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
- * old file descriptors are stashed away so that the redirection can be
- * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
- * standard output, and the standard error if it becomes a duplicate of
- * stdout.
- */
-
-static void
-redirect(union node *redir, int flags)
-{
-       union node *n;
-       struct redirtab *sv = NULL;
-       int i;
-       int fd;
-       int newfd;
-       int try;
-       int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
-
-       if (flags & REDIR_PUSH) {
-               sv = ckmalloc(sizeof (struct redirtab));
-               for (i = 0 ; i < 10 ; i++)
-                       sv->renamed[i] = EMPTY;
-               sv->next = redirlist;
-               redirlist = sv;
-       }
-       for (n = redir ; n ; n = n->nfile.next) {
-               fd = n->nfile.fd;
-               try = 0;
-               if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
-                   n->ndup.dupfd == fd)
-                       continue; /* redirect from/to same file descriptor */
-
-               INTOFF;
-               newfd = openredirect(n);
-               if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
-                       if (newfd == fd) {
-                               try++;
-                       } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
-                               switch (errno) {
-                               case EBADF:
-                                       if (!try) {
-                                               dupredirect(n, newfd, fd1dup);
-                                               try++;
-                                               break;
-                                       }
-                                       /* FALLTHROUGH*/
-                               default:
-                                       if (newfd >= 0) {
-                                               close(newfd);
-                                       }
-                                       INTON;
-                                       error("%d: %m", fd);
-                                       /* NOTREACHED */
-                               }
-                       }
-                       if (!try) {
-                               close(fd);
-                               if (flags & REDIR_PUSH) {
-                                       sv->renamed[fd] = i;
-                               }
-                       }
-               } else if (fd != newfd) {
-                       close(fd);
-               }
-               if (fd == 0)
-                       fd0_redirected++;
-               if (!try)
-                       dupredirect(n, newfd, fd1dup);
-               INTON;
-       }
-}
-
-
-static void
-dupredirect(const union node *redir, int f, int fd1dup)
-{
-       int fd = redir->nfile.fd;
-
-       if(fd==1)
-               fd1dup = 0;
-       if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
-               if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
-                       if (redir->ndup.dupfd!=1 || fd1dup!=1)
-                               dup_as_newfd(redir->ndup.dupfd, fd);
-               }
-               return;
-       }
-
-       if (f != fd) {
-               dup_as_newfd(f, fd);
-               close(f);
-       }
-       return;
-}
-
-
-
-/*
- * Undo the effects of the last redirection.
- */
-
-static void
-popredir(void)
-{
-       struct redirtab *rp = redirlist;
-       int i;
-
-       INTOFF;
-       for (i = 0 ; i < 10 ; i++) {
-               if (rp->renamed[i] != EMPTY) {
-                       if (i == 0)
-                               fd0_redirected--;
-                       close(i);
-                       if (rp->renamed[i] >= 0) {
-                               dup_as_newfd(rp->renamed[i], i);
-                               close(rp->renamed[i]);
-                       }
-               }
-       }
-       redirlist = rp->next;
-       ckfree(rp);
-       INTON;
-}
-
-/*
- * Discard all saved file descriptors.
- */
-
-static void
-clearredir(void) {
-       struct redirtab *rp;
-       int i;
-
-       for (rp = redirlist ; rp ; rp = rp->next) {
-               for (i = 0 ; i < 10 ; i++) {
-                       if (rp->renamed[i] >= 0) {
-                               close(rp->renamed[i]);
-                       }
-                       rp->renamed[i] = EMPTY;
-               }
-       }
-}
-
-
-/*
- * Copy a file descriptor to be >= to.  Returns -1
- * if the source file descriptor is closed, EMPTY if there are no unused
- * file descriptors left.
- */
-
-static int
-dup_as_newfd(from, to)
-       int from;
-       int to;
-{
-       int newfd;
-
-       newfd = fcntl(from, F_DUPFD, to);
-       if (newfd < 0) {
-               if (errno == EMFILE)
-                       return EMPTY;
-               else
-                       error("%d: %m", from);
-       }
-       return newfd;
-}
-
-/*#ifdef __weak_alias
-__weak_alias(getmode,_getmode)
-__weak_alias(setmode,_setmode)
-#endif*/
-
-#ifndef S_ISTXT
-#if defined(__GLIBC__) && __GLIBC__ >= 2
-#define S_ISTXT __S_ISVTX
-#else
-#define S_ISTXT S_ISVTX
-#endif
-#endif
-
-#define SET_LEN 6               /* initial # of bitcmd struct to malloc */
-#define SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
-
-typedef struct bitcmd {
-       char    cmd;
-       char    cmd2;
-       mode_t  bits;
-} BITCMD;
-
-#define CMD2_CLR        0x01
-#define CMD2_SET        0x02
-#define CMD2_GBITS      0x04
-#define CMD2_OBITS      0x08
-#define CMD2_UBITS      0x10
-
-static BITCMD   *addcmd (BITCMD *, int, int, int, u_int);
-static void      compress_mode (BITCMD *);
-#ifdef SETMODE_DEBUG
-static void      dumpmode (BITCMD *);
-#endif
-
-/*
- * Given the old mode and an array of bitcmd structures, apply the operations
- * described in the bitcmd structures to the old mode, and return the new mode.
- * Note that there is no '=' command; a strict assignment is just a '-' (clear
- * bits) followed by a '+' (set bits).
- */
-static mode_t
-getmode(bbox, omode)
-       const void *bbox;
-       mode_t omode;
-{
-       const BITCMD *set;
-       mode_t clrval, newmode, value;
-
-       _DIAGASSERT(bbox != NULL);
-
-       set = (const BITCMD *)bbox;
-       newmode = omode;
-       for (value = 0;; set++)
-               switch(set->cmd) {
-               /*
-                * When copying the user, group or other bits around, we "know"
-                * where the bits are in the mode so that we can do shifts to
-                * copy them around.  If we don't use shifts, it gets real
-                * grundgy with lots of single bit checks and bit sets.
-                */
-               case 'u':
-                       value = (newmode & S_IRWXU) >> 6;
-                       goto common;
-
-               case 'g':
-                       value = (newmode & S_IRWXG) >> 3;
-                       goto common;
-
-               case 'o':
-                       value = newmode & S_IRWXO;
-common:                 if (set->cmd2 & CMD2_CLR) {
-                               clrval =
-                                   (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode &= ~((clrval<<6) & set->bits);
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode &= ~((clrval<<3) & set->bits);
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode &= ~(clrval & set->bits);
-                       }
-                       if (set->cmd2 & CMD2_SET) {
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode |= (value<<6) & set->bits;
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode |= (value<<3) & set->bits;
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode |= value & set->bits;
-                       }
-                       break;
-
-               case '+':
-                       newmode |= set->bits;
-                       break;
-
-               case '-':
-                       newmode &= ~set->bits;
-                       break;
-
-               case 'X':
-                       if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
-                               newmode |= set->bits;
-                       break;
-
-               case '\0':
-               default:
-#ifdef SETMODE_DEBUG
-                       (void)printf("getmode:%04o -> %04o\n", omode, newmode);
-#endif
-                       return (newmode);
-               }
-}
-
-#define ADDCMD(a, b, c, d) do {                                         \
-       if (set >= endset) {                                            \
-               BITCMD *newset;                                         \
-               setlen += SET_LEN_INCR;                                 \
-               newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
-               if (newset == NULL) {                                   \
-                       free(saveset);                                  \
-                       return (NULL);                                  \
-               }                                                       \
-               set = newset + (set - saveset);                         \
-               saveset = newset;                                       \
-               endset = newset + (setlen - 2);                         \
-       }                                                               \
-       set = addcmd(set, (a), (b), (c), (d));                          \
-} while (/*CONSTCOND*/0)
-
-#define STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
-
-static void *
-setmode(p)
-       const char *p;
-{
-       int perm, who;
-       char op, *ep;
-       BITCMD *set, *saveset, *endset;
-       sigset_t mysigset, sigoset;
-       mode_t mask;
-       int equalopdone = 0;    /* pacify gcc */
-       int permXbits, setlen;
-
-       if (!*p)
-               return (NULL);
-
-       /*
-        * Get a copy of the mask for the permissions that are mask relative.
-        * Flip the bits, we want what's not set.  Since it's possible that
-        * the caller is opening files inside a signal handler, protect them
-        * as best we can.
-        */
-       sigfillset(&mysigset);
-       (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
-       (void)umask(mask = umask(0));
-       mask = ~mask;
-       (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
-
-       setlen = SET_LEN + 2;
-
-       if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
-               return (NULL);
-       saveset = set;
-       endset = set + (setlen - 2);
-
-       /*
-        * If an absolute number, get it and return; disallow non-octal digits
-        * or illegal bits.
-        */
-       if (is_digit((unsigned char)*p)) {
-               perm = (mode_t)strtol(p, &ep, 8);
-               if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
-                       free(saveset);
-                       return (NULL);
-               }
-               ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
-               set->cmd = 0;
-               return (saveset);
-       }
-
-       /*
-        * Build list of structures to set/clear/copy bits as described by
-        * each clause of the symbolic mode.
-        */
-       for (;;) {
-               /* First, find out which bits might be modified. */
-               for (who = 0;; ++p) {
-                       switch (*p) {
-                       case 'a':
-                               who |= STANDARD_BITS;
-                               break;
-                       case 'u':
-                               who |= S_ISUID|S_IRWXU;
-                               break;
-                       case 'g':
-                               who |= S_ISGID|S_IRWXG;
-                               break;
-                       case 'o':
-                               who |= S_IRWXO;
-                               break;
-                       default:
-                               goto getop;
-                       }
-               }
-
-getop:          if ((op = *p++) != '+' && op != '-' && op != '=') {
-                       free(saveset);
-                       return (NULL);
-               }
-               if (op == '=')
-                       equalopdone = 0;
-
-               who &= ~S_ISTXT;
-               for (perm = 0, permXbits = 0;; ++p) {
-                       switch (*p) {
-                       case 'r':
-                               perm |= S_IRUSR|S_IRGRP|S_IROTH;
-                               break;
-                       case 's':
-                               /*
-                                * If specific bits where requested and
-                                * only "other" bits ignore set-id.
-                                */
-                               if (who == 0 || (who & ~S_IRWXO))
-                                       perm |= S_ISUID|S_ISGID;
-                               break;
-                       case 't':
-                               /*
-                                * If specific bits where requested and
-                                * only "other" bits ignore set-id.
-                                */
-                               if (who == 0 || (who & ~S_IRWXO)) {
-                                       who |= S_ISTXT;
-                                       perm |= S_ISTXT;
-                               }
-                               break;
-                       case 'w':
-                               perm |= S_IWUSR|S_IWGRP|S_IWOTH;
-                               break;
-                       case 'X':
-                               permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'x':
-                               perm |= S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'u':
-                       case 'g':
-                       case 'o':
-                               /*
-                                * When ever we hit 'u', 'g', or 'o', we have
-                                * to flush out any partial mode that we have,
-                                * and then do the copying of the mode bits.
-                                */
-                               if (perm) {
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (op == '=')
-                                       equalopdone = 1;
-                               if (op == '+' && permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               ADDCMD(*p, who, op, mask);
-                               break;
-
-                       default:
-                               /*
-                                * Add any permissions that we haven't already
-                                * done.
-                                */
-                               if (perm || (op == '=' && !equalopdone)) {
-                                       if (op == '=')
-                                               equalopdone = 1;
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               goto apply;
-                       }
-               }
-
-apply:          if (!*p)
-                       break;
-               if (*p != ',')
-                       goto getop;
-               ++p;
-       }
-       set->cmd = 0;
-#ifdef SETMODE_DEBUG
-       (void)printf("Before compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       compress_mode(saveset);
-#ifdef SETMODE_DEBUG
-       (void)printf("After compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       return (saveset);
-}
-
-static BITCMD *
-addcmd(set, op, who, oparg, mask)
-       BITCMD *set;
-       int oparg, who;
-       int op;
-       u_int mask;
-{
-
-       _DIAGASSERT(set != NULL);
-
-       switch (op) {
-       case '=':
-               set->cmd = '-';
-               set->bits = who ? who : STANDARD_BITS;
-               set++;
-
-               op = '+';
-               /* FALLTHROUGH */
-       case '+':
-       case '-':
-       case 'X':
-               set->cmd = op;
-               set->bits = (who ? who : mask) & oparg;
-               break;
-
-       case 'u':
-       case 'g':
-       case 'o':
-               set->cmd = op;
-               if (who) {
-                       set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
-                                   ((who & S_IRGRP) ? CMD2_GBITS : 0) |
-                                   ((who & S_IROTH) ? CMD2_OBITS : 0);
-                       set->bits = (mode_t)~0;
-               } else {
-                       set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
-                       set->bits = mask;
-               }
-
-               if (oparg == '+')
-                       set->cmd2 |= CMD2_SET;
-               else if (oparg == '-')
-                       set->cmd2 |= CMD2_CLR;
-               else if (oparg == '=')
-                       set->cmd2 |= CMD2_SET|CMD2_CLR;
-               break;
-       }
-       return (set + 1);
-}
-
-#ifdef SETMODE_DEBUG
-static void
-dumpmode(set)
-       BITCMD *set;
-{
-
-       _DIAGASSERT(set != NULL);
-
-       for (; set->cmd; ++set)
-               (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
-                   set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
-                   set->cmd2 & CMD2_CLR ? " CLR" : "",
-                   set->cmd2 & CMD2_SET ? " SET" : "",
-                   set->cmd2 & CMD2_UBITS ? " UBITS" : "",
-                   set->cmd2 & CMD2_GBITS ? " GBITS" : "",
-                   set->cmd2 & CMD2_OBITS ? " OBITS" : "");
-}
-#endif
-
-/*
- * Given an array of bitcmd structures, compress by compacting consecutive
- * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
- * 'g' and 'o' commands continue to be separate.  They could probably be
- * compacted, but it's not worth the effort.
- */
-static void
-compress_mode(set)
-       BITCMD *set;
-{
-       BITCMD *nset;
-       int setbits, clrbits, Xbits, op;
-
-       _DIAGASSERT(set != NULL);
-
-       for (nset = set;;) {
-               /* Copy over any 'u', 'g' and 'o' commands. */
-               while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
-                       *set++ = *nset++;
-                       if (!op)
-                               return;
-               }
-
-               for (setbits = clrbits = Xbits = 0;; nset++) {
-                       if ((op = nset->cmd) == '-') {
-                               clrbits |= nset->bits;
-                               setbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == '+') {
-                               setbits |= nset->bits;
-                               clrbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == 'X')
-                               Xbits |= nset->bits & ~setbits;
-                       else
-                               break;
-               }
-               if (clrbits) {
-                       set->cmd = '-';
-                       set->cmd2 = 0;
-                       set->bits = clrbits;
-                       set++;
-               }
-               if (setbits) {
-                       set->cmd = '+';
-                       set->cmd2 = 0;
-                       set->bits = setbits;
-                       set++;
-               }
-               if (Xbits) {
-                       set->cmd = 'X';
-                       set->cmd2 = 0;
-                       set->bits = Xbits;
-                       set++;
-               }
-       }
-}
-#ifdef DEBUG
-static void shtree (union node *, int, char *, FILE*);
-static void shcmd (union node *, FILE *);
-static void sharg (union node *, FILE *);
-static void indent (int, char *, FILE *);
-static void trstring (char *);
-
-
-static void
-showtree(n)
-       union node *n;
-{
-       trputs("showtree called\n");
-       shtree(n, 1, NULL, stdout);
-}
-
-
-static void
-shtree(n, ind, pfx, fp)
-       union node *n;
-       int ind;
-       char *pfx;
-       FILE *fp;
-{
-       struct nodelist *lp;
-       const char *s;
-
-       if (n == NULL)
-               return;
-
-       indent(ind, pfx, fp);
-       switch(n->type) {
-       case NSEMI:
-               s = "; ";
-               goto binop;
-       case NAND:
-               s = " && ";
-               goto binop;
-       case NOR:
-               s = " || ";
-binop:
-               shtree(n->nbinary.ch1, ind, NULL, fp);
-          /*    if (ind < 0) */
-                       fputs(s, fp);
-               shtree(n->nbinary.ch2, ind, NULL, fp);
-               break;
-       case NCMD:
-               shcmd(n, fp);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       case NPIPE:
-               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-                       shcmd(lp->n, fp);
-                       if (lp->next)
-                               fputs(" | ", fp);
-               }
-               if (n->npipe.backgnd)
-                       fputs(" &", fp);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       default:
-               fprintf(fp, "<node type %d>", n->type);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       }
-}
-
-
-
-static void
-shcmd(cmd, fp)
-       union node *cmd;
-       FILE *fp;
-{
-       union node *np;
-       int first;
-       const char *s;
-       int dftfd;
-
-       first = 1;
-       for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
-               if (! first)
-                       putchar(' ');
-               sharg(np, fp);
-               first = 0;
-       }
-       for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
-               if (! first)
-                       putchar(' ');
-               switch (np->nfile.type) {
-                       case NTO:       s = ">";  dftfd = 1; break;
-                       case NAPPEND:   s = ">>"; dftfd = 1; break;
-                       case NTOFD:     s = ">&"; dftfd = 1; break;
-                       case NTOOV:     s = ">|"; dftfd = 1; break;
-                       case NFROM:     s = "<";  dftfd = 0; break;
-                       case NFROMFD:   s = "<&"; dftfd = 0; break;
-                       case NFROMTO:   s = "<>"; dftfd = 0; break;
-                       default:        s = "*error*"; dftfd = 0; break;
-               }
-               if (np->nfile.fd != dftfd)
-                       fprintf(fp, "%d", np->nfile.fd);
-               fputs(s, fp);
-               if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
-                       fprintf(fp, "%d", np->ndup.dupfd);
-               } else {
-                       sharg(np->nfile.fname, fp);
-               }
-               first = 0;
-       }
-}
-
-
-
-static void
-sharg(arg, fp)
-       union node *arg;
-       FILE *fp;
-       {
-       char *p;
-       struct nodelist *bqlist;
-       int subtype;
-
-       if (arg->type != NARG) {
-               printf("<node type %d>\n", arg->type);
-               fflush(stdout);
-               abort();
-       }
-       bqlist = arg->narg.backquote;
-       for (p = arg->narg.text ; *p ; p++) {
-               switch (*p) {
-               case CTLESC:
-                       putc(*++p, fp);
-                       break;
-               case CTLVAR:
-                       putc('$', fp);
-                       putc('{', fp);
-                       subtype = *++p;
-                       if (subtype == VSLENGTH)
-                               putc('#', fp);
-
-                       while (*p != '=')
-                               putc(*p++, fp);
-
-                       if (subtype & VSNUL)
-                               putc(':', fp);
-
-                       switch (subtype & VSTYPE) {
-                       case VSNORMAL:
-                               putc('}', fp);
-                               break;
-                       case VSMINUS:
-                               putc('-', fp);
-                               break;
-                       case VSPLUS:
-                               putc('+', fp);
-                               break;
-                       case VSQUESTION:
-                               putc('?', fp);
-                               break;
-                       case VSASSIGN:
-                               putc('=', fp);
-                               break;
-                       case VSTRIMLEFT:
-                               putc('#', fp);
-                               break;
-                       case VSTRIMLEFTMAX:
-                               putc('#', fp);
-                               putc('#', fp);
-                               break;
-                       case VSTRIMRIGHT:
-                               putc('%', fp);
-                               break;
-                       case VSTRIMRIGHTMAX:
-                               putc('%', fp);
-                               putc('%', fp);
-                               break;
-                       case VSLENGTH:
-                               break;
-                       default:
-                               printf("<subtype %d>", subtype);
-                       }
-                       break;
-               case CTLENDVAR:
-                    putc('}', fp);
-                    break;
-               case CTLBACKQ:
-               case CTLBACKQ|CTLQUOTE:
-                       putc('$', fp);
-                       putc('(', fp);
-                       shtree(bqlist->n, -1, NULL, fp);
-                       putc(')', fp);
-                       break;
-               default:
-                       putc(*p, fp);
-                       break;
-               }
-       }
-}
-
-
-static void
-indent(amount, pfx, fp)
-       int amount;
-       char *pfx;
-       FILE *fp;
-{
-       int i;
-
-       for (i = 0 ; i < amount ; i++) {
-               if (pfx && i == amount - 1)
-                       fputs(pfx, fp);
-               putc('\t', fp);
-       }
-}
-#endif
-
-
-
-/*
- * Debugging stuff.
- */
-
-
-#ifdef DEBUG
-FILE *tracefile;
-
-#if DEBUG == 2
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-
-
-static void
-trputc(c)
-       int c;
-{
-       if (tracefile == NULL)
-               return;
-       putc(c, tracefile);
-       if (c == '\n')
-               fflush(tracefile);
-}
-
-static void
-trace(const char *fmt, ...)
-{
-       va_list va;
-       va_start(va, fmt);
-       if (tracefile != NULL) {
-               (void) vfprintf(tracefile, fmt, va);
-               if (strchr(fmt, '\n'))
-                       (void) fflush(tracefile);
-       }
-       va_end(va);
-}
-
-
-static void
-trputs(s)
-       const char *s;
-{
-       if (tracefile == NULL)
-               return;
-       fputs(s, tracefile);
-       if (strchr(s, '\n'))
-               fflush(tracefile);
-}
-
-
-static void
-trstring(s)
-       char *s;
-{
-       char *p;
-       char c;
-
-       if (tracefile == NULL)
-               return;
-       putc('"', tracefile);
-       for (p = s ; *p ; p++) {
-               switch (*p) {
-               case '\n':  c = 'n';  goto backslash;
-               case '\t':  c = 't';  goto backslash;
-               case '\r':  c = 'r';  goto backslash;
-               case '"':  c = '"';  goto backslash;
-               case '\\':  c = '\\';  goto backslash;
-               case CTLESC:  c = 'e';  goto backslash;
-               case CTLVAR:  c = 'v';  goto backslash;
-               case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
-               case CTLBACKQ:  c = 'q';  goto backslash;
-               case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
-backslash:        putc('\\', tracefile);
-                       putc(c, tracefile);
-                       break;
-               default:
-                       if (*p >= ' ' && *p <= '~')
-                               putc(*p, tracefile);
-                       else {
-                               putc('\\', tracefile);
-                               putc(*p >> 6 & 03, tracefile);
-                               putc(*p >> 3 & 07, tracefile);
-                               putc(*p & 07, tracefile);
-                       }
-                       break;
-               }
-       }
-       putc('"', tracefile);
-}
-
-
-static void
-trargs(ap)
-       char **ap;
-{
-       if (tracefile == NULL)
-               return;
-       while (*ap) {
-               trstring(*ap++);
-               if (*ap)
-                       putc(' ', tracefile);
-               else
-                       putc('\n', tracefile);
-       }
-       fflush(tracefile);
-}
-
-
-static void
-opentrace() {
-       char s[100];
-#ifdef O_APPEND
-       int flags;
-#endif
-
-       if (!debug)
-               return;
-#ifdef not_this_way
-       {
-               char *p;
-               if ((p = getenv("HOME")) == NULL) {
-                       if (geteuid() == 0)
-                               p = "/";
-                       else
-                               p = "/tmp";
-               }
-               strcpy(s, p);
-               strcat(s, "/trace");
-       }
-#else
-       strcpy(s, "./trace");
-#endif /* not_this_way */
-       if ((tracefile = fopen(s, "a")) == NULL) {
-               fprintf(stderr, "Can't open %s\n", s);
-               return;
-       }
-#ifdef O_APPEND
-       if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
-               fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
-#endif
-       fputs("\nTracing started.\n", tracefile);
-       fflush(tracefile);
-}
-#endif /* DEBUG */
-
-
-/*
- * The trap builtin.
- */
-
-static int
-trapcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *action;
-       char **ap;
-       int signo;
-
-       if (argc <= 1) {
-               for (signo = 0 ; signo < NSIG ; signo++) {
-                       if (trap[signo] != NULL) {
-                               char *p;
-                               const char *sn;
-
-                               p = single_quote(trap[signo]);
-                               sn = sys_siglist[signo];
-                               if(sn==NULL)
-                                       sn = u_signal_names(0, &signo, 0);
-                               if(sn==NULL)
-                                       sn = "???";
-                               printf("trap -- %s %s\n", p, sn);
-                               stunalloc(p);
-                       }
-               }
-               return 0;
-       }
-       ap = argv + 1;
-       if (argc == 2)
-               action = NULL;
-       else
-               action = *ap++;
-       while (*ap) {
-               if ((signo = decode_signal(*ap, 0)) < 0)
-                       error("%s: bad trap", *ap);
-               INTOFF;
-               if (action) {
-                       if (action[0] == '-' && action[1] == '\0')
-                               action = NULL;
-                       else
-                               action = savestr(action);
-               }
-               if (trap[signo])
-                       ckfree(trap[signo]);
-               trap[signo] = action;
-               if (signo != 0)
-                       setsignal(signo);
-               INTON;
-               ap++;
-       }
-       return 0;
-}
-
-
-
-
-
-
-/*
- * Set the signal handler for the specified signal.  The routine figures
- * out what it should be set to.
- */
-
-static void
-setsignal(int signo)
-{
-       int action;
-       char *t;
-       struct sigaction act;
-
-       if ((t = trap[signo]) == NULL)
-               action = S_DFL;
-       else if (*t != '\0')
-               action = S_CATCH;
-       else
-               action = S_IGN;
-       if (rootshell && action == S_DFL) {
-               switch (signo) {
-               case SIGINT:
-                       if (iflag || minusc || sflag == 0)
-                               action = S_CATCH;
-                       break;
-               case SIGQUIT:
-#ifdef DEBUG
-                       {
-
-                       if (debug)
-                               break;
-                       }
-#endif
-                       /* FALLTHROUGH */
-               case SIGTERM:
-                       if (iflag)
-                               action = S_IGN;
-                       break;
-#ifdef JOBS
-               case SIGTSTP:
-               case SIGTTOU:
-                       if (mflag)
-                               action = S_IGN;
-                       break;
-#endif
-               }
-       }
-
-       t = &sigmode[signo - 1];
-       if (*t == 0) {
-               /*
-                * current setting unknown
-                */
-               if (sigaction(signo, 0, &act) == -1) {
-                       /*
-                        * Pretend it worked; maybe we should give a warning
-                        * here, but other shells don't. We don't alter
-                        * sigmode, so that we retry every time.
-                        */
-                       return;
-               }
-               if (act.sa_handler == SIG_IGN) {
-                       if (mflag && (signo == SIGTSTP ||
-                            signo == SIGTTIN || signo == SIGTTOU)) {
-                               *t = S_IGN;     /* don't hard ignore these */
-                       } else
-                               *t = S_HARD_IGN;
-               } else {
-                       *t = S_RESET;   /* force to be set */
-               }
-       }
-       if (*t == S_HARD_IGN || *t == action)
-               return;
-       switch (action) {
-       case S_CATCH:
-               act.sa_handler = onsig;
-               break;
-       case S_IGN:
-               act.sa_handler = SIG_IGN;
-               break;
-       default:
-               act.sa_handler = SIG_DFL;
-       }
-       *t = action;
-       act.sa_flags = 0;
-       sigemptyset(&act.sa_mask);
-       sigaction(signo, &act, 0);
-}
-
-/*
- * Ignore a signal.
- */
-
-static void
-ignoresig(signo)
-       int signo;
-{
-       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
-               signal(signo, SIG_IGN);
-       }
-       sigmode[signo - 1] = S_HARD_IGN;
-}
-
-
-/*
- * Signal handler.
- */
-
-static void
-onsig(int signo)
-{
-       if (signo == SIGINT && trap[SIGINT] == NULL) {
-               onint();
-               return;
-       }
-       gotsig[signo - 1] = 1;
-       pendingsigs++;
-}
-
-
-/*
- * Called to execute a trap.  Perhaps we should avoid entering new trap
- * handlers while we are executing a trap handler.
- */
-
-static void
-dotrap(void)
-{
-       int i;
-       int savestatus;
-
-       for (;;) {
-               for (i = 1 ; ; i++) {
-                       if (gotsig[i - 1])
-                               break;
-                       if (i >= NSIG - 1)
-                               goto done;
-               }
-               gotsig[i - 1] = 0;
-               savestatus=exitstatus;
-               evalstring(trap[i], 0);
-               exitstatus=savestatus;
-       }
-done:
-       pendingsigs = 0;
-}
-
-/*
- * Called to exit the shell.
- */
-
-static void
-exitshell(int status)
-{
-       struct jmploc loc1, loc2;
-       char *p;
-
-       TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
-       if (setjmp(loc1.loc)) {
-               goto l1;
-       }
-       if (setjmp(loc2.loc)) {
-               goto l2;
-       }
-       handler = &loc1;
-       if ((p = trap[0]) != NULL && *p != '\0') {
-               trap[0] = NULL;
-               evalstring(p, 0);
-       }
-l1:   handler = &loc2;                  /* probably unnecessary */
-       flushall();
-#ifdef JOBS
-       setjobctl(0);
-#endif
-l2:   _exit(status);
-       /* NOTREACHED */
-}
-
-static int decode_signal(const char *string, int minsig)
-{
-       int signo;
-       const char *name = u_signal_names(string, &signo, minsig);
-
-       return name ? signo : -1;
-}
-
-static struct var **hashvar (const char *);
-static void showvars (const char *, int, int);
-static struct var **findvar (struct var **, const char *);
-
-/*
- * Initialize the varable symbol tables and import the environment
- */
-
-/*
- * This routine initializes the builtin variables.  It is called when the
- * shell is initialized and again when a shell procedure is spawned.
- */
-
-static void
-initvar() {
-       const struct varinit *ip;
-       struct var *vp;
-       struct var **vpp;
-
-       for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
-               if ((vp->flags & VEXPORT) == 0) {
-                       vpp = hashvar(ip->text);
-                       vp->next = *vpp;
-                       *vpp = vp;
-                       vp->text = strdup(ip->text);
-                       vp->flags = ip->flags;
-                       vp->func = ip->func;
-               }
-       }
-       /*
-        * PS1 depends on uid
-        */
-       if ((vps1.flags & VEXPORT) == 0) {
-               vpp = hashvar("PS1=");
-               vps1.next = *vpp;
-               *vpp = &vps1;
-               vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
-               vps1.flags = VSTRFIXED|VTEXTFIXED;
-       }
-}
-
-/*
- * Set the value of a variable.  The flags argument is ored with the
- * flags of the variable.  If val is NULL, the variable is unset.
- */
-
-static void
-setvar(name, val, flags)
-       const char *name, *val;
-       int flags;
-{
-       const char *p;
-       int len;
-       int namelen;
-       char *nameeq;
-       int isbad;
-       int vallen = 0;
-
-       isbad = 0;
-       p = name;
-       if (! is_name(*p))
-               isbad = 1;
-       p++;
-       for (;;) {
-               if (! is_in_name(*p)) {
-                       if (*p == '\0' || *p == '=')
-                               break;
-                       isbad = 1;
-               }
-               p++;
-       }
-       namelen = p - name;
-       if (isbad)
-               error("%.*s: bad variable name", namelen, name);
-       len = namelen + 2;              /* 2 is space for '=' and '\0' */
-       if (val == NULL) {
-               flags |= VUNSET;
-       } else {
-               len += vallen = strlen(val);
-       }
-       INTOFF;
-       nameeq = ckmalloc(len);
-       memcpy(nameeq, name, namelen);
-       nameeq[namelen] = '=';
-       if (val) {
-               memcpy(nameeq + namelen + 1, val, vallen + 1);
-       } else {
-               nameeq[namelen + 1] = '\0';
-       }
-       setvareq(nameeq, flags);
-       INTON;
-}
-
-
-
-/*
- * Same as setvar except that the variable and value are passed in
- * the first argument as name=value.  Since the first argument will
- * be actually stored in the table, it should not be a string that
- * will go away.
- */
-
-static void
-setvareq(s, flags)
-       char *s;
-       int flags;
-{
-       struct var *vp, **vpp;
-
-       vpp = hashvar(s);
-       flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
-       if ((vp = *findvar(vpp, s))) {
-               if (vp->flags & VREADONLY) {
-                       size_t len = strchr(s, '=') - s;
-                       error("%.*s: is read only", len, s);
-               }
-               INTOFF;
-
-               if (vp->func && (flags & VNOFUNC) == 0)
-                       (*vp->func)(strchr(s, '=') + 1);
-
-               if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
-                       ckfree(vp->text);
-
-               vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
-               vp->flags |= flags;
-               vp->text = s;
-
-               /*
-                * We could roll this to a function, to handle it as
-                * a regular variable function callback, but why bother?
-                */
-               if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
-                       chkmail(1);
-               INTON;
-               return;
-       }
-       /* not found */
-       vp = ckmalloc(sizeof (*vp));
-       vp->flags = flags;
-       vp->text = s;
-       vp->next = *vpp;
-       vp->func = NULL;
-       *vpp = vp;
-}
-
-
-
-/*
- * Process a linked list of variable assignments.
- */
-
-static void
-listsetvar(mylist)
-       struct strlist *mylist;
-       {
-       struct strlist *lp;
-
-       INTOFF;
-       for (lp = mylist ; lp ; lp = lp->next) {
-               setvareq(savestr(lp->text), 0);
-       }
-       INTON;
-}
-
-
-
-/*
- * Find the value of a variable.  Returns NULL if not set.
- */
-
-static const char *
-lookupvar(name)
-       const char *name;
-       {
-       struct var *v;
-
-       if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
-               return strchr(v->text, '=') + 1;
-       }
-       return NULL;
-}
-
-
-
-/*
- * Search the environment of a builtin command.
- */
-
-static const char *
-bltinlookup(const char *name)
-{
-       const struct strlist *sp;
-
-       for (sp = cmdenviron ; sp ; sp = sp->next) {
-               if (varequal(sp->text, name))
-                       return strchr(sp->text, '=') + 1;
-       }
-       return lookupvar(name);
-}
-
-
-
-/*
- * Generate a list of exported variables.  This routine is used to construct
- * the third argument to execve when executing a program.
- */
-
-static char **
-environment() {
-       int nenv;
-       struct var **vpp;
-       struct var *vp;
-       char **env;
-       char **ep;
-
-       nenv = 0;
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next)
-                       if (vp->flags & VEXPORT)
-                               nenv++;
-       }
-       ep = env = stalloc((nenv + 1) * sizeof *env);
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next)
-                       if (vp->flags & VEXPORT)
-                               *ep++ = vp->text;
-       }
-       *ep = NULL;
-       return env;
-}
-
-
-/*
- * Called when a shell procedure is invoked to clear out nonexported
- * variables.  It is also necessary to reallocate variables of with
- * VSTACK set since these are currently allocated on the stack.
- */
-
-static void
-shprocvar(void) {
-       struct var **vpp;
-       struct var *vp, **prev;
-
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (prev = vpp ; (vp = *prev) != NULL ; ) {
-                       if ((vp->flags & VEXPORT) == 0) {
-                               *prev = vp->next;
-                               if ((vp->flags & VTEXTFIXED) == 0)
-                                       ckfree(vp->text);
-                               if ((vp->flags & VSTRFIXED) == 0)
-                                       ckfree(vp);
-                       } else {
-                               if (vp->flags & VSTACK) {
-                                       vp->text = savestr(vp->text);
-                                       vp->flags &=~ VSTACK;
-                               }
-                               prev = &vp->next;
-                       }
-               }
-       }
-       initvar();
-}
-
-
-
-/*
- * Command to list all variables which are set.  Currently this command
- * is invoked from the set command when the set command is called without
- * any variables.
- */
-
-static int
-showvarscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       showvars(nullstr, VUNSET, VUNSET);
-       return 0;
-}
-
-
-
-/*
- * The export and readonly commands.
- */
-
-static int
-exportcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct var *vp;
-       char *name;
-       const char *p;
-       int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
-       int pflag;
-
-       listsetvar(cmdenviron);
-       pflag = (nextopt("p") == 'p');
-       if (argc > 1 && !pflag) {
-               while ((name = *argptr++) != NULL) {
-                       if ((p = strchr(name, '=')) != NULL) {
-                               p++;
-                       } else {
-                               if ((vp = *findvar(hashvar(name), name))) {
-                                       vp->flags |= flag;
-                                       goto found;
-                               }
-                       }
-                       setvar(name, p, flag);
-found:;
-               }
-       } else {
-               showvars(argv[0], flag, 0);
-       }
-       return 0;
-}
-
-
-/*
- * The "local" command.
- */
-
-/* funcnest nonzero if we are currently evaluating a function */
-
-static int
-localcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *name;
-
-       if (! funcnest)
-               error("Not in a function");
-       while ((name = *argptr++) != NULL) {
-               mklocal(name);
-       }
-       return 0;
-}
-
-
-/*
- * Make a variable a local variable.  When a variable is made local, it's
- * value and flags are saved in a localvar structure.  The saved values
- * will be restored when the shell function returns.  We handle the name
- * "-" as a special case.
- */
-
-static void
-mklocal(name)
-       char *name;
-       {
-       struct localvar *lvp;
-       struct var **vpp;
-       struct var *vp;
-
-       INTOFF;
-       lvp = ckmalloc(sizeof (struct localvar));
-       if (name[0] == '-' && name[1] == '\0') {
-               char *p;
-               p = ckmalloc(sizeof optet_vals);
-               lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
-               vp = NULL;
-       } else {
-               vpp = hashvar(name);
-               vp = *findvar(vpp, name);
-               if (vp == NULL) {
-                       if (strchr(name, '='))
-                               setvareq(savestr(name), VSTRFIXED);
-                       else
-                               setvar(name, NULL, VSTRFIXED);
-                       vp = *vpp;      /* the new variable */
-                       lvp->text = NULL;
-                       lvp->flags = VUNSET;
-               } else {
-                       lvp->text = vp->text;
-                       lvp->flags = vp->flags;
-                       vp->flags |= VSTRFIXED|VTEXTFIXED;
-                       if (strchr(name, '='))
-                               setvareq(savestr(name), 0);
-               }
-       }
-       lvp->vp = vp;
-       lvp->next = localvars;
-       localvars = lvp;
-       INTON;
-}
-
-
-/*
- * Called after a function returns.
- */
-
-static void
-poplocalvars() {
-       struct localvar *lvp;
-       struct var *vp;
-
-       while ((lvp = localvars) != NULL) {
-               localvars = lvp->next;
-               vp = lvp->vp;
-               if (vp == NULL) {       /* $- saved */
-                       memcpy(optet_vals, lvp->text, sizeof optet_vals);
-                       ckfree(lvp->text);
-               } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
-                       (void)unsetvar(vp->text);
-               } else {
-                       if ((vp->flags & VTEXTFIXED) == 0)
-                               ckfree(vp->text);
-                       vp->flags = lvp->flags;
-                       vp->text = lvp->text;
-               }
-               ckfree(lvp);
-       }
-}
-
-
-static int
-setvarcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc <= 2)
-               return unsetcmd(argc, argv);
-       else if (argc == 3)
-               setvar(argv[1], argv[2], 0);
-       else
-               error("List assignment not implemented");
-       return 0;
-}
-
-
-/*
- * The unset builtin command.  We unset the function before we unset the
- * variable to allow a function to be unset when there is a readonly variable
- * with the same name.
- */
-
-static int
-unsetcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **ap;
-       int i;
-       int flg_func = 0;
-       int flg_var = 0;
-       int ret = 0;
-
-       while ((i = nextopt("vf")) != '\0') {
-               if (i == 'f')
-                       flg_func = 1;
-               else
-                       flg_var = 1;
-       }
-       if (flg_func == 0 && flg_var == 0)
-               flg_var = 1;
-
-       for (ap = argptr; *ap ; ap++) {
-               if (flg_func)
-                       unsetfunc(*ap);
-               if (flg_var)
-                       ret |= unsetvar(*ap);
-       }
-       return ret;
-}
-
-
-/*
- * Unset the specified variable.
- */
-
-static int
-unsetvar(const char *s)
-{
-       struct var **vpp;
-       struct var *vp;
-
-       vpp = findvar(hashvar(s), s);
-       vp = *vpp;
-       if (vp) {
-               if (vp->flags & VREADONLY)
-                       return (1);
-               INTOFF;
-               if (*(strchr(vp->text, '=') + 1) != '\0')
-                       setvar(s, nullstr, 0);
-               vp->flags &= ~VEXPORT;
-               vp->flags |= VUNSET;
-               if ((vp->flags & VSTRFIXED) == 0) {
-                       if ((vp->flags & VTEXTFIXED) == 0)
-                               ckfree(vp->text);
-                       *vpp = vp->next;
-                       ckfree(vp);
-               }
-               INTON;
-               return (0);
-       }
-
-       return (0);
-}
-
-
-
-/*
- * Find the appropriate entry in the hash table from the name.
- */
-
-static struct var **
-hashvar(const char *p)
-{
-       unsigned int hashval;
-
-       hashval = ((unsigned char) *p) << 4;
-       while (*p && *p != '=')
-               hashval += (unsigned char) *p++;
-       return &vartab[hashval % VTABSIZE];
-}
-
-
-
-/*
- * Returns true if the two strings specify the same varable.  The first
- * variable name is terminated by '='; the second may be terminated by
- * either '=' or '\0'.
- */
-
-static int
-varequal(const char *p, const char *q)
-{
-       while (*p == *q++) {
-               if (*p++ == '=')
-                       return 1;
-       }
-       if (*p == '=' && *(q - 1) == '\0')
-               return 1;
-       return 0;
-}
-
-static void
-showvars(const char *myprefix, int mask, int xor)
-{
-       struct var **vpp;
-       struct var *vp;
-       const char *sep = myprefix == nullstr ? myprefix : spcstr;
-
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next) {
-                       if ((vp->flags & mask) ^ xor) {
-                               char *p;
-                               int len;
-
-                               p = strchr(vp->text, '=') + 1;
-                               len = p - vp->text;
-                               p = single_quote(p);
-
-                               printf("%s%s%.*s%s\n", myprefix, sep, len,
-                                       vp->text, p);
-                               stunalloc(p);
-                       }
-               }
-       }
-}
-
-static struct var **
-findvar(struct var **vpp, const char *name)
-{
-       for (; *vpp; vpp = &(*vpp)->next) {
-               if (varequal((*vpp)->text, name)) {
-                       break;
-               }
-       }
-       return vpp;
-}
-
-/*
- * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
- * This file contains code for the times builtin.
- * $Id: ash.c,v 1.17.2.3 2001/09/06 17:59:36 andersen Exp $
- */
-static int timescmd (int argc, char **argv)
-{
-       struct tms buf;
-       long int clk_tck = sysconf(_SC_CLK_TCK);
-
-       times(&buf);
-       printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
-              (int) (buf.tms_utime / clk_tck / 60),
-              ((double) buf.tms_utime) / clk_tck,
-              (int) (buf.tms_stime / clk_tck / 60),
-              ((double) buf.tms_stime) / clk_tck,
-              (int) (buf.tms_cutime / clk_tck / 60),
-              ((double) buf.tms_cutime) / clk_tck,
-              (int) (buf.tms_cstime / clk_tck / 60),
-              ((double) buf.tms_cstime) / clk_tck);
-       return 0;
-}
-
-#ifdef ASH_MATH_SUPPORT
-/* The let builtin.  */
-int letcmd(int argc, char **argv)
-{
-       int errcode;
-       long result=0;
-       if (argc == 2) {
-               char *tmp, *expression, p[13];
-               expression = strchr(argv[1], '=');
-               if (!expression) {
-                       /* Cannot use 'error()' here, or the return code
-                        * will be incorrect */
-                       out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
-                       return 0;
-               }
-               *expression = '\0';
-               tmp = ++expression;
-               result = arith(tmp, &errcode);
-               if (errcode < 0) {
-                       /* Cannot use 'error()' here, or the return code
-                        * will be incorrect */
-                       out2fmt("sh: let: ");
-                       if(errcode == -2)
-                               out2fmt("divide by zero");
-                       else
-                               out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
-                       return 0;
-               }
-               snprintf(p, 12, "%ld", result);
-               setvar(argv[1], savestr(p), 0);
-       } else if (argc >= 3)
-               synerror("invalid operand");
-       return !result;
-}
-#endif
-
-
-
-/*-
- * Copyright (c) 1989, 1991, 1993, 1994
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
- *
- * 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.
- */
diff --git a/busybox/basename.c b/busybox/basename.c
deleted file mode 100644 (file)
index c15afd5..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini basename implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdlib.h>
-#include "busybox.h"
-#include <string.h>
-
-extern int basename_main(int argc, char **argv)
-{
-       int m, n;
-       char *s;
-
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       argv++;
-
-       s = get_last_path_component(*argv);
-
-       if (argc>2) {
-               argv++;
-               n = strlen(*argv);
-               m = strlen(s);
-               if (m>n && strncmp(s+m-n, *argv, n)==0)
-                       s[m-n] = '\0';
-       }
-       puts(s);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/busybox.c b/busybox/busybox.c
deleted file mode 100644 (file)
index 33efb5d..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-#endif
-
-int been_there_done_that = 0; /* Also used in applets.c */
-const char *applet_name;
-
-#ifdef BB_FEATURE_INSTALLER
-/* 
- * directory table
- *             this should be consistent w/ the enum, busybox.h::Location,
- *             or else...
- */
-static char* install_dir[] = {
-       "/",
-       "/bin",
-       "/sbin",
-       "/usr/bin",
-       "/usr/sbin",
-};
-
-/* abstract link() */
-typedef int (*__link_f)(const char *, const char *);
-
-/* 
- * Where in the filesystem is this busybox?
- * [return]
- *             malloc'd string w/ full pathname of busybox's location
- *             NULL on failure
- */
-static char *busybox_fullpath()
-{
-       return xreadlink("/proc/self/exe");
-}
-
-/* create (sym)links for each applet */
-static void install_links(const char *busybox, int use_symbolic_links)
-{
-       __link_f Link = link;
-
-       char *fpc;
-       int i;
-       int rc;
-
-       if (use_symbolic_links) 
-               Link = symlink;
-
-       for (i = 0; applets[i].name != NULL; i++) {
-               fpc = concat_path_file(
-                       install_dir[applets[i].location], applets[i].name);
-               rc = Link(busybox, fpc);
-               if (rc!=0 && errno!=EEXIST) {
-                       perror_msg("%s", fpc);
-               }
-               free(fpc);
-       }
-}
-
-#endif /* BB_FEATURE_INSTALLER */
-
-int main(int argc, char **argv)
-{
-       const char *s;
-
-       applet_name = argv[0];
-
-       if (applet_name[0] == '-')
-               applet_name++;
-
-       for (s = applet_name; *s != '\0';) {
-               if (*s++ == '/')
-                       applet_name = s;
-       }
-
-#ifdef BB_LOCALE_SUPPORT 
-#ifdef BB_INIT
-       if(getpid()!=1) /* Do not set locale for `init' */
-#endif
-       {
-               setlocale(LC_ALL, "");
-       }
-#endif
-
-       run_applet_by_name(applet_name, argc, argv);
-       error_msg_and_die("applet not found");
-}
-
-
-int busybox_main(int argc, char **argv)
-{
-       int col = 0, len, i;
-
-#ifdef BB_FEATURE_INSTALLER    
-       /* 
-        * This style of argument parsing doesn't scale well 
-        * in the event that busybox starts wanting more --options.
-        * If someone has a cleaner approach, by all means implement it.
-        */
-       if (argc > 1 && (strcmp(argv[1], "--install") == 0)) {
-               int use_symbolic_links = 0;
-               int rc = 0;
-               char *busybox;
-
-               /* to use symlinks, or not to use symlinks... */
-               if (argc > 2) {
-                       if ((strcmp(argv[2], "-s") == 0)) { 
-                               use_symbolic_links = 1; 
-                       }
-               }
-
-               /* link */
-               busybox = busybox_fullpath();
-               if (busybox) {
-                       install_links(busybox, use_symbolic_links);
-                       free(busybox);
-               } else {
-                       rc = 1;
-               }
-               return rc;
-       }
-#endif /* BB_FEATURE_INSTALLER */
-
-       argc--;
-
-       /* If we've already been here once, exit now */
-       if (been_there_done_that == 1 || argc < 1) {
-               const struct BB_applet *a = applets;
-
-               fprintf(stderr, "%s\n\n"
-                               "Usage: busybox [function] [arguments]...\n"
-                               "   or: [function] [arguments]...\n\n"
-                               "\tBusyBox is a multi-call binary that combines many common Unix\n"
-                               "\tutilities into a single executable.  Most people will create a\n"
-                               "\tlink to busybox for each function they wish to use, and BusyBox\n"
-                               "\twill act like whatever it was invoked as.\n" 
-                               "\nCurrently defined functions:\n", full_version);
-
-               while (a->name != 0) {
-                       col +=
-                               fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
-                                               (a++)->name);
-                       if (col > 60 && a->name != 0) {
-                               fprintf(stderr, ",\n");
-                               col = 0;
-                       }
-               }
-               fprintf(stderr, "\n\n");
-               exit(0);
-       }
-
-       /* Flag that we've been here already */
-       been_there_done_that = 1;
-       
-       /* Move the command line down a notch */
-       len = argv[argc] + strlen(argv[argc]) - argv[1];
-       memmove(argv[0], argv[1], len);
-       memset(argv[0] + len, 0, argv[1] - argv[0]);
-
-       /* Fix up the argv pointers */
-       len = argv[1] - argv[0];
-       memmove(argv, argv + 1, sizeof(char *) * (argc + 1));
-       for (i = 0; i < argc; i++)
-               argv[i] -= len;
-
-       return (main(argc, argv));
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/busybox.h b/busybox/busybox.h
deleted file mode 100644 (file)
index f79dac8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Busybox main internal header file
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-#ifndef        _BB_INTERNAL_H_
-#define        _BB_INTERNAL_H_    1
-
-#include "Config.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")"
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#include <features.h>
-
-
-enum Location {
-       _BB_DIR_ROOT = 0,
-       _BB_DIR_BIN,
-       _BB_DIR_SBIN,
-       _BB_DIR_USR_BIN,
-       _BB_DIR_USR_SBIN
-};
-
-struct BB_applet {
-       const   char*   name;
-       int     (*main)(int argc, char** argv);
-       enum    Location        location;
-};
-/* From busybox.c */
-extern const struct BB_applet applets[];
-
-/* Automagically pull in all the applet function prototypes and
- * applet usage strings.  These are all of the form:
- *             extern int foo_main(int argc, char **argv);
- *             extern const char foo_usage[];
- * These are all autogenerated from the set of currently defined applets. 
- */
-#define PROTOTYPES
-#include "applets.h"
-#undef PROTOTYPES
-
-#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK
-#define RESERVE_BB_BUFFER(buffer,len)           char buffer[len]
-#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len]
-#define RELEASE_BB_BUFFER(buffer)      ((void)0)
-#else
-#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS
-#define RESERVE_BB_BUFFER(buffer,len)  static          char buffer[len]
-#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len]
-#define RELEASE_BB_BUFFER(buffer)      ((void)0)
-#else
-#define RESERVE_BB_BUFFER(buffer,len)           char *buffer=xmalloc(len)
-#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len)
-#define RELEASE_BB_BUFFER(buffer)      free (buffer)
-#endif
-#endif
-
-
-/* Bit map related macros -- libc5 doens't provide these... sigh.  */
-#ifndef setbit
-#define NBBY            CHAR_BIT
-#define setbit(a,i)     ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
-#define clrbit(a,i)     ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
-#define isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
-#define isclr(a,i)      (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
-#endif
-
-#ifndef RB_POWER_OFF
-/* Stop system and switch power off if possible.  */
-#define RB_POWER_OFF   0x4321fedc
-#endif
-
-
-/* Pull in the utility routines from libbb */
-#include "libbb/libbb.h"
-
-
-
-#endif /* _BB_INTERNAL_H_ */
diff --git a/busybox/busybox.mkll b/busybox/busybox.mkll
deleted file mode 100755 (executable)
index 4e15e16..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# Make busybox links list file.
-
-# input $1: full path to Config.h
-# input $2: full path to applets.h
-# output (stdout): list of pathnames that should be linked to busybox
-
-# Maintainer: Larry Doolittle <ldoolitt@recycle.lbl.gov>
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-CONFIG_H=${1:-Config.h}
-APPLETS_H=${2:-applets.h}
-gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H |
-  awk '/^[ \t]*LINK/{
-       dir=substr($2,8)
-       gsub("_","/",dir)
-       if(dir=="/ROOT") dir=""
-       file=$3
-       gsub("\"","",file)
-       if (file=="busybox") next
-       print tolower(dir) "/" file
-  }'
diff --git a/busybox/busybox.sh b/busybox/busybox.sh
deleted file mode 100755 (executable)
index 9ab0f4b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-RAW=` \
-    $CC -E -dM ${1:-Config.h} | \
-    sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\<BB_\(.*\)\>/\1.c/gp;' \
-    | tr A-Z a-z | sort
-`
-test "${RAW}" != "" ||  exit
-if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi
-# By running $RAW through "ls", we avoid listing
-# source files that don't exist.
-ls $RAW 2>/dev/null | tr '\n' ' '
-
diff --git a/busybox/busybox.spec b/busybox/busybox.spec
deleted file mode 100644 (file)
index 5cf13ca..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-%define name   busybox
-%define epoch   0
-%define version        0.60.2.pre
-%define release        %(date -I | sed -e 's/-/_/g')
-%define serial  1
-
-Name:   %{name}
-#Epoch:   %{epoch}
-Version: %{version}
-Release: %{release}
-Serial:         %{serial}
-Copyright: GPL
-Group: System/Utilities
-Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
-URL:    http://busybox.lineo.com/
-Source:         ftp://oss.lineo.com/busybox/%{name}-%{version}.tar.gz
-Buildroot: /var/tmp/%{name}-%{version}
-Packager : Erik Andersen <andersen@lineo.com>
-
-%Description
-BusyBox combines tiny versions of many common UNIX utilities into a single
-small executable. It provides minimalist replacements for most of the utilities
-you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
-tar, etc.  BusyBox provides a fairly complete POSIX environment for any small
-or emdedded system.  The utilities in BusyBox generally have fewer options then
-their full featured GNU cousins; however, the options that are provided behave
-very much like their GNU counterparts.
-
-%Prep
-%setup -q -n %{name}-%{version}
-
-%Build
-make
-
-%Install
-rm -rf $RPM_BUILD_ROOT
-make PREFIX=$RPM_BUILD_ROOT install
-
-%Clean
-rm -rf $RPM_BUILD_ROOT
-
-%Files 
-%defattr(-,root,root)
-/
diff --git a/busybox/cat.c b/busybox/cat.c
deleted file mode 100644 (file)
index aa8528d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini Cat implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-extern int cat_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-
-       if (argc == 1) {
-               print_file(stdin);
-               return status;
-       }
-
-       while (--argc > 0) {
-               if(!(strcmp(*++argv, "-"))) {
-                       print_file(stdin);
-               } else if (print_file_by_name(*argv) == FALSE) {
-                       status = EXIT_FAILURE;
-               }
-       }
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/chgrp.c b/busybox/chgrp.c
deleted file mode 100644 (file)
index fbc1036..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Don't use lchown for libc5 or glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
-
-
-static long gid;
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
-               return (TRUE);
-       }
-       perror(fileName);
-       return (FALSE);
-}
-
-int chgrp_main(int argc, char **argv)
-{
-       int opt;
-       int recursiveFlag = FALSE;
-       char *p=NULL;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "R")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* Find the selected group */
-               gid = strtoul(argv[optind], &p, 10);    /* maybe it's already numeric */
-               if (argv[optind] == p)
-                       gid = my_getgrnam(argv[optind]);
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       while (++optind < argc) {
-               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
-                                       fileAction, fileAction, NULL) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/chmod.c b/busybox/chmod.c
deleted file mode 100644 (file)
index 9139b3f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (!parse_mode((char *)junk, &(statbuf->st_mode)))
-               error_msg_and_die("internal error");
-       if (chmod(fileName, statbuf->st_mode) == 0)
-               return (TRUE);
-       perror(fileName);
-       return (FALSE);
-}
-
-int chmod_main(int argc, char **argv)
-{
-       int i;
-       int opt;
-       int recursiveFlag = FALSE;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "R")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* Parse the specified mode */
-               mode_t mode;
-               if (parse_mode(argv[optind], &mode) == FALSE) {
-                       error_msg_and_die( "unknown mode: %s", argv[optind]);
-               }
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       for (i = optind + 1; i < argc; i++) {
-               if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction,
-                                       fileAction, argv[optind]) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/chown.c b/busybox/chown.c
deleted file mode 100644 (file)
index d1e52de..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Don't use lchown for libc5 or glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
-
-static long uid;
-static long gid;
-
-static int (*chown_func)(const char *, __uid_t, __gid_t) = chown;
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (chown_func(fileName, uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
-               return (TRUE);
-       }
-       perror(fileName);
-       return (FALSE);
-}
-
-int chown_main(int argc, char **argv)
-{
-       int opt;
-       int recursiveFlag = FALSE,
-               noderefFlag = FALSE;
-       char *groupName=NULL;
-       char *p=NULL;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "Rh")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       case 'h':
-                               noderefFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (noderefFlag) chown_func = lchown;
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* First, check if there is a group name here */
-               groupName = strchr(argv[optind], '.');
-               if (groupName == NULL)
-                       groupName = strchr(argv[optind], ':');
-               if (groupName) {
-                       *groupName++ = '\0';
-                       gid = strtoul(groupName, &p, 10);
-                       if (groupName == p)
-                               gid = my_getgrnam(groupName);
-               } else {
-                       gid = -1;
-               }
-               /* Now check for the username */
-               uid = strtoul(argv[optind], &p, 10);    /* Is is numeric? */
-               if (argv[optind] == p) {
-                       uid = my_getpwnam(argv[optind]);
-               }
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       while (++optind < argc) {
-               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
-                                       fileAction, fileAction, NULL) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/chroot.c b/busybox/chroot.c
deleted file mode 100644 (file)
index de6a2ea..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chroot implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include "busybox.h"
-
-int chroot_main(int argc, char **argv)
-{
-       char *prog;
-
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-       argc--;
-       argv++;
-
-       if (chroot(*argv) || (chdir("/"))) {
-               perror_msg_and_die("cannot change root directory to %s", *argv);
-       }
-
-       argc--;
-       argv++;
-       if (argc >= 1) {
-               prog = *argv;
-               execvp(*argv, argv);
-       } else {
-#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL
-               char shell[] = "/bin/sh";
-               char *shell_argv[2] = { shell, NULL };
-               applet_name = shell;
-               shell_main(1, shell_argv);
-               return EXIT_SUCCESS;
-#else
-               prog = getenv("SHELL");
-               if (!prog)
-                       prog = "/bin/sh";
-               execlp(prog, prog, NULL);
-#endif
-       }
-       perror_msg_and_die("cannot execute %s", prog);
-
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/chvt.c b/busybox/chvt.c
deleted file mode 100644 (file)
index c76e9c7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * chvt.c - aeb - 940227 - Change virtual terminal
- *
- * busyboxed by Erik Andersen
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/vt.h> */
-static const int VT_ACTIVATE = 0x5606;  /* make vt active */
-static const int VT_WAITACTIVE = 0x5607;  /* wait for vt active */
-
-int chvt_main(int argc, char **argv)
-{
-       int fd, num;
-
-       if ((argc != 2) || (**(argv + 1) == '-'))
-               show_usage();
-       fd = get_console_fd("/dev/console");
-       num = atoi(argv[1]);
-       if (ioctl(fd, VT_ACTIVATE, num))
-               perror_msg_and_die("VT_ACTIVATE");
-       if (ioctl(fd, VT_WAITACTIVE, num))
-               perror_msg_and_die("VT_WAITACTIVE");
-       return EXIT_SUCCESS;
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/clear.c b/busybox/clear.c
deleted file mode 100644 (file)
index 503bafa..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini clear implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-extern int clear_main(int argc, char **argv)
-{
-       printf("\033[H\033[J");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/cmdedit.c b/busybox/cmdedit.c
deleted file mode 100644 (file)
index 16ec2f8..0000000
+++ /dev/null
@@ -1,1521 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Termios command line History and Editting.
- *
- * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license.
- * Written by:   Vladimir Oleynik <dzo@simtreas.ru>
- *
- * Used ideas:
- *      Adam Rogoyski    <rogoyski@cs.utexas.edu>
- *      Dave Cinege      <dcinege@psychosis.com>
- *      Jakub Jelinek (c) 1995
- *      Erik Andersen    <andersee@debian.org> (Majorly adjusted for busybox)
- *
- * This code is 'as is' with no warranty.
- *
- *
- */
-
-/*
-   Usage and Known bugs:
-   Terminal key codes are not extensive, and more will probably
-   need to be added. This version was created on Debian GNU/Linux 2.x.
-   Delete, Backspace, Home, End, and the arrow keys were tested
-   to work in an Xterm and console. Ctrl-A also works as Home.
-   Ctrl-E also works as End.
-
-   Small bugs (simple effect):
-   - not true viewing if terminal size (x*y symbols) less
-     size (prompt + editor`s line + 2 symbols)
-   - not true viewing if length prompt less terminal width
- */
-
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <limits.h>
-
-#include "busybox.h"
-
-#ifdef BB_LOCALE_SUPPORT
-#define Isprint(c) isprint((c))
-#else
-#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
-#endif
-
-#ifndef TEST
-
-#define D(x)
-
-#else
-
-#define BB_FEATURE_COMMAND_EDITING
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-#define BB_FEATURE_CLEAN_UP
-
-#define D(x)  x
-
-#endif                                                 /* TEST */
-
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-#include <dirent.h>
-#include <sys/stat.h>
-#endif
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-
-#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION
-#undef  BB_FEATURE_COMMAND_USERNAME_COMPLETION
-#endif
-
-#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT)
-#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-#endif
-
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-#       ifndef TEST
-#               include "pwd_grp/pwd.h"
-#       else
-#               include <pwd.h>
-#       endif  /* TEST */
-#endif                                                 /* advanced FEATURES */
-
-
-
-struct history {
-       char *s;
-       struct history *p;
-       struct history *n;
-};
-
-/* Maximum length of the linked list for the command line history */
-static const int MAX_HISTORY = 15;
-
-/* First element in command line list */
-static struct history *his_front = NULL;
-
-/* Last element in command line list */
-static struct history *his_end = NULL;
-
-
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
-#define getTermSettings(fd,argp) tcgetattr(fd, argp);
-
-/* Current termio and the previous termio before starting sh */
-static struct termios initial_settings, new_settings;
-
-
-static
-volatile int cmdedit_termw = 80;       /* actual terminal width */
-static int history_counter = 0;        /* Number of commands in history list */
-static
-volatile int handlers_sets = 0;        /* Set next bites: */
-
-enum {
-       SET_ATEXIT = 1,         /* when atexit() has been called 
-                                  and get euid,uid,gid to fast compare */
-       SET_WCHG_HANDLERS = 2,  /* winchg signal handler */
-       SET_RESET_TERM = 4,     /* if the terminal needs to be reset upon exit */
-};
-
-
-static int cmdedit_x;          /* real x terminal position */
-static int cmdedit_y;          /* pseudoreal y terminal position */
-static int cmdedit_prmt_len;   /* lenght prompt without colores string */
-
-static int cursor;             /* required global for signal handler */
-static int len;                        /* --- "" - - "" - -"- --""-- --""--- */
-static char *command_ps;       /* --- "" - - "" - -"- --""-- --""--- */
-static
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       const
-#endif
-char *cmdedit_prompt;          /* --- "" - - "" - -"- --""-- --""--- */
-
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-static char *user_buf = "";
-static char *home_pwd_buf = "";
-static int my_euid;
-#endif
-
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-static char *hostname_buf = "";
-static int num_ok_lines = 1;
-#endif
-
-
-#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
-
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-static int my_euid;
-#endif
-
-static int my_uid;
-static int my_gid;
-
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-
-/* It seems that libc5 doesn't know what a sighandler_t is... */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-typedef void (*sighandler_t) (int);
-#endif
-
-static void cmdedit_setwidth(int w, int redraw_flg);
-
-static void win_changed(int nsig)
-{
-       struct winsize win = { 0, 0, 0, 0 };
-       static sighandler_t previous_SIGWINCH_handler;  /* for reset */
-
-       /*   emulate      || signal call */
-       if (nsig == -SIGWINCH || nsig == SIGWINCH) {
-               ioctl(0, TIOCGWINSZ, &win);
-               if (win.ws_col > 0) {
-                       cmdedit_setwidth(win.ws_col, nsig == SIGWINCH);
-               } 
-       }
-       /* Unix not all standart in recall signal */
-
-       if (nsig == -SIGWINCH)          /* save previous handler   */
-               previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
-       else if (nsig == SIGWINCH)      /* signaled called handler */
-               signal(SIGWINCH, win_changed);  /* set for next call       */
-       else                                            /* nsig == 0 */
-               /* set previous handler    */
-               signal(SIGWINCH, previous_SIGWINCH_handler);    /* reset    */
-}
-
-static void cmdedit_reset_term(void)
-{
-       if ((handlers_sets & SET_RESET_TERM) != 0) {
-/* sparc and other have broken termios support: use old termio handling. */
-               setTermSettings(fileno(stdin), (void *) &initial_settings);
-               handlers_sets &= ~SET_RESET_TERM;
-       }
-       if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
-               /* reset SIGWINCH handler to previous (default) */
-               win_changed(0);
-               handlers_sets &= ~SET_WCHG_HANDLERS;
-       }
-       fflush(stdout);
-#ifdef BB_FEATURE_CLEAN_UP
-       if (his_front) {
-               struct history *n;
-
-               while (his_front != his_end) {
-                       n = his_front->n;
-                       free(his_front->s);
-                       free(his_front);
-                       his_front = n;
-               }
-       }
-#endif
-}
-
-
-/* special for recount position for scroll and remove terminal margin effect */
-static void cmdedit_set_out_char(int next_char)
-{
-
-       int c = (int)((unsigned char) command_ps[cursor]);
-
-       if (c == 0)
-               c = ' ';        /* destroy end char? */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-       if (!Isprint(c)) {      /* Inverse put non-printable characters */
-               if (c >= 128)
-                       c -= 128;
-               if (c < ' ')
-                       c += '@';
-               if (c == 127)
-                       c = '?';
-               printf("\033[7m%c\033[0m", c);
-       } else
-#endif
-               putchar(c);
-       if (++cmdedit_x >= cmdedit_termw) {
-               /* terminal is scrolled down */
-               cmdedit_y++;
-               cmdedit_x = 0;
-
-               if (!next_char)
-                       next_char = ' ';
-               /* destroy "(auto)margin" */
-               putchar(next_char);
-               putchar('\b');
-       }
-       cursor++;
-}
-
-/* Move to end line. Bonus: rewrite line from cursor */
-static void input_end(void)
-{
-       while (cursor < len)
-               cmdedit_set_out_char(0);
-}
-
-/* Go to the next line */
-static void goto_new_line(void)
-{
-       input_end();
-       if (cmdedit_x)
-               putchar('\n');
-}
-
-
-static inline void out1str(const char *s)
-{
-       fputs(s, stdout);
-}
-static inline void beep(void)
-{
-       putchar('\007');
-}
-
-/* Move back one charactor */
-/* special for slow terminal */
-static void input_backward(int num)
-{
-       if (num > cursor)
-               num = cursor;
-       cursor -= num;          /* new cursor (in command, not terminal) */
-
-       if (cmdedit_x >= num) {         /* no to up line */
-               cmdedit_x -= num;
-               if (num < 4)
-                       while (num-- > 0)
-                               putchar('\b');
-
-               else
-                       printf("\033[%dD", num);
-       } else {
-               int count_y;
-
-               if (cmdedit_x) {
-                       putchar('\r');          /* back to first terminal pos.  */
-                       num -= cmdedit_x;       /* set previous backward        */
-               }
-               count_y = 1 + num / cmdedit_termw;
-               printf("\033[%dA", count_y);
-               cmdedit_y -= count_y;
-               /*  require  forward  after  uping   */
-               cmdedit_x = cmdedit_termw * count_y - num;
-               printf("\033[%dC", cmdedit_x);  /* set term cursor   */
-       }
-}
-
-static void put_prompt(void)
-{
-       out1str(cmdedit_prompt);
-       cmdedit_x = cmdedit_prmt_len;   /* count real x terminal position */
-       cursor = 0;
-       cmdedit_y = 0;                  /* new quasireal y */
-}
-
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-static void parse_prompt(const char *prmt_ptr)
-{
-       cmdedit_prompt = prmt_ptr;
-       cmdedit_prmt_len = strlen(prmt_ptr);
-       put_prompt();
-}
-#else
-static void parse_prompt(const char *prmt_ptr)
-{
-       int prmt_len = 0;
-       int sub_len = 0;
-       char  flg_not_length = '[';
-       char *prmt_mem_ptr = xcalloc(1, 1);
-       char *pwd_buf = xgetcwd(0);
-       char  buf2[PATH_MAX + 1];
-       char  buf[2];
-       char  c;
-       char *pbuf;
-
-       if (!pwd_buf) {
-               pwd_buf=(char *)unknown;
-       }
-
-       while (*prmt_ptr) {
-               pbuf    = buf;
-               pbuf[1] = 0;
-               c = *prmt_ptr++;
-               if (c == '\\') {
-                       const char *cp = prmt_ptr;
-                       int l;
-                       
-                       c = process_escape_sequence(&prmt_ptr);
-                       if(prmt_ptr==cp) {
-                         if (*cp == 0)
-                               break;
-                         c = *prmt_ptr++;
-                         switch (c) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'u':
-                               pbuf = user_buf;
-                               break;
-#endif 
-                         case 'h':
-                               pbuf = hostname_buf;
-                               if (*pbuf == 0) {
-                                       pbuf = xcalloc(256, 1);
-                                       if (gethostname(pbuf, 255) < 0) {
-                                               strcpy(pbuf, "?");
-                                       } else {
-                                               char *s = strchr(pbuf, '.');
-
-                                               if (s)
-                                                       *s = 0;
-                                       }
-                                       hostname_buf = pbuf;
-                               }
-                               break;
-                         case '$':
-                               c = my_euid == 0 ? '#' : '$';
-                               break;
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'w':
-                               pbuf = pwd_buf;
-                               l = strlen(home_pwd_buf);
-                               if (home_pwd_buf[0] != 0 &&
-                                   strncmp(home_pwd_buf, pbuf, l) == 0 &&
-                                   (pbuf[l]=='/' || pbuf[l]=='\0') &&
-                                   strlen(pwd_buf+l)<PATH_MAX) {
-                                       pbuf = buf2;
-                                       *pbuf = '~';
-                                       strcpy(pbuf+1, pwd_buf+l);
-                                       }
-                               break;
-#endif 
-                         case 'W':
-                               pbuf = pwd_buf;
-                               cp = strrchr(pbuf,'/');
-                               if ( (cp != NULL) && (cp != pbuf) )
-                                       pbuf += (cp-pbuf)+1;
-                               break;
-                         case '!':
-                               snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
-                               break;
-                         case 'e': case 'E':     /* \e \E = \033 */
-                               c = '\033';
-                               break;
-                         case 'x': case 'X': 
-                               for (l = 0; l < 3;) {
-                                       int h;
-                                       buf2[l++] = *prmt_ptr;
-                                       buf2[l] = 0;
-                                       h = strtol(buf2, &pbuf, 16);
-                                       if (h > UCHAR_MAX || (pbuf - buf2) < l) {
-                                               l--;
-                                               break;
-                                       }
-                                       prmt_ptr++;
-                               }
-                               buf2[l] = 0;
-                               c = (char)strtol(buf2, 0, 16);
-                               if(c==0)
-                                       c = '?';
-                               pbuf = buf;
-                               break;
-                         case '[': case ']':
-                               if (c == flg_not_length) {
-                                       flg_not_length = flg_not_length == '[' ? ']' : '[';
-                                       continue;
-                               }
-                               break;
-                         }
-                       } 
-               }
-               if(pbuf == buf)
-                       *pbuf = c;
-               prmt_len += strlen(pbuf);
-               prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
-               if (flg_not_length == ']')
-                       sub_len++;
-       }
-       if(pwd_buf!=(char *)unknown)
-               free(pwd_buf);
-       cmdedit_prompt = prmt_mem_ptr;
-       cmdedit_prmt_len = prmt_len - sub_len;
-       put_prompt();
-}
-#endif
-
-
-/* draw promt, editor line, and clear tail */
-static void redraw(int y, int back_cursor)
-{
-       if (y > 0)                              /* up to start y */
-               printf("\033[%dA", y);
-       putchar('\r');
-       put_prompt();
-       input_end();                            /* rewrite */
-       printf("\033[J");                       /* destroy tail after cursor */
-       input_backward(back_cursor);
-}
-
-/* Delete the char in front of the cursor */
-static void input_delete(void)
-{
-       int j = cursor;
-
-       if (j == len)
-               return;
-
-       strcpy(command_ps + j, command_ps + j + 1);
-       len--;
-       input_end();                    /* rewtite new line */
-       cmdedit_set_out_char(0);        /* destroy end char */
-       input_backward(cursor - j);     /* back to old pos cursor */
-}
-
-/* Delete the char in back of the cursor */
-static void input_backspace(void)
-{
-       if (cursor > 0) {
-               input_backward(1);
-               input_delete();
-       }
-}
-
-
-/* Move forward one charactor */
-static void input_forward(void)
-{
-       if (cursor < len)
-               cmdedit_set_out_char(command_ps[cursor + 1]);
-}
-
-
-static void cmdedit_setwidth(int w, int redraw_flg)
-{
-       cmdedit_termw = cmdedit_prmt_len + 2;
-       if (w <= cmdedit_termw) {
-               cmdedit_termw = cmdedit_termw % w;
-       }
-       if (w > cmdedit_termw) {
-               cmdedit_termw = w;
-
-               if (redraw_flg) {
-                       /* new y for current cursor */
-                       int new_y = (cursor + cmdedit_prmt_len) / w;
-
-                       /* redraw */
-                       redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
-                       fflush(stdout);
-               }
-       } 
-}
-
-static void cmdedit_init(void)
-{
-       cmdedit_prmt_len = 0;
-       if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
-               /* emulate usage handler to set handler and call yours work */
-               win_changed(-SIGWINCH);
-               handlers_sets |= SET_WCHG_HANDLERS;
-       }
-
-       if ((handlers_sets & SET_ATEXIT) == 0) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-               struct passwd *entry;
-
-               my_euid = geteuid();
-               entry = getpwuid(my_euid);
-               if (entry) {
-                       user_buf = xstrdup(entry->pw_name);
-                       home_pwd_buf = xstrdup(entry->pw_dir);
-               }
-#endif
-
-#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
-
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-               my_euid = geteuid();
-#endif
-               my_uid = getuid();
-               my_gid = getgid();
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-               handlers_sets |= SET_ATEXIT;
-               atexit(cmdedit_reset_term);     /* be sure to do this only once */
-       }
-}
-
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-
-static int is_execute(const struct stat *st)
-{
-       if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
-               (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
-               (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
-               (st->st_mode & S_IXOTH)) return TRUE;
-       return FALSE;
-}
-
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-
-static char **username_tab_completion(char *ud, int *num_matches)
-{
-       struct passwd *entry;
-       int userlen;
-       char *temp;
-
-
-       ud++;                           /* ~user/... to user/... */
-       userlen = strlen(ud);
-
-       if (num_matches == 0) {         /* "~/..." or "~user/..." */
-               char *sav_ud = ud - 1;
-               char *home = 0;
-
-               if (*ud == '/') {       /* "~/..."     */
-                       home = home_pwd_buf;
-               } else {
-                       /* "~user/..." */
-                       temp = strchr(ud, '/');
-                       *temp = 0;              /* ~user\0 */
-                       entry = getpwnam(ud);
-                       *temp = '/';            /* restore ~user/... */
-                       ud = temp;
-                       if (entry)
-                               home = entry->pw_dir;
-               }
-               if (home) {
-                       if ((userlen + strlen(home) + 1) < BUFSIZ) {
-                               char temp2[BUFSIZ];     /* argument size */
-
-                               /* /home/user/... */
-                               sprintf(temp2, "%s%s", home, ud);
-                               strcpy(sav_ud, temp2);
-                       }
-               }
-               return 0;       /* void, result save to argument :-) */
-       } else {
-               /* "~[^/]*" */
-               char **matches = (char **) NULL;
-               int nm = 0;
-
-               setpwent();
-
-               while ((entry = getpwent()) != NULL) {
-                       /* Null usernames should result in all users as possible completions. */
-                       if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
-
-                               temp = xmalloc(3 + strlen(entry->pw_name));
-                               sprintf(temp, "~%s/", entry->pw_name);
-                               matches = xrealloc(matches, (nm + 1) * sizeof(char *));
-
-                               matches[nm++] = temp;
-                       }
-               }
-
-               endpwent();
-               (*num_matches) = nm;
-               return (matches);
-       }
-}
-#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */
-
-enum {
-       FIND_EXE_ONLY = 0,
-       FIND_DIR_ONLY = 1,
-       FIND_FILE_ONLY = 2,
-};
-
-static int path_parse(char ***p, int flags)
-{
-       int npth;
-       char *tmp;
-       char *pth;
-
-       /* if not setenv PATH variable, to search cur dir "." */
-       if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 ||
-               /* PATH=<empty> or PATH=:<empty> */
-               *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
-               return 1;
-       }
-
-       tmp = pth;
-       npth = 0;
-
-       for (;;) {
-               npth++;                 /* count words is + 1 count ':' */
-               tmp = strchr(tmp, ':');
-               if (tmp) {
-                       if (*++tmp == 0)
-                               break;  /* :<empty> */
-               } else
-                       break;
-       }
-
-       *p = xmalloc(npth * sizeof(char *));
-
-       tmp = pth;
-       (*p)[0] = xstrdup(tmp);
-       npth = 1;                       /* count words is + 1 count ':' */
-
-       for (;;) {
-               tmp = strchr(tmp, ':');
-               if (tmp) {
-                       (*p)[0][(tmp - pth)] = 0;       /* ':' -> '\0' */
-                       if (*++tmp == 0)
-                               break;                  /* :<empty> */
-               } else
-                       break;
-               (*p)[npth++] = &(*p)[0][(tmp - pth)];   /* p[next]=p[0][&'\0'+1] */
-       }
-
-       return npth;
-}
-
-static char *add_quote_for_spec_chars(char *found)
-{
-       int l = 0;
-       char *s = xmalloc((strlen(found) + 1) * 2);
-
-       while (*found) {
-               if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
-                       s[l++] = '\\';
-               s[l++] = *found++;
-       }
-       s[l] = 0;
-       return s;
-}
-
-static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
-                                       int type)
-{
-
-       char **matches = 0;
-       DIR *dir;
-       struct dirent *next;
-       char dirbuf[BUFSIZ];
-       int nm = *num_matches;
-       struct stat st;
-       char *path1[1];
-       char **paths = path1;
-       int npaths;
-       int i;
-       char *found;
-       char *pfind = strrchr(command, '/');
-
-       path1[0] = ".";
-
-       if (pfind == NULL) {
-               /* no dir, if flags==EXE_ONLY - get paths, else "." */
-               npaths = path_parse(&paths, type);
-               pfind = command;
-       } else {
-               /* with dir */
-               /* save for change */
-               strcpy(dirbuf, command);
-               /* set dir only */
-               dirbuf[(pfind - command) + 1] = 0;
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               if (dirbuf[0] == '~')   /* ~/... or ~user/... */
-                       username_tab_completion(dirbuf, 0);
-#endif
-               /* "strip" dirname in command */
-               pfind++;
-
-               paths[0] = dirbuf;
-               npaths = 1;                             /* only 1 dir */
-       }
-
-       for (i = 0; i < npaths; i++) {
-
-               dir = opendir(paths[i]);
-               if (!dir)                       /* Don't print an error */
-                       continue;
-
-               while ((next = readdir(dir)) != NULL) {
-                       char *str_found = next->d_name;
-
-                       /* matched ? */
-                       if (strncmp(str_found, pfind, strlen(pfind)))
-                               continue;
-                       /* not see .name without .match */
-                       if (*str_found == '.' && *pfind == 0) {
-                               if (*paths[i] == '/' && paths[i][1] == 0
-                                       && str_found[1] == 0) str_found = "";   /* only "/" */
-                               else
-                                       continue;
-                       }
-                       found = concat_path_file(paths[i], str_found);
-                       /* hmm, remover in progress? */
-                       if (stat(found, &st) < 0) 
-                               goto cont;
-                       /* find with dirs ? */
-                       if (paths[i] != dirbuf)
-                               strcpy(found, next->d_name);    /* only name */
-                       if (S_ISDIR(st.st_mode)) {
-                               /* name is directory      */
-                               str_found = found;
-                               found = concat_path_file(found, "");
-                               free(str_found);
-                               str_found = add_quote_for_spec_chars(found);
-                       } else {
-                               /* not put found file if search only dirs for cd */
-                               if (type == FIND_DIR_ONLY) 
-                                       goto cont;
-                               str_found = add_quote_for_spec_chars(found);
-                               if (type == FIND_FILE_ONLY ||
-                                       (type == FIND_EXE_ONLY && is_execute(&st) == TRUE))
-                                       strcat(str_found, " ");
-                       }
-                       /* Add it to the list */
-                       matches = xrealloc(matches, (nm + 1) * sizeof(char *));
-
-                       matches[nm++] = str_found;
-cont:
-                       free(found);
-               }
-               closedir(dir);
-       }
-       if (paths != path1) {
-               free(paths[0]);                 /* allocated memory only in first member */
-               free(paths);
-       }
-       *num_matches = nm;
-       return (matches);
-}
-
-static int match_compare(const void *a, const void *b)
-{
-       return strcmp(*(char **) a, *(char **) b);
-}
-
-
-
-#define QUOT    (UCHAR_MAX+1)
-
-#define collapse_pos(is, in) { \
-       memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \
-       memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); }
-
-static int find_match(char *matchBuf, int *len_with_quotes)
-{
-       int i, j;
-       int command_mode;
-       int c, c2;
-       int int_buf[BUFSIZ + 1];
-       int pos_buf[BUFSIZ + 1];
-
-       /* set to integer dimension characters and own positions */
-       for (i = 0;; i++) {
-               int_buf[i] = (int) ((unsigned char) matchBuf[i]);
-               if (int_buf[i] == 0) {
-                       pos_buf[i] = -1;        /* indicator end line */
-                       break;
-               } else
-                       pos_buf[i] = i;
-       }
-
-       /* mask \+symbol and convert '\t' to ' ' */
-       for (i = j = 0; matchBuf[i]; i++, j++)
-               if (matchBuf[i] == '\\') {
-                       collapse_pos(j, j + 1);
-                       int_buf[j] |= QUOT;
-                       i++;
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-                       if (matchBuf[i] == '\t')        /* algorithm equivalent */
-                               int_buf[j] = ' ' | QUOT;
-#endif
-               }
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-               else if (matchBuf[i] == '\t')
-                       int_buf[j] = ' ';
-#endif
-
-       /* mask "symbols" or 'symbols' */
-       c2 = 0;
-       for (i = 0; int_buf[i]; i++) {
-               c = int_buf[i];
-               if (c == '\'' || c == '"') {
-                       if (c2 == 0)
-                               c2 = c;
-                       else {
-                               if (c == c2)
-                                       c2 = 0;
-                               else
-                                       int_buf[i] |= QUOT;
-                       }
-               } else if (c2 != 0 && c != '$')
-                       int_buf[i] |= QUOT;
-       }
-
-       /* skip commands with arguments if line have commands delimiters */
-       /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
-       for (i = 0; int_buf[i]; i++) {
-               c = int_buf[i];
-               c2 = int_buf[i + 1];
-               j = i ? int_buf[i - 1] : -1;
-               command_mode = 0;
-               if (c == ';' || c == '&' || c == '|') {
-                       command_mode = 1 + (c == c2);
-                       if (c == '&') {
-                               if (j == '>' || j == '<')
-                                       command_mode = 0;
-                       } else if (c == '|' && j == '>')
-                               command_mode = 0;
-               }
-               if (command_mode) {
-                       collapse_pos(0, i + command_mode);
-                       i = -1;                         /* hack incremet */
-               }
-       }
-       /* collapse `command...` */
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == '`') {
-                       for (j = i + 1; int_buf[j]; j++)
-                               if (int_buf[j] == '`') {
-                                       collapse_pos(i, j + 1);
-                                       j = 0;
-                                       break;
-                               }
-                       if (j) {
-                               /* not found close ` - command mode, collapse all previous */
-                               collapse_pos(0, i + 1);
-                               break;
-                       } else
-                               i--;                    /* hack incremet */
-               }
-
-       /* collapse (command...(command...)...) or {command...{command...}...} */
-       c = 0;                                          /* "recursive" level */
-       c2 = 0;
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == '(' || int_buf[i] == '{') {
-                       if (int_buf[i] == '(')
-                               c++;
-                       else
-                               c2++;
-                       collapse_pos(0, i + 1);
-                       i = -1;                         /* hack incremet */
-               }
-       for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
-               if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
-                       if (int_buf[i] == ')')
-                               c--;
-                       else
-                               c2--;
-                       collapse_pos(0, i + 1);
-                       i = -1;                         /* hack incremet */
-               }
-
-       /* skip first not quote space */
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] != ' ')
-                       break;
-       if (i)
-               collapse_pos(0, i);
-
-       /* set find mode for completion */
-       command_mode = FIND_EXE_ONLY;
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
-                       if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
-                               && matchBuf[pos_buf[0]]=='c'
-                               && matchBuf[pos_buf[1]]=='d' )
-                               command_mode = FIND_DIR_ONLY;
-                       else {
-                               command_mode = FIND_FILE_ONLY;
-                               break;
-                       }
-               }
-       /* "strlen" */
-       for (i = 0; int_buf[i]; i++);
-       /* find last word */
-       for (--i; i >= 0; i--) {
-               c = int_buf[i];
-               if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
-                       collapse_pos(0, i + 1);
-                       break;
-               }
-       }
-       /* skip first not quoted '\'' or '"' */
-       for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
-       /* collapse quote or unquote // or /~ */
-       while ((int_buf[i] & ~QUOT) == '/' && 
-                       ((int_buf[i + 1] & ~QUOT) == '/'
-                        || (int_buf[i + 1] & ~QUOT) == '~')) {
-               i++;
-       }
-
-       /* set only match and destroy quotes */
-       j = 0;
-       for (c = 0; pos_buf[i] >= 0; i++) {
-               matchBuf[c++] = matchBuf[pos_buf[i]];
-               j = pos_buf[i] + 1;
-       }
-       matchBuf[c] = 0;
-       /* old lenght matchBuf with quotes symbols */
-       *len_with_quotes = j ? j - pos_buf[0] : 0;
-
-       return command_mode;
-}
-
-
-static void input_tab(int *lastWasTab)
-{
-       /* Do TAB completion */
-       static int num_matches;
-       static char **matches;
-
-       if (lastWasTab == 0) {          /* free all memory */
-               if (matches) {
-                       while (num_matches > 0)
-                               free(matches[--num_matches]);
-                       free(matches);
-                       matches = (char **) NULL;
-               }
-               return;
-       }
-       if (*lastWasTab == FALSE) {
-
-               char *tmp;
-               int len_found;
-               char matchBuf[BUFSIZ];
-               int find_type;
-               int recalc_pos;
-
-               *lastWasTab = TRUE;             /* flop trigger */
-
-               /* Make a local copy of the string -- up
-                * to the position of the cursor */
-               tmp = strncpy(matchBuf, command_ps, cursor);
-               tmp[cursor] = 0;
-
-               find_type = find_match(matchBuf, &recalc_pos);
-
-               /* Free up any memory already allocated */
-               input_tab(0);
-
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               /* If the word starts with `~' and there is no slash in the word,
-                * then try completing this word as a username. */
-
-               if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
-                       matches = username_tab_completion(matchBuf, &num_matches);
-#endif
-               /* Try to match any executable in our path and everything
-                * in the current working directory that matches.  */
-               if (!matches)
-                       matches =
-                               exe_n_cwd_tab_completion(matchBuf,
-                                       &num_matches, find_type);
-               /* Remove duplicate found */
-               if(matches) {
-                       int i, j;
-                       /* bubble */
-                       for(i=0; i<(num_matches-1); i++)
-                               for(j=i+1; j<num_matches; j++)
-                                       if(matches[i]!=0 && matches[j]!=0 &&
-                                               strcmp(matches[i], matches[j])==0) {
-                                                       free(matches[j]);
-                                                       matches[j]=0;
-                                       }
-                       j=num_matches;
-                       num_matches = 0;
-                       for(i=0; i<j; i++)
-                               if(matches[i]) {
-                                       if(!strcmp(matches[i], "./"))
-                                               matches[i][1]=0;
-                                       else if(!strcmp(matches[i], "../"))
-                                               matches[i][2]=0;
-                                       matches[num_matches++]=matches[i];
-                               }
-               }
-               /* Did we find exactly one match? */
-               if (!matches || num_matches > 1) {
-                       char *tmp1;
-
-                       beep();
-                       if (!matches)
-                               return;         /* not found */
-                       /* sort */
-                       qsort(matches, num_matches, sizeof(char *), match_compare);
-
-                       /* find minimal match */
-                       tmp = xstrdup(matches[0]);
-                       for (tmp1 = tmp; *tmp1; tmp1++)
-                               for (len_found = 1; len_found < num_matches; len_found++)
-                                       if (matches[len_found][(tmp1 - tmp)] != *tmp1) {
-                                               *tmp1 = 0;
-                                               break;
-                                       }
-                       if (*tmp == 0) {        /* have unique */
-                               free(tmp);
-                               return;
-                       }
-               } else {                        /* one match */
-                       tmp = matches[0];
-                       /* for next completion current found */
-                       *lastWasTab = FALSE;
-               }
-
-               len_found = strlen(tmp);
-               /* have space to placed match? */
-               if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
-
-                       /* before word for match   */
-                       command_ps[cursor - recalc_pos] = 0;
-                       /* save   tail line        */
-                       strcpy(matchBuf, command_ps + cursor);
-                       /* add    match            */
-                       strcat(command_ps, tmp);
-                       /* add    tail             */
-                       strcat(command_ps, matchBuf);
-                       /* back to begin word for match    */
-                       input_backward(recalc_pos);
-                       /* new pos                         */
-                       recalc_pos = cursor + len_found;
-                       /* new len                         */
-                       len = strlen(command_ps);
-                       /* write out the matched command   */
-                       redraw(cmdedit_y, len - recalc_pos);
-               }
-               if (tmp != matches[0])
-                       free(tmp);
-       } else {
-               /* Ok -- the last char was a TAB.  Since they
-                * just hit TAB again, print a list of all the
-                * available choices... */
-               if (matches && num_matches > 0) {
-                       int i, col, l;
-                       int sav_cursor = cursor;        /* change goto_new_line() */
-
-                       /* Go to the next line */
-                       goto_new_line();
-                       for (i = 0, col = 0; i < num_matches; i++) {
-                               l = strlen(matches[i]);
-                               if (l < 14)
-                                       l = 14;
-                               printf("%-14s  ", matches[i]);
-                               if ((l += 2) > 16)
-                                       while (l % 16) {
-                                               putchar(' ');
-                                               l++;
-                                       }
-                               col += l;
-                               col -= (col / cmdedit_termw) * cmdedit_termw;
-                               if (col > 60 && matches[i + 1] != NULL) {
-                                       putchar('\n');
-                                       col = 0;
-                               }
-                       }
-                       /* Go to the next line and rewrite */
-                       putchar('\n');
-                       redraw(0, len - sav_cursor);
-               }
-       }
-}
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-
-static void get_previous_history(struct history **hp, struct history *p)
-{
-       if ((*hp)->s)
-               free((*hp)->s);
-       (*hp)->s = xstrdup(command_ps);
-       *hp = p;
-}
-
-static inline void get_next_history(struct history **hp)
-{
-       get_previous_history(hp, (*hp)->n);
-}
-
-enum {
-       ESC = 27,
-       DEL = 127,
-};
-
-
-/*
- * This function is used to grab a character buffer
- * from the input file descriptor and allows you to
- * a string with full command editing (sortof like
- * a mini readline).
- *
- * The following standard commands are not implemented:
- * ESC-b -- Move back one word
- * ESC-f -- Move forward one word
- * ESC-d -- Delete back one word
- * ESC-h -- Delete forward one word
- * CTL-t -- Transpose two characters
- *
- * Furthermore, the "vi" command editing keys are not implemented.
- *
- */
-
-int cmdedit_read_input(char *prompt, char command[BUFSIZ])
-{
-
-       int break_out = 0;
-       int lastWasTab = FALSE;
-       unsigned char c = 0;
-       struct history *hp = his_end;
-
-       /* prepare before init handlers */
-       cmdedit_y = 0;  /* quasireal y, not true work if line > xt*yt */
-       len = 0;
-       command_ps = command;
-
-       getTermSettings(0, (void *) &initial_settings);
-       memcpy(&new_settings, &initial_settings, sizeof(struct termios));
-       new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
-       /* Turn off echoing and CTRL-C, so we can trap it */
-       new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
-#ifndef linux
-       /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-       new_settings.c_cc[VMIN] = 1;
-       new_settings.c_cc[VTIME] = 0;
-       /* Turn off CTRL-C, so we can trap it */
-#       ifndef _POSIX_VDISABLE
-#               define _POSIX_VDISABLE '\0'
-#       endif
-       new_settings.c_cc[VINTR] = _POSIX_VDISABLE;     
-#endif
-       command[0] = 0;
-
-       setTermSettings(0, (void *) &new_settings);
-       handlers_sets |= SET_RESET_TERM;
-
-       /* Now initialize things */
-       cmdedit_init();
-       /* Print out the command prompt */
-       parse_prompt(prompt);
-
-       while (1) {
-
-               fflush(stdout);                 /* buffered out to fast */
-
-               if (safe_read(0, &c, 1) < 1)
-                       /* if we can't read input then exit */
-                       goto prepare_to_die;
-
-               switch (c) {
-               case '\n':
-               case '\r':
-                       /* Enter */
-                       goto_new_line();
-                       break_out = 1;
-                       break;
-               case 1:
-                       /* Control-a -- Beginning of line */
-                       input_backward(cursor);
-                       break;
-               case 2:
-                       /* Control-b -- Move back one character */
-                       input_backward(1);
-                       break;
-               case 3:
-                       /* Control-c -- stop gathering input */
-                       goto_new_line();
-                       command[0] = 0;
-                       len = 0;
-                       lastWasTab = FALSE;
-                       put_prompt();
-                       break;
-               case 4:
-                       /* Control-d -- Delete one character, or exit
-                        * if the len=0 and no chars to delete */
-                       if (len == 0) {
-prepare_to_die:
-#if !defined(BB_ASH)
-                               printf("exit");
-                               goto_new_line();
-                               /* cmdedit_reset_term() called in atexit */
-                               exit(EXIT_SUCCESS);
-#else
-                               break_out = -1; /* for control stoped jobs */
-                               break;
-#endif
-                       } else {
-                               input_delete();
-                       }
-                       break;
-               case 5:
-                       /* Control-e -- End of line */
-                       input_end();
-                       break;
-               case 6:
-                       /* Control-f -- Move forward one character */
-                       input_forward();
-                       break;
-               case '\b':
-               case DEL:
-                       /* Control-h and DEL */
-                       input_backspace();
-                       break;
-               case '\t':
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-                       input_tab(&lastWasTab);
-#endif
-                       break;
-               case 14:
-                       /* Control-n -- Get next command in history */
-                       if (hp && hp->n && hp->n->s) {
-                               get_next_history(&hp);
-                               goto rewrite_line;
-                       } else {
-                               beep();
-                       }
-                       break;
-               case 16:
-                       /* Control-p -- Get previous command from history */
-                       if (hp && hp->p) {
-                               get_previous_history(&hp, hp->p);
-                               goto rewrite_line;
-                       } else {
-                               beep();
-                       }
-                       break;
-               case 21:
-                       /* Control-U -- Clear line before cursor */
-                       if (cursor) {
-                               strcpy(command, command + cursor);
-                               redraw(cmdedit_y, len -= cursor);
-                       }
-                       break;
-
-               case ESC:{
-                       /* escape sequence follows */
-                       if (safe_read(0, &c, 1) < 1)
-                               goto prepare_to_die;
-                       /* different vt100 emulations */
-                       if (c == '[' || c == 'O') {
-                               if (safe_read(0, &c, 1) < 1)
-                                       goto prepare_to_die;
-                       }
-                       switch (c) {
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-                       case '\t':                      /* Alt-Tab */
-
-                               input_tab(&lastWasTab);
-                               break;
-#endif
-                       case 'A':
-                               /* Up Arrow -- Get previous command from history */
-                               if (hp && hp->p) {
-                                       get_previous_history(&hp, hp->p);
-                                       goto rewrite_line;
-                               } else {
-                                       beep();
-                               }
-                               break;
-                       case 'B':
-                               /* Down Arrow -- Get next command in history */
-                               if (hp && hp->n && hp->n->s) {
-                                       get_next_history(&hp);
-                                       goto rewrite_line;
-                               } else {
-                                       beep();
-                               }
-                               break;
-
-                               /* Rewrite the line with the selected history item */
-                         rewrite_line:
-                               /* change command */
-                               len = strlen(strcpy(command, hp->s));
-                               /* redraw and go to end line */
-                               redraw(cmdedit_y, 0);
-                               break;
-                       case 'C':
-                               /* Right Arrow -- Move forward one character */
-                               input_forward();
-                               break;
-                       case 'D':
-                               /* Left Arrow -- Move back one character */
-                               input_backward(1);
-                               break;
-                       case '3':
-                               /* Delete */
-                               input_delete();
-                               break;
-                       case '1':
-                       case 'H':
-                               /* Home (Ctrl-A) */
-                               input_backward(cursor);
-                               break;
-                       case '4':
-                       case 'F':
-                               /* End (Ctrl-E) */
-                               input_end();
-                               break;
-                       default:
-                               if (!(c >= '1' && c <= '9'))
-                                       c = 0;
-                               beep();
-                       }
-                       if (c >= '1' && c <= '9')
-                               do
-                                       if (safe_read(0, &c, 1) < 1)
-                                               goto prepare_to_die;
-                               while (c != '~');
-                       break;
-               }
-
-               default:        /* If it's regular input, do the normal thing */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-                       /* Control-V -- Add non-printable symbol */
-                       if (c == 22) {
-                               if (safe_read(0, &c, 1) < 1)
-                                       goto prepare_to_die;
-                               if (c == 0) {
-                                       beep();
-                                       break;
-                               }
-                       } else
-#endif
-                       if (!Isprint(c))        /* Skip non-printable characters */
-                               break;
-
-                       if (len >= (BUFSIZ - 2))        /* Need to leave space for enter */
-                               break;
-
-                       len++;
-
-                       if (cursor == (len - 1)) {      /* Append if at the end of the line */
-                               *(command + cursor) = c;
-                               *(command + cursor + 1) = 0;
-                               cmdedit_set_out_char(0);
-                       } else {                        /* Insert otherwise */
-                               int sc = cursor;
-
-                               memmove(command + sc + 1, command + sc, len - sc);
-                               *(command + sc) = c;
-                               sc++;
-                               /* rewrite from cursor */
-                               input_end();
-                               /* to prev x pos + 1 */
-                               input_backward(cursor - sc);
-                       }
-
-                       break;
-               }
-               if (break_out)                  /* Enter is the command terminator, no more input. */
-                       break;
-
-               if (c != '\t')
-                       lastWasTab = FALSE;
-       }
-
-       setTermSettings(0, (void *) &initial_settings);
-       handlers_sets &= ~SET_RESET_TERM;
-
-       /* Handle command history log */
-       if (len) {                                      /* no put empty line */
-
-               struct history *h = his_end;
-               char *ss;
-
-               ss = xstrdup(command);  /* duplicate */
-
-               if (h == 0) {
-                       /* No previous history -- this memory is never freed */
-                       h = his_front = xmalloc(sizeof(struct history));
-                       h->n = xmalloc(sizeof(struct history));
-
-                       h->p = NULL;
-                       h->s = ss;
-                       h->n->p = h;
-                       h->n->n = NULL;
-                       h->n->s = NULL;
-                       his_end = h->n;
-                       history_counter++;
-               } else {
-                       /* Add a new history command -- this memory is never freed */
-                       h->n = xmalloc(sizeof(struct history));
-
-                       h->n->p = h;
-                       h->n->n = NULL;
-                       h->n->s = NULL;
-                       h->s = ss;
-                       his_end = h->n;
-
-                       /* After max history, remove the oldest command */
-                       if (history_counter >= MAX_HISTORY) {
-
-                               struct history *p = his_front->n;
-
-                               p->p = NULL;
-                               free(his_front->s);
-                               free(his_front);
-                               his_front = p;
-                       } else {
-                               history_counter++;
-                       }
-               }
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-               num_ok_lines++;
-#endif
-       }
-       if(break_out>0) {
-       command[len++] = '\n';          /* set '\n' */
-       command[len] = 0;
-       }
-#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION)
-       input_tab(0);                           /* strong free */
-#endif
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-       free(cmdedit_prompt);
-#endif
-       cmdedit_reset_term();
-       return len;
-}
-
-
-
-#endif /* BB_FEATURE_COMMAND_EDITING */
-
-
-#ifdef TEST
-
-const char *applet_name = "debug stuff usage";
-const char *memory_exhausted = "Memory exhausted";
-
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-#include <locale.h>
-#endif
-
-int main(int argc, char **argv)
-{
-       char buff[BUFSIZ];
-       char *prompt =
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-               "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
-\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
-\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
-#else
-               "% ";
-#endif
-
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-       setlocale(LC_ALL, "");
-#endif
-       while(1) {
-               int l;
-               cmdedit_read_input(prompt, buff);
-               l = strlen(buff);
-               if(l==0)
-                       break;
-               if(l > 0 && buff[l-1] == '\n')
-                       buff[l-1] = 0;
-               printf("*** cmdedit_read_input() returned line =%s=\n", buff);
-       }
-       printf("*** cmdedit_read_input() detect ^C\n");
-       return 0;
-}
-
-#endif /* TEST */
diff --git a/busybox/cmdedit.h b/busybox/cmdedit.h
deleted file mode 100644 (file)
index 8389357..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef CMDEDIT_H
-#define CMDEDIT_H
-
-int     cmdedit_read_input(char* promptStr, char* command);
-
-#endif /* CMDEDIT_H */
diff --git a/busybox/cmp.c b/busybox/cmp.c
deleted file mode 100644 (file)
index 6d57946..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cmp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "busybox.h"
-
-int cmp_main(int argc, char **argv)
-{
-       FILE *fp1 = NULL, *fp2 = stdin;
-       char *filename1, *filename2 = "-";
-       int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE;
-
-       while ((c = getopt(argc, argv, "s")) != EOF) {
-               switch (c) {
-                       case 's':
-                               silent = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       filename1 = argv[optind];
-       switch (argc - optind) {
-               case 2:
-                       fp2 = xfopen(filename2 = argv[optind + 1], "r");
-               case 1:
-                       fp1 = xfopen(filename1, "r");
-                       break;
-               default:
-                       show_usage();
-       }
-
-       do {
-               c1 = fgetc(fp1);
-               c2 = fgetc(fp2);
-               if (c1 != c2) {
-                       if (silent)
-                               return EXIT_FAILURE;
-                       if (c1 == EOF)
-                               printf("EOF on %s\n", filename1);
-                       else if (c2 == EOF)
-                               printf("EOF on %s\n", filename2);
-                       else
-                               printf("%s %s differ: char %d, line %d\n", filename1, filename2,
-                                               char_pos, line_pos);
-                       return EXIT_FAILURE;
-               }
-               char_pos++;
-               if (c1 == '\n')
-                       line_pos++;
-       } while (c1 != EOF);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/console-tools/chvt.c b/busybox/console-tools/chvt.c
deleted file mode 100644 (file)
index c76e9c7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * chvt.c - aeb - 940227 - Change virtual terminal
- *
- * busyboxed by Erik Andersen
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/vt.h> */
-static const int VT_ACTIVATE = 0x5606;  /* make vt active */
-static const int VT_WAITACTIVE = 0x5607;  /* wait for vt active */
-
-int chvt_main(int argc, char **argv)
-{
-       int fd, num;
-
-       if ((argc != 2) || (**(argv + 1) == '-'))
-               show_usage();
-       fd = get_console_fd("/dev/console");
-       num = atoi(argv[1]);
-       if (ioctl(fd, VT_ACTIVATE, num))
-               perror_msg_and_die("VT_ACTIVATE");
-       if (ioctl(fd, VT_WAITACTIVE, num))
-               perror_msg_and_die("VT_WAITACTIVE");
-       return EXIT_SUCCESS;
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/console-tools/clear.c b/busybox/console-tools/clear.c
deleted file mode 100644 (file)
index 503bafa..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini clear implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-extern int clear_main(int argc, char **argv)
-{
-       printf("\033[H\033[J");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/console-tools/deallocvt.c b/busybox/console-tools/deallocvt.c
deleted file mode 100644 (file)
index 15cd0c9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
- * Renamed deallocvt.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/vt.h> */
-static const int VT_DISALLOCATE = 0x5608;  /* free memory associated to vt */
-
-int deallocvt_main(int argc, char *argv[])
-{
-       int fd, num, i;
-
-       //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-')))
-       if (argc > 2)
-               show_usage();
-
-       fd = get_console_fd("/dev/console");
-
-       if (argc == 1) {
-               /* deallocate all unused consoles */
-               if (ioctl(fd, VT_DISALLOCATE, 0))
-                       perror_msg_and_die("VT_DISALLOCATE");
-       } else {
-               for (i = 1; i < argc; i++) {
-                       num = atoi(argv[i]);
-                       if (num == 0)
-                               error_msg("0: illegal VT number");
-                       else if (num == 1)
-                               error_msg("VT 1 cannot be deallocated");
-                       else if (ioctl(fd, VT_DISALLOCATE, num))
-                               perror_msg_and_die("VT_DISALLOCATE");
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/console-tools/dumpkmap.c b/busybox/console-tools/dumpkmap.c
deleted file mode 100644 (file)
index 22652a5..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dumpkmap implementation for busybox
- *
- * Copyright (C) Arne Bernin <arne@matrix.loopback.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/kd.h> */
-struct kbentry {
-       unsigned char kb_table;
-       unsigned char kb_index;
-       unsigned short kb_value;
-};
-static const int KDGKBENT = 0x4B46;  /* gets one entry in translation table */
-
-/* From <linux/keyboard.h> */
-static const int NR_KEYS = 128;
-static const int MAX_NR_KEYMAPS = 256;
-
-int dumpkmap_main(int argc, char **argv)
-{
-       struct kbentry ke;
-       int i, j, fd;
-       char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap";
-
-       if (argc>=2 && *argv[1]=='-') {
-               show_usage();
-       }
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0) {
-               perror_msg("Error opening " CURRENT_VC);
-               return EXIT_FAILURE;
-       }
-
-       write(1, magic, 7);
-
-       for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0;
-       flags[0]=1; 
-       flags[1]=1;
-       flags[2]=1;
-       flags[4]=1;
-       flags[5]=1;
-       flags[6]=1;
-       flags[8]=1;
-       flags[9]=1;
-       flags[10]=1;
-       flags[12]=1;
-       
-       /* dump flags */
-       for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); 
-
-       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
-               if (flags[i] == 1) {
-                       for (j = 0; j < NR_KEYS; j++) {
-                               ke.kb_index = j;
-                               ke.kb_table = i;
-                               if (ioctl(fd, KDGKBENT, &ke) < 0) {
-                               
-                                       error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value);
-                                       }
-                               else {
-                                       write(1,(void*)&ke.kb_value,2); 
-                                       }       
-                               
-                       }
-               }
-       }
-       close(fd);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/console-tools/loadacm.c b/busybox/console-tools/loadacm.c
deleted file mode 100644 (file)
index 3fb4e76..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Derived from
- * mapscrn.c - version 0.92
- *
- * Was taken from console-tools and adapted by 
- * Peter Novodvorsky <petya@logic.ru>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/kd.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-typedef unsigned short unicode;
-
-static long int ctoi(unsigned char *s, int *is_unicode);
-static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]);
-static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode);
-static unicode utf8_to_ucs2(char *buf);
-static int screen_map_load(int fd, FILE * fp);
-
-int loadacm_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc>=2 && *argv[1]=='-') {
-               show_usage();
-       }
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0) {
-               perror_msg_and_die("Error opening " CURRENT_VC);
-       }
-
-       if (screen_map_load(fd, stdin)) {
-               perror_msg_and_die("Error loading acm");
-       }
-
-       write(fd, "\033(K", 3);
-
-       return EXIT_SUCCESS;
-}
-
-static int screen_map_load(int fd, FILE * fp)
-{
-       struct stat stbuf;
-       unicode wbuf[E_TABSZ];
-       unsigned char buf[E_TABSZ];
-       int parse_failed = 0;
-       int is_unicode;
-
-       if (fstat(fileno(fp), &stbuf))
-               perror_msg_and_die("Cannot stat map file");
-
-       /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */
-       if (!
-               (parse_failed =
-                (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode)))
-|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) {       /* test for binary UTF map by size */
-               if (parse_failed) {
-                       if (-1 == fseek(fp, 0, SEEK_SET)) {
-                               if (errno == ESPIPE)
-                                       error_msg_and_die("16bit screen-map MUST be a regular file.");
-                               else
-                                       perror_msg_and_die("fseek failed reading binary 16bit screen-map");
-                       }
-
-                       if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1)
-                               perror_msg_and_die("Cannot read [new] map from file");
-#if 0
-                       else
-                               error_msg("Input screen-map is binary.");
-#endif
-               }
-
-               /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */
-               /* same if it was binary, ie. if parse_failed */
-               if (parse_failed || is_unicode) {
-                       if (ioctl(fd, PIO_UNISCRNMAP, wbuf))
-                               perror_msg_and_die("PIO_UNISCRNMAP ioctl");
-                       else
-                               return 0;
-               }
-       }
-
-       /* rewind... */
-       if (-1 == fseek(fp, 0, SEEK_SET)) {
-               if (errno == ESPIPE)
-                       error_msg("Assuming 8bit screen-map - MUST be a regular file."),
-                               exit(1);
-               else
-                       perror_msg_and_die("fseek failed assuming 8bit screen-map");
-       }
-
-       /* ... and try an old 8-bit screen-map */
-       if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) ||
-               (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) {       /* test for binary old 8-bit map by size */
-               if (parse_failed) {
-                       if (-1 == fseek(fp, 0, SEEK_SET)) {
-                               if (errno == ESPIPE)
-                                       /* should not - it succedeed above */
-                                       error_msg_and_die("fseek() returned ESPIPE !");
-                               else
-                                       perror_msg_and_die("fseek for binary 8bit screen-map");
-                       }
-
-                       if (fread(buf, E_TABSZ, 1, fp) != 1)
-                               perror_msg_and_die("Cannot read [old] map from file");
-#if 0
-                       else
-                               error_msg("Input screen-map is binary.");
-#endif
-               }
-
-               if (ioctl(fd, PIO_SCRNMAP, buf))
-                       perror_msg_and_die("PIO_SCRNMAP ioctl");
-               else
-                       return 0;
-       }
-       error_msg("Error parsing symbolic map");
-       return(1);
-}
-
-
-/*
- * - reads `fp' as a 16-bit ASCII SFM file.
- * - returns -1 on error.
- * - returns it in `unicode' in an E_TABSZ-elements array.
- * - sets `*is_unicode' flagiff there were any non-8-bit
- *   (ie. real 16-bit) mapping.
- *
- * FIXME: ignores everything after second word
- */
-static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode)
-{
-       char buffer[256];                       /* line buffer reading file */
-       char *p, *q;                            /* 1st + 2nd words in line */
-       int in, on;                                     /* the same, as numbers */
-       int tmp_is_unicode;                     /* tmp for is_unicode calculation */
-       int i;                                          /* loop index - result holder */
-       int ret_code = 0;                       /* return code */
-       sigset_t acmsigset, old_sigset;
-
-       assert(is_unicode);
-
-       *is_unicode = 0;
-
-       /* first 128 codes defaults to ASCII */
-       for (i = 0; i < 128; i++)
-               buf[i] = i;
-       /* remaining defaults to replacement char (usually E_TABSZ = 256) */
-       for (; i < E_TABSZ; i++)
-               buf[i] = 0xfffd;
-
-       /* block SIGCHLD */
-       sigemptyset(&acmsigset);
-       sigaddset(&acmsigset, SIGCHLD);
-       sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset);
-
-       do {
-               if (NULL == fgets(buffer, sizeof(buffer), fp)) {
-                       if (feof(fp))
-                               break;
-                       else
-                               perror_msg_and_die("uni_screen_map_read_ascii() can't read line");
-               }
-
-               /* get "charset-relative charcode", stripping leading spaces */
-               p = strtok(buffer, " \t\n");
-
-               /* skip empty lines and comments */
-               if (!p || *p == '#')
-                       continue;
-
-               /* get unicode mapping */
-               q = strtok(NULL, " \t\n");
-               if (q) {
-                       in = ctoi(p, NULL);
-                       if (in < 0 || in > 255) {
-                               ret_code = -1;
-                               break;
-                       }
-
-                       on = ctoi(q, &tmp_is_unicode);
-                       if (in < 0 && on > 65535) {
-                               ret_code = -1;
-                               break;
-                       }
-
-                       *is_unicode |= tmp_is_unicode;
-                       buf[in] = on;
-               } else {
-                       ret_code = -1;
-                       break;
-               }
-       }
-       while (1);                                      /* terminated by break on feof() */
-
-       /* restore sig mask */
-       sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-       return ret_code;
-}
-
-
-static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[])
-{
-       char buffer[256];
-       int in, on;
-       char *p, *q;
-
-       for (in = 0; in < 256; in++)
-               buf[in] = in;
-
-       while (fgets(buffer, sizeof(buffer) - 1, fp)) {
-               p = strtok(buffer, " \t\n");
-
-               if (!p || *p == '#')
-                       continue;
-
-               q = strtok(NULL, " \t\n#");
-               if (q) {
-                       in = ctoi(p, NULL);
-                       if (in < 0 || in > 255)
-                               return -1;
-
-                       on = ctoi(q, NULL);
-                       if (in < 0 && on > 255)
-                               return -1;
-
-                       buf[in] = on;
-               } else
-                       return -1;
-       }
-
-       return (0);
-}
-
-
-/*
- * - converts a string into an int.
- * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars.
- * - returns the converted value
- * - if `is_unicode != NULL', use it to tell whether it was unicode
- *
- * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones.
- */
-static long int ctoi(unsigned char *s, int *is_unicode)
-{
-       int i;
-       size_t ls;
-
-       ls = strlen(s);
-       if (is_unicode)
-               *is_unicode = 0;
-
-       /* hex-specified UCS2 */
-       if ((strncmp(s, "U+", 2) == 0) &&
-               (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) {
-               sscanf(s + 2, "%x", &i);
-               if (is_unicode)
-                       *is_unicode = 1;
-       }
-
-       /* hex-specified byte */
-       else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) &&
-                        (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2))
-               sscanf(s + 2, "%x", &i);
-
-       /* oct-specified number (byte) */
-       else if ((*s == '0') && (strspn(s, "01234567") == ls))
-               sscanf(s, "%o", &i);
-
-       /* dec-specified number (byte) */
-       else if (strspn(s, "0123456789") == ls)
-               sscanf(s, "%d", &i);
-
-       /* single-byte quoted char */
-       else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
-               i = s[1];
-
-       /* multi-byte UTF8 quoted char */
-       else if ((s[0] == '\'') && (s[ls - 1] == '\'')) {
-               s[ls - 1] = 0;                  /* ensure we'll not "parse UTF too far" */
-               i = utf8_to_ucs2(s + 1);
-               if (is_unicode)
-                       *is_unicode = 1;
-       } else
-               return (-1);
-
-       return (i);
-}
-
-
-static unicode utf8_to_ucs2(char *buf)
-{
-       int utf_count = 0;
-       long utf_char = 0;
-       unicode tc = 0;
-       unsigned char c;
-
-       do {
-               c = *buf;
-               buf++;
-
-               /* if byte should be part of multi-byte sequence */
-               if (c & 0x80) {
-                       /* if we have already started to parse a UTF8 sequence */
-                       if (utf_count > 0 && (c & 0xc0) == 0x80) {
-                               utf_char = (utf_char << 6) | (c & 0x3f);
-                               utf_count--;
-                               if (utf_count == 0)
-                                       tc = utf_char;
-                               else
-                                       continue;
-                       } else {                        /* Possibly 1st char of a UTF8 sequence */
-
-                               if ((c & 0xe0) == 0xc0) {
-                                       utf_count = 1;
-                                       utf_char = (c & 0x1f);
-                               } else if ((c & 0xf0) == 0xe0) {
-                                       utf_count = 2;
-                                       utf_char = (c & 0x0f);
-                               } else if ((c & 0xf8) == 0xf0) {
-                                       utf_count = 3;
-                                       utf_char = (c & 0x07);
-                               } else if ((c & 0xfc) == 0xf8) {
-                                       utf_count = 4;
-                                       utf_char = (c & 0x03);
-                               } else if ((c & 0xfe) == 0xfc) {
-                                       utf_count = 5;
-                                       utf_char = (c & 0x01);
-                               } else
-                                       utf_count = 0;
-                               continue;
-                       }
-               } else {                                /* not part of multi-byte sequence - treat as ASCII
-                                                                  * this makes incomplete sequences to be ignored
-                                                                */
-                       tc = c;
-                       utf_count = 0;
-               }
-       }
-       while (utf_count);
-
-       return tc;
-}
diff --git a/busybox/console-tools/loadfont.c b/busybox/console-tools/loadfont.c
deleted file mode 100644 (file)
index d665001..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * loadfont.c - Eugene Crosser & Andries Brouwer
- *
- * Version 0.96bb
- *
- * Loads the console font, and possibly the corresponding screen map(s).
- * (Adapted for busybox by Matej Vela.)
- */
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <memory.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/kd.h>
-#include <endian.h>
-#include "busybox.h"
-
-static const int PSF_MAGIC1 = 0x36;
-static const int PSF_MAGIC2 = 0x04;
-
-static const int PSF_MODE512 = 0x01;
-static const int PSF_MODEHASTAB = 0x02;
-static const int PSF_MAXMODE = 0x03;
-static const int PSF_SEPARATOR = 0xFFFF;
-
-struct psf_header {
-       unsigned char magic1, magic2;   /* Magic number */
-       unsigned char mode;                     /* PSF font mode */
-       unsigned char charsize;         /* Character size */
-};
-
-#define PSF_MAGIC_OK(x)        ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
-
-static void loadnewfont(int fd);
-
-extern int loadfont_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc != 1)
-               show_usage();
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0)
-               perror_msg_and_die("Error opening " CURRENT_VC);
-       loadnewfont(fd);
-
-       return EXIT_SUCCESS;
-}
-
-static void do_loadfont(int fd, char *inbuf, int unit, int fontsize)
-{
-       char buf[16384];
-       int i;
-
-       memset(buf, 0, sizeof(buf));
-
-       if (unit < 1 || unit > 32)
-               error_msg_and_die("Bad character size %d", unit);
-
-       for (i = 0; i < fontsize; i++)
-               memcpy(buf + (32 * i), inbuf + (unit * i), unit);
-
-#if defined( PIO_FONTX ) && !defined( __sparc__ )
-       {
-               struct consolefontdesc cfd;
-
-               cfd.charcount = fontsize;
-               cfd.charheight = unit;
-               cfd.chardata = buf;
-
-               if (ioctl(fd, PIO_FONTX, &cfd) == 0)
-                       return;                         /* success */
-               perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)");
-       }
-#endif
-       if (ioctl(fd, PIO_FONT, buf))
-               perror_msg_and_die("PIO_FONT ioctl error");
-}
-
-static void
-do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
-{
-       struct unimapinit advice;
-       struct unimapdesc ud;
-       struct unipair *up;
-       int ct = 0, maxct;
-       int glyph;
-       u_short unicode;
-
-       maxct = tailsz;                         /* more than enough */
-       up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair));
-
-       for (glyph = 0; glyph < fontsize; glyph++) {
-               while (tailsz >= 2) {
-                       unicode = (((u_short) inbuf[1]) << 8) + inbuf[0];
-                       tailsz -= 2;
-                       inbuf += 2;
-                       if (unicode == PSF_SEPARATOR)
-                               break;
-                       up[ct].unicode = unicode;
-                       up[ct].fontpos = glyph;
-                       ct++;
-               }
-       }
-
-       /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
-          this printf did not work on many kernels */
-
-       advice.advised_hashsize = 0;
-       advice.advised_hashstep = 0;
-       advice.advised_hashlevel = 0;
-       if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
-#ifdef ENOIOCTLCMD
-               if (errno == ENOIOCTLCMD) {
-                       error_msg("It seems this kernel is older than 1.1.92");
-                       error_msg_and_die("No Unicode mapping table loaded.");
-               } else
-#endif
-                       perror_msg_and_die("PIO_UNIMAPCLR");
-       }
-       ud.entry_ct = ct;
-       ud.entries = up;
-       if (ioctl(fd, PIO_UNIMAP, &ud)) {
-#if 0
-               if (errno == ENOMEM) {
-                       /* change advice parameters */
-               }
-#endif
-               perror_msg_and_die("PIO_UNIMAP");
-       }
-}
-
-static void loadnewfont(int fd)
-{
-       int unit;
-       char inbuf[32768];                      /* primitive */
-       unsigned int inputlth, offset;
-
-       /*
-        * We used to look at the length of the input file
-        * with stat(); now that we accept compressed files,
-        * just read the entire file.
-        */
-       inputlth = fread(inbuf, 1, sizeof(inbuf), stdin);
-       if (ferror(stdin))
-               perror_msg_and_die("Error reading input font");
-       /* use malloc/realloc in case of giant files;
-          maybe these do not occur: 16kB for the font,
-          and 16kB for the map leaves 32 unicode values
-          for each font position */
-       if (!feof(stdin))
-               perror_msg_and_die("Font too large");
-
-       /* test for psf first */
-       {
-               struct psf_header psfhdr;
-               int fontsize;
-               int hastable;
-               unsigned int head0, head;
-
-               if (inputlth < sizeof(struct psf_header))
-                       goto no_psf;
-
-               psfhdr = *(struct psf_header *) &inbuf[0];
-
-               if (!PSF_MAGIC_OK(psfhdr))
-                       goto no_psf;
-
-               if (psfhdr.mode > PSF_MAXMODE)
-                       error_msg_and_die("Unsupported psf file mode");
-               fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
-#if !defined( PIO_FONTX ) || defined( __sparc__ )
-               if (fontsize != 256)
-                       error_msg_and_die("Only fontsize 256 supported");
-#endif
-               hastable = (psfhdr.mode & PSF_MODEHASTAB);
-               unit = psfhdr.charsize;
-               head0 = sizeof(struct psf_header);
-
-               head = head0 + fontsize * unit;
-               if (head > inputlth || (!hastable && head != inputlth))
-                       error_msg_and_die("Input file: bad length");
-               do_loadfont(fd, inbuf + head0, unit, fontsize);
-               if (hastable)
-                       do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
-               return;
-       }
-  no_psf:
-
-       /* file with three code pages? */
-       if (inputlth == 9780) {
-               offset = 40;
-               unit = 16;
-       } else {
-               /* bare font */
-               if (inputlth & 0377)
-                       error_msg_and_die("Bad input file size");
-               offset = 0;
-               unit = inputlth / 256;
-       }
-       do_loadfont(fd, inbuf + offset, unit, 256);
-}
diff --git a/busybox/console-tools/loadkmap.c b/busybox/console-tools/loadkmap.c
deleted file mode 100644 (file)
index 4f217d6..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini loadkmap implementation for busybox
- *
- * Copyright (C) 1998 Enrique Zanardi <ezanardi@ull.es>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#define BINARY_KEYMAP_MAGIC "bkeymap"
-
-/* From <linux/kd.h> */
-struct kbentry {
-       unsigned char kb_table;
-       unsigned char kb_index;
-       unsigned short kb_value;
-};
-static const int KDSKBENT = 0x4B47;  /* sets one entry in translation table */
-
-/* From <linux/keyboard.h> */
-static const int NR_KEYS = 128;
-static const int MAX_NR_KEYMAPS = 256;
-
-int loadkmap_main(int argc, char **argv)
-{
-       struct kbentry ke;
-       u_short *ibuff;
-       int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short);
-       char flags[MAX_NR_KEYMAPS], buff[7];
-
-       if (argc != 1)
-               show_usage();
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0)
-               perror_msg_and_die("Error opening " CURRENT_VC);
-
-       read(0, buff, 7);
-       if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7))
-               error_msg_and_die("This is not a valid binary keymap.");
-
-       if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS))
-               perror_msg_and_die("Error reading keymap flags");
-
-       ibuff = (u_short *) xmalloc(ibuffsz);
-
-       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
-               if (flags[i] == 1) {
-                       pos = 0;
-                       while (pos < ibuffsz) {
-                               if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0)
-                                       perror_msg_and_die("Error reading keymap");
-                               pos += readsz;
-                       }
-                       for (j = 0; j < NR_KEYS; j++) {
-                               ke.kb_index = j;
-                               ke.kb_table = i;
-                               ke.kb_value = ibuff[j];
-                               ioctl(fd, KDSKBENT, &ke);
-                       }
-               }
-       }
-       /* Don't bother to close files.  Exit does that 
-        * automagically, so we can save a few bytes */
-       /* close(fd); */
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/console-tools/reset.c b/busybox/console-tools/reset.c
deleted file mode 100644 (file)
index 755c4c3..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini reset implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *        and Kent Robotti <robotti@metconnect.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int reset_main(int argc, char **argv)
-{
-       printf("\033c");
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/console-tools/setkeycodes.c b/busybox/console-tools/setkeycodes.c
deleted file mode 100644 (file)
index c3c7e09..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * setkeycodes
- *
- * Copyright (C) 1994-1998 Andries E. Brouwer <aeb@cwi.nl>
- *
- * Adjusted for BusyBox by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-
-/* From <linux/kd.h> */
-struct kbkeycode {
-       unsigned int scancode, keycode;
-};
-static const int KDSETKEYCODE = 0x4B4D;  /* write kernel keycode table entry */
-
-extern int 
-setkeycodes_main(int argc, char** argv)
-{
-    char *ep;
-    int fd, sc;
-    struct kbkeycode a;
-
-    if (argc % 2 != 1 || argc < 2) {
-      show_usage();
-       }
-        
-       fd = get_console_fd("/dev/console");
-
-    while (argc > 2) {
-       a.keycode = atoi(argv[2]);
-       a.scancode = sc = strtol(argv[1], &ep, 16);
-       if (*ep) {
-      error_msg_and_die("error reading SCANCODE: '%s'", argv[1]);
-       }
-       if (a.scancode > 127) {
-           a.scancode -= 0xe000;
-           a.scancode += 128;
-       }
-       if (a.scancode > 255 || a.keycode > 127) {
-      error_msg_and_die("SCANCODE or KEYCODE outside bounds");
-       }
-       if (ioctl(fd,KDSETKEYCODE,&a)) {
-           perror("KDSETKEYCODE");
-               error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode);
-       }
-       argc -= 2;
-       argv += 2;
-    }
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/basename.c b/busybox/coreutils/basename.c
deleted file mode 100644 (file)
index c15afd5..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini basename implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdlib.h>
-#include "busybox.h"
-#include <string.h>
-
-extern int basename_main(int argc, char **argv)
-{
-       int m, n;
-       char *s;
-
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       argv++;
-
-       s = get_last_path_component(*argv);
-
-       if (argc>2) {
-               argv++;
-               n = strlen(*argv);
-               m = strlen(s);
-               if (m>n && strncmp(s+m-n, *argv, n)==0)
-                       s[m-n] = '\0';
-       }
-       puts(s);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/cat.c b/busybox/coreutils/cat.c
deleted file mode 100644 (file)
index aa8528d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini Cat implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-extern int cat_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-
-       if (argc == 1) {
-               print_file(stdin);
-               return status;
-       }
-
-       while (--argc > 0) {
-               if(!(strcmp(*++argv, "-"))) {
-                       print_file(stdin);
-               } else if (print_file_by_name(*argv) == FALSE) {
-                       status = EXIT_FAILURE;
-               }
-       }
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/chgrp.c b/busybox/coreutils/chgrp.c
deleted file mode 100644 (file)
index fbc1036..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Don't use lchown for libc5 or glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
-
-
-static long gid;
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
-               return (TRUE);
-       }
-       perror(fileName);
-       return (FALSE);
-}
-
-int chgrp_main(int argc, char **argv)
-{
-       int opt;
-       int recursiveFlag = FALSE;
-       char *p=NULL;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "R")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* Find the selected group */
-               gid = strtoul(argv[optind], &p, 10);    /* maybe it's already numeric */
-               if (argv[optind] == p)
-                       gid = my_getgrnam(argv[optind]);
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       while (++optind < argc) {
-               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
-                                       fileAction, fileAction, NULL) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/chmod.c b/busybox/coreutils/chmod.c
deleted file mode 100644 (file)
index 9139b3f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (!parse_mode((char *)junk, &(statbuf->st_mode)))
-               error_msg_and_die("internal error");
-       if (chmod(fileName, statbuf->st_mode) == 0)
-               return (TRUE);
-       perror(fileName);
-       return (FALSE);
-}
-
-int chmod_main(int argc, char **argv)
-{
-       int i;
-       int opt;
-       int recursiveFlag = FALSE;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "R")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* Parse the specified mode */
-               mode_t mode;
-               if (parse_mode(argv[optind], &mode) == FALSE) {
-                       error_msg_and_die( "unknown mode: %s", argv[optind]);
-               }
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       for (i = optind + 1; i < argc; i++) {
-               if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction,
-                                       fileAction, argv[optind]) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/chown.c b/busybox/coreutils/chown.c
deleted file mode 100644 (file)
index d1e52de..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chown/chmod/chgrp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Don't use lchown for libc5 or glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
-
-static long uid;
-static long gid;
-
-static int (*chown_func)(const char *, __uid_t, __gid_t) = chown;
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (chown_func(fileName, uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
-               return (TRUE);
-       }
-       perror(fileName);
-       return (FALSE);
-}
-
-int chown_main(int argc, char **argv)
-{
-       int opt;
-       int recursiveFlag = FALSE,
-               noderefFlag = FALSE;
-       char *groupName=NULL;
-       char *p=NULL;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "Rh")) > 0) {
-               switch (opt) {
-                       case 'R':
-                               recursiveFlag = TRUE;
-                               break;
-                       case 'h':
-                               noderefFlag = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (noderefFlag) chown_func = lchown;
-
-       if (argc > optind && argc > 2 && argv[optind]) {
-               /* First, check if there is a group name here */
-               groupName = strchr(argv[optind], '.');
-               if (groupName == NULL)
-                       groupName = strchr(argv[optind], ':');
-               if (groupName) {
-                       *groupName++ = '\0';
-                       gid = strtoul(groupName, &p, 10);
-                       if (groupName == p)
-                               gid = my_getgrnam(groupName);
-               } else {
-                       gid = -1;
-               }
-               /* Now check for the username */
-               uid = strtoul(argv[optind], &p, 10);    /* Is is numeric? */
-               if (argv[optind] == p) {
-                       uid = my_getpwnam(argv[optind]);
-               }
-       } else {
-               error_msg_and_die(too_few_args);
-       }
-
-       /* Ok, ready to do the deed now */
-       while (++optind < argc) {
-               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
-                                       fileAction, fileAction, NULL) == FALSE) {
-                       return EXIT_FAILURE;
-               }
-       }
-       return EXIT_SUCCESS;
-
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/chroot.c b/busybox/coreutils/chroot.c
deleted file mode 100644 (file)
index de6a2ea..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini chroot implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include "busybox.h"
-
-int chroot_main(int argc, char **argv)
-{
-       char *prog;
-
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-       argc--;
-       argv++;
-
-       if (chroot(*argv) || (chdir("/"))) {
-               perror_msg_and_die("cannot change root directory to %s", *argv);
-       }
-
-       argc--;
-       argv++;
-       if (argc >= 1) {
-               prog = *argv;
-               execvp(*argv, argv);
-       } else {
-#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL
-               char shell[] = "/bin/sh";
-               char *shell_argv[2] = { shell, NULL };
-               applet_name = shell;
-               shell_main(1, shell_argv);
-               return EXIT_SUCCESS;
-#else
-               prog = getenv("SHELL");
-               if (!prog)
-                       prog = "/bin/sh";
-               execlp(prog, prog, NULL);
-#endif
-       }
-       perror_msg_and_die("cannot execute %s", prog);
-
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/cmp.c b/busybox/coreutils/cmp.c
deleted file mode 100644 (file)
index 6d57946..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cmp implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "busybox.h"
-
-int cmp_main(int argc, char **argv)
-{
-       FILE *fp1 = NULL, *fp2 = stdin;
-       char *filename1, *filename2 = "-";
-       int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE;
-
-       while ((c = getopt(argc, argv, "s")) != EOF) {
-               switch (c) {
-                       case 's':
-                               silent = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       filename1 = argv[optind];
-       switch (argc - optind) {
-               case 2:
-                       fp2 = xfopen(filename2 = argv[optind + 1], "r");
-               case 1:
-                       fp1 = xfopen(filename1, "r");
-                       break;
-               default:
-                       show_usage();
-       }
-
-       do {
-               c1 = fgetc(fp1);
-               c2 = fgetc(fp2);
-               if (c1 != c2) {
-                       if (silent)
-                               return EXIT_FAILURE;
-                       if (c1 == EOF)
-                               printf("EOF on %s\n", filename1);
-                       else if (c2 == EOF)
-                               printf("EOF on %s\n", filename2);
-                       else
-                               printf("%s %s differ: char %d, line %d\n", filename1, filename2,
-                                               char_pos, line_pos);
-                       return EXIT_FAILURE;
-               }
-               char_pos++;
-               if (c1 == '\n')
-                       line_pos++;
-       } while (c1 != EOF);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/cp.c b/busybox/coreutils/cp.c
deleted file mode 100644 (file)
index 82d43ad..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cp implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-extern int cp_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int flags = 0;
-       int i;
-
-       while ((opt = getopt(argc, argv, "adfipR")) != -1)
-               switch (opt) {
-               case 'a':
-                       flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR;
-                       /* fallthrough */
-               case 'd':
-                       flags |= FILEUTILS_PRESERVE_SYMLINKS;
-                       break;
-               case 'f':
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               case 'p':
-                       flags |= FILEUTILS_PRESERVE_STATUS;
-                       break;
-               case 'R':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               default:
-                       show_usage();
-               }
-       
-       if (optind + 2 > argc)
-               show_usage();
-
-       /* If there are only two arguments and...  */
-       if (optind + 2 == argc) {
-               struct stat source_stat;
-               struct stat dest_stat;
-               int source_exists = 1;
-               int dest_exists = 1;
-
-               if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                               lstat(argv[optind], &source_stat) < 0) ||
-                               (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                                stat(argv[optind], &source_stat))) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind]);
-                       source_exists = 0;
-               }
-
-               if (stat(argv[optind + 1], &dest_stat) < 0) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
-                       dest_exists = 0;
-               }
-               
-               /* ...if neither is a directory or...  */
-               if (((!source_exists || !S_ISDIR(source_stat.st_mode)) &&
-                               (!dest_exists || !S_ISDIR(dest_stat.st_mode))) ||
-                               /* ...recursing, the first is a directory, and the
-                                * second doesn't exist, then... */
-                               ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) &&
-                                !dest_exists)) {
-                       /* ...do a simple copy.  */
-                       if (copy_file(argv[optind], argv[optind + 1], flags) < 0)
-                               status = 1;
-                       return status;
-               }
-       }
-
-       for (i = optind; i < argc - 1; i++) {
-               char *dest = concat_path_file(argv[argc - 1],
-                               get_last_path_component(argv[i]));
-               if (copy_file(argv[i], dest, flags) < 0)
-                       status = 1;
-               free(dest);
-       }
-
-       return status;
-}
diff --git a/busybox/coreutils/cut.c b/busybox/coreutils/cut.c
deleted file mode 100644 (file)
index 3ed2648..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * cut.c - minimalist version of cut
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h> /* getopt */
-#include <string.h>
-#include <limits.h>
-#include "busybox.h"
-
-
-/* globals from other files */
-extern int optind;
-extern char *optarg;
-
-
-/* option vars */
-static char part = 0; /* (b)yte, (c)har, (f)ields */
-static unsigned int supress_non_delimited_lines = 0;
-static char delim = '\t'; /* delimiter, default is tab */
-
-struct cut_list {
-       int startpos;
-       int endpos;
-};
-
-static const int BOL = 0;
-static const int EOL = INT_MAX;
-static const int NON_RANGE = -1;
-
-static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
-static unsigned int nlists = 0; /* number of elements in above list */
-
-
-static int cmpfunc(const void *a, const void *b)
-{
-       struct cut_list *la = (struct cut_list *)a;
-       struct cut_list *lb = (struct cut_list *)b;
-
-       if (la->startpos > lb->startpos)
-               return 1;
-       if (la->startpos < lb->startpos)
-               return -1;
-       return 0;
-}
-
-
-/*
- * parse_lists() - parses a list and puts values into startpos and endpos.
- * valid list formats: N, N-, N-M, -M 
- * more than one list can be seperated by commas
- */
-static void parse_lists(char *lists)
-{
-       char *ltok = NULL;
-       char *ntok = NULL;
-       char *junk;
-       int s = 0, e = 0;
-
-       /* take apart the lists, one by one (they are seperated with commas */
-       while ((ltok = strsep(&lists, ",")) != NULL) {
-
-               /* it's actually legal to pass an empty list */
-               if (strlen(ltok) == 0)
-                       continue;
-
-               /* get the start pos */
-               ntok = strsep(&ltok, "-");
-               if (ntok == NULL) {
-                       fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
-               } else if (strlen(ntok) == 0) {
-                       s = BOL;
-               } else {
-                       s = strtoul(ntok, &junk, 10);
-                       if(*junk != '\0' || s < 0)
-                               error_msg_and_die("invalid byte or field list");
-                       
-                       /* account for the fact that arrays are zero based, while the user
-                        * expects the first char on the line to be char # 1 */
-                       if (s != 0)
-                               s--;
-               }
-
-               /* get the end pos */
-               ntok = strsep(&ltok, "-");
-               if (ntok == NULL) {
-                       e = NON_RANGE;
-               } else if (strlen(ntok) == 0) {
-                       e = EOL;
-               } else {
-                       e = strtoul(ntok, &junk, 10);
-                       if(*junk != '\0' || e < 0)
-                               error_msg_and_die("invalid byte or field list");
-                       /* if the user specified and end position of 0, that means "til the
-                        * end of the line */
-                       if (e == 0)
-                               e = INT_MAX;
-                       e--; /* again, arrays are zero based, lines are 1 based */
-                       if (e == s)
-                               e = NON_RANGE;
-               }
-
-               /* if there's something left to tokenize, the user past an invalid list */
-               if (ltok)
-                       error_msg_and_die("invalid byte or field list");
-               
-               /* add the new list */
-               cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
-               cut_lists[nlists-1].startpos = s;
-               cut_lists[nlists-1].endpos = e;
-       }
-
-       /* make sure we got some cut positions out of all that */
-       if (nlists == 0)
-               error_msg_and_die("missing list of positions");
-
-       /* now that the lists are parsed, we need to sort them to make life easier
-        * on us when it comes time to print the chars / fields / lines */
-       qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
-
-}
-
-
-static void cut_line_by_chars(const char *line)
-{
-       int c, l;
-       /* set up a list so we can keep track of what's been printed */
-       char *printed = xcalloc(strlen(line), sizeof(char));
-
-       /* print the chars specified in each cut list */
-       for (c = 0; c < nlists; c++) {
-               l = cut_lists[c].startpos;
-               while (l < strlen(line)) {
-                       if (!printed[l]) {
-                               putchar(line[l]);
-                               printed[l] = 'X';
-                       }
-                       l++;
-                       if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
-                               break;
-               }
-       }
-       putchar('\n'); /* cuz we were handed a chomped line */
-       free(printed);
-}
-
-
-static void cut_line_by_fields(char *line)
-{
-       int c, f;
-       int ndelim = -1; /* zero-based / one-based problem */
-       int nfields_printed = 0;
-       char *field = NULL;
-       char d[2] = { delim, 0 };
-       char *printed;
-
-       /* test the easy case first: does this line contain any delimiters? */
-       if (strchr(line, delim) == NULL) {
-               if (!supress_non_delimited_lines)
-                       puts(line);
-               return;
-       }
-
-       /* set up a list so we can keep track of what's been printed */
-       printed = xcalloc(strlen(line), sizeof(char));
-
-       /* process each list on this line, for as long as we've got a line to process */
-       for (c = 0; c < nlists && line; c++) {
-               f = cut_lists[c].startpos;
-               do {
-
-                       /* find the field we're looking for */
-                       while (line && ndelim < f) {
-                               field = strsep(&line, d);
-                               ndelim++;
-                       }
-
-                       /* we found it, and it hasn't been printed yet */
-                       if (field && ndelim == f && !printed[ndelim]) {
-                               /* if this isn't our first time through, we need to print the
-                                * delimiter after the last field that was printed */
-                               if (nfields_printed > 0)
-                                       putchar(delim);
-                               fputs(field, stdout);
-                               printed[ndelim] = 'X';
-                               nfields_printed++;
-                       }
-
-                       f++;
-
-                       /* keep going as long as we have a line to work with, this is a
-                        * list, and we're not at the end of that list */
-               } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
-       }
-
-       /* if we printed anything at all, we need to finish it with a newline cuz
-        * we were handed a chomped line */
-       putchar('\n');
-
-       free(printed);
-}
-
-
-static void cut_file_by_lines(const char *line, unsigned int linenum)
-{
-       static int c = 0;
-       static int l = -1;
-       
-       /* I can't initialize this above cuz the "initializer isn't
-        * constant" *sigh* */
-       if (l == -1)
-               l = cut_lists[c].startpos;
-
-       /* get out if we have no more lists to process or if the lines are lower
-        * than what we're interested in */
-       if (c >= nlists || linenum < l)
-               return;
-
-       /* if the line we're looking for is lower than the one we were passed, it
-        * means we displayed it already, so move on */
-       while (l < linenum) {
-               l++;
-               /* move on to the next list if we're at the end of this one */
-               if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
-                       c++;
-                       /* get out if there's no more lists to process */
-                       if (c >= nlists)
-                               return;
-                       l = cut_lists[c].startpos;
-                       /* get out if the current line is lower than the one we just became
-                        * interested in */
-                       if (linenum < l)
-                               return;
-               }
-       }
-
-       /* If we made it here, it means we've found the line we're looking for, so print it */
-       puts(line);
-}
-
-
-/*
- * snippy-snip
- */
-static void cut_file(FILE *file)
-{
-       char *line = NULL;
-       unsigned int linenum = 0; /* keep these zero-based to be consistent */
-
-       /* go through every line in the file */
-       while ((line = get_line_from_file(file)) != NULL) {
-               chomp(line);
-
-               /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
-               if (part == 'c' || part == 'b')
-                       cut_line_by_chars(line);
-
-               /* cut based on fields */
-               else if (part == 'f') {
-                       if (delim == '\n')
-                               cut_file_by_lines(line, linenum);
-                       else
-                               cut_line_by_fields(line);
-               }
-
-               linenum++;
-               free(line);
-       }
-}
-
-
-extern int cut_main(int argc, char **argv)
-{
-       int opt;
-
-       while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) {
-               switch (opt) {
-                       case 'b':
-                       case 'c':
-                       case 'f':
-                               /* make sure they didn't ask for two types of lists */
-                               if (part != 0) {
-                                       error_msg_and_die("only one type of list may be specified");
-                               }
-                               part = (char)opt;
-                               parse_lists(optarg);
-                               break;
-                       case 'd':
-                               if (strlen(optarg) > 1) {
-                                       error_msg_and_die("the delimiter must be a single character");
-                               }
-                               delim = optarg[0];
-                               break;
-                       case 'n':
-                               /* no-op */
-                               break;
-                       case 's':
-                               supress_non_delimited_lines++;
-                               break;
-               }
-       }
-
-       if (part == 0) {
-               error_msg_and_die("you must specify a list of bytes, characters, or fields");
-       }
-
-       /*  non-field (char or byte) cutting has some special handling */
-       if (part != 'f') {
-               if (supress_non_delimited_lines) {
-                       error_msg_and_die("suppressing non-delimited lines makes sense"
-                                       " only when operating on fields");
-               }
-               if (delim != '\t' && part != 'f') {
-                       error_msg_and_die("a delimiter may be specified only when operating on fields");
-               }
-       }
-
-       /* argv[(optind)..(argc-1)] should be names of file to process. If no
-        * files were specified or '-' was specified, take input from stdin.
-        * Otherwise, we process all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               cut_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       file = wfopen(argv[i], "r");
-                       if(file) {
-                               cut_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/date.c b/busybox/coreutils/date.c
deleted file mode 100644 (file)
index 6db3e28..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini date implementation for busybox
- *
- * by Matthew Grant <grantma@anathoth.gen.nz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-
-/* This 'date' command supports only 2 time setting formats, 
-   all the GNU strftime stuff (its in libc, lets use it),
-   setting time using UTC and displaying int, as well as
-   an RFC 822 complient date output for shell scripting
-   mail commands */
-
-/* Input parsing code is always bulky - used heavy duty libc stuff as
-   much as possible, missed out a lot of bounds checking */
-
-/* Default input handling to save suprising some people */
-
-static struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
-{
-       int nr;
-
-       nr = sscanf(t_string, "%2d%2d%2d%2d%d",
-                               &(tm_time->tm_mon),
-                               &(tm_time->tm_mday),
-                               &(tm_time->tm_hour),
-                               &(tm_time->tm_min), &(tm_time->tm_year));
-
-       if (nr < 4 || nr > 5) {
-               error_msg_and_die(invalid_date, t_string); 
-       }
-
-       /* correct for century  - minor Y2K problem here? */
-       if (tm_time->tm_year >= 1900)
-               tm_time->tm_year -= 1900;
-       /* adjust date */
-       tm_time->tm_mon -= 1;
-
-       return (tm_time);
-
-}
-
-
-/* The new stuff for LRP */
-
-static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
-{
-       struct tm t;
-
-       /* Parse input and assign appropriately to tm_time */
-
-       if (t=*tm_time,sscanf(t_string, "%d:%d:%d",
-                          &t.tm_hour, &t.tm_min, &t.tm_sec) == 3) {
-                                       /* no adjustments needed */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d:%d",
-                                         &t.tm_hour, &t.tm_min) == 2) {
-                                       /* no adjustments needed */
-
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d:%d",
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour,
-                                         &t.tm_min, &t.tm_sec) == 5) {
-
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d",
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour, &t.tm_min) == 4) {
-
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d:%d",
-                                         &t.tm_year,
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour,
-                                         &t.tm_min, &t.tm_sec) == 6) {
-
-               t.tm_year -= 1900;      /* Adjust years */
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d",
-                                         &t.tm_year,
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour, &t.tm_min) == 5) {
-               t.tm_year -= 1900;      /* Adjust years */
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else {
-               error_msg_and_die(invalid_date, t_string); 
-       }
-       *tm_time = t;
-       return (tm_time);
-}
-
-
-int date_main(int argc, char **argv)
-{
-       char *date_str = NULL;
-       char *date_fmt = NULL;
-       char *t_buff;
-       int c;
-       int set_time = 0;
-       int rfc822 = 0;
-       int utc = 0;
-       int use_arg = 0;
-       time_t tm;
-       struct tm tm_time;
-
-       /* Interpret command line args */
-       while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
-               switch (c) {
-                       case 'R':
-                               rfc822 = 1;
-                               break;
-                       case 's':
-                               set_time = 1;
-                               if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
-                                       show_usage();
-                               }
-                               break;
-                       case 'u':
-                               utc = 1;
-                               if (putenv("TZ=UTC0") != 0)
-                                       error_msg_and_die(memory_exhausted);
-                               break;
-                       case 'd':
-                               use_arg = 1;
-                               if ((date_str != NULL) || ((date_str = optarg) == NULL))
-                                       show_usage();
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
-               date_fmt = &argv[optind][1];   /* Skip over the '+' */
-       else if (date_str == NULL) {
-               set_time = 1;
-               date_str = argv[optind];
-       } 
-#if 0
-       else {
-               error_msg("date_str='%s'  date_fmt='%s'\n", date_str, date_fmt);
-               show_usage();
-       }
-#endif
-
-       /* Now we have parsed all the information except the date format
-          which depends on whether the clock is being set or read */
-
-       time(&tm);
-       memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
-       /* Zero out fields - take her back to midnight! */
-       if (date_str != NULL) {
-               tm_time.tm_sec = 0;
-               tm_time.tm_min = 0;
-               tm_time.tm_hour = 0;
-       }
-
-       /* Process any date input to UNIX time since 1 Jan 1970 */
-       if (date_str != NULL) {
-
-               if (strchr(date_str, ':') != NULL) {
-                       date_conv_ftime(&tm_time, date_str);
-               } else {
-                       date_conv_time(&tm_time, date_str);
-               }
-
-               /* Correct any day of week and day of year etc. fields */
-               tm = mktime(&tm_time);
-               if (tm < 0)
-                       error_msg_and_die(invalid_date, date_str); 
-               if ( utc ) {
-                       if (putenv("TZ=UTC0") != 0)
-                               error_msg_and_die(memory_exhausted);
-               }
-
-               /* if setting time, set it */
-               if (set_time) {
-                       if (stime(&tm) < 0) {
-                               perror_msg("cannot set date");
-                       }
-               }
-       }
-
-       /* Display output */
-
-       /* Deal with format string */
-       if (date_fmt == NULL) {
-               date_fmt = (rfc822
-                                       ? (utc
-                                          ? "%a, %_d %b %Y %H:%M:%S GMT"
-                                          : "%a, %_d %b %Y %H:%M:%S %z")
-                                       : "%a %b %e %H:%M:%S %Z %Y");
-
-       } else if (*date_fmt == '\0') {
-               /* Imitate what GNU 'date' does with NO format string! */
-               printf("\n");
-               return EXIT_SUCCESS;
-       }
-
-       /* Handle special conversions */
-
-       if (strncmp(date_fmt, "%f", 2) == 0) {
-               date_fmt = "%Y.%m.%d-%H:%M:%S";
-       }
-
-       /* Print OUTPUT (after ALL that!) */
-       t_buff = xmalloc(201);
-       strftime(t_buff, 200, date_fmt, &tm_time);
-       puts(t_buff);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/dd.c b/busybox/coreutils/dd.c
deleted file mode 100644 (file)
index d46db82..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dd implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include "busybox.h"
-
-
-static const struct suffix_mult dd_suffixes[] = {
-       { "c", 1 },
-       { "w", 2 },
-       { "b", 512 },
-       { "kD", 1000 },
-       { "k", 1024 },
-       { "MD", 1000000 },
-       { "M", 1048576 },
-       { "GD", 1000000000 },
-       { "G", 1073741824 },
-       { NULL, 0 }
-};
-
-int dd_main(int argc, char **argv)
-{
-       int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE;
-       size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
-       size_t bs = 512, count = -1;
-       ssize_t n;
-       off_t seek = 0, skip = 0;
-       char *infile = NULL, *outfile = NULL, *buf;
-
-       for (i = 1; i < argc; i++) {
-               if (strncmp("bs=", argv[i], 3) == 0)
-                       bs = parse_number(argv[i]+3, dd_suffixes);
-               else if (strncmp("count=", argv[i], 6) == 0)
-                       count = parse_number(argv[i]+6, dd_suffixes);
-               else if (strncmp("seek=", argv[i], 5) == 0)
-                       seek = parse_number(argv[i]+5, dd_suffixes);
-               else if (strncmp("skip=", argv[i], 5) == 0)
-                       skip = parse_number(argv[i]+5, dd_suffixes);
-               else if (strncmp("if=", argv[i], 3) == 0)
-                       infile = argv[i]+3;
-               else if (strncmp("of=", argv[i], 3) == 0)
-                       outfile = argv[i]+3;
-               else if (strncmp("conv=", argv[i], 5) == 0) {
-                       buf = argv[i]+5;
-                       while (1) {
-                               if (strncmp("notrunc", buf, 7) == 0) {
-                                       trunc = FALSE;
-                                       buf += 7;
-                               } else if (strncmp("sync", buf, 4) == 0) {
-                                       sync_flag = TRUE;
-                                       buf += 4;
-                               } else {
-                                       error_msg_and_die("invalid conversion `%s'", argv[i]+5);
-                               }
-                               if (buf[0] == '\0')
-                                       break;
-                               if (buf[0] == ',')
-                                       buf++;
-                       }
-               } else
-                       show_usage();
-       }
-
-       buf = xmalloc(bs);
-
-       if (infile != NULL) {
-               if ((ifd = open(infile, O_RDONLY)) < 0)
-                       perror_msg_and_die("%s", infile);
-       } else {
-               ifd = STDIN_FILENO;
-               infile = "standard input";
-       }
-
-       if (outfile != NULL) {
-               oflag = O_WRONLY | O_CREAT;
-
-               if (!seek && trunc)
-                       oflag |= O_TRUNC;
-
-               if ((ofd = open(outfile, oflag, 0666)) < 0)
-                       perror_msg_and_die("%s", outfile);
-
-               if (seek && trunc) {
-                       if (ftruncate(ofd, seek * bs) < 0)
-                               perror_msg_and_die("%s", outfile);
-               }
-       } else {
-               ofd = STDOUT_FILENO;
-               outfile = "standard output";
-       }
-
-       if (skip) {
-               if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
-                       perror_msg_and_die("%s", infile);
-       }
-
-       if (seek) {
-               if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
-                       perror_msg_and_die("%s", outfile);
-       }
-
-       while (in_full + in_part != count) {
-               n = safe_read(ifd, buf, bs);
-               if (n < 0)
-                       perror_msg_and_die("%s", infile);
-               if (n == 0)
-                       break;
-               if (n == bs)
-                       in_full++;
-               else
-                       in_part++;
-               if (sync_flag) {
-                       memset(buf + n, '\0', bs - n);
-                       n = bs;
-               }
-               n = full_write(ofd, buf, n);
-               if (n < 0)
-                       perror_msg_and_die("%s", outfile);
-               if (n == bs)
-                       out_full++;
-               else
-                       out_part++;
-       }
-
-       fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part);
-       fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/df.c b/busybox/coreutils/df.c
deleted file mode 100644 (file)
index 8cb13fa..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini df implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mntent.h>
-#include <sys/vfs.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern const char mtab_file[]; /* Defined in utility.c */
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long df_disp_hr = KILOBYTE; 
-#endif
-
-static int do_df(char *device, const char *mount_point)
-{
-       struct statfs s;
-       long blocks_used;
-       long blocks_percent_used;
-
-       if (statfs(mount_point, &s) != 0) {
-               perror_msg("%s", mount_point);
-               return FALSE;
-       }
-
-       if (s.f_blocks > 0) {
-               blocks_used = s.f_blocks - s.f_bfree;
-               if(blocks_used == 0)
-                       blocks_percent_used = 0;
-               else {
-                       blocks_percent_used = (long)
-                         (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
-               }
-               if (strcmp(device, "/dev/root") == 0) {
-                       /* Adjusts device to be the real root device,
-                        * or leaves device alone if it can't find it */
-                       device = find_real_root_device_name(device);
-                       if(device==NULL)
-                               return FALSE;
-               }
-#ifdef BB_FEATURE_HUMAN_READABLE
-               printf("%-20s %9s ", device,
-                               make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
-
-               printf("%9s ",
-                               make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr));
-
-               printf("%9s %3ld%% %s\n",
-                               make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
-                               blocks_percent_used, mount_point);
-#else
-               printf("%-20s %9ld %9ld %9ld %3ld%% %s\n",
-                               device,
-                               (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)),
-                               (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)),
-                               (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)),
-                               blocks_percent_used, mount_point);
-#endif
-       }
-
-       return TRUE;
-}
-
-extern int df_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int opt = 0;
-       int i = 0;
-       char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */
-
-       while ((opt = getopt(argc, argv, "k"
-#ifdef BB_FEATURE_HUMAN_READABLE
-       "hm"
-#endif
-)) > 0)
-       {
-               switch (opt) {
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h':
-                               df_disp_hr = 0;
-                               strcpy(disp_units_hdr, "     Size");
-                               break;
-                       case 'm':
-                               df_disp_hr = MEGABYTE;
-                               strcpy(disp_units_hdr, "1M-blocks");
-                               break;
-#endif
-                       case 'k':
-                               /* default display is kilobytes */
-                               break;
-                       default:
-                                         show_usage();
-               }
-       }
-
-       printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr,
-              "Used", "Available", "Use%", "Mounted on");
-
-       if(optind < argc) {
-               struct mntent *mount_entry;
-               for(i = optind; i < argc; i++)
-               {
-                       if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) {
-                               error_msg("%s: can't find mount point.", argv[i]);
-                               status = EXIT_FAILURE;
-                       } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
-                               status = EXIT_FAILURE;
-               }
-       } else {
-               FILE *mount_table;
-               struct mntent *mount_entry;
-
-               mount_table = setmntent(mtab_file, "r");
-               if (mount_table == 0) {
-                       perror_msg("%s", mtab_file);
-                       return EXIT_FAILURE;
-               }
-
-               while ((mount_entry = getmntent(mount_table))) {
-                       if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
-                               status = EXIT_FAILURE;
-               }
-               endmntent(mount_table);
-       }
-
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/dirname.c b/busybox/coreutils/dirname.c
deleted file mode 100644 (file)
index b534e69..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dirname implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-extern int dirname_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-'))
-               show_usage();
-       argv++;
-
-       puts (dirname (argv[0]));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/dos2unix.c b/busybox/coreutils/dos2unix.c
deleted file mode 100644 (file)
index cb30c56..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * dos2unix for BusyBox
- *
- * dos2unix '\n' convertor 0.5.0
- *   based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
- * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
- * All rights reserved.
- *
- * dos2unix filters reading input from stdin and writing output to stdout.
- * Without arguments it reverts the format (e.i. if source is in UNIX format,
- * output is in DOS format and vice versa).
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- * See the COPYING file for license information.
- */
-
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include "busybox.h"
-
-
-/* We are making a lame pseudo-random string generator here.  in
- * convert(), each pass through the while loop will add more and more
- * stuff into value, which is _supposed_ to wrap.  We don't care about
- * it being accurate.  We care about it being messy, since we then mod
- * it by the sizeof(letters) and then use that as an index into letters
- * to pick a random letter to add to out temporary file. */
-typedef unsigned long int bb_uint64_t;
-
-static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-// if fn is NULL then input is stdin and output is stdout
-static int convert(char *fn, int ConvType) 
-{
-       int c, fd;
-       struct timeval tv;
-       char tempFn[BUFSIZ];
-       static bb_uint64_t value=0;
-       FILE *in = stdin, *out = stdout;
-
-       if (fn != NULL) {
-               if ((in = wfopen(fn, "rw")) == NULL) {
-                       return -1;
-               }
-               strcpy(tempFn, fn);
-               c = strlen(tempFn);
-               tempFn[c] = '.';
-               while(1) {
-                   if (c >=BUFSIZ)
-                       error_msg_and_die("unique name not found");
-                   /* Get some semi random stuff to try and make a
-                    * random filename based (and in the same dir as)
-                    * the input file... */
-                   gettimeofday (&tv, NULL);
-                   value += ((bb_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
-                   tempFn[++c] = letters[value % 62];
-                   tempFn[c+1] = '\0';
-                   value /= 62;
-
-                   if ((fd = open(tempFn, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 ) {
-                       continue;
-                   }
-                   out = fdopen(fd, "w+");
-                   if (!out) {
-                       close(fd);
-                       remove(tempFn);
-                       continue;
-                   }
-                   break;
-               }
-       }
-
-       while ((c = fgetc(in)) != EOF) {
-               if (c == '\r') {
-                       if ((ConvType == CT_UNIX2DOS) && (fn != NULL)) {
-                               // file is alredy in DOS format so it is not necessery to touch it
-                               remove(tempFn);
-                               if (fclose(in) < 0 || fclose(out) < 0) {
-                                       perror_msg(NULL);
-                                       return -2;
-                               }
-                               return 0;
-                       }
-                       if (!ConvType)
-                               ConvType = CT_DOS2UNIX;
-                       break;
-               }
-               if (c == '\n') {
-                       if ((ConvType == CT_DOS2UNIX) && (fn != NULL)) {
-                               // file is alredy in UNIX format so it is not necessery to touch it
-                               remove(tempFn);
-                               if ((fclose(in) < 0) || (fclose(out) < 0)) {
-                                       perror_msg(NULL);
-                                       return -2;
-                               }
-                               return 0;
-                       }
-                       if (!ConvType) {
-                               ConvType = CT_UNIX2DOS;
-                       }
-                       if (ConvType == CT_UNIX2DOS) {
-                               fputc('\r', out);
-                       }
-                       fputc('\n', out);
-                       break;
-               }
-               fputc(c, out);
-       }
-       if (c != EOF)
-               while ((c = fgetc(in)) != EOF) {
-                       if (c == '\r')
-                               continue;
-                       if (c == '\n') {
-                               if (ConvType == CT_UNIX2DOS)
-                                       fputc('\r', out);
-                               fputc('\n', out);
-                               continue;
-                       }
-               fputc(c, out);
-       }
-
-       if (fn != NULL) {
-           if (fclose(in) < 0 || fclose(out) < 0) {
-               perror_msg(NULL);
-               remove(tempFn);
-               return -2;
-           }
-
-           /* Assume they are both on the same filesystem (which
-            * should be true since we put them into the same directory
-            * so we _should_ be ok, but you never know... */
-           if (rename(tempFn, fn) < 0) {
-               perror_msg("unable to rename '%s' as '%s'", tempFn, fn);
-               return -1;
-           }
-       }
-
-       return 0;
-}
-
-int dos2unix_main(int argc, char *argv[]) 
-{
-       int ConvType = CT_AUTO;
-       int o;
-
-       //See if we are supposed to be doing dos2unix or unix2dos 
-       if (argv[0][0]=='d') {
-           ConvType = CT_DOS2UNIX;
-       }
-       if (argv[0][0]=='u') {
-           ConvType = CT_UNIX2DOS;
-       }
-
-       // process parameters
-       while ((o = getopt(argc, argv, "du")) != EOF) {
-               switch (o) {
-               case 'd':
-                       ConvType = CT_UNIX2DOS;
-                       break;
-               case 'u':
-                       ConvType = CT_DOS2UNIX;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if (optind < argc) {
-               while(optind < argc)
-                       if ((o = convert(argv[optind++], ConvType)) < 0)
-                               break;
-       }
-       else
-               o = convert(NULL, ConvType);
-
-       return o;
-}
-
diff --git a/busybox/coreutils/du.c b/busybox/coreutils/du.c
deleted file mode 100644 (file)
index fb649ae..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini du implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-#include <errno.h>
-#include "busybox.h"
-
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long disp_hr = KILOBYTE;
-#endif
-
-typedef void (Display) (long, char *);
-
-static int du_depth = 0;
-static int count_hardlinks = 0;
-
-static Display *print;
-
-static void print_normal(long size, char *filename)
-{
-#ifdef BB_FEATURE_HUMAN_READABLE
-       printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
-#else
-       printf("%ld\t%s\n", size, filename);
-#endif
-}
-
-static void print_summary(long size, char *filename)
-{
-       if (du_depth == 1) {
-               print_normal(size, filename);
-       }
-}
-
-#define HASH_SIZE       311             /* Should be prime */
-#define hash_inode(i)   ((i) % HASH_SIZE)
-
-typedef struct ino_dev_hash_bucket_struct {
-  struct ino_dev_hash_bucket_struct *next;
-  ino_t ino;
-  dev_t dev;
-  char name[1];
-} ino_dev_hashtable_bucket_t;
-
-static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
-
-/*
- * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
- * `ino_dev_hashtable', else return 0
- *
- * If NAME is a non-NULL pointer to a character pointer, and there is
- * a match, then set *NAME to the value of the name slot in that
- * bucket.
- */
-static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
-{
-       ino_dev_hashtable_bucket_t *bucket;
-
-       bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
-       while (bucket != NULL) {
-         if ((bucket->ino == statbuf->st_ino) &&
-                 (bucket->dev == statbuf->st_dev))
-         {
-               if (name) *name = bucket->name;
-               return 1;
-         }
-         bucket = bucket->next;
-       }
-       return 0;
-}
-
-/* Add statbuf to statbuf hash table */
-static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
-{
-       int i;
-       size_t s;
-       ino_dev_hashtable_bucket_t *bucket;
-
-       i = hash_inode(statbuf->st_ino);
-       s = name ? strlen(name) : 0;
-       bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
-       bucket->ino = statbuf->st_ino;
-       bucket->dev = statbuf->st_dev;
-       if (name)
-               strcpy(bucket->name, name);
-       else
-               bucket->name[0] = '\0';
-       bucket->next = ino_dev_hashtable[i];
-       ino_dev_hashtable[i] = bucket;
-}
-
-/* Clear statbuf hash table */
-static void reset_ino_dev_hashtable(void)
-{
-       int i;
-       ino_dev_hashtable_bucket_t *bucket;
-
-       for (i = 0; i < HASH_SIZE; i++) {
-               while (ino_dev_hashtable[i] != NULL) {
-                       bucket = ino_dev_hashtable[i]->next;
-                       free(ino_dev_hashtable[i]);
-                       ino_dev_hashtable[i] = bucket;
-               }
-       }
-}
-
-/* tiny recursive du */
-static long du(char *filename)
-{
-       struct stat statbuf;
-       long sum;
-
-       if ((lstat(filename, &statbuf)) != 0) {
-               perror_msg("%s", filename);
-               return 0;
-       }
-
-       du_depth++;
-       sum = (statbuf.st_blocks >> 1);
-
-       /* Don't add in stuff pointed to by symbolic links */
-       if (S_ISLNK(statbuf.st_mode)) {
-               sum = 0L;
-               if (du_depth == 1) {
-               }
-       }
-       if (S_ISDIR(statbuf.st_mode)) {
-               DIR *dir;
-               struct dirent *entry;
-               char *newfile;
-
-               dir = opendir(filename);
-               if (!dir) {
-                       du_depth--;
-                       return 0;
-               }
-
-               newfile = last_char_is(filename, '/');
-               if (newfile)
-                       *newfile = '\0';
-
-               while ((entry = readdir(dir))) {
-                       char *name = entry->d_name;
-
-                       if ((strcmp(name, "..") == 0)
-                               || (strcmp(name, ".") == 0)) {
-                               continue;
-                       }
-                       newfile = concat_path_file(filename, name);
-                       sum += du(newfile);
-                       free(newfile);
-               }
-               closedir(dir);
-               print(sum, filename);
-       }
-       else if (statbuf.st_nlink > 1 && !count_hardlinks) {
-               /* Add files with hard links only once */
-               if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
-                       sum = 0L;
-                       if (du_depth == 1)
-                               print(sum, filename);
-               }
-               else {
-                       add_to_ino_dev_hashtable(&statbuf, NULL);
-               }
-       }
-       du_depth--;
-       return sum;
-}
-
-int du_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int i;
-       int c;
-
-       /* default behaviour */
-       print = print_normal;
-
-       /* parse argv[] */
-       while ((c = getopt(argc, argv, "sl"
-#ifdef BB_FEATURE_HUMAN_READABLE
-"hm"
-#endif
-"k")) != EOF) {
-                       switch (c) {
-                       case 's':
-                                       print = print_summary;
-                                       break;
-                       case 'l':
-                                       count_hardlinks = 1;
-                                       break;
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h': disp_hr = 0;        break;
-                       case 'm': disp_hr = MEGABYTE; break;
-#endif
-                       case 'k': break;
-                       default:
-                                       show_usage();
-                       }
-       }
-
-       /* go through remaining args (if any) */
-       if (optind >= argc) {
-               if (du(".") == 0)
-                       status = EXIT_FAILURE;
-       } else {
-               long sum;
-
-               for (i=optind; i < argc; i++) {
-                       sum = du(argv[i]);
-                       if(is_directory(argv[i], FALSE, NULL)==FALSE) {
-                               print_normal(sum, argv[i]);
-                       }
-                       reset_ino_dev_hashtable();
-               }
-       }
-
-       return status;
-}
-
-/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/echo.c b/busybox/coreutils/echo.c
deleted file mode 100644 (file)
index 31c0315..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * echo implementation for busybox
- *
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int 
-echo_main(int argc, char** argv)
-{
-       int nflag = 0;
-       int eflag = 0;
-
-       /* Skip argv[0]. */
-       argc--;
-       argv++;
-
-       while (argc > 0 && *argv[0] == '-')
-       {
-               register char *temp;
-               register int ix;
-
-               /*
-                * If it appears that we are handling options, then make sure
-                * that all of the options specified are actually valid.
-                * Otherwise, the string should just be echoed.
-                */
-               temp = argv[0] + 1;
-
-               for (ix = 0; temp[ix]; ix++)
-               {
-                       if (strrchr("neE", temp[ix]) == 0)
-                               goto just_echo;
-               }
-
-               if (!*temp)
-                       goto just_echo;
-
-               /*
-                * All of the options in temp are valid options to echo.
-                * Handle them.
-                */
-               while (*temp)
-               {
-                       if (*temp == 'n')
-                               nflag = 1;
-                       else if (*temp == 'e')
-                               eflag = 1;
-                       else if (*temp == 'E')
-                               eflag = 0;
-                       else
-                               goto just_echo;
-
-                       temp++;
-               }
-               argc--;
-               argv++;
-       }
-
-just_echo:
-       while (argc > 0) {
-               const char *arg = argv[0];
-               register int c;
-
-               while ((c = *arg++)) {
-
-                       /* Check for escape sequence. */
-                       if (c == '\\' && eflag && *arg) {
-                               if (*arg == 'c') {
-                                       /* '\c' means cancel newline. */
-                                       nflag = 1;
-                                       arg++;
-                                       continue;
-                               } else {
-                                       c = process_escape_sequence(&arg);
-                               }
-                       }
-
-                       putchar(c);
-               }
-               argc--;
-               argv++;
-               if (argc > 0)
-                       putchar(' ');
-       }
-       if (!nflag)
-               putchar('\n');
-       fflush(stdout);
-
-       return EXIT_SUCCESS;
-}
-
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- *     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.
- *
- *     @(#)echo.c      8.1 (Berkeley) 5/31/93
- */
diff --git a/busybox/coreutils/env.c b/busybox/coreutils/env.c
deleted file mode 100644 (file)
index 8bb690b..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * env implementation for busybox
- *
- * Copyright (c) 1988, 1993, 1994
- *     The Regents of the University of California.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
- *
- * Modified for BusyBox by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int env_main(int argc, char** argv)
-{
-       char **ep, *p;
-       char *cleanenv[1];
-       int ignore_environment = 0;
-       int ch;
-
-       while ((ch = getopt(argc, argv, "+iu:")) != -1) {
-               switch(ch) {
-               case 'i':
-                       ignore_environment = 1;
-                       break;
-               case 'u':
-                       unsetenv(optarg);
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-       if (optind != argc && !strcmp(argv[optind], "-")) {
-               ignore_environment = 1;
-               argv++;
-       }
-       if (ignore_environment) {
-               environ = cleanenv;
-               cleanenv[0] = NULL;
-       }
-       for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
-               if (putenv(*argv) < 0)
-                       perror_msg_and_die("%s", *argv);
-       if (*argv) {
-               execvp(*argv, argv);
-               perror_msg_and_die("%s", *argv);
-       }
-       for (ep = environ; *ep; ep++)
-               puts(*ep);
-       return 0;
-}
-
-/*
- * Copyright (c) 1988, 1993, 1994
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
diff --git a/busybox/coreutils/expr.c b/busybox/coreutils/expr.c
deleted file mode 100644 (file)
index d6cc82e..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini expr implementation for busybox
- *
- * based on GNU expr Mike Parker.
- * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
- *
- * Busybox modifications 
- * Copyright (c) 2000  Edward Betts <edward@debian.org>.
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2 of the license, or
- * (at your option) any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the gnu
- * general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; if not, write to the free software
- * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
- *
- */
-
-/* This program evaluates expressions.  Each token (operator, operand,
- * parenthesis) of the expression must be a seperate argument.  The
- * parser used is a reasonably general one, though any incarnation of
- * it is language-specific.  It is especially nice for expressions.
- *
- * No parse tree is needed; a new node is evaluated immediately.
- * One function can handle multiple operators all of equal precedence,
- * provided they all associate ((x op x) op x). */
-
-/* no getopt needed */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <regex.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-
-/* The kinds of value we can have.  */
-enum valtype {
-       integer,
-       string
-};
-typedef enum valtype TYPE;
-
-/* A value is.... */
-struct valinfo {
-       TYPE type;                      /* Which kind. */
-       union {                         /* The value itself. */
-               int i;
-               char *s;
-       } u;
-};
-typedef struct valinfo VALUE;
-
-/* The arguments given to the program, minus the program name.  */
-static char **args;
-
-static VALUE *docolon (VALUE *sv, VALUE *pv);
-static VALUE *eval (void);
-static VALUE *int_value (int i);
-static VALUE *str_value (char *s);
-static int nextarg (char *str);
-static int null (VALUE *v);
-static int toarith (VALUE *v);
-static void freev (VALUE *v);
-static void tostring (VALUE *v);
-
-int expr_main (int argc, char **argv)
-{
-       VALUE *v;
-
-       if (argc == 1) {
-               error_msg_and_die("too few arguments");
-       }
-
-       args = argv + 1;
-
-       v = eval ();
-       if (*args)
-               error_msg_and_die ("syntax error");
-
-       if (v->type == integer)
-               printf ("%d\n", v->u.i);
-       else
-               puts (v->u.s);
-
-       exit (null (v));
-}
-
-/* Return a VALUE for I.  */
-
-static VALUE *int_value (int i)
-{
-       VALUE *v;
-
-       v = xmalloc (sizeof(VALUE));
-       v->type = integer;
-       v->u.i = i;
-       return v;
-}
-
-/* Return a VALUE for S.  */
-
-static VALUE *str_value (char *s)
-{
-       VALUE *v;
-
-       v = xmalloc (sizeof(VALUE));
-       v->type = string;
-       v->u.s = strdup (s);
-       return v;
-}
-
-/* Free VALUE V, including structure components.  */
-
-static void freev (VALUE *v)
-{
-       if (v->type == string)
-               free (v->u.s);
-       free (v);
-}
-
-/* Return nonzero if V is a null-string or zero-number.  */
-
-static int null (VALUE *v)
-{
-       switch (v->type) {
-               case integer:
-                       return v->u.i == 0;
-               case string:
-                       return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
-               default:
-                       abort ();
-       }
-}
-
-/* Coerce V to a string value (can't fail).  */
-
-static void tostring (VALUE *v)
-{
-       char *temp;
-
-       if (v->type == integer) {
-               temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
-               sprintf (temp, "%d", v->u.i);
-               v->u.s = temp;
-               v->type = string;
-       }
-}
-
-/* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
-
-static int toarith (VALUE *v)
-{
-       int i;
-
-       switch (v->type) {
-               case integer:
-                       return 1;
-               case string:
-                       i = 0;
-                       /* Don't interpret the empty string as an integer.  */
-                       if (v->u.s == 0)
-                               return 0;
-                       i = atoi(v->u.s);
-                       free (v->u.s);
-                       v->u.i = i;
-                       v->type = integer;
-                       return 1;
-               default:
-                       abort ();
-       }
-}
-
-/* Return nonzero if the next token matches STR exactly.
-   STR must not be NULL.  */
-
-static int
-nextarg (char *str)
-{
-       if (*args == NULL)
-               return 0;
-       return strcmp (*args, str) == 0;
-}
-
-/* The comparison operator handling functions.  */
-
-#define cmpf(name, rel)                                        \
-static int name (l, r) VALUE *l; VALUE *r;             \
-{                                                      \
-       if (l->type == string || r->type == string) {           \
-               tostring (l);                           \
-               tostring (r);                           \
-               return strcmp (l->u.s, r->u.s) rel 0;   \
-       }                                               \
-       else                                            \
-               return l->u.i rel r->u.i;               \
-}
- cmpf (less_than, <)
- cmpf (less_equal, <=)
- cmpf (equal, ==)
- cmpf (not_equal, !=)
- cmpf (greater_equal, >=)
- cmpf (greater_than, >)
-
-#undef cmpf
-
-/* The arithmetic operator handling functions.  */
-
-#define arithf(name, op)                       \
-static                                         \
-int name (l, r) VALUE *l; VALUE *r;            \
-{                                              \
-  if (!toarith (l) || !toarith (r))            \
-    error_msg_and_die ("non-numeric argument");        \
-  return l->u.i op r->u.i;                     \
-}
-
-#define arithdivf(name, op)                    \
-static int name (l, r) VALUE *l; VALUE *r;             \
-{                                              \
-  if (!toarith (l) || !toarith (r))            \
-    error_msg_and_die ( "non-numeric argument");       \
-  if (r->u.i == 0)                             \
-    error_msg_and_die ( "division by zero");           \
-  return l->u.i op r->u.i;                     \
-}
-
- arithf (plus, +)
- arithf (minus, -)
- arithf (multiply, *)
- arithdivf (divide, /)
- arithdivf (mod, %)
-
-#undef arithf
-#undef arithdivf
-
-/* Do the : operator.
-   SV is the VALUE for the lhs (the string),
-   PV is the VALUE for the rhs (the pattern).  */
-
-static VALUE *docolon (VALUE *sv, VALUE *pv)
-{
-       VALUE *v;
-       const char *errmsg;
-       struct re_pattern_buffer re_buffer;
-       struct re_registers re_regs;
-       int len;
-
-       tostring (sv);
-       tostring (pv);
-
-       if (pv->u.s[0] == '^') {
-               fprintf (stderr, "\
-warning: unportable BRE: `%s': using `^' as the first character\n\
-of a basic regular expression is not portable; it is being ignored",
-               pv->u.s);
-       }
-
-       len = strlen (pv->u.s);
-       memset (&re_buffer, 0, sizeof (re_buffer));
-       memset (&re_regs, 0, sizeof (re_regs));
-       re_buffer.allocated = 2 * len;
-       re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
-       re_buffer.translate = 0;
-       re_syntax_options = RE_SYNTAX_POSIX_BASIC;
-       errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
-       if (errmsg) {
-               error_msg_and_die("%s", errmsg);
-       }
-
-       len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
-       if (len >= 0) {
-               /* Were \(...\) used? */
-               if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
-                       sv->u.s[re_regs.end[1]] = '\0';
-                       v = str_value (sv->u.s + re_regs.start[1]);
-               }
-               else
-                       v = int_value (len);
-       }
-       else {
-               /* Match failed -- return the right kind of null.  */
-               if (re_buffer.re_nsub > 0)
-                       v = str_value ("");
-               else
-                       v = int_value (0);
-       }
-       free (re_buffer.buffer);
-       return v;
-}
-
-/* Handle bare operands and ( expr ) syntax.  */
-
-static VALUE *eval7 (void)
-{
-       VALUE *v;
-
-       if (!*args)
-               error_msg_and_die ( "syntax error");
-
-       if (nextarg ("(")) {
-               args++;
-               v = eval ();
-               if (!nextarg (")"))
-                       error_msg_and_die ( "syntax error");
-                       args++;
-                       return v;
-               }
-
-       if (nextarg (")"))
-               error_msg_and_die ( "syntax error");
-
-       return str_value (*args++);
-}
-
-/* Handle match, substr, index, length, and quote keywords.  */
-
-static VALUE *eval6 (void)
-{
-       VALUE *l, *r, *v, *i1, *i2;
-
-       if (nextarg ("quote")) {
-               args++;
-               if (!*args)
-                       error_msg_and_die ( "syntax error");
-               return str_value (*args++);
-       }
-       else if (nextarg ("length")) {
-               args++;
-               r = eval6 ();
-               tostring (r);
-               v = int_value (strlen (r->u.s));
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("match")) {
-               args++;
-               l = eval6 ();
-               r = eval6 ();
-               v = docolon (l, r);
-               freev (l);
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("index")) {
-               args++;
-               l = eval6 ();
-               r = eval6 ();
-               tostring (l);
-               tostring (r);
-               v = int_value (strcspn (l->u.s, r->u.s) + 1);
-               if (v->u.i == (int) strlen (l->u.s) + 1)
-                       v->u.i = 0;
-               freev (l);
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("substr")) {
-               args++;
-               l = eval6 ();
-               i1 = eval6 ();
-               i2 = eval6 ();
-               tostring (l);
-               if (!toarith (i1) || !toarith (i2)
-                       || i1->u.i > (int) strlen (l->u.s)
-                       || i1->u.i <= 0 || i2->u.i <= 0)
-               v = str_value ("");
-               else {
-                       v = xmalloc (sizeof(VALUE));
-                       v->type = string;
-                       v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
-                               l->u.s + i1->u.i - 1, i2->u.i);
-                               v->u.s[i2->u.i] = 0;
-               }
-               freev (l);
-               freev (i1);
-               freev (i2);
-               return v;
-       }
-       else
-               return eval7 ();
-}
-
-/* Handle : operator (pattern matching).
-   Calls docolon to do the real work.  */
-
-static VALUE *eval5 (void)
-{
-       VALUE *l, *r, *v;
-
-       l = eval6 ();
-       while (nextarg (":")) {
-               args++;
-               r = eval6 ();
-               v = docolon (l, r);
-               freev (l);
-               freev (r);
-               l = v;
-       }
-       return l;
-}
-
-/* Handle *, /, % operators.  */
-
-static VALUE *eval4 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval5 ();
-       while (1) {
-               if (nextarg ("*"))
-                       fxn = multiply;
-               else if (nextarg ("/"))
-                       fxn = divide;
-               else if (nextarg ("%"))
-                       fxn = mod;
-               else
-                       return l;
-               args++;
-               r = eval5 ();
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle +, - operators.  */
-
-static VALUE *eval3 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval4 ();
-       while (1) {
-               if (nextarg ("+"))
-                       fxn = plus;
-               else if (nextarg ("-"))
-                       fxn = minus;
-               else
-                       return l;
-               args++;
-               r = eval4 ();
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle comparisons.  */
-
-static VALUE *eval2 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval3 ();
-       while (1) {
-               if (nextarg ("<"))
-                       fxn = less_than;
-               else if (nextarg ("<="))
-                       fxn = less_equal;
-               else if (nextarg ("=") || nextarg ("=="))
-                       fxn = equal;
-               else if (nextarg ("!="))
-                       fxn = not_equal;
-               else if (nextarg (">="))
-                       fxn = greater_equal;
-               else if (nextarg (">"))
-                       fxn = greater_than;
-               else
-                       return l;
-               args++;
-               r = eval3 ();
-               toarith (l);
-               toarith (r);
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle &.  */
-
-static VALUE *eval1 (void)
-{
-       VALUE *l, *r;
-
-       l = eval2 ();
-       while (nextarg ("&")) {
-               args++;
-               r = eval2 ();
-               if (null (l) || null (r)) {
-                       freev (l);
-                       freev (r);
-                       l = int_value (0);
-               }
-               else
-                       freev (r);
-       }
-       return l;
-}
-
-/* Handle |.  */
-
-static VALUE *eval (void)
-{
-       VALUE *l, *r;
-
-       l = eval1 ();
-       while (nextarg ("|")) {
-               args++;
-               r = eval1 ();
-               if (null (l)) {
-                       freev (l);
-                       l = r;
-               }
-               else
-                       freev (r);
-       }
-       return l;
-}
diff --git a/busybox/coreutils/head.c b/busybox/coreutils/head.c
deleted file mode 100644 (file)
index 688c250..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini head implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-static int head(int len, FILE *fp)
-{
-       int i;
-       char *input;
-
-       for (i = 0; i < len; i++) {
-               if ((input = get_line_from_file(fp)) == NULL)
-                       break;
-               fputs(input, stdout);
-               free(input);
-       }
-       return 0;
-}
-
-/* BusyBoxed head(1) */
-int head_main(int argc, char **argv)
-{
-       FILE *fp;
-       int need_headers, opt, len = 10, status = EXIT_SUCCESS;
-
-       /* parse argv[] */
-       while ((opt = getopt(argc, argv, "n:")) > 0) {
-               switch (opt) {
-               case 'n':
-                       len = atoi(optarg);
-                       if (len >= 1)
-                               break;
-                       /* fallthrough */
-               default:
-                       show_usage();
-               }
-       }
-
-       /* get rest of argv[] or stdin if nothing's left */
-       if (argv[optind] == NULL) {
-               head(len, stdin);
-               return status;
-       } 
-
-       need_headers = optind != (argc - 1);
-       while (argv[optind]) {
-               if (strcmp(argv[optind], "-") == 0) {
-                       fp = stdin;
-                       argv[optind] = "standard input";
-               } else {
-                       if ((fp = wfopen(argv[optind], "r")) == NULL)
-                               status = EXIT_FAILURE;
-               }
-               if (fp) {
-                       if (need_headers) {
-                               printf("==> %s <==\n", argv[optind]);
-                       }
-                       head(len, fp);
-                       if (ferror(fp)) {
-                               perror_msg("%s", argv[optind]);
-                               status = EXIT_FAILURE;
-                       }
-                       if (optind < argc - 1)
-                               putchar('\n');
-                       if (fp != stdin)
-                               fclose(fp);
-               }
-               optind++;
-       }
-
-       return status;
-}
diff --git a/busybox/coreutils/hostid.c b/busybox/coreutils/hostid.c
deleted file mode 100644 (file)
index 68a2cc6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini hostid implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int hostid_main(int argc, char **argv)
-{
-       printf("%lx\n", gethostid());
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/id.c b/busybox/coreutils/id.c
deleted file mode 100644 (file)
index 85b288c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini id implementation for busybox
- *
- * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <string.h>
-#include <sys/types.h>
-
-extern int id_main(int argc, char **argv)
-{
-       int no_user = 0, no_group = 0, print_real = 0;
-       int name_not_number = 0;
-       char user[9], group[9];
-       long gid;
-       long pwnam, grnam;
-       int opt;
-       
-       gid = 0;
-
-       while ((opt = getopt(argc, argv, "ugrn")) > 0) {
-               switch (opt) {
-                       case 'u':
-                               no_group++;
-                               break;
-                       case 'g':
-                               no_user++;
-                               break;
-                       case 'r':
-                               print_real++;
-                               break;
-                       case 'n':
-                               name_not_number++;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (no_user && no_group) show_usage();
-
-       if (argv[optind] == NULL) {
-               if (print_real) {
-                       my_getpwuid(user, getuid());
-                       my_getgrgid(group, getgid());
-               } else {
-                       my_getpwuid(user, geteuid());
-                       my_getgrgid(group, getegid());
-               }
-       } else {
-               strncpy(user, argv[optind], 8);
-               user[8] = '\0';
-           gid = my_getpwnamegid(user);
-               my_getgrgid(group, gid);
-       }
-
-       pwnam=my_getpwnam(user);
-       grnam=my_getgrnam(group);
-
-       if (no_group) {
-               if(name_not_number && user)
-                       puts(user);
-               else
-                       printf("%ld\n", pwnam);
-       } else if (no_user) {
-               if(name_not_number && group)
-                       puts(group);
-               else
-                       printf("%ld\n", grnam);
-       } else {
-               printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group);
-       }
-       return(0);
-}
-
-
-/* END CODE */
diff --git a/busybox/coreutils/length.c b/busybox/coreutils/length.c
deleted file mode 100644 (file)
index 73becd2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "busybox.h"
-
-extern int length_main(int argc, char **argv)
-{
-       if (argc != 2 || **(argv + 1) == '-')
-               show_usage();
-       printf("%lu\n", (long)strlen(argv[1]));
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/ln.c b/busybox/coreutils/ln.c
deleted file mode 100644 (file)
index 7412a86..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ln implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-static const int LN_SYMLINK = 1;
-static const int LN_FORCE = 2;
-static const int LN_NODEREFERENCE = 4;
-
-/*
- * linkDestName is where the link points to,
- * linkSrcName is the name of the link to be created.
- */
-static int fs_link(const char *link_destname, const char *link_srcname, 
-               const int flag)
-{
-       int status;
-       int src_is_dir;
-       char *src_name;
-
-       if (link_destname==NULL)
-               return(FALSE);
-
-       src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1);
-
-       if (link_srcname==NULL)
-               strcpy(src_name, link_destname);
-       else
-               strcpy(src_name, link_srcname);
-
-       if (flag&LN_NODEREFERENCE)
-               src_is_dir = is_directory(src_name, TRUE, NULL);
-       else
-               src_is_dir = is_directory(src_name, FALSE, NULL);       
-       
-       if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) {
-               char* srcdir_name;
-
-               srcdir_name = xstrdup(link_destname);
-               strcat(src_name, "/");
-               strcat(src_name, get_last_path_component(srcdir_name));
-               free(srcdir_name);
-       }
-       
-       if (flag&LN_FORCE)
-               unlink(src_name);
-               
-       if (flag&LN_SYMLINK)
-               status = symlink(link_destname, src_name);
-       else
-               status = link(link_destname, src_name);
-
-       if (status != 0) {
-               perror_msg(src_name);
-               return(FALSE);
-       }
-       return(TRUE);
-}
-
-extern int ln_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int flag = 0;
-       int opt;
-       
-       /* Parse any options */
-       while ((opt=getopt(argc, argv, "sfn")) != -1) {
-               switch(opt) {
-                       case 's':
-                               flag |= LN_SYMLINK;
-                               break;
-                       case 'f':
-                               flag |= LN_FORCE;
-                               break;
-                       case 'n':
-                               flag |= LN_NODEREFERENCE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       if (optind > (argc-1)) {
-               show_usage();
-       } 
-       if (optind == (argc-1)) {
-               if (fs_link(argv[optind], 
-                                       get_last_path_component(argv[optind]), flag)==FALSE)
-                       status = EXIT_FAILURE;
-       }
-       while(optind<(argc-1)) {
-               if (fs_link(argv[optind], argv[argc-1], flag)==FALSE)
-                       status = EXIT_FAILURE;
-               optind++;
-       }
-       exit(status);
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/logname.c b/busybox/coreutils/logname.c
deleted file mode 100644 (file)
index 0924b24..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini logname implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int logname_main(int argc, char **argv)
-{
-       char user[9];
-
-       if (argc > 1)
-               show_usage();
-
-       my_getpwuid(user, geteuid());
-       if (*user) {
-               puts(user);
-               return EXIT_SUCCESS;
-       }
-       error_msg_and_die("no login name");
-}
diff --git a/busybox/coreutils/ls.c b/busybox/coreutils/ls.c
deleted file mode 100644 (file)
index 8d0282d..0000000
+++ /dev/null
@@ -1,937 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * tiny-ls.c version 0.1.0: A minimalist 'ls'
- * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * To achieve a small memory footprint, this version of 'ls' doesn't do any
- * file sorting, and only has the most essential command line switches
- * (i.e., the ones I couldn't live without :-) All features which involve
- * linking in substantial chunks of libc can be disabled.
- *
- * Although I don't really want to add new features to this program to
- * keep it small, I *am* interested to receive bug fixes and ways to make
- * it more portable.
- *
- * KNOWN BUGS:
- * 1. ls -l of a directory doesn't give "total <blocks>" header
- * 2. ls of a symlink to a directory doesn't list directory contents
- * 3. hidden files can make column width too large
- *
- * NON-OPTIMAL BEHAVIOUR:
- * 1. autowidth reads directories twice
- * 2. if you do a short directory listing without filetype characters
- *    appended, there's no need to stat each one
- * PORTABILITY:
- * 1. requires lstat (BSD) - how do you do it without?
- */
-
-enum {
-       TERMINAL_WIDTH = 80,            /* use 79 if terminal has linefold bug */
-       COLUMN_WIDTH = 14,                      /* default if AUTOWIDTH not defined */
-       COLUMN_GAP = 2,                         /* includes the file type char */
-};
-
-
-/************************************************************************/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-#include <time.h>
-#endif
-
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
-/* what is the overall style of the listing */
-enum {
-STYLE_AUTO = 0,
-STYLE_LONG = 1,                /* one record per line, extended info */
-STYLE_SINGLE = 2,              /* one record per line */
-STYLE_COLUMNS = 3              /* fill columns */
-};
-
-/* 51306 lrwxrwxrwx  1 root     root         2 May 11 01:43 /bin/view -> vi* */
-/* what file information will be listed */
-#define LIST_INO               (1<<0)
-#define LIST_BLOCKS            (1<<1)
-#define LIST_MODEBITS  (1<<2)
-#define LIST_NLINKS            (1<<3)
-#define LIST_ID_NAME   (1<<4)
-#define LIST_ID_NUMERIC        (1<<5)
-#define LIST_SIZE              (1<<6)
-#define LIST_DEV               (1<<7)
-#define LIST_DATE_TIME (1<<8)
-#define LIST_FULLTIME  (1<<9)
-#define LIST_FILENAME  (1<<10)
-#define LIST_SYMLINK   (1<<11)
-#define LIST_FILETYPE  (1<<12)
-#define LIST_EXEC              (1<<13)
-
-/* what files will be displayed */
-#define DISP_NORMAL            (0)             /* show normal filenames */
-#define DISP_DIRNAME   (1<<0)  /* 2 or more items? label directories */
-#define DISP_HIDDEN            (1<<1)  /* show filenames starting with .  */
-#define DISP_DOT               (1<<2)  /* show . and .. */
-#define DISP_NOLIST            (1<<3)  /* show directory as itself, not contents */
-#define DISP_RECURSIVE (1<<4)  /* show directory and everything below it */
-#define DISP_ROWS              (1<<5)  /* print across rows */
-
-#ifdef BB_FEATURE_LS_SORTFILES
-/* how will the files be sorted */
-static const int SORT_FORWARD = 0;             /* sort in reverse order */
-static const int SORT_REVERSE = 1;             /* sort in reverse order */
-static const int SORT_NAME = 2;                /* sort by file name */
-static const int SORT_SIZE = 3;                /* sort by file size */
-static const int SORT_ATIME = 4;               /* sort by last access time */
-static const int SORT_CTIME = 5;               /* sort by last change time */
-static const int SORT_MTIME = 6;               /* sort by last modification time */
-static const int SORT_VERSION = 7;             /* sort by version */
-static const int SORT_EXT = 8;         /* sort by file name extension */
-static const int SORT_DIR = 9;         /* sort by file or directory */
-#endif
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-/* which of the three times will be used */
-static const int TIME_MOD = 0;
-static const int TIME_CHANGE = 1;
-static const int TIME_ACCESS = 2;
-#endif
-
-#define LIST_SHORT             (LIST_FILENAME)
-#define LIST_ISHORT            (LIST_INO | LIST_FILENAME)
-#define LIST_LONG              (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | \
-                                               LIST_SIZE | LIST_DATE_TIME | LIST_FILENAME | \
-                                               LIST_SYMLINK)
-#define LIST_ILONG             (LIST_INO | LIST_LONG)
-
-static const int SPLIT_DIR = 0;
-static const int SPLIT_FILE = 1;
-static const int SPLIT_SUBDIR = 2;
-
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
-#ifdef BB_FEATURE_LS_FILETYPES
-#define APPCHAR(mode)   ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
-#endif
-
-/*
- * a directory entry and its stat info are stored here
- */
-struct dnode {                         /* the basic node */
-    char *name;                                /* the dir entry name */
-    char *fullname;                    /* the dir entry name */
-    struct stat dstat;         /* the file stat info */
-    struct dnode *next;                /* point at the next node */
-};
-typedef struct dnode dnode_t;
-
-static struct dnode **list_dir(char *);
-static struct dnode **dnalloc(int);
-static int list_single(struct dnode *);
-
-static unsigned int disp_opts;
-static unsigned int style_fmt;
-static unsigned int list_fmt;
-#ifdef BB_FEATURE_LS_SORTFILES
-static unsigned int sort_opts;
-static unsigned int sort_order;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-static unsigned int time_fmt;
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-static unsigned int follow_links=FALSE;
-#endif
-
-static unsigned short column = 0;
-#ifdef BB_FEATURE_AUTOWIDTH
-static unsigned short terminal_width = TERMINAL_WIDTH;
-static unsigned short column_width = COLUMN_WIDTH;
-static unsigned short tabstops = COLUMN_GAP;
-#else
-static unsigned short column_width = COLUMN_WIDTH;
-#endif
-
-static int status = EXIT_SUCCESS;
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long ls_disp_hr = 0;
-#endif
-
-static int my_stat(struct dnode *cur)
-{
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-       if (follow_links == TRUE) {
-               if (stat(cur->fullname, &cur->dstat)) {
-                       perror_msg("%s", cur->fullname);
-                       status = EXIT_FAILURE;
-                       free(cur->fullname);
-                       free(cur);
-                       return -1;
-               }
-       } else
-#endif
-       if (lstat(cur->fullname, &cur->dstat)) {
-               perror_msg("%s", cur->fullname);
-               status = EXIT_FAILURE;
-               free(cur->fullname);
-               free(cur);
-               return -1;
-       }
-       return 0;
-}
-
-static void newline(void)
-{
-    if (column > 0) {
-        putchar('\n');
-        column = 0;
-    }
-}
-
-/*----------------------------------------------------------------------*/
-#ifdef BB_FEATURE_LS_FILETYPES
-static char append_char(mode_t mode)
-{
-       if ( !(list_fmt & LIST_FILETYPE))
-               return '\0';
-       if ((list_fmt & LIST_EXEC) && S_ISREG(mode)
-           && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
-               return APPCHAR(mode);
-}
-#endif
-
-/*----------------------------------------------------------------------*/
-static void nexttabstop( void )
-{
-       static short nexttab= 0;
-       int n=0;
-
-       if (column > 0) {
-               n= nexttab - column;
-               if (n < 1) n= 1;
-               while (n--) {
-                       putchar(' ');
-                       column++;
-               }
-       }
-       nexttab= column + column_width + COLUMN_GAP; 
-}
-
-/*----------------------------------------------------------------------*/
-static int is_subdir(struct dnode *dn)
-{
-       return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 &&
-                       strcmp(dn->name, "..") != 0);
-}
-
-static int countdirs(struct dnode **dn, int nfiles)
-{
-       int i, dirs;
-
-       if (dn==NULL || nfiles < 1) return(0);
-       dirs= 0;
-       for (i=0; i<nfiles; i++) {
-               if (S_ISDIR(dn[i]->dstat.st_mode)) dirs++;
-       }
-       return(dirs);
-}
-
-static int countsubdirs(struct dnode **dn, int nfiles)
-{
-       int i, subdirs;
-
-       if (dn == NULL || nfiles < 1) return 0;
-       subdirs = 0;
-       for (i = 0; i < nfiles; i++)
-               if (is_subdir(dn[i]))
-                       subdirs++;
-       return subdirs;
-}
-
-static int countfiles(struct dnode **dnp)
-{
-       int nfiles;
-       struct dnode *cur;
-
-       if (dnp == NULL) return(0);
-       nfiles= 0;
-       for (cur= dnp[0];  cur->next != NULL ; cur= cur->next) nfiles++;
-       nfiles++;
-       return(nfiles);
-}
-
-/* get memory to hold an array of pointers */
-static struct dnode **dnalloc(int num)
-{
-       struct dnode **p;
-
-       if (num < 1) return(NULL);
-
-       p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *)));
-       return(p);
-}
-
-#ifdef BB_FEATURE_LS_RECURSIVE
-static void dfree(struct dnode **dnp)
-{
-       struct dnode *cur, *next;
-
-       if(dnp == NULL) return;
-
-       cur=dnp[0];
-       while (cur != NULL) {
-               if (cur->fullname != NULL) free(cur->fullname); /* free the filename */
-               next= cur->next;
-               free(cur);                              /* free the dnode */
-               cur= next;
-       }
-       free(dnp);      /* free the array holding the dnode pointers */
-}
-#endif
-
-static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
-{
-       int dncnt, i, d;
-       struct dnode **dnp;
-
-       if (dn==NULL || nfiles < 1) return(NULL);
-
-       /* count how many dirs and regular files there are */
-       if (which == SPLIT_SUBDIR)
-               dncnt = countsubdirs(dn, nfiles);
-       else {
-               dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */
-               if (which == SPLIT_FILE)
-                       dncnt= nfiles - dncnt;  /* looking for files */
-       }
-
-       /* allocate a file array and a dir array */
-       dnp= dnalloc(dncnt);
-
-       /* copy the entrys into the file or dir array */
-       for (d= i=0; i<nfiles; i++) {
-               if (which == SPLIT_DIR) {
-                       if (S_ISDIR(dn[i]->dstat.st_mode)) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the file */
-               } else if (which == SPLIT_SUBDIR) {
-                       if (is_subdir(dn[i])) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the file or dir */
-               } else {
-                       if (!(S_ISDIR(dn[i]->dstat.st_mode))) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the dir */
-               }
-       }
-       return(dnp);
-}
-
-/*----------------------------------------------------------------------*/
-#ifdef BB_FEATURE_LS_SORTFILES
-static int sortcmp(struct dnode *d1, struct dnode *d2)
-{
-       int cmp, dif;
-
-       cmp= 0;
-       if (sort_opts == SORT_SIZE) {
-               dif= (int)(d1->dstat.st_size - d2->dstat.st_size);
-       } else if (sort_opts == SORT_ATIME) {
-               dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime);
-       } else if (sort_opts == SORT_CTIME) {
-               dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime);
-       } else if (sort_opts == SORT_MTIME) {
-               dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime);
-       } else if (sort_opts == SORT_DIR) {
-               dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode);
-       /* } else if (sort_opts == SORT_VERSION) { */
-       /* } else if (sort_opts == SORT_EXT) { */
-       } else {    /* assume SORT_NAME */
-               dif= 0;
-       }
-
-       if (dif > 0) cmp= -1;
-       if (dif < 0) cmp=  1;
-       if (dif == 0) {
-               /* sort by name- may be a tie_breaker for time or size cmp */
-               dif= strcmp(d1->name, d2->name);
-               if (dif > 0) cmp=  1;
-               if (dif < 0) cmp= -1;
-       }
-
-       if (sort_order == SORT_REVERSE) {
-               cmp=  -1 * cmp;
-       }
-       return(cmp);
-}
-
-/*----------------------------------------------------------------------*/
-static void shellsort(struct dnode **dn, int size)
-{
-       struct dnode *temp;
-       int gap, i, j;
-
-       /* shell short the array */
-       if(dn==NULL || size < 2) return;
-
-       for (gap= size/2; gap>0; gap /=2) {
-               for (i=gap; i<size; i++) {
-                       for (j= i-gap; j>=0; j-=gap) {
-                               if (sortcmp(dn[j], dn[j+gap]) <= 0)
-                                       break;
-                               /* they are out of order, swap them */
-                               temp= dn[j];
-                               dn[j]= dn[j+gap];
-                               dn[j+gap]= temp;
-                       }
-               }
-       }
-}
-#endif
-
-/*----------------------------------------------------------------------*/
-static void showfiles(struct dnode **dn, int nfiles)
-{
-       int i, ncols, nrows, row, nc;
-#ifdef BB_FEATURE_AUTOWIDTH
-       int len;
-#endif
-
-       if(dn==NULL || nfiles < 1) return;
-
-#ifdef BB_FEATURE_AUTOWIDTH
-       /* find the longest file name-  use that as the column width */
-       column_width= 0;
-       for (i=0; i<nfiles; i++) {
-               len= strlen(dn[i]->name) +
-                       ((list_fmt & LIST_INO) ? 8 : 0) +
-                       ((list_fmt & LIST_BLOCKS) ? 5 : 0)
-                       ;
-               if (column_width < len) 
-                       column_width= len;
-       }
-       if (column_width >= 6)
-               ncols = (int)(terminal_width / (column_width + COLUMN_GAP));
-       else {
-               ncols = 1;
-               column_width = COLUMN_WIDTH;
-       }
-#else
-       ncols= TERMINAL_WIDTH;
-#endif
-       switch (style_fmt) {
-               case STYLE_LONG:        /* one record per line, extended info */
-               case STYLE_SINGLE:      /* one record per line */
-                       ncols= 1;
-                       break;
-       }
-
-       if (ncols > 1) {
-               nrows = nfiles / ncols;
-       } else {
-               nrows = nfiles;
-               ncols = 1;
-       }
-       if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */
-
-       if (nrows > nfiles) nrows= nfiles;
-       for (row=0; row<nrows; row++) {
-               for (nc=0; nc<ncols; nc++) {
-                       /* reach into the array based on the column and row */
-                       i= (nc * nrows) + row;          /* assume display by column */
-                       if (disp_opts & DISP_ROWS)
-                               i= (row * ncols) + nc;  /* display across row */
-                       if (i < nfiles) {
-                               nexttabstop();
-                               list_single(dn[i]);
-                       }
-               }
-               newline();
-       }
-}
-
-/*----------------------------------------------------------------------*/
-static void showdirs(struct dnode **dn, int ndirs)
-{
-       int i, nfiles;
-       struct dnode **subdnp;
-#ifdef BB_FEATURE_LS_RECURSIVE
-       int dndirs;
-       struct dnode **dnd;
-#endif
-
-       if (dn==NULL || ndirs < 1) return;
-
-       for (i=0; i<ndirs; i++) {
-               if (disp_opts & (DISP_DIRNAME | DISP_RECURSIVE)) {
-                       printf("\n%s:\n", dn[i]->fullname);
-               }
-               subdnp= list_dir(dn[i]->fullname);
-               nfiles= countfiles(subdnp);
-               if (nfiles > 0) {
-                       /* list all files at this level */
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(subdnp, nfiles);
-#endif
-                       showfiles(subdnp, nfiles);
-#ifdef BB_FEATURE_LS_RECURSIVE
-                       if (disp_opts & DISP_RECURSIVE) {
-                               /* recursive- list the sub-dirs */
-                               dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
-                               dndirs= countsubdirs(subdnp, nfiles);
-                               if (dndirs > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                                       shellsort(dnd, dndirs);
-#endif
-                                       showdirs(dnd, dndirs);
-                                       free(dnd);  /* free the array of dnode pointers to the dirs */
-                               }
-                       }
-                       dfree(subdnp);  /* free the dnodes and the fullname mem */
-#endif
-               }
-       }
-}
-
-/*----------------------------------------------------------------------*/
-static struct dnode **list_dir(char *path)
-{
-       struct dnode *dn, *cur, **dnp;
-       struct dirent *entry;
-       DIR *dir;
-       int i, nfiles;
-
-       if (path==NULL) return(NULL);
-
-       dn= NULL;
-       nfiles= 0;
-       dir = opendir(path);
-       if (dir == NULL) {
-               perror_msg("%s", path);
-               status = EXIT_FAILURE;
-               return(NULL);   /* could not open the dir */
-       }
-       while ((entry = readdir(dir)) != NULL) {
-               /* are we going to list the file- it may be . or .. or a hidden file */
-               if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT))
-                       continue;
-               if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT))
-                       continue;
-               if ((entry->d_name[0] ==  '.') && !(disp_opts & DISP_HIDDEN))
-                       continue;
-               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
-               cur->fullname = concat_path_file(path, entry->d_name);
-               cur->name = cur->fullname +
-                               (strlen(cur->fullname) - strlen(entry->d_name));
-               if (my_stat(cur))
-                       continue;
-               cur->next= dn;
-               dn= cur;
-               nfiles++;
-       }
-       closedir(dir);
-
-       /* now that we know how many files there are
-       ** allocate memory for an array to hold dnode pointers
-       */
-       if (nfiles < 1) return(NULL);
-       dnp= dnalloc(nfiles);
-       for (i=0, cur=dn; i<nfiles; i++) {
-               dnp[i]= cur;   /* save pointer to node in array */
-               cur= cur->next;
-       }
-
-       return(dnp);
-}
-
-/*----------------------------------------------------------------------*/
-static int list_single(struct dnode *dn)
-{
-       int i;
-       char scratch[BUFSIZ + 1];
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       char *filetime;
-       time_t ttime, age;
-#endif
-#if defined (BB_FEATURE_LS_FILETYPES)
-       struct stat info;
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-       char append;
-#endif
-
-       if (dn==NULL || dn->fullname==NULL) return(0);
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       ttime= dn->dstat.st_mtime;      /* the default time */
-       if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime;
-       if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime;
-       filetime= ctime(&ttime);
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-       append = append_char(dn->dstat.st_mode);
-#endif
-
-       for (i=0; i<=31; i++) {
-               switch (list_fmt & (1<<i)) {
-                       case LIST_INO:
-                               printf("%7ld ", (long int)dn->dstat.st_ino);
-                               column += 8;
-                               break;
-                       case LIST_BLOCKS:
-#ifdef BB_FEATURE_HUMAN_READABLE
-                               fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, 
-                                                       KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE));
-#else
-#if _FILE_OFFSET_BITS == 64
-                               printf("%4lld ", dn->dstat.st_blocks>>1);
-#else
-                               printf("%4ld ", dn->dstat.st_blocks>>1);
-#endif
-#endif
-                               column += 5;
-                               break;
-                       case LIST_MODEBITS:
-                               printf("%-10s ", (char *)mode_string(dn->dstat.st_mode));
-                               column += 10;
-                               break;
-                       case LIST_NLINKS:
-                               printf("%4ld ", (long)dn->dstat.st_nlink);
-                               column += 10;
-                               break;
-                       case LIST_ID_NAME:
-#ifdef BB_FEATURE_LS_USERNAME
-                               my_getpwuid(scratch, dn->dstat.st_uid);
-                               printf("%-8.8s ", scratch);
-                               my_getgrgid(scratch, dn->dstat.st_gid);
-                               printf("%-8.8s", scratch);
-                               column += 17;
-                               break;
-#endif
-                       case LIST_ID_NUMERIC:
-                               printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid);
-                               column += 17;
-                               break;
-                       case LIST_SIZE:
-                       case LIST_DEV:
-                               if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
-                                       printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev));
-                               } else {
-#ifdef BB_FEATURE_HUMAN_READABLE
-                                       if (ls_disp_hr==TRUE) {
-                                               fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0));
-                                       } else 
-#endif 
-                                       {
-#if _FILE_OFFSET_BITS == 64
-                                               printf("%9lld ", (long long)dn->dstat.st_size);
-#else
-                                               printf("%9ld ", dn->dstat.st_size);
-#endif
-                                       }
-                               }
-                               column += 10;
-                               break;
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-                       case LIST_FULLTIME:
-                       case LIST_DATE_TIME:
-                               if (list_fmt & LIST_FULLTIME) {
-                                       printf("%24.24s ", filetime);
-                                       column += 25;
-                                       break;
-                               }
-                               age = time(NULL) - ttime;
-                               printf("%6.6s ", filetime+4);
-                               if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
-                                       /* hh:mm if less than 6 months old */
-                                       printf("%5.5s ", filetime+11);
-                               } else {
-                                       printf(" %4.4s ", filetime+20);
-                               }
-                               column += 13;
-                               break;
-#endif
-                       case LIST_FILENAME:
-                               printf("%s", dn->name);
-                               column += strlen(dn->name);
-                               break;
-                       case LIST_SYMLINK:
-                               if (S_ISLNK(dn->dstat.st_mode)) {
-                                       char *lpath = xreadlink(dn->fullname);
-                                       if (lpath) {
-                                               printf(" -> %s", lpath);
-#ifdef BB_FEATURE_LS_FILETYPES
-                                               if (!stat(dn->fullname, &info)) {
-                                                       append = append_char(info.st_mode);
-                                               }
-#endif
-                                               column += strlen(lpath) + 4;
-                                               free(lpath);
-                                       }
-                               }
-                               break;
-#ifdef BB_FEATURE_LS_FILETYPES
-                       case LIST_FILETYPE:
-                               if (append != '\0') {
-                                       printf("%1c", append);
-                                       column++;
-                               }
-                               break;
-#endif
-               }
-       }
-
-       return(0);
-}
-
-/*----------------------------------------------------------------------*/
-extern int ls_main(int argc, char **argv)
-{
-       struct dnode **dnf, **dnd;
-       int dnfiles, dndirs;
-       struct dnode *dn, *cur, **dnp;
-       int i, nfiles;
-       int opt;
-       int oi, ac;
-       char **av;
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-#endif
-
-       disp_opts= DISP_NORMAL;
-       style_fmt= STYLE_AUTO;
-       list_fmt=  LIST_SHORT;
-#ifdef BB_FEATURE_LS_SORTFILES
-       sort_opts= SORT_NAME;
-       sort_order=     SORT_FORWARD;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       time_fmt= TIME_MOD;
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-       ioctl(fileno(stdout), TIOCGWINSZ, &win);
-       if (win.ws_row > 4)
-               column_width = win.ws_row - 2;
-       if (win.ws_col > 0)
-               terminal_width = win.ws_col - 1;
-#endif
-       nfiles=0;
-
-       /* process options */
-       while ((opt = getopt(argc, argv, "1AaCdgilnsx"
-#ifdef BB_FEATURE_AUTOWIDTH
-"T:w:"
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-"Fp"
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-"R"
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-"rSvX"
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-"cetu"
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-"L"
-#endif
-#ifdef BB_FEATURE_HUMAN_READABLE
-"h"
-#endif
-"k")) > 0) {
-               switch (opt) {
-                       case '1': style_fmt = STYLE_SINGLE; break;
-                       case 'A': disp_opts |= DISP_HIDDEN; break;
-                       case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break;
-                       case 'C': style_fmt = STYLE_COLUMNS; break;
-                       case 'd': disp_opts |= DISP_NOLIST; break;
-                       case 'g': /* ignore -- for ftp servers */ break;
-                       case 'i': list_fmt |= LIST_INO; break;
-                       case 'l':
-                               style_fmt = STYLE_LONG;
-                               list_fmt |= LIST_LONG;
-#ifdef BB_FEATURE_HUMAN_READABLE
-                               ls_disp_hr = FALSE;
-#endif
-                       break;
-                       case 'n': list_fmt |= LIST_ID_NUMERIC; break;
-                       case 's': list_fmt |= LIST_BLOCKS; break;
-                       case 'x': disp_opts = DISP_ROWS; break;
-#ifdef BB_FEATURE_LS_FILETYPES
-                       case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break;
-                       case 'p': list_fmt |= LIST_FILETYPE; break;
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-                       case 'R': disp_opts |= DISP_RECURSIVE; break;
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-                       case 'r': sort_order |= SORT_REVERSE; break;
-                       case 'S': sort_opts= SORT_SIZE; break;
-                       case 'v': sort_opts= SORT_VERSION; break;
-                       case 'X': sort_opts= SORT_EXT; break;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-                       case 'e': list_fmt |= LIST_FULLTIME; break;
-                       case 'c':
-                               time_fmt = TIME_CHANGE;
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_CTIME;
-#endif
-                               break;
-                       case 'u':
-                               time_fmt = TIME_ACCESS;
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_ATIME;
-#endif
-                               break;
-                       case 't':
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_MTIME;
-#endif
-                               break;
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-                       case 'L': follow_links= TRUE; break;
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-                       case 'T': tabstops= atoi(optarg); break;
-                       case 'w': terminal_width= atoi(optarg); break;
-#endif
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h': ls_disp_hr = TRUE; break;
-#endif
-                       case 'k': break;
-                       default:
-                               goto print_usage_message;
-               }
-       }
-
-       /* sort out which command line options take precedence */
-#ifdef BB_FEATURE_LS_RECURSIVE
-       if (disp_opts & DISP_NOLIST)
-               disp_opts &= ~DISP_RECURSIVE;   /* no recurse if listing only dir */
-#endif
-#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES)
-       if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME;
-       if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME;
-#endif
-       if (style_fmt != STYLE_LONG)
-                       list_fmt &= ~LIST_ID_NUMERIC;  /* numeric uid only for long list */
-#ifdef BB_FEATURE_LS_USERNAME
-       if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC))
-                       list_fmt &= ~LIST_ID_NAME;  /* don't list names if numeric uid */
-#endif
-
-       /* choose a display format */
-       if (style_fmt == STYLE_AUTO)
-               style_fmt = isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE;
-
-       /*
-        * when there are no cmd line args we have to supply a default "." arg.
-        * we will create a second argv array, "av" that will hold either
-        * our created "." arg, or the real cmd line args.  The av array
-        * just holds the pointers- we don't move the date the pointers
-        * point to.
-        */
-       ac= argc - optind;   /* how many cmd line args are left */
-       if (ac < 1) {
-               av= (char **)xcalloc((size_t)1, (size_t)(sizeof(char *)));
-               av[0]= xstrdup(".");
-               ac=1;
-       } else {
-               av= (char **)xcalloc((size_t)ac, (size_t)(sizeof(char *)));
-               for (oi=0 ; oi < ac; oi++) {
-                       av[oi]= argv[optind++];  /* copy pointer to real cmd line arg */
-               }
-       }
-
-       /* now, everything is in the av array */
-       if (ac > 1)
-               disp_opts |= DISP_DIRNAME;   /* 2 or more items? label directories */
-
-       /* stuff the command line file names into an dnode array */
-       dn=NULL;
-       for (oi=0 ; oi < ac; oi++) {
-               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
-               cur->fullname= xstrdup(av[oi]);
-               cur->name= cur->fullname;
-               if (my_stat(cur))
-                       continue;
-               cur->next= dn;
-               dn= cur;
-               nfiles++;
-       }
-
-       /* now that we know how many files there are
-       ** allocate memory for an array to hold dnode pointers
-       */
-       dnp= dnalloc(nfiles);
-       for (i=0, cur=dn; i<nfiles; i++) {
-               dnp[i]= cur;   /* save pointer to node in array */
-               cur= cur->next;
-       }
-
-
-       if (disp_opts & DISP_NOLIST) {
-#ifdef BB_FEATURE_LS_SORTFILES
-               shellsort(dnp, nfiles);
-#endif
-               if (nfiles > 0) showfiles(dnp, nfiles);
-       } else {
-               dnd= splitdnarray(dnp, nfiles, SPLIT_DIR);
-               dnf= splitdnarray(dnp, nfiles, SPLIT_FILE);
-               dndirs= countdirs(dnp, nfiles);
-               dnfiles= nfiles - dndirs;
-               if (dnfiles > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(dnf, dnfiles);
-#endif
-                       showfiles(dnf, dnfiles);
-               }
-               if (dndirs > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(dnd, dndirs);
-#endif
-                       showdirs(dnd, dndirs);
-               }
-       }
-       return(status);
-
-  print_usage_message:
-       show_usage();
-}
diff --git a/busybox/coreutils/md5sum.c b/busybox/coreutils/md5sum.c
deleted file mode 100644 (file)
index bb4d115..0000000
+++ /dev/null
@@ -1,1074 +0,0 @@
-/* md5sum.c - Compute MD5 checksum of files or strings according to the
- *            definition of MD5 in RFC 1321 from April 1992.
- * Copyright (C) 1995-1999 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
-/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
-
-/*
- * June 29, 2001        Manuel Novoa III
- *
- * Added MD5SUM_SIZE_VS_SPEED configuration option.
- *
- * Current valid values, with data from my system for comparison, are:
- *   (using uClibc and running on linux-2.4.4.tar.bz2)
- *                     user times (sec)  text size (386)
- *     0 (fastest)         1.1                6144
- *     1                   1.4                5392
- *     2                   3.0                5088
- *     3 (smallest)        5.1                4912
- */
-
-#define MD5SUM_SIZE_VS_SPEED 2
-
-/**********************************************************************/
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <endian.h>
-#include <sys/types.h>
-#if defined HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include "busybox.h"
-
-/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
-#undef TRUE
-#undef FALSE
-#define FALSE   ((int) 1)
-#define TRUE    ((int) 0)
-
-//----------------------------------------------------------------------------
-//--------md5.c
-//----------------------------------------------------------------------------
-
-/* md5.c - Functions to compute MD5 message digest of files or memory blocks
- *         according to the definition of MD5 in RFC 1321 from April 1992.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
-
-//----------------------------------------------------------------------------
-//--------md5.h
-//----------------------------------------------------------------------------
-
-/* md5.h - Declaration of functions and data types used for MD5 sum
-   computing library functions. */
-
-typedef u_int32_t md5_uint32;
-
-/* Structure to save state of computation between the single steps.  */
-struct md5_ctx
-{
-  md5_uint32 A;
-  md5_uint32 B;
-  md5_uint32 C;
-  md5_uint32 D;
-
-  md5_uint32 total[2];
-  md5_uint32 buflen;
-  char buffer[128];
-};
-
-/*
- * The following three functions are build up the low level used in
- * the functions `md5_stream' and `md5_buffer'.
- */
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-static void md5_init_ctx __P ((struct md5_ctx *ctx));
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is necessary that LEN is a multiple of 64!!! */
-static void md5_process_block __P ((const void *buffer, size_t len,
-                                   struct md5_ctx *ctx));
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is NOT required that LEN is a multiple of 64.  */
-static void md5_process_bytes __P ((const void *buffer, size_t len,
-                                   struct md5_ctx *ctx));
-
-/* Process the remaining bytes in the buffer and put result from CTX
-   in first 16 bytes following RESBUF.  The result is always in little
-   endian byte order, so that a byte-wise output yields to the wanted
-   ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-static void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
-
-
-
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-static int md5_stream __P ((FILE *stream, void *resblock));
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-static void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
-
-//----------------------------------------------------------------------------
-//--------end of md5.h
-//----------------------------------------------------------------------------
-
-/* Handle endian-ness */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-       #define SWAP(n) (n)
-#else
-       #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
-#endif
-
-
-
-#if MD5SUM_SIZE_VS_SPEED == 0
-/* This array contains the bytes used to pad the buffer to the next
-   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
-static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */  };
-#endif
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-void md5_init_ctx(struct md5_ctx *ctx)
-{
-  ctx->A = 0x67452301;
-  ctx->B = 0xefcdab89;
-  ctx->C = 0x98badcfe;
-  ctx->D = 0x10325476;
-
-  ctx->total[0] = ctx->total[1] = 0;
-  ctx->buflen = 0;
-}
-
-/* Process the remaining bytes in the internal buffer and the usual
-   prolog according to the standard and write the result to RESBUF.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
-{
-  /* Take yet unprocessed bytes into account.  */
-  md5_uint32 bytes = ctx->buflen;
-  size_t pad;
-
-  /* Now count remaining bytes.  */
-  ctx->total[0] += bytes;
-  if (ctx->total[0] < bytes)
-    ++ctx->total[1];
-
-  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
-#if MD5SUM_SIZE_VS_SPEED > 0
-  memset(&ctx->buffer[bytes], 0, pad);
-  ctx->buffer[bytes] = 0x80;
-#else
-  memcpy(&ctx->buffer[bytes], fillbuf, pad);
-#endif
-
-  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
-  *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
-  *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
-    SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
-
-  /* Process last bytes.  */
-  md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
-
-/* Put result from CTX in first 16 bytes following RESBUF.  The result is
-   always in little endian byte order, so that a byte-wise output yields
-   to the wanted ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-  ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
-  ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
-  ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
-  ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
-
-  return resbuf;
-}
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-static int md5_stream(FILE *stream, void *resblock)
-{
-  /* Important: BLOCKSIZE must be a multiple of 64.  */
-static const int BLOCKSIZE = 4096;
-  struct md5_ctx ctx;
-  char buffer[BLOCKSIZE + 72];
-  size_t sum;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx(&ctx);
-
-  /* Iterate over full file contents.  */
-  while (1) {
-    /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-       computation function processes the whole buffer so that with the
-       next round of the loop another block can be read.  */
-    size_t n;
-    sum = 0;
-
-    /* Read block.  Take care for partial reads.  */
-    do {
-      n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-      sum += n;
-    }
-    while (sum < BLOCKSIZE && n != 0);
-    if (n == 0 && ferror(stream))
-      return 1;
-
-    /* If end of file is reached, end the loop.  */
-    if (n == 0)
-      break;
-
-    /* Process buffer with BLOCKSIZE bytes.  Note that
-       BLOCKSIZE % 64 == 0
-    */
-    md5_process_block(buffer, BLOCKSIZE, &ctx);
-  }
-
-  /* Add the last bytes if necessary.  */
-  if (sum > 0)
-    md5_process_bytes(buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  md5_finish_ctx(&ctx, resblock);
-  return 0;
-}
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-static void *md5_buffer(const char *buffer, size_t len, void *resblock)
-{
-  struct md5_ctx ctx;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx(&ctx);
-
-  /* Process whole buffer but last len % 64 bytes.  */
-  md5_process_bytes(buffer, len, &ctx);
-
-  /* Put result in desired memory area.  */
-  return md5_finish_ctx(&ctx, resblock);
-}
-
-static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
-{
-  /* When we already have some bits in our internal buffer concatenate
-     both inputs first.  */
-  if (ctx->buflen != 0) {
-    size_t left_over = ctx->buflen;
-    size_t add = 128 - left_over > len ? len : 128 - left_over;
-
-    memcpy(&ctx->buffer[left_over], buffer, add);
-    ctx->buflen += add;
-
-    if (left_over + add > 64) {
-      md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
-      /* The regions in the following copy operation cannot overlap.  */
-      memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
-            (left_over + add) & 63);
-      ctx->buflen = (left_over + add) & 63;
-    }
-
-    buffer = (const char *) buffer + add;
-    len -= add;
-  }
-
-  /* Process available complete blocks.  */
-  if (len > 64) {
-    md5_process_block(buffer, len & ~63, ctx);
-    buffer = (const char *) buffer + (len & ~63);
-    len &= 63;
-  }
-
-  /* Move remaining bytes in internal buffer.  */
-  if (len > 0) {
-    memcpy(ctx->buffer, buffer, len);
-    ctx->buflen = len;
-  }
-}
-
-/* These are the four functions used in the four steps of the MD5 algorithm
-   and defined in the RFC 1321.  The first function is a little bit optimized
-   (as found in Colin Plumbs public domain implementation).  */
-/* #define FF(b, c, d) ((b & c) | (~b & d)) */
-#define FF(b, c, d) (d ^ (b & (c ^ d)))
-#define FG(b, c, d) FF (d, b, c)
-#define FH(b, c, d) (b ^ c ^ d)
-#define FI(b, c, d) (c ^ (b | ~d))
-
-/* Process LEN bytes of BUFFER, accumulating context into CTX.
-   It is assumed that LEN % 64 == 0.  */
-static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
-{
-  md5_uint32 correct_words[16];
-  const md5_uint32 *words = buffer;
-  size_t nwords = len / sizeof(md5_uint32);
-  const md5_uint32 *endp = words + nwords;
-#if MD5SUM_SIZE_VS_SPEED > 0
-  static const md5_uint32 C_array[] = {
-      /* round 1 */
-      0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
-      0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
-      0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
-      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
-      /* round 2 */
-      0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
-      0xd62f105d, 0x2441453,  0xd8a1e681, 0xe7d3fbc8,
-      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
-      0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
-      /* round 3 */
-      0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
-      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
-      0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
-      0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
-      /* round 4 */
-      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
-      0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
-      0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
-      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
-  };
-
-  static const char P_array[] = {
-#if MD5SUM_SIZE_VS_SPEED > 1
-      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
-#endif
-      1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
-      5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
-      0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
-  };
-
-#if MD5SUM_SIZE_VS_SPEED > 1
-  static const char S_array[] = {
-      7, 12, 17, 22,
-      5, 9, 14, 20,
-      4, 11, 16, 23,
-      6, 10, 15, 21
-  };
-#endif
-#endif
-
-  md5_uint32 A = ctx->A;
-  md5_uint32 B = ctx->B;
-  md5_uint32 C = ctx->C;
-  md5_uint32 D = ctx->D;
-
-  /* First increment the byte count.  RFC 1321 specifies the possible
-     length of the file up to 2^64 bits.  Here we only compute the
-     number of bytes.  Do a double word increment.  */
-  ctx->total[0] += len;
-  if (ctx->total[0] < len)
-    ++ctx->total[1];
-
-  /* Process all bytes in the buffer with 64 bytes in each round of
-     the loop.  */
-  while (words < endp) {
-    md5_uint32 *cwp = correct_words;
-    md5_uint32 A_save = A;
-    md5_uint32 B_save = B;
-    md5_uint32 C_save = C;
-    md5_uint32 D_save = D;
-
-#if MD5SUM_SIZE_VS_SPEED > 1
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
-    const md5_uint32 *pc;
-    const char *pp;
-    const char *ps;
-    int i;
-    md5_uint32 temp;
-
-    for ( i=0 ; i < 16 ; i++ ) {
-       cwp[i] = SWAP(words[i]);
-    }
-    words += 16;
-
-#if MD5SUM_SIZE_VS_SPEED > 2
-    pc = C_array; pp = P_array; ps = S_array - 4;
-
-    for ( i = 0 ; i < 64 ; i++ ) {
-       if ((i&0x0f) == 0) ps += 4;
-       temp = A;
-       switch (i>>4) {
-           case 0:
-               temp += FF(B,C,D);
-               break;
-           case 1:
-               temp += FG(B,C,D);
-               break;
-           case 2:
-               temp += FH(B,C,D);
-               break;
-           case 3:
-               temp += FI(B,C,D);
-       }
-       temp += cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-#else
-    pc = C_array; pp = P_array; ps = S_array;
-
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-
-#endif
-#else
-    /* First round: using the given function, the context and a constant
-       the next context is computed.  Because the algorithms processing
-       unit is a 32-bit word and it is determined to work on words in
-       little endian byte order we perhaps have to change the byte order
-       before the computation.  To reduce the work for the next steps
-       we store the swapped words in the array CORRECT_WORDS.  */
-
-#define OP(a, b, c, d, s, T)                                           \
-      do                                                               \
-        {                                                              \
-         a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;             \
-         ++words;                                                      \
-         CYCLIC (a, s);                                                \
-         a += b;                                                       \
-        }                                                              \
-      while (0)
-
-    /* It is unfortunate that C does not provide an operator for
-       cyclic rotation.  Hope the C compiler is smart enough.  */
-    /* gcc 2.95.4 seems to be --aaronl */
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
-    /* Before we start, one word to the strange constants.
-       They are defined in RFC 1321 as
-
-       T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
-    */
-
-#if MD5SUM_SIZE_VS_SPEED == 1
-    const md5_uint32 *pc;
-    const char *pp;
-    int i;
-#endif
-
-    /* Round 1.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    pc = C_array;
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(A, B, C, D, 7, *pc++);
-       OP(D, A, B, C, 12, *pc++);
-       OP(C, D, A, B, 17, *pc++);
-       OP(B, C, D, A, 22, *pc++);
-    }
-#else
-    OP(A, B, C, D, 7, 0xd76aa478);
-    OP(D, A, B, C, 12, 0xe8c7b756);
-    OP(C, D, A, B, 17, 0x242070db);
-    OP(B, C, D, A, 22, 0xc1bdceee);
-    OP(A, B, C, D, 7, 0xf57c0faf);
-    OP(D, A, B, C, 12, 0x4787c62a);
-    OP(C, D, A, B, 17, 0xa8304613);
-    OP(B, C, D, A, 22, 0xfd469501);
-    OP(A, B, C, D, 7, 0x698098d8);
-    OP(D, A, B, C, 12, 0x8b44f7af);
-    OP(C, D, A, B, 17, 0xffff5bb1);
-    OP(B, C, D, A, 22, 0x895cd7be);
-    OP(A, B, C, D, 7, 0x6b901122);
-    OP(D, A, B, C, 12, 0xfd987193);
-    OP(C, D, A, B, 17, 0xa679438e);
-    OP(B, C, D, A, 22, 0x49b40821);
-#endif
-
-    /* For the second to fourth round we have the possibly swapped words
-       in CORRECT_WORDS.  Redefine the macro to take an additional first
-       argument specifying the function to use.  */
-#undef OP
-#define OP(f, a, b, c, d, k, s, T)                                     \
-      do                                                               \
-       {                                                               \
-         a += f (b, c, d) + correct_words[k] + T;                      \
-         CYCLIC (a, s);                                                \
-         a += b;                                                       \
-       }                                                               \
-      while (0)
-
-    /* Round 2.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    pp = P_array;
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
-       OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
-       OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
-       OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
-    }
-#else
-    OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
-    OP(FG, D, A, B, C, 6, 9, 0xc040b340);
-    OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
-    OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
-    OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
-    OP(FG, D, A, B, C, 10, 9, 0x02441453);
-    OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
-    OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
-    OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
-    OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
-    OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
-    OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
-    OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
-    OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
-    OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
-    OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
-#endif
-
-    /* Round 3.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
-       OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
-       OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
-       OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
-    }
-#else
-    OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
-    OP(FH, D, A, B, C, 8, 11, 0x8771f681);
-    OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
-    OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
-    OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
-    OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
-    OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
-    OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
-    OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
-    OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
-    OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
-    OP(FH, B, C, D, A, 6, 23, 0x04881d05);
-    OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
-    OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
-    OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
-    OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
-#endif
-
-    /* Round 4.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
-       OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
-       OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
-       OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
-    }
-#else
-    OP(FI, A, B, C, D, 0, 6, 0xf4292244);
-    OP(FI, D, A, B, C, 7, 10, 0x432aff97);
-    OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
-    OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
-    OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
-    OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
-    OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
-    OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
-    OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
-    OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
-    OP(FI, C, D, A, B, 6, 15, 0xa3014314);
-    OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
-    OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
-    OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
-    OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
-    OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
-#endif
-#endif
-
-    /* Add the starting values of the context.  */
-    A += A_save;
-    B += B_save;
-    C += C_save;
-    D += D_save;
-  }
-
-  /* Put checksum in context given as argument.  */
-  ctx->A = A;
-  ctx->B = B;
-  ctx->C = C;
-  ctx->D = D;
-}
-
-//----------------------------------------------------------------------------
-//--------end of md5.c
-//----------------------------------------------------------------------------
-
-#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
-#define ISXDIGIT(c) (isxdigit (c))
-
-/* The minimum length of a valid digest line in a file produced
-   by `md5sum FILE' and read by `md5sum -c'.  This length does
-   not include any newline character at the end of a line.  */
-static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
-                                      2 - blank and binary indicator
-                                      1 - minimum filename length */
-
-static int have_read_stdin; /* Nonzero if any of the files read were
-                               the standard input. */
-
-static int status_only = 0; /* With -c, don't generate any output.
-                               The exit code indicates success or failure */
-static int warn = 0; /* With -w, print a message to standard error warning
-                        about each improperly formatted MD5 checksum line */
-
-static int split_3(char *s,
-                   size_t s_len,
-                   unsigned char **u,
-                   char **w)
-{
-  size_t i = 0;
-  int escaped_filename = 0;
-
-  while (ISWHITE(s[i]))
-    ++i;
-
-  /* The line must have at least 35 (36 if the first is a backslash)
-     more characters to contain correct message digest information.
-     Ignore this line if it is too short.  */
-  if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
-        || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
-    return FALSE;
-
-  if (s[i] == '\\') {
-    ++i;
-    escaped_filename = 1;
-  }
-  *u = (unsigned char *) &s[i];
-
-  /* The first field has to be the 32-character hexadecimal
-     representation of the message digest.  If it is not followed
-     immediately by a white space it's an error.  */
-  i += 32;
-  if (!ISWHITE(s[i]))
-    return FALSE;
-
-  s[i++] = '\0';
-
-  if (s[i] != ' ' && s[i++] != '*')
-    return FALSE;
-
-  /* All characters between the type indicator and end of line are
-     significant -- that includes leading and trailing white space.  */
-  *w = &s[i];
-
-  if (escaped_filename) {
-    /* Translate each `\n' string in the file name to a NEWLINE,
-       and each `\\' string to a backslash.  */
-
-    char *dst = &s[i];
-
-    while (i < s_len) {
-      switch (s[i]) {
-       case '\\':
-        if (i == s_len - 1) {
-          /* A valid line does not end with a backslash.  */
-          return FALSE;
-        }
-        ++i;
-        switch (s[i++]) {
-         case 'n':
-          *dst++ = '\n';
-          break;
-         case '\\':
-          *dst++ = '\\';
-          break;
-         default:
-          /* Only `\' or `n' may follow a backslash.  */
-          return FALSE;
-        }
-        break;
-
-       case '\0':
-        /* The file name may not contain a NUL.  */
-        return FALSE;
-        break;
-
-       default:
-        *dst++ = s[i++];
-        break;
-      }
-    }
-    *dst = '\0';
-  }
-  return TRUE;
-}
-
-static inline int hex_digits(unsigned char const *s)
-{
-  while (*s) {
-    if (!ISXDIGIT(*s))
-      return TRUE;
-    ++s;
-  }
-  return FALSE;
-}
-
-/* An interface to md5_stream.  Operate on FILENAME (it may be "-") and
-   put the result in *MD5_RESULT.  Return non-zero upon failure, zero
-   to indicate success.  */
-static int md5_file(const char *filename,
-                    unsigned char *md5_result)
-{
-  FILE *fp;
-
-  if (filename[0] == '-' && filename[1] == '\0') {
-    have_read_stdin = 1;
-    fp = stdin;
-  } else {
-    fp = wfopen(filename, "r");
-    if (fp == NULL)
-      return FALSE;
-    }
-
-  if (md5_stream(fp, md5_result)) {
-    perror_msg("%s", filename);
-
-    if (fp != stdin)
-      fclose(fp);
-    return FALSE;
-  }
-
-  if (fp != stdin && fclose(fp) == EOF) {
-    perror_msg("%s", filename);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static int md5_check(const char *checkfile_name)
-{
-  FILE *checkfile_stream;
-  int n_properly_formated_lines = 0;
-  int n_mismatched_checksums = 0;
-  int n_open_or_read_failures = 0;
-  unsigned char md5buffer[16];
-  size_t line_number;
-  char line[BUFSIZ];
-
-  if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
-    have_read_stdin = 1;
-    checkfile_stream = stdin;
-  } else {
-    checkfile_stream = wfopen(checkfile_name, "r");
-    if (checkfile_stream == NULL)
-      return FALSE;
-    }
-
-  line_number = 0;
-
-  do {
-    char *filename;
-    unsigned char *md5num;
-    int line_length;
-
-    ++line_number;
-
-    fgets(line, BUFSIZ-1, checkfile_stream);
-    line_length = strlen(line);
-
-    if (line_length <= 0 || line==NULL)
-      break;
-
-    /* Ignore comment lines, which begin with a '#' character.  */
-    if (line[0] == '#')
-      continue;
-
-    /* Remove any trailing newline.  */
-    if (line[line_length - 1] == '\n')
-      line[--line_length] = '\0';
-
-    if (split_3(line, line_length, &md5num, &filename)
-        || !hex_digits(md5num)) {
-      if (warn) {
-        error_msg("%s: %lu: improperly formatted MD5 checksum line",
-                 checkfile_name, (unsigned long) line_number);
-      }
-    } else {
-      static const char bin2hex[] = {
-        '0', '1', '2', '3',
-        '4', '5', '6', '7',
-        '8', '9', 'a', 'b',
-        'c', 'd', 'e', 'f'
-      };
-
-      ++n_properly_formated_lines;
-
-      if (md5_file(filename, md5buffer)) {
-        ++n_open_or_read_failures;
-        if (!status_only) {
-          printf("%s: FAILED open or read\n", filename);
-          fflush(stdout);
-        }
-      } else {
-        size_t cnt;
-        /* Compare generated binary number with text representation
-           in check file.  Ignore case of hex digits.  */
-        for (cnt = 0; cnt < 16; ++cnt) {
-          if (tolower(md5num[2 * cnt])
-              != bin2hex[md5buffer[cnt] >> 4]
-              || (tolower(md5num[2 * cnt + 1])
-                  != (bin2hex[md5buffer[cnt] & 0xf])))
-            break;
-        }
-        if (cnt != 16)
-          ++n_mismatched_checksums;
-
-        if (!status_only) {
-          printf("%s: %s\n", filename,
-                 (cnt != 16 ? "FAILED" : "OK"));
-          fflush(stdout);
-        }
-      }
-    }
-  }
-
-  while (!feof(checkfile_stream) && !ferror(checkfile_stream));
-
-  if (ferror(checkfile_stream)) {
-    error_msg("%s: read error", checkfile_name);
-    return FALSE;
-  }
-
-  if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
-    perror_msg("md5sum: %s", checkfile_name);
-    return FALSE;
-  }
-
-  if (n_properly_formated_lines == 0) {
-    /* Warn if no tests are found.  */
-    error_msg("%s: no properly formatted MD5 checksum lines found",
-             checkfile_name);
-    return FALSE;
-  } else {
-    if (!status_only) {
-      int n_computed_checkums = (n_properly_formated_lines
-                                 - n_open_or_read_failures);
-
-      if (n_open_or_read_failures > 0) {
-        error_msg("WARNING: %d of %d listed files could not be read",
-                 n_open_or_read_failures, n_properly_formated_lines);
-        return FALSE;
-      }
-
-      if (n_mismatched_checksums > 0) {
-        error_msg("WARNING: %d of %d computed checksums did NOT match",
-                 n_mismatched_checksums, n_computed_checkums);
-        return FALSE;
-      }
-    }
-  }
-
-  return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
-           && n_open_or_read_failures == 0) ? 0 : 1);
-}
-
-int md5sum_main(int argc,
-                char **argv)
-{
-  unsigned char md5buffer[16];
-  int do_check = 0;
-  int opt;
-  char **string = NULL;
-  size_t n_strings = 0;
-  size_t err = 0;
-  char file_type_specified = 0;
-  char binary = 0;
-
-  while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
-    switch (opt) {
-     case 'g': { /* read a string */
-       if (string == NULL)
-         string = (char **) xmalloc ((argc - 1) * sizeof (char *));
-
-       string[n_strings++] = optarg;
-       break;
-     }
-
-     case 'b': /* read files in binary mode */
-      file_type_specified = 1;
-      binary = 1;
-      break;
-
-     case 'c': /* check MD5 sums against given list */
-      do_check = 1;
-      break;
-
-     case 's':  /* don't output anything, status code shows success */
-      status_only = 1;
-      warn = 0;
-      break;
-
-     case 't': /* read files in text mode (default) */
-      file_type_specified = 1;
-      binary = 0;
-      break;
-
-     case 'w': /* warn about improperly formated MD5 checksum lines */
-      status_only = 0;
-      warn = 1;
-      break;
-
-     default:
-      show_usage();
-    }
-  }
-
-  if (file_type_specified && do_check) {
-    error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
-  }
-
-  if (n_strings > 0 && do_check) {
-    error_msg_and_die("the -g and -c options are mutually exclusive");
-  }
-
-  if (status_only && !do_check) {
-    error_msg_and_die("the -s option is meaningful only when verifying checksums");
-  }
-
-  if (warn && !do_check) {
-    error_msg_and_die("the -w option is meaningful only when verifying checksums");
-  }
-
-  if (n_strings > 0) {
-    size_t i;
-
-    if (optind < argc) {
-      error_msg_and_die("no files may be specified when using -g");
-    }
-    for (i = 0; i < n_strings; ++i) {
-      size_t cnt;
-      md5_buffer (string[i], strlen (string[i]), md5buffer);
-
-      for (cnt = 0; cnt < 16; ++cnt)
-        printf ("%02x", md5buffer[cnt]);
-
-      printf ("  \"%s\"\n", string[i]);
-    }
-  } else if (do_check) {
-    if (optind + 1 < argc) {
-      error_msg("only one argument may be specified when using -c");
-    }
-
-    err = md5_check ((optind == argc) ? "-" : argv[optind]);
-  } else {
-    if (optind == argc)
-      argv[argc++] = "-";
-
-    for (; optind < argc; ++optind) {
-      int fail;
-      char *file = argv[optind];
-
-      fail = md5_file (file, md5buffer);
-      err |= fail;
-      if (!fail && file[0]=='-' && file[1] == '\0') {
-         size_t i;
-         for (i = 0; i < 16; ++i)
-             printf ("%02x", md5buffer[i]);
-         putchar ('\n');
-      } else if (!fail) {
-        size_t i;
-        /* Output a leading backslash if the file name contains
-           a newline or backslash.  */
-        if (strchr (file, '\n') || strchr (file, '\\'))
-          putchar ('\\');
-
-        for (i = 0; i < 16; ++i)
-          printf ("%02x", md5buffer[i]);
-
-        putchar (' ');
-        if (binary)
-          putchar ('*');
-        else
-          putchar (' ');
-
-        /* Translate each NEWLINE byte to the string, "\\n",
-           and each backslash to "\\\\".  */
-        for (i = 0; i < strlen (file); ++i) {
-          switch (file[i]) {
-           case '\n':
-            fputs ("\\n", stdout);
-            break;
-
-           case '\\':
-            fputs ("\\\\", stdout);
-            break;
-
-           default:
-            putchar (file[i]);
-            break;
-          }
-        }
-        putchar ('\n');
-      }
-    }
-  }
-
-  if (fclose (stdout) == EOF) {
-    error_msg_and_die("write error");
-  }
-
-  if (have_read_stdin && fclose (stdin) == EOF) {
-    error_msg_and_die("standard input");
-  }
-
-  if (err == 0)
-         return EXIT_SUCCESS;
-  else
-         return EXIT_FAILURE;
-}
diff --git a/busybox/coreutils/mkdir.c b/busybox/coreutils/mkdir.c
deleted file mode 100644 (file)
index 03c49f0..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mkdir implementation for busybox
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "busybox.h"
-
-extern int mkdir_main (int argc, char **argv)
-{
-       mode_t mode = -1;
-       int flags = 0;
-       int status = 0;
-       int i, opt;
-
-       while ((opt = getopt (argc, argv, "m:p")) != -1) {
-               switch (opt) {
-               case 'm':
-                       mode = 0777;
-                       if (!parse_mode (optarg, &mode))
-                               error_msg_and_die ("invalid mode `%s'", optarg);
-                       break;
-               case 'p':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               default:
-                       show_usage ();
-               }
-       }
-
-       if (optind == argc)
-               show_usage ();
-
-       for (i = optind; i < argc; i++)
-               if (make_directory (argv[i], mode, flags) < 0)
-                       status = 1;
-
-       return status;
-}
diff --git a/busybox/coreutils/mkfifo.c b/busybox/coreutils/mkfifo.c
deleted file mode 100644 (file)
index ca217fa..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mkfifo implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int mkfifo_main(int argc, char **argv)
-{
-       char *thisarg;
-       mode_t mode = 0666;
-
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (argc > 1) {
-               if (**argv != '-')
-                       show_usage();
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'm':
-                       argc--;
-                       argv++;
-                       parse_mode(*argv, &mode);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc < 1 || *argv[0] == '-')
-               show_usage();
-       if (mkfifo(*argv, mode) < 0)
-               perror_msg_and_die("mkfifo");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/mknod.c b/busybox/coreutils/mknod.c
deleted file mode 100644 (file)
index b4d4b82..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mknod implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-int mknod_main(int argc, char **argv)
-{
-       char *thisarg;
-       mode_t mode = 0;
-       mode_t perm = 0666;
-       dev_t dev = 0;
-
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (argc > 1) {
-               if (**argv != '-')
-                       break;
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'm':
-                       argc--;
-                       argv++;
-                       parse_mode(*argv, &perm);
-                       umask(0);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc != 4 && argc != 2) {
-               show_usage();
-       }
-       switch (argv[1][0]) {
-       case 'c':
-       case 'u':
-               mode = S_IFCHR;
-               break;
-       case 'b':
-               mode = S_IFBLK;
-               break;
-       case 'p':
-               mode = S_IFIFO;
-               if (argc!=2) {
-                       show_usage();
-               }
-               break;
-       default:
-               show_usage();
-       }
-
-       if (mode == S_IFCHR || mode == S_IFBLK) {
-               dev = (atoi(argv[2]) << 8) | atoi(argv[3]);
-       }
-
-       mode |= perm;
-
-       if (mknod(argv[0], mode, dev) != 0)
-               perror_msg_and_die("%s", argv[0]);
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/coreutils/mv.c b/busybox/coreutils/mv.c
deleted file mode 100644 (file)
index b890abf..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mv implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-static int flags;
-
-static int manual_rename(const char *source, const char *dest)
-{
-       struct stat source_stat;
-       struct stat dest_stat;
-       int source_exists = 1;
-       int dest_exists = 1;
-
-       if (stat(source, &source_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", source);
-                       return -1;
-               }
-               source_exists = 0;
-       }
-
-       if (stat(dest, &dest_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", dest);
-                       return -1;
-               }
-               dest_exists = 0;
-       }
-
-       if (dest_exists) {
-               if (S_ISDIR(dest_stat.st_mode) &&
-                         (!source_exists || !S_ISDIR(source_stat.st_mode))) {
-                       error_msg("cannot overwrite directory with non-directory");
-                       return -1;
-               }
-
-               if (!S_ISDIR(dest_stat.st_mode) && source_exists &&
-                               S_ISDIR(source_stat.st_mode)) {
-                       error_msg("cannot overwrite non-directory with directory");
-                       return -1;
-               }
-
-               if (unlink(dest) < 0) {
-                       perror_msg("cannot remove `%s'", dest);
-                       return -1;
-               }
-       }
-
-       if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS |
-                       FILEUTILS_PRESERVE_SYMLINKS) < 0)
-               return -1;
-
-       if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int move_file(const char *source, const char *dest)
-{
-       struct stat dest_stat;
-       int dest_exists = 1;
-
-       if (stat(dest, &dest_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", dest);
-                       return -1;
-               }
-               dest_exists = 0;
-       }
-
-       if (dest_exists && !(flags & FILEUTILS_FORCE) &&
-                       ((access(dest, W_OK) < 0 && isatty(0)) ||
-                        (flags & FILEUTILS_INTERACTIVE))) {
-               fprintf(stderr, "mv: overwrite `%s'? ", dest);
-               if (!ask_confirmation())
-                       return 0;
-       }
-
-       if (rename(source, dest) < 0) {
-               if (errno == EXDEV)
-                       return manual_rename(source, dest);
-
-               perror_msg("unable to rename `%s'", source);
-               return -1;
-       }
-       
-       return 0;
-}
-
-extern int mv_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int i;
-
-       while ((opt = getopt(argc, argv, "fi")) != -1)
-               switch (opt) {
-               case 'f':
-                       flags &= ~FILEUTILS_INTERACTIVE;
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags &= ~FILEUTILS_FORCE;
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               default:
-                       show_usage();
-               }
-
-       if (optind + 2 > argc)
-               show_usage();
-
-       if (optind + 2 == argc) {
-               struct stat dest_stat;
-               int dest_exists = 1;
-
-               if (stat(argv[optind + 1], &dest_stat) < 0) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
-                       dest_exists = 0;
-               }
-
-               if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) {
-                       if (move_file(argv[optind], argv[optind + 1]) < 0)
-                               status = 1;
-                       return status;
-               }
-       }
-
-       for (i = optind; i < argc - 1; i++) {
-               char *dest = concat_path_file(argv[argc - 1],
-                               get_last_path_component(argv[i]));
-               if (move_file(argv[i], dest) < 0)
-                       status = 1;
-               free(dest);
-       }
-
-       return status;
-}
diff --git a/busybox/coreutils/printf.c b/busybox/coreutils/printf.c
deleted file mode 100644 (file)
index d579a9b..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* printf - format and print data
-   Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Usage: printf format [argument...]
-
-   A front end to the printf function that lets it be used from the shell.
-
-   Backslash escapes:
-
-   \" = double quote
-   \\ = backslash
-   \a = alert (bell)
-   \b = backspace
-   \c = produce no further output
-   \f = form feed
-   \n = new line
-   \r = carriage return
-   \t = horizontal tab
-   \v = vertical tab
-   \0ooo = octal number (ooo is 0 to 3 digits)
-   \xhhh = hexadecimal number (hhh is 1 to 3 digits)
-
-   Additional directive:
-
-   %b = print an argument string, interpreting backslash escapes
-
-   The `format' argument is re-used as many times as necessary
-   to convert all of the given arguments.
-
-   David MacKenzie <djm@gnu.ai.mit.edu> */
-
-
-//   19990508 Busy Boxed! Dave Cinege
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include "busybox.h"
-
-
-#ifndef S_IFMT
-static const int S_IFMT = 0170000;
-#endif
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-# define       S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-# define       S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-# define       S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG) && defined(S_IFREG)
-# define       S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-# define       S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define       S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-# define       S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISMPB) && defined(S_IFMPB)      /* V7 */
-# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
-# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
-#endif
-#if !defined(S_ISNWK) && defined(S_IFNWK)      /* HP/UX */
-# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
-#endif
-
-#define IN_CTYPE_DOMAIN(c) 1
-
-#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
-#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
-#define ISDIGIT(c) (((unsigned char) (c)) - '0' <= 9)
-
-#define isodigit(c) ((c) >= '0' && (c) <= '7')
-#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
-#define octtobin(c) ((c) - '0')
-
-static double xstrtod __P((char *s));
-static int print_esc __P((char *escstart));
-static int print_formatted __P((char *format, int argc, char **argv));
-static long xstrtol __P((char *s));
-static unsigned long xstrtoul __P((char *s));
-static void print_direc
-__P(
-
-       (char *start, size_t length, int field_width, int precision,
-        char *argument));
-static void print_esc_char __P((int c));
-static void print_esc_string __P((char *str));
-static void verify __P((char *s, char *end));
-
-/* The value to return to the calling program.  */
-static int exit_status;
-
-int printf_main(int argc, char **argv)
-{
-       char *format;
-       int args_used;
-
-       exit_status = 0;
-       if (argc <= 1 || **(argv + 1) == '-') {
-               show_usage();
-       }
-
-       format = argv[1];
-       argc -= 2;
-       argv += 2;
-
-       do {
-               args_used = print_formatted(format, argc, argv);
-               argc -= args_used;
-               argv += args_used;
-       }
-       while (args_used > 0 && argc > 0);
-
-/*
-  if (argc > 0)
-    fprintf(stderr, "excess args ignored");
-*/
-
-       return(exit_status);
-}
-
-/* Print the text in FORMAT, using ARGV (with ARGC elements) for
-   arguments to any `%' directives.
-   Return the number of elements of ARGV used.  */
-
-static int print_formatted(char *format, int argc, char **argv)
-{
-       int save_argc = argc;           /* Preserve original value.  */
-       char *f;                                        /* Pointer into `format'.  */
-       char *direc_start;                      /* Start of % directive.  */
-       size_t direc_length;            /* Length of % directive.  */
-       int field_width;                        /* Arg to first '*', or -1 if none.  */
-       int precision;                          /* Arg to second '*', or -1 if none.  */
-
-       for (f = format; *f; ++f) {
-               switch (*f) {
-               case '%':
-                       direc_start = f++;
-                       direc_length = 1;
-                       field_width = precision = -1;
-                       if (*f == '%') {
-                               putchar('%');
-                               break;
-                       }
-                       if (*f == 'b') {
-                               if (argc > 0) {
-                                       print_esc_string(*argv);
-                                       ++argv;
-                                       --argc;
-                               }
-                               break;
-                       }
-                       if (strchr("-+ #", *f)) {
-                               ++f;
-                               ++direc_length;
-                       }
-                       if (*f == '*') {
-                               ++f;
-                               ++direc_length;
-                               if (argc > 0) {
-                                       field_width = xstrtoul(*argv);
-                                       ++argv;
-                                       --argc;
-                               } else
-                                       field_width = 0;
-                       } else
-                               while (ISDIGIT(*f)) {
-                                       ++f;
-                                       ++direc_length;
-                               }
-                       if (*f == '.') {
-                               ++f;
-                               ++direc_length;
-                               if (*f == '*') {
-                                       ++f;
-                                       ++direc_length;
-                                       if (argc > 0) {
-                                               precision = xstrtoul(*argv);
-                                               ++argv;
-                                               --argc;
-                                       } else
-                                               precision = 0;
-                               } else
-                                       while (ISDIGIT(*f)) {
-                                               ++f;
-                                               ++direc_length;
-                                       }
-                       }
-                       if (*f == 'l' || *f == 'L' || *f == 'h') {
-                               ++f;
-                               ++direc_length;
-                       }
-                       /*  
-                          if (!strchr ("diouxXfeEgGcs", *f))
-                          fprintf(stderr, "%%%c: invalid directive", *f);
-                        */
-                       ++direc_length;
-                       if (argc > 0) {
-                               print_direc(direc_start, direc_length, field_width,
-                                                       precision, *argv);
-                               ++argv;
-                               --argc;
-                       } else
-                               print_direc(direc_start, direc_length, field_width,
-                                                       precision, "");
-                       break;
-
-               case '\\':
-                       f += print_esc(f);
-                       break;
-
-               default:
-                       putchar(*f);
-               }
-       }
-
-       return save_argc - argc;
-}
-
-/* Print a \ escape sequence starting at ESCSTART.
-   Return the number of characters in the escape sequence
-   besides the backslash. */
-
-static int print_esc(char *escstart)
-{
-       register char *p = escstart + 1;
-       int esc_value = 0;                      /* Value of \nnn escape. */
-       int esc_length;                         /* Length of \nnn escape. */
-
-       /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
-       if (*p == 'x') {
-               for (esc_length = 0, ++p;
-                        esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
-                       esc_value = esc_value * 16 + hextobin(*p);
-/*      if (esc_length == 0)
-       fprintf(stderr, "missing hex in esc");
-*/
-               putchar(esc_value);
-       } else if (*p == '0') {
-               for (esc_length = 0, ++p;
-                        esc_length < 3 && isodigit(*p); ++esc_length, ++p)
-                       esc_value = esc_value * 8 + octtobin(*p);
-               putchar(esc_value);
-       } else if (strchr("\"\\abcfnrtv", *p))
-               print_esc_char(*p++);
-/*  else
-    fprintf(stderr, "\\%c: invalid esc", *p);
-*/
-       return p - escstart - 1;
-}
-
-/* Output a single-character \ escape.  */
-
-static void print_esc_char(int c)
-{
-       switch (c) {
-       case 'a':                                       /* Alert. */
-               putchar(7);
-               break;
-       case 'b':                                       /* Backspace. */
-               putchar(8);
-               break;
-       case 'c':                                       /* Cancel the rest of the output. */
-               exit(0);
-               break;
-       case 'f':                                       /* Form feed. */
-               putchar(12);
-               break;
-       case 'n':                                       /* New line. */
-               putchar(10);
-               break;
-       case 'r':                                       /* Carriage return. */
-               putchar(13);
-               break;
-       case 't':                                       /* Horizontal tab. */
-               putchar(9);
-               break;
-       case 'v':                                       /* Vertical tab. */
-               putchar(11);
-               break;
-       default:
-               putchar(c);
-               break;
-       }
-}
-
-/* Print string STR, evaluating \ escapes. */
-
-static void print_esc_string(char *str)
-{
-       for (; *str; str++)
-               if (*str == '\\')
-                       str += print_esc(str);
-               else
-                       putchar(*str);
-}
-
-static void
-print_direc(char *start, size_t length, int field_width, int precision,
-                       char *argument)
-{
-       char *p;                                        /* Null-terminated copy of % directive. */
-
-       p = xmalloc((unsigned) (length + 1));
-       strncpy(p, start, length);
-       p[length] = 0;
-
-       switch (p[length - 1]) {
-       case 'd':
-       case 'i':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtol(argument));
-                       else
-                               printf(p, precision, xstrtol(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtol(argument));
-                       else
-                               printf(p, field_width, precision, xstrtol(argument));
-               }
-               break;
-
-       case 'o':
-       case 'u':
-       case 'x':
-       case 'X':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtoul(argument));
-                       else
-                               printf(p, precision, xstrtoul(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtoul(argument));
-                       else
-                               printf(p, field_width, precision, xstrtoul(argument));
-               }
-               break;
-
-       case 'f':
-       case 'e':
-       case 'E':
-       case 'g':
-       case 'G':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtod(argument));
-                       else
-                               printf(p, precision, xstrtod(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtod(argument));
-                       else
-                               printf(p, field_width, precision, xstrtod(argument));
-               }
-               break;
-
-       case 'c':
-               printf(p, *argument);
-               break;
-
-       case 's':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, argument);
-                       else
-                               printf(p, precision, argument);
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, argument);
-                       else
-                               printf(p, field_width, precision, argument);
-               }
-               break;
-       }
-
-       free(p);
-}
-
-static unsigned long xstrtoul(char *s)
-{
-       char *end;
-       unsigned long val;
-
-       errno = 0;
-       val = strtoul(s, &end, 0);
-       verify(s, end);
-       return val;
-}
-
-static long xstrtol(char *s)
-{
-       char *end;
-       long val;
-
-       errno = 0;
-       val = strtol(s, &end, 0);
-       verify(s, end);
-       return val;
-}
-
-static double xstrtod(char *s)
-{
-       char *end;
-       double val;
-
-       errno = 0;
-       val = strtod(s, &end);
-       verify(s, end);
-       return val;
-}
-
-static void verify(char *s, char *end)
-{
-       if (errno) {
-               fprintf(stderr, "%s", s);
-               exit_status = 1;
-       } else if (*end) {
-               /*
-                  if (s == end)
-                  fprintf(stderr, "%s: expected numeric", s);
-                  else
-                  fprintf(stderr, "%s: not completely converted", s);
-                */
-               exit_status = 1;
-       }
-}
diff --git a/busybox/coreutils/pwd.c b/busybox/coreutils/pwd.c
deleted file mode 100644 (file)
index f6a00bf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini pwd implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int pwd_main(int argc, char **argv)
-{
-       static char *buf; 
-       
-       buf = xgetcwd(buf);
-       
-       if (buf != NULL) {
-               puts(buf);
-               return EXIT_SUCCESS;
-       }
-       return EXIT_FAILURE;
-}
diff --git a/busybox/coreutils/rm.c b/busybox/coreutils/rm.c
deleted file mode 100644 (file)
index 51c9f4c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rm implementation for busybox
- *
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <utime.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int rm_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int flags = 0;
-       int i;
-
-       while ((opt = getopt(argc, argv, "fiRr")) != -1) {
-               switch (opt) {
-               case 'f':
-                       flags &= ~FILEUTILS_INTERACTIVE;
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags &= ~FILEUTILS_FORCE;
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               case 'R':
-               case 'r':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               }
-       }
-
-       if (!(flags & FILEUTILS_FORCE) && optind == argc)
-               show_usage();
-
-       for (i = optind; i < argc; i++) {
-               char *base = get_last_path_component(argv[i]);
-
-               if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) {
-                       error_msg("cannot remove `.' or `..'");
-                       status = 1;
-                       continue;
-               }
-
-               if (remove_file(argv[i], flags) < 0)
-                       status = 1;
-       }
-
-       return status;
-}
diff --git a/busybox/coreutils/rmdir.c b/busybox/coreutils/rmdir.c
deleted file mode 100644 (file)
index cac27ca..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rmdir implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <getopt.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-
-/* Return true if a path is composed of multiple components.  */
-
-static int
-multiple_components_p (const char *path)
-{
-       const char *s = path;
-
-       while (s[0] != '\0' && s[0] != '/')
-               s++;
-
-       while (s[0] == '/')
-               s++;
-
-       return (s[0] != '\0');
-}
-
-
-/* Remove a directory.  Returns 0 if successful, -1 on error.  */
-
-static int
-remove_directory (char *path, int flags)
-{
-       if (!(flags & FILEUTILS_RECUR)) {
-               if (rmdir (path) < 0) {
-                       perror_msg ("unable to remove `%s'", path);
-                       return -1;
-               }
-       } else {
-               if (remove_directory (path, 0) < 0)
-                       return -1;
-
-               if (multiple_components_p (path))
-                       if (remove_directory (dirname (path), flags) < 0)
-                               return -1;
-       }
-
-       return 0;
-}
-
-
-extern int
-rmdir_main (int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int flags = 0;
-       int i, opt;
-
-       while ((opt = getopt (argc, argv, "p")) != -1)
-               switch (opt) {
-                       case 'p':
-                               flags |= FILEUTILS_RECUR;
-                               break;
-
-                       default:
-                               show_usage ();
-               }
-
-       if (optind == argc)
-               show_usage();
-
-       for (i = optind; i < argc; i++)
-               if (remove_directory (argv[i], flags) < 0)
-                       status = EXIT_FAILURE;
-
-       return status;
-}
diff --git a/busybox/coreutils/sleep.c b/busybox/coreutils/sleep.c
deleted file mode 100644 (file)
index 3bcab88..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sleep implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int sleep_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       if (sleep(atoi(*(++argv))) != 0)
-               perror_msg_and_die("sleep");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/sort.c b/busybox/coreutils/sort.c
deleted file mode 100644 (file)
index 4f4979c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sort implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int compare_ascii(const void *x, const void *y)
-{
-       return strcmp(*(char **)x, *(char **)y);
-}
-
-static int compare_numeric(const void *x, const void *y)
-{
-       int z = atoi(*(char **)x) - atoi(*(char **)y);
-       return z ? z : strcmp(*(char **)x, *(char **)y);
-}
-
-int sort_main(int argc, char **argv)
-{
-       FILE *fp;
-       char *line, **lines = NULL;
-       int i, opt, nlines = 0;
-       int (*compare)(const void *, const void *) = compare_ascii;
-#ifdef BB_FEATURE_SORT_REVERSE
-       int reverse = FALSE;
-#endif
-#ifdef BB_FEATURE_SORT_UNIQUE
-       int unique = FALSE;
-#endif
-
-       while ((opt = getopt(argc, argv, "nru")) != -1) {
-               switch (opt) {
-                       case 'n':
-                               compare = compare_numeric;
-                               break;
-#ifdef BB_FEATURE_SORT_REVERSE
-                       case 'r':
-                               reverse = TRUE;
-                               break;
-#endif
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       case 'u':
-                               unique = TRUE;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* read the input */
-       for (i = optind; i == optind || i < argc; i++) {
-               if (argv[i] == NULL)
-                       fp = stdin;
-               else
-                       fp = xfopen(argv[i], "r");
-
-               while ((line = get_line_from_file(fp)) != NULL) {
-                       lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
-                       chomp(line);
-                       lines[nlines++] = line;
-               }
-       }
-
-       /* sort it */
-       qsort(lines, nlines, sizeof(char *), compare);
-
-       /* print it */
-#ifdef BB_FEATURE_SORT_REVERSE
-       if (reverse) {
-               for (i = --nlines; 0 <= i; i--)
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i])))
-#endif
-                               puts(lines[i]);
-       } else
-#endif
-               for (i = 0; i < nlines; i++)
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i])))
-#endif
-                               puts(lines[i]);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/stty.c b/busybox/coreutils/stty.c
deleted file mode 100644 (file)
index 2e00a49..0000000
+++ /dev/null
@@ -1,1376 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* stty -- change and print terminal line settings
-   Copyright (C) 1990-1999 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Usage: stty [-ag] [-F device] [setting...]
-
-   Options:
-   -a Write all current settings to stdout in human-readable form.
-   -g Write all current settings to stdout in stty-readable form.
-   -F Open and use the specified device instead of stdin
-
-   If no args are given, write to stdout the baud rate and settings that
-   have been changed from their defaults.  Mode reading and changes
-   are done on the specified device, or stdin if none was specified.
-
-   David MacKenzie <djm@gnu.ai.mit.edu>
-
-   Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
-
-   */
-
-//#define TEST
-
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <getopt.h>
-
-#include <sys/param.h>
-#include <unistd.h>
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <memory.h>
-#include <fcntl.h>
-#include "busybox.h"
-
-#define STREQ(a, b) (strcmp ((a), (b)) == 0)
-
-
-#ifndef _POSIX_VDISABLE
-# define _POSIX_VDISABLE ((unsigned char) 0)
-#endif
-
-#define Control(c) ((c) & 0x1f)
-/* Canonical values for control characters. */
-#ifndef CINTR
-# define CINTR Control ('c')
-#endif
-#ifndef CQUIT
-# define CQUIT 28
-#endif
-#ifndef CERASE
-# define CERASE 127
-#endif
-#ifndef CKILL
-# define CKILL Control ('u')
-#endif
-#ifndef CEOF
-# define CEOF Control ('d')
-#endif
-#ifndef CEOL
-# define CEOL _POSIX_VDISABLE
-#endif
-#ifndef CSTART
-# define CSTART Control ('q')
-#endif
-#ifndef CSTOP
-# define CSTOP Control ('s')
-#endif
-#ifndef CSUSP
-# define CSUSP Control ('z')
-#endif
-#if defined(VEOL2) && !defined(CEOL2)
-# define CEOL2 _POSIX_VDISABLE
-#endif
-/* ISC renamed swtch to susp for termios, but we'll accept either name.  */
-#if defined(VSUSP) && !defined(VSWTCH)
-# define VSWTCH VSUSP
-# define CSWTCH CSUSP
-#endif
-#if defined(VSWTCH) && !defined(CSWTCH)
-# define CSWTCH _POSIX_VDISABLE
-#endif
-
-/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
-   So the default is to disable `swtch.'  */
-#if defined (__sparc__) && defined (__svr4__)
-# undef CSWTCH
-# define CSWTCH _POSIX_VDISABLE
-#endif
-
-#if defined(VWERSE) && !defined (VWERASE)       /* AIX-3.2.5 */
-# define VWERASE VWERSE
-#endif
-#if defined(VDSUSP) && !defined (CDSUSP)
-# define CDSUSP Control ('y')
-#endif
-#if !defined(VREPRINT) && defined(VRPRNT)       /* Irix 4.0.5 */
-# define VREPRINT VRPRNT
-#endif
-#if defined(VREPRINT) && !defined(CRPRNT)
-# define CRPRNT Control ('r')
-#endif
-#if defined(VWERASE) && !defined(CWERASE)
-# define CWERASE Control ('w')
-#endif
-#if defined(VLNEXT) && !defined(CLNEXT)
-# define CLNEXT Control ('v')
-#endif
-#if defined(VDISCARD) && !defined(VFLUSHO)
-# define VFLUSHO VDISCARD
-#endif
-#if defined(VFLUSH) && !defined(VFLUSHO)        /* Ultrix 4.2 */
-# define VFLUSHO VFLUSH
-#endif
-#if defined(CTLECH) && !defined(ECHOCTL)        /* Ultrix 4.3 */
-# define ECHOCTL CTLECH
-#endif
-#if defined(TCTLECH) && !defined(ECHOCTL)       /* Ultrix 4.2 */
-# define ECHOCTL TCTLECH
-#endif
-#if defined(CRTKIL) && !defined(ECHOKE)         /* Ultrix 4.2 and 4.3 */
-# define ECHOKE CRTKIL
-#endif
-#if defined(VFLUSHO) && !defined(CFLUSHO)
-# define CFLUSHO Control ('o')
-#endif
-#if defined(VSTATUS) && !defined(CSTATUS)
-# define CSTATUS Control ('t')
-#endif
-
-/* Which speeds to set.  */
-enum speed_setting {
-       input_speed, output_speed, both_speeds
-};
-
-/* What to output and how.  */
-enum output_type {
-       changed, all, recoverable       /* Default, -a, -g.  */
-};
-
-/* Which member(s) of `struct termios' a mode uses.  */
-enum mode_type {
-       control, input, output, local, combination
-};
-
-
-static const char evenp     [] = "evenp";
-static const char raw       [] = "raw";
-static const char stty_min  [] = "min";
-static const char stty_time [] = "time";
-static const char stty_swtch[] = "swtch";
-static const char stty_eol  [] = "eol";
-static const char stty_eof  [] = "eof";
-static const char parity    [] = "parity";
-static const char stty_oddp [] = "oddp";
-static const char stty_nl   [] = "nl";
-static const char stty_ek   [] = "ek";
-static const char stty_sane [] = "sane";
-static const char cbreak    [] = "cbreak";
-static const char stty_pass8[] = "pass8";
-static const char litout    [] = "litout";
-static const char cooked    [] = "cooked";
-static const char decctlq   [] = "decctlq";
-static const char stty_tabs [] = "tabs";
-static const char stty_lcase[] = "lcase";
-static const char stty_LCASE[] = "LCASE";
-static const char stty_crt  [] = "crt";
-static const char stty_dec  [] = "dec";
-
-
-/* Flags for `struct mode_info'. */
-#define SANE_SET 1              /* Set in `sane' mode.                  */
-#define SANE_UNSET 2            /* Unset in `sane' mode.                */
-#define REV 4                   /* Can be turned off by prepending `-'. */
-#define OMIT 8                  /* Don't display value.                 */
-
-/* Each mode.  */
-struct mode_info {
-       const char *name;       /* Name given on command line.           */
-       enum mode_type type;    /* Which structure element to change.    */
-       char flags;             /* Setting and display options.          */
-       unsigned long bits;     /* Bits to set for this mode.            */
-       unsigned long mask;     /* Other bits to turn off for this mode. */
-};
-
-static const struct  mode_info mode_info[] = {
-       {"parenb",   control,     REV,               PARENB,     0 },
-       {"parodd",   control,     REV,               PARODD,     0 },
-       {"cs5",      control,     0,                 CS5,     CSIZE},
-       {"cs6",      control,     0,                 CS6,     CSIZE},
-       {"cs7",      control,     0,                 CS7,     CSIZE},
-       {"cs8",      control,     0,                 CS8,     CSIZE},
-       {"hupcl",    control,     REV,               HUPCL,      0 },
-       {"hup",      control,     REV        | OMIT, HUPCL,      0 },
-       {"cstopb",   control,     REV,               CSTOPB,     0 },
-       {"cread",    control,     SANE_SET   | REV,  CREAD,      0 },
-       {"clocal",   control,     REV,               CLOCAL,     0 },
-#ifdef CRTSCTS
-       {"crtscts",  control,     REV,               CRTSCTS,    0 },
-#endif
-       {"ignbrk",   input,       SANE_UNSET | REV,  IGNBRK,     0 },
-       {"brkint",   input,       SANE_SET   | REV,  BRKINT,     0 },
-       {"ignpar",   input,       REV,               IGNPAR,     0 },
-       {"parmrk",   input,       REV,               PARMRK,     0 },
-       {"inpck",    input,       REV,               INPCK,      0 },
-       {"istrip",   input,       REV,               ISTRIP,     0 },
-       {"inlcr",    input,       SANE_UNSET | REV,  INLCR,      0 },
-       {"igncr",    input,       SANE_UNSET | REV,  IGNCR,      0 },
-       {"icrnl",    input,       SANE_SET   | REV,  ICRNL,      0 },
-       {"ixon",     input,       REV,               IXON,       0 },
-       {"ixoff",    input,       SANE_UNSET | REV,  IXOFF,      0 },
-       {"tandem",   input,       REV        | OMIT, IXOFF,      0 },
-#ifdef IUCLC
-       {"iuclc",    input,       SANE_UNSET | REV,  IUCLC,      0 },
-#endif
-#ifdef IXANY
-       {"ixany",    input,       SANE_UNSET | REV,  IXANY,      0 },
-#endif
-#ifdef IMAXBEL
-       {"imaxbel",  input,       SANE_SET   | REV,  IMAXBEL,    0 },
-#endif
-       {"opost",    output,      SANE_SET   | REV,  OPOST,      0 },
-#ifdef OLCUC
-       {"olcuc",    output,      SANE_UNSET | REV,  OLCUC,      0 },
-#endif
-#ifdef OCRNL
-       {"ocrnl",    output,      SANE_UNSET | REV,  OCRNL,      0 },
-#endif
-#ifdef ONLCR
-       {"onlcr",    output,      SANE_SET   | REV,  ONLCR,      0 },
-#endif
-#ifdef ONOCR
-       {"onocr",    output,      SANE_UNSET | REV,  ONOCR,      0 },
-#endif
-#ifdef ONLRET
-       {"onlret",   output,      SANE_UNSET | REV,  ONLRET,     0 },
-#endif
-#ifdef OFILL
-       {"ofill",    output,      SANE_UNSET | REV,  OFILL,      0 },
-#endif
-#ifdef OFDEL
-       {"ofdel",    output,      SANE_UNSET | REV,  OFDEL,      0 },
-#endif
-#ifdef NLDLY
-       {"nl1",      output,      SANE_UNSET,        NL1,     NLDLY},
-       {"nl0",      output,      SANE_SET,          NL0,     NLDLY},
-#endif
-#ifdef CRDLY
-       {"cr3",      output,      SANE_UNSET,        CR3,     CRDLY},
-       {"cr2",      output,      SANE_UNSET,        CR2,     CRDLY},
-       {"cr1",      output,      SANE_UNSET,        CR1,     CRDLY},
-       {"cr0",      output,      SANE_SET,          CR0,     CRDLY},
-#endif
-
-#ifdef TABDLY
-       {"tab3",     output,      SANE_UNSET,        TAB3,   TABDLY},
-       {"tab2",     output,      SANE_UNSET,        TAB2,   TABDLY},
-       {"tab1",     output,      SANE_UNSET,        TAB1,   TABDLY},
-       {"tab0",     output,      SANE_SET,          TAB0,   TABDLY},
-#else
-# ifdef OXTABS
-       {"tab3",     output,      SANE_UNSET,        OXTABS,     0 },
-# endif
-#endif
-
-#ifdef BSDLY
-       {"bs1",      output,      SANE_UNSET,        BS1,     BSDLY},
-       {"bs0",      output,      SANE_SET,          BS0,     BSDLY},
-#endif
-#ifdef VTDLY
-       {"vt1",      output,      SANE_UNSET,        VT1,     VTDLY},
-       {"vt0",      output,      SANE_SET,          VT0,     VTDLY},
-#endif
-#ifdef FFDLY
-       {"ff1",      output,      SANE_UNSET,        FF1,     FFDLY},
-       {"ff0",      output,      SANE_SET,          FF0,     FFDLY},
-#endif
-       {"isig",     local,       SANE_SET   | REV,  ISIG,       0 },
-       {"icanon",   local,       SANE_SET   | REV,  ICANON,     0 },
-#ifdef IEXTEN
-       {"iexten",   local,       SANE_SET   | REV,  IEXTEN,     0 },
-#endif
-       {"echo",     local,       SANE_SET   | REV,  ECHO,       0 },
-       {"echoe",    local,       SANE_SET   | REV,  ECHOE,      0 },
-       {"crterase", local,       REV        | OMIT, ECHOE,      0 },
-       {"echok",    local,       SANE_SET   | REV,  ECHOK,      0 },
-       {"echonl",   local,       SANE_UNSET | REV,  ECHONL,     0 },
-       {"noflsh",   local,       SANE_UNSET | REV,  NOFLSH,     0 },
-#ifdef XCASE
-       {"xcase",    local,       SANE_UNSET | REV,  XCASE,      0 },
-#endif
-#ifdef TOSTOP
-       {"tostop",   local,       SANE_UNSET | REV,  TOSTOP,     0 },
-#endif
-#ifdef ECHOPRT
-       {"echoprt",  local,       SANE_UNSET | REV,  ECHOPRT,    0 },
-       {"prterase", local,       REV | OMIT,        ECHOPRT,    0 },
-#endif
-#ifdef ECHOCTL
-       {"echoctl",  local,       SANE_SET   | REV,  ECHOCTL,    0 },
-       {"ctlecho",  local,       REV        | OMIT, ECHOCTL,    0 },
-#endif
-#ifdef ECHOKE
-       {"echoke",   local,       SANE_SET   | REV,  ECHOKE,     0 },
-       {"crtkill",  local,       REV        | OMIT, ECHOKE,     0 },
-#endif
-       {evenp,      combination, REV        | OMIT, 0,          0 },
-       {parity,     combination, REV        | OMIT, 0,          0 },
-       {stty_oddp,  combination, REV        | OMIT, 0,          0 },
-       {stty_nl,    combination, REV        | OMIT, 0,          0 },
-       {stty_ek,    combination, OMIT,              0,          0 },
-       {stty_sane,  combination, OMIT,              0,          0 },
-       {cooked,     combination, REV        | OMIT, 0,          0 },
-       {raw,        combination, REV        | OMIT, 0,          0 },
-       {stty_pass8, combination, REV        | OMIT, 0,          0 },
-       {litout,     combination, REV        | OMIT, 0,          0 },
-       {cbreak,     combination, REV        | OMIT, 0,          0 },
-#ifdef IXANY
-       {decctlq,    combination, REV        | OMIT, 0,          0 },
-#endif
-#if defined (TABDLY) || defined (OXTABS)
-       {stty_tabs,  combination, REV        | OMIT, 0,          0 },
-#endif
-#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
-       {stty_lcase, combination, REV        | OMIT, 0,          0 },
-       {stty_LCASE, combination, REV        | OMIT, 0,          0 },
-#endif
-       {stty_crt,   combination, OMIT,              0,          0 },
-       {stty_dec,   combination, OMIT,              0,          0 },
-};
-
-static const int NUM_mode_info =
-
-       (sizeof(mode_info) / sizeof(struct mode_info));
-
-/* Control character settings.  */
-struct control_info {
-       const char *name;                       /* Name given on command line.  */
-       unsigned char saneval;          /* Value to set for `stty sane'.  */
-       int offset;                                     /* Offset in c_cc.  */
-};
-
-/* Control characters. */
-
-static const struct  control_info control_info[] = {
-       {"intr",     CINTR,   VINTR},
-       {"quit",     CQUIT,   VQUIT},
-       {"erase",    CERASE,  VERASE},
-       {"kill",     CKILL,   VKILL},
-       {stty_eof,   CEOF,    VEOF},
-       {stty_eol,   CEOL,    VEOL},
-#ifdef VEOL2
-       {"eol2",     CEOL2,   VEOL2},
-#endif
-#ifdef VSWTCH
-       {stty_swtch, CSWTCH,  VSWTCH},
-#endif
-       {"start",    CSTART,  VSTART},
-       {"stop",     CSTOP,   VSTOP},
-       {"susp",     CSUSP,   VSUSP},
-#ifdef VDSUSP
-       {"dsusp",    CDSUSP,  VDSUSP},
-#endif
-#ifdef VREPRINT
-       {"rprnt",    CRPRNT,  VREPRINT},
-#endif
-#ifdef VWERASE
-       {"werase",   CWERASE, VWERASE},
-#endif
-#ifdef VLNEXT
-       {"lnext",    CLNEXT,  VLNEXT},
-#endif
-#ifdef VFLUSHO
-       {"flush",    CFLUSHO, VFLUSHO},
-#endif
-#ifdef VSTATUS
-       {"status",   CSTATUS, VSTATUS},
-#endif
-       /* These must be last because of the display routines. */
-       {stty_min,   1,       VMIN},
-       {stty_time,  0,       VTIME},
-};
-
-static const int NUM_control_info =
-       (sizeof(control_info) / sizeof(struct control_info));
-
-
-static const char *  visible(unsigned int ch);
-static unsigned long baud_to_value(speed_t speed);
-static int           recover_mode(char *arg, struct termios *mode);
-static int           screen_columns(void);
-static int           set_mode(const struct mode_info *info,
-                                       int reversed, struct termios *mode);
-static speed_t       string_to_baud(const char *arg);
-static tcflag_t*     mode_type_flag(enum mode_type type, struct termios *mode);
-static void          display_all(struct termios *mode, int fd,
-                                       const char *device_name);
-static void          display_changed(struct termios *mode);
-static void          display_recoverable(struct termios *mode);
-static void          display_settings(enum output_type output_type,
-                                       struct termios *mode, int fd,
-                                       const char *device_name);
-static void          display_speed(struct termios *mode, int fancy);
-static void          display_window_size(int fancy, int fd,
-                                       const char *device_name);
-static void          sane_mode(struct termios *mode);
-static void          set_control_char(const struct control_info *info,
-                                       const char *arg, struct termios *mode);
-static void          set_speed(enum speed_setting type,
-                                       const char *arg, struct termios *mode);
-static void          set_window_size(int rows, int cols, int fd,
-                                       const char *device_name);
-
-/* The width of the screen, for output wrapping. */
-static int max_col;
-
-/* Current position, to know when to wrap. */
-static int current_col;
-
-/* Print format string MESSAGE and optional args.
-   Wrap to next line first if it won't fit.
-   Print a space first unless MESSAGE will start a new line. */
-
-static void wrapf(const char *message, ...)
-{
-       va_list args;
-       char buf[1024];                 /* Plenty long for our needs. */
-       int buflen;
-
-       va_start(args, message);
-       vsprintf(buf, message, args);
-       va_end(args);
-       buflen = strlen(buf);
-       if (current_col + (current_col > 0) + buflen >= max_col) {
-               putchar('\n');
-               current_col = 0;
-       }
-       if (current_col > 0) {
-               putchar(' ');
-               current_col++;
-       }
-       fputs(buf, stdout);
-       current_col += buflen;
-}
-
-static const struct suffix_mult stty_suffixes[] = {
-       {"b",  512 },
-       {"k",  1024},
-       {"B",  1024},
-       {NULL, 0   }
-};
-
-#ifndef TEST
-extern int stty_main(int argc, char **argv)
-#else
-extern int main(int argc, char **argv)
-#endif
-{
-       struct termios mode;
-       enum   output_type output_type;
-       int    optc;
-       int    require_set_attr;
-       int    speed_was_set;
-       int    verbose_output;
-       int    recoverable_output;
-       int    k;
-       int    noargs = 1;
-       char * file_name = NULL;
-       int    fd;
-       const char *device_name;
-
-       output_type = changed;
-       verbose_output = 0;
-       recoverable_output = 0;
-
-       /* Don't print error messages for unrecognized options.  */
-       opterr = 0;
-
-       while ((optc = getopt(argc, argv, "agF:")) != -1) {
-               switch (optc) {
-               case 'a':
-                       verbose_output = 1;
-                       output_type = all;
-                       break;
-
-               case 'g':
-                       recoverable_output = 1;
-                       output_type = recoverable;
-                       break;
-
-               case 'F':
-                       if (file_name)
-                               error_msg_and_die("only one device may be specified");
-                       file_name = optarg;
-                       break;
-
-               default:                /* unrecognized option */
-                       noargs = 0;
-                       break;
-               }
-
-               if (noargs == 0)
-                       break;
-       }
-
-       if (optind < argc)
-               noargs = 0;
-
-       /* Specifying both -a and -g gets an error.  */
-       if (verbose_output && recoverable_output)
-               error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
-
-       /* Specifying any other arguments with -a or -g gets an error.  */
-       if (!noargs && (verbose_output || recoverable_output))
-               error_msg_and_die ("modes may not be set when specifying an output style");
-
-       /* FIXME: it'd be better not to open the file until we've verified
-          that all arguments are valid.  Otherwise, we could end up doing
-          only some of the requested operations and then failing, probably
-          leaving things in an undesirable state.  */
-
-       if (file_name) {
-               int fdflags;
-
-               device_name = file_name;
-               fd = open(device_name, O_RDONLY | O_NONBLOCK);
-               if (fd < 0)
-                       perror_msg_and_die("%s", device_name);
-               if ((fdflags = fcntl(fd, F_GETFL)) == -1
-                       || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
-                       perror_msg_and_die("%s: couldn't reset non-blocking mode",
-                                                          device_name);
-       } else {
-               fd = 0;
-               device_name = "standard input";
-       }
-
-       /* Initialize to all zeroes so there is no risk memcmp will report a
-          spurious difference in an uninitialized portion of the structure.  */
-       memset(&mode, 0, sizeof(mode));
-       if (tcgetattr(fd, &mode))
-               perror_msg_and_die("%s", device_name);
-
-       if (verbose_output || recoverable_output || noargs) {
-               max_col = screen_columns();
-               current_col = 0;
-               display_settings(output_type, &mode, fd, device_name);
-               return EXIT_SUCCESS;
-       }
-
-       speed_was_set = 0;
-       require_set_attr = 0;
-       k = optind;
-       while (k < argc) {
-               int match_found = 0;
-               int reversed = 0;
-               int i;
-
-               if (argv[k][0] == '-') {
-                       ++argv[k];
-                       reversed = 1;
-               }
-               for (i = 0; i < NUM_mode_info; ++i)
-                       if (STREQ(argv[k], mode_info[i].name)) {
-                               match_found = set_mode(&mode_info[i], reversed, &mode);
-                               require_set_attr = 1;
-                               break;
-                       }
-
-               if (match_found == 0 && reversed)
-                       error_msg_and_die("invalid argument `%s'", --argv[k]);
-
-               if (match_found == 0)
-                       for (i = 0; i < NUM_control_info; ++i)
-                               if (STREQ(argv[k], control_info[i].name)) {
-                                       if (k == argc - 1)
-                                           error_msg_and_die("missing argument to `%s'", argv[k]);
-                                       match_found = 1;
-                                       ++k;
-                                       set_control_char(&control_info[i], argv[k], &mode);
-                                       require_set_attr = 1;
-                                       break;
-                               }
-
-               if (match_found == 0) {
-                       if (STREQ(argv[k], "ispeed")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_speed(input_speed, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       } else if (STREQ(argv[k], "ospeed")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_speed(output_speed, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       }
-#ifdef TIOCGWINSZ
-                       else if (STREQ(argv[k], "rows")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_window_size((int) parse_number(argv[k], stty_suffixes),
-                                                               -1, fd, device_name);
-                       } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_window_size(-1,
-                                               (int) parse_number(argv[k], stty_suffixes),
-                                               fd, device_name);
-                       } else if (STREQ(argv[k], "size")) {
-                               max_col = screen_columns();
-                               current_col = 0;
-                               display_window_size(0, fd, device_name);
-                       }
-#endif
-#ifdef HAVE_C_LINE
-                       else if (STREQ(argv[k], "line")) {
-                               if (k == argc - 1)
-                                       error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               mode.c_line = parse_number(argv[k], stty_suffixes);
-                               require_set_attr = 1;
-                       }
-#endif
-                       else if (STREQ(argv[k], "speed")) {
-                               max_col = screen_columns();
-                               display_speed(&mode, 0);
-                       } else if (recover_mode(argv[k], &mode) == 1)
-                               require_set_attr = 1;
-                       else if (string_to_baud(argv[k]) != (speed_t) - 1) {
-                               set_speed(both_speeds, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       } else
-                               error_msg_and_die("invalid argument `%s'", argv[k]);
-               }
-               k++;
-       }
-
-       if (require_set_attr) {
-               struct termios new_mode;
-
-               if (tcsetattr(fd, TCSADRAIN, &mode))
-                       perror_msg_and_die("%s", device_name);
-
-               /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
-                  it performs *any* of the requested operations.  This means it
-                  can report `success' when it has actually failed to perform
-                  some proper subset of the requested operations.  To detect
-                  this partial failure, get the current terminal attributes and
-                  compare them to the requested ones.  */
-
-               /* Initialize to all zeroes so there is no risk memcmp will report a
-                  spurious difference in an uninitialized portion of the structure.  */
-               memset(&new_mode, 0, sizeof(new_mode));
-               if (tcgetattr(fd, &new_mode))
-                       perror_msg_and_die("%s", device_name);
-
-               /* Normally, one shouldn't use memcmp to compare structures that
-                  may have `holes' containing uninitialized data, but we have been
-                  careful to initialize the storage of these two variables to all
-                  zeroes.  One might think it more efficient simply to compare the
-                  modified fields, but that would require enumerating those fields --
-                  and not all systems have the same fields in this structure.  */
-
-               if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
-#ifdef CIBAUD
-                       /* SunOS 4.1.3 (at least) has the problem that after this sequence,
-                          tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
-                          sometimes (m1 != m2).  The only difference is in the four bits
-                          of the c_cflag field corresponding to the baud rate.  To save
-                          Sun users a little confusion, don't report an error if this
-                          happens.  But suppress the error only if we haven't tried to
-                          set the baud rate explicitly -- otherwise we'd never give an
-                          error for a true failure to set the baud rate.  */
-
-                       new_mode.c_cflag &= (~CIBAUD);
-                       if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
-#endif
-                               error_msg_and_die ("%s: unable to perform all requested operations",
-                                        device_name);
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/* Return 0 if not applied because not reversible; otherwise return 1.  */
-
-static int
-set_mode(const struct mode_info *info, int reversed, struct termios *mode)
-{
-       tcflag_t *bitsp;
-
-       if (reversed && (info->flags & REV) == 0)
-               return 0;
-
-       bitsp = mode_type_flag(info->type, mode);
-
-       if (bitsp == NULL) {
-               /* Combination mode. */
-               if (info->name == evenp || info->name == parity) {
-                       if (reversed)
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                       else
-                               mode->c_cflag =
-                                       (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
-               } else if (info->name == stty_oddp) {
-                       if (reversed)
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                       else
-                               mode->c_cflag =
-                                       (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
-               } else if (info->name == stty_nl) {
-                       if (reversed) {
-                               mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
-                               mode->c_oflag = (mode->c_oflag
-#ifdef ONLCR
-                                                                | ONLCR
-#endif
-                                       )
-#ifdef OCRNL
-                                       & ~OCRNL
-#endif
-#ifdef ONLRET
-                                       & ~ONLRET
-#endif
-                                       ;
-                       } else {
-                               mode->c_iflag = mode->c_iflag & ~ICRNL;
-#ifdef ONLCR
-                               mode->c_oflag = mode->c_oflag & ~ONLCR;
-#endif
-                       }
-               } else if (info->name == stty_ek) {
-                       mode->c_cc[VERASE] = CERASE;
-                       mode->c_cc[VKILL] = CKILL;
-               } else if (info->name == stty_sane)
-                       sane_mode(mode);
-               else if (info->name == cbreak) {
-                       if (reversed)
-                               mode->c_lflag |= ICANON;
-                       else
-                               mode->c_lflag &= ~ICANON;
-               } else if (info->name == stty_pass8) {
-                       if (reversed) {
-                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
-                               mode->c_iflag |= ISTRIP;
-                       } else {
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                               mode->c_iflag &= ~ISTRIP;
-                       }
-               } else if (info->name == litout) {
-                       if (reversed) {
-                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
-                               mode->c_iflag |= ISTRIP;
-                               mode->c_oflag |= OPOST;
-                       } else {
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                               mode->c_iflag &= ~ISTRIP;
-                               mode->c_oflag &= ~OPOST;
-                       }
-               } else if (info->name == raw || info->name == cooked) {
-                       if ((info->name[0] == 'r' && reversed)
-                               || (info->name[0] == 'c' && !reversed)) {
-                               /* Cooked mode. */
-                               mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
-                               mode->c_oflag |= OPOST;
-                               mode->c_lflag |= ISIG | ICANON;
-#if VMIN == VEOF
-                               mode->c_cc[VEOF] = CEOF;
-#endif
-#if VTIME == VEOL
-                               mode->c_cc[VEOL] = CEOL;
-#endif
-                       } else {
-                               /* Raw mode. */
-                               mode->c_iflag = 0;
-                               mode->c_oflag &= ~OPOST;
-                               mode->c_lflag &= ~(ISIG | ICANON
-#ifdef XCASE
-                                                                  | XCASE
-#endif
-                                       );
-                               mode->c_cc[VMIN] = 1;
-                               mode->c_cc[VTIME] = 0;
-                       }
-               }
-#ifdef IXANY
-               else if (info->name == decctlq) {
-                       if (reversed)
-                               mode->c_iflag |= IXANY;
-                       else
-                               mode->c_iflag &= ~IXANY;
-               }
-#endif
-#ifdef TABDLY
-               else if (info->name == stty_tabs) {
-                       if (reversed)
-                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
-                       else
-                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
-               }
-#else
-# ifdef OXTABS
-               else if (info->name == stty_tabs) {
-                       if (reversed)
-                               mode->c_oflag = mode->c_oflag | OXTABS;
-                       else
-                               mode->c_oflag = mode->c_oflag & ~OXTABS;
-               }
-# endif
-#endif
-#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
-               else if (info->name == stty_lcase || info->name == stty_LCASE) {
-                       if (reversed) {
-                               mode->c_lflag &= ~XCASE;
-                               mode->c_iflag &= ~IUCLC;
-                               mode->c_oflag &= ~OLCUC;
-                       } else {
-                               mode->c_lflag |= XCASE;
-                               mode->c_iflag |= IUCLC;
-                               mode->c_oflag |= OLCUC;
-                       }
-               }
-#endif
-               else if (info->name == stty_crt)
-                       mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
-                               | ECHOCTL
-#endif
-#ifdef ECHOKE
-                               | ECHOKE
-#endif
-                               ;
-               else if (info->name == stty_dec) {
-                       mode->c_cc[VINTR] = 3;  /* ^C */
-                       mode->c_cc[VERASE] = 127;       /* DEL */
-                       mode->c_cc[VKILL] = 21; /* ^U */
-                       mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
-                               | ECHOCTL
-#endif
-#ifdef ECHOKE
-                               | ECHOKE
-#endif
-                               ;
-#ifdef IXANY
-                       mode->c_iflag &= ~IXANY;
-#endif
-               }
-       } else if (reversed)
-               *bitsp = *bitsp & ~info->mask & ~info->bits;
-       else
-               *bitsp = (*bitsp & ~info->mask) | info->bits;
-
-       return 1;
-}
-
-static void
-set_control_char(const struct control_info *info, const char *arg,
-                                struct termios *mode)
-{
-       unsigned char value;
-
-       if (info->name == stty_min || info->name == stty_time)
-               value = parse_number(arg, stty_suffixes);
-       else if (arg[0] == '\0' || arg[1] == '\0')
-               value = arg[0];
-       else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
-               value = _POSIX_VDISABLE;
-       else if (arg[0] == '^' && arg[1] != '\0') {     /* Ignore any trailing junk. */
-               if (arg[1] == '?')
-                       value = 127;
-               else
-                       value = arg[1] & ~0140; /* Non-letters get weird results. */
-       } else
-               value = parse_number(arg, stty_suffixes);
-       mode->c_cc[info->offset] = value;
-}
-
-static void
-set_speed(enum speed_setting type, const char *arg, struct termios *mode)
-{
-       speed_t baud;
-
-       baud = string_to_baud(arg);
-       if (type == input_speed || type == both_speeds)
-               cfsetispeed(mode, baud);
-       if (type == output_speed || type == both_speeds)
-               cfsetospeed(mode, baud);
-}
-
-#ifdef TIOCGWINSZ
-
-static int get_win_size(int fd, struct winsize *win)
-{
-       int err = ioctl(fd, TIOCGWINSZ, (char *) win);
-
-       return err;
-}
-
-static void
-set_window_size(int rows, int cols, int fd, const char *device_name)
-{
-       struct winsize win;
-
-       if (get_win_size(fd, &win)) {
-               if (errno != EINVAL)
-                       perror_msg_and_die("%s", device_name);
-               memset(&win, 0, sizeof(win));
-       }
-
-       if (rows >= 0)
-               win.ws_row = rows;
-       if (cols >= 0)
-               win.ws_col = cols;
-
-# ifdef TIOCSSIZE
-       /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
-          The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
-          This comment from sys/ttold.h describes Sun's twisted logic - a better
-          test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
-          At any rate, the problem is gone in Solaris 2.x. */
-
-       if (win.ws_row == 0 || win.ws_col == 0) {
-               struct ttysize ttysz;
-
-               ttysz.ts_lines = win.ws_row;
-               ttysz.ts_cols = win.ws_col;
-
-               win.ws_row = 1;
-               win.ws_col = 1;
-
-               if (ioctl(fd, TIOCSWINSZ, (char *) &win))
-                       perror_msg_and_die("%s", device_name);
-
-               if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
-                       perror_msg_and_die("%s", device_name);
-               return;
-       }
-# endif
-
-       if (ioctl(fd, TIOCSWINSZ, (char *) &win))
-               perror_msg_and_die("%s", device_name);
-}
-
-static void display_window_size(int fancy, int fd, const char *device_name)
-{
-       struct winsize win;
-
-       if (get_win_size(fd, &win)) {
-               if (errno != EINVAL)
-                       perror_msg_and_die("%s", device_name);
-               if (!fancy)
-                       perror_msg_and_die("%s: no size information for this device",
-                                                          device_name);
-       } else {
-               wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
-                         win.ws_row, win.ws_col);
-               if (!fancy)
-                       current_col = 0;
-       }
-}
-#endif
-
-static int screen_columns(void)
-{
-#ifdef TIOCGWINSZ
-       struct winsize win;
-
-       /* With Solaris 2.[123], this ioctl fails and errno is set to
-          EINVAL for telnet (but not rlogin) sessions.
-          On ISC 3.0, it fails for the console and the serial port
-          (but it works for ptys).
-          It can also fail on any system when stdout isn't a tty.
-          In case of any failure, just use the default.  */
-       if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
-               return win.ws_col;
-#endif
-
-       if (getenv("COLUMNS"))
-               return atoi(getenv("COLUMNS"));
-       return 80;
-}
-
-static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
-{
-       switch (type) {
-       case control:
-               return &mode->c_cflag;
-
-       case input:
-               return &mode->c_iflag;
-
-       case output:
-               return &mode->c_oflag;
-
-       case local:
-               return &mode->c_lflag;
-
-       default:                                        /* combination: */
-               return NULL;
-       }
-}
-
-static void
-display_settings(enum output_type output_type, struct termios *mode,
-                                int fd, const char *device_name)
-{
-       switch (output_type) {
-       case changed:
-               display_changed(mode);
-               break;
-
-       case all:
-               display_all(mode, fd, device_name);
-               break;
-
-       case recoverable:
-               display_recoverable(mode);
-               break;
-       }
-}
-
-static void display_changed(struct termios *mode)
-{
-       int i;
-       int empty_line;
-       tcflag_t *bitsp;
-       unsigned long mask;
-       enum mode_type prev_type = control;
-
-       display_speed(mode, 1);
-#ifdef HAVE_C_LINE
-       wrapf("line = %d;", mode->c_line);
-#endif
-       putchar('\n');
-       current_col = 0;
-
-       empty_line = 1;
-       for (i = 0; control_info[i].name != stty_min; ++i) {
-               if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
-                       continue;
-               /* If swtch is the same as susp, don't print both.  */
-#if VSWTCH == VSUSP
-               if (control_info[i].name == stty_swtch)
-                       continue;
-#endif
-               /* If eof uses the same slot as min, only print whichever applies.  */
-#if VEOF == VMIN
-               if ((mode->c_lflag & ICANON) == 0
-                       && (control_info[i].name == stty_eof
-                               || control_info[i].name == stty_eol)) continue;
-#endif
-
-               empty_line = 0;
-               wrapf("%s = %s;", control_info[i].name,
-                         visible(mode->c_cc[control_info[i].offset]));
-       }
-       if ((mode->c_lflag & ICANON) == 0) {
-               wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
-                         (int) mode->c_cc[VTIME]);
-       } else if (empty_line == 0)
-               putchar('\n');
-       current_col = 0;
-
-       empty_line = 1;
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & OMIT)
-                       continue;
-               if (mode_info[i].type != prev_type) {
-                       if (empty_line == 0) {
-                               putchar('\n');
-                               current_col = 0;
-                               empty_line = 1;
-                       }
-                       prev_type = mode_info[i].type;
-               }
-
-               bitsp = mode_type_flag(mode_info[i].type, mode);
-               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
-               if ((*bitsp & mask) == mode_info[i].bits) {
-                       if (mode_info[i].flags & SANE_UNSET) {
-                               wrapf("%s", mode_info[i].name);
-                               empty_line = 0;
-                       }
-               }
-                       else if ((mode_info[i].flags & (SANE_SET | REV)) ==
-                                        (SANE_SET | REV)) {
-                       wrapf("-%s", mode_info[i].name);
-                       empty_line = 0;
-               }
-       }
-       if (empty_line == 0)
-               putchar('\n');
-       current_col = 0;
-}
-
-static void
-display_all(struct termios *mode, int fd, const char *device_name)
-{
-       int i;
-       tcflag_t *bitsp;
-       unsigned long mask;
-       enum mode_type prev_type = control;
-
-       display_speed(mode, 1);
-#ifdef TIOCGWINSZ
-       display_window_size(1, fd, device_name);
-#endif
-#ifdef HAVE_C_LINE
-       wrapf("line = %d;", mode->c_line);
-#endif
-       putchar('\n');
-       current_col = 0;
-
-       for (i = 0; control_info[i].name != stty_min; ++i) {
-               /* If swtch is the same as susp, don't print both.  */
-#if VSWTCH == VSUSP
-               if (control_info[i].name == stty_swtch)
-                       continue;
-#endif
-               /* If eof uses the same slot as min, only print whichever applies.  */
-#if VEOF == VMIN
-               if ((mode->c_lflag & ICANON) == 0
-                       && (control_info[i].name == stty_eof
-                               || control_info[i].name == stty_eol)) continue;
-#endif
-               wrapf("%s = %s;", control_info[i].name,
-                         visible(mode->c_cc[control_info[i].offset]));
-       }
-#if VEOF == VMIN
-       if ((mode->c_lflag & ICANON) == 0)
-#endif
-               wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
-       if (current_col != 0)
-               putchar('\n');
-       current_col = 0;
-
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & OMIT)
-                       continue;
-               if (mode_info[i].type != prev_type) {
-                       putchar('\n');
-                       current_col = 0;
-                       prev_type = mode_info[i].type;
-               }
-
-               bitsp = mode_type_flag(mode_info[i].type, mode);
-               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
-               if ((*bitsp & mask) == mode_info[i].bits)
-                       wrapf("%s", mode_info[i].name);
-               else if (mode_info[i].flags & REV)
-                       wrapf("-%s", mode_info[i].name);
-       }
-       putchar('\n');
-       current_col = 0;
-}
-
-static void display_speed(struct termios *mode, int fancy)
-{
-       if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
-               wrapf(fancy ? "speed %lu baud;" : "%lu\n",
-                         baud_to_value(cfgetospeed(mode)));
-       else
-               wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
-                         baud_to_value(cfgetispeed(mode)),
-                         baud_to_value(cfgetospeed(mode)));
-       if (!fancy)
-               current_col = 0;
-}
-
-static void display_recoverable(struct termios *mode)
-{
-       int i;
-
-       printf("%lx:%lx:%lx:%lx",
-                  (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
-                  (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
-       for (i = 0; i < NCCS; ++i)
-               printf(":%x", (unsigned int) mode->c_cc[i]);
-       putchar('\n');
-}
-
-static int recover_mode(char *arg, struct termios *mode)
-{
-       int i, n;
-       unsigned int chr;
-       unsigned long iflag, oflag, cflag, lflag;
-
-       /* Scan into temporaries since it is too much trouble to figure out
-          the right format for `tcflag_t'.  */
-       if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
-                          &iflag, &oflag, &cflag, &lflag, &n) != 4)
-               return 0;
-       mode->c_iflag = iflag;
-       mode->c_oflag = oflag;
-       mode->c_cflag = cflag;
-       mode->c_lflag = lflag;
-       arg += n;
-       for (i = 0; i < NCCS; ++i) {
-               if (sscanf(arg, ":%x%n", &chr, &n) != 1)
-                       return 0;
-               mode->c_cc[i] = chr;
-               arg += n;
-       }
-
-       /* Fail if there are too many fields.  */
-       if (*arg != '\0')
-               return 0;
-
-       return 1;
-}
-
-struct speed_map {
-       speed_t speed;                          /* Internal form. */
-       unsigned long value;            /* Numeric value. */
-};
-
-static const struct speed_map speeds[] = {
-       {B0, 0},
-       {B50, 50},
-       {B75, 75},
-       {B110, 110},
-       {B134, 134},
-       {B150, 150},
-       {B200, 200},
-       {B300, 300},
-       {B600, 600},
-       {B1200, 1200},
-       {B1800, 1800},
-       {B2400, 2400},
-       {B4800, 4800},
-       {B9600, 9600},
-       {B19200, 19200},
-       {B38400, 38400},
-#ifdef B57600
-       {B57600, 57600},
-#endif
-#ifdef B115200
-       {B115200, 115200},
-#endif
-#ifdef B230400
-       {B230400, 230400},
-#endif
-#ifdef B460800
-       {B460800, 460800},
-#endif
-};
-
-static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
-
-static speed_t string_to_baud(const char *arg)
-{
-       int i;
-
-       for (i = 0; i < NUM_SPEEDS; ++i)
-               if (parse_number(arg, 0) == speeds[i].value)
-                       return speeds[i].speed;
-       return (speed_t) - 1;
-}
-
-static unsigned long baud_to_value(speed_t speed)
-{
-       int i;
-
-       for (i = 0; i < NUM_SPEEDS; ++i)
-               if (speed == speeds[i].speed)
-                       return speeds[i].value;
-       return 0;
-}
-
-static void sane_mode(struct termios *mode)
-{
-       int i;
-       tcflag_t *bitsp;
-
-       for (i = 0; i < NUM_control_info; ++i) {
-#if VMIN == VEOF
-               if (control_info[i].name == stty_min)
-                       break;
-#endif
-               mode->c_cc[control_info[i].offset] = control_info[i].saneval;
-       }
-
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & SANE_SET) {
-                       bitsp = mode_type_flag(mode_info[i].type, mode);
-                       *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
-               } else if (mode_info[i].flags & SANE_UNSET) {
-                       bitsp = mode_type_flag(mode_info[i].type, mode);
-                       *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
-               }
-       }
-}
-
-/* Return a string that is the printable representation of character CH.  */
-/* Adapted from `cat' by Torbjorn Granlund.  */
-
-static const char *visible(unsigned int ch)
-{
-       static char buf[10];
-       char *bpout = buf;
-
-       if (ch == _POSIX_VDISABLE)
-               return "<undef>";
-
-       if (ch >= 32) {
-               if (ch < 127)
-                       *bpout++ = ch;
-               else if (ch == 127) {
-                       *bpout++ = '^';
-                       *bpout++ = '?';
-               } else {
-                       *bpout++ = 'M', *bpout++ = '-';
-                       if (ch >= 128 + 32) {
-                               if (ch < 128 + 127)
-                                       *bpout++ = ch - 128;
-                               else {
-                                       *bpout++ = '^';
-                                       *bpout++ = '?';
-                               }
-                       } else {
-                               *bpout++ = '^';
-                               *bpout++ = ch - 128 + 64;
-                       }
-               }
-       } else {
-               *bpout++ = '^';
-               *bpout++ = ch + 64;
-       }
-       *bpout = '\0';
-       return (const char *) buf;
-}
-
-#ifdef TEST
-
-const char *applet_name = "stty";
-
-#endif
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/sync.c b/busybox/coreutils/sync.c
deleted file mode 100644 (file)
index ee22ae1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sync implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int sync_main(int argc, char **argv)
-{
-       if (argc > 1 && **(argv + 1) == '-')
-               show_usage();
-       sync();
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/coreutils/tail.c b/busybox/coreutils/tail.c
deleted file mode 100644 (file)
index 90cc2a6..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tail implementation for busybox
- *
- *
- * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <fcntl.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-static const struct suffix_mult tail_suffixes[] = {
-       { "b", 512 },
-       { "k", 1024 },
-       { "m", 1048576 },
-       { NULL, 0 }
-};
-
-static const int BYTES = 0;
-static const int LINES = 1;
-
-static char *tailbuf;
-static int taillen;
-static int newline;
-
-static void tailbuf_append(char *buf, int len)
-{
-       tailbuf = xrealloc(tailbuf, taillen + len);
-       memcpy(tailbuf + taillen, buf, len);
-       taillen += len;
-}
-
-static void tailbuf_trunc()
-{
-       char *s;
-       s = memchr(tailbuf, '\n', taillen);
-       memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf));
-       taillen -= (s + 1) - tailbuf;
-       newline = 0;
-}
-
-int tail_main(int argc, char **argv)
-{
-       int from_top = 0, units = LINES, count = 10, sleep_period = 1;
-       int show_headers = 0, hide_headers = 0, follow = 0;
-       int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0;
-       char *s, *start, *end, buf[BUFSIZ];
-       int i, opt;
-
-       while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) {
-               switch (opt) {
-                       case 'f':
-                               follow = 1;
-                               break;
-#ifdef BB_FEATURE_FANCY_TAIL
-                       case 'c':
-                               units = BYTES;
-                               /* FALLS THROUGH */
-#endif
-                       case 'n':
-                               count = parse_number(optarg, tail_suffixes);
-                               if (count < 0)
-                                       count = -count;
-                               if (optarg[0] == '+')
-                                       from_top = 1;
-                               break;
-#ifdef BB_FEATURE_FANCY_TAIL
-                       case 'q':
-                               hide_headers = 1;
-                               break;
-                       case 's':
-                               sleep_period = parse_number(optarg, 0);
-                               break;
-                       case 'v':
-                               show_headers = 1;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* open all the files */
-       fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1));
-       if (argc == optind) {
-               fds[nfiles++] = STDIN_FILENO;
-               argv[optind] = "standard input";
-       } else {
-               for (i = optind; i < argc; i++) {
-                       if (strcmp(argv[i], "-") == 0) {
-                               fds[nfiles++] = STDIN_FILENO;
-                               argv[i] = "standard input";
-                       } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) {
-                               perror_msg("%s", argv[i]);
-                               status = EXIT_FAILURE;
-                       }
-               }
-       }
-       
-#ifdef BB_FEATURE_FANCY_TAIL
-       /* tail the files */
-       if (!from_top && units == BYTES)
-               tailbuf = xmalloc(count);
-#endif
-
-       for (i = 0; i < nfiles; i++) {
-               if (fds[i] == -1)
-                       continue;
-               if (!count) {
-                       lseek(fds[i], 0, SEEK_END);
-                       continue;
-               }
-               seen = 0;
-               if (show_headers || (!hide_headers && nfiles > 1))
-                       printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]);
-               while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
-                       if (from_top) {
-#ifdef BB_FEATURE_FANCY_TAIL
-                               if (units == BYTES) {
-                                       if (count - 1 <= seen)
-                                               nwrite = nread;
-                                       else if (count - 1 <= seen + nread)
-                                               nwrite = nread + seen - (count - 1);
-                                       else
-                                               nwrite = 0;
-                                       seen += nread;
-                               } else {
-#else
-                               {
-#endif
-                                       if (count - 1 <= seen)
-                                               nwrite = nread;
-                                       else {
-                                               nwrite = 0;
-                                               for (s = memchr(buf, '\n', nread); s != NULL;
-                                                               s = memchr(s+1, '\n', nread - (s + 1 - buf))) {
-                                                       if (count - 1 <= ++seen) {
-                                                               nwrite = nread - (s + 1 - buf);
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               }
-                               if (full_write(STDOUT_FILENO, buf + nread - nwrite,
-                                                       nwrite) < 0) {
-                                       perror_msg("write");
-                                       status = EXIT_FAILURE;
-                                       break;
-                               }
-                       } else {
-#ifdef BB_FEATURE_FANCY_TAIL
-                               if (units == BYTES) {
-                                       if (nread < count) {
-                                               memmove(tailbuf, tailbuf + nread, count - nread);
-                                               memcpy(tailbuf + count - nread, buf, nread);
-                                       } else {
-                                               memcpy(tailbuf, buf + nread - count, count);
-                                       }
-                                       seen += nread;
-                               } else {
-#else
-                               {
-#endif
-                                       for (start = buf, end = memchr(buf, '\n', nread);
-                                                       end != NULL; start = end+1,
-                                                       end = memchr(start, '\n', nread - (start - buf))) {
-                                               if (newline && count <= seen)
-                                                       tailbuf_trunc();
-                                               tailbuf_append(start, end - start + 1);
-                                               seen++;
-                                               newline = 1;
-                                       }
-                                       if (newline && count <= seen && nread - (start - buf) > 0)
-                                               tailbuf_trunc();
-                                       tailbuf_append(start, nread - (start - buf));
-                               }
-                       }
-               }
-
-               if (nread < 0) {
-                       perror_msg("read");
-                       status = EXIT_FAILURE;
-               }
-
-#ifdef BB_FEATURE_FANCY_TAIL
-               if (!from_top && units == BYTES) {
-                       if (count < seen)
-                               seen = count;
-                       if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) {
-                               perror_msg("write");
-                               status = EXIT_FAILURE;
-                       }
-               }
-#endif
-
-               if (!from_top && units == LINES) {
-                       if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) {
-                               perror_msg("write");
-                               status = EXIT_FAILURE;
-                       }
-               }
-
-               taillen = 0;
-       }
-
-       while (follow) {
-               sleep(sleep_period);
-
-               for (i = 0; i < nfiles; i++) {
-                       if (fds[i] == -1)
-                               continue;
-
-                       if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
-                               if (show_headers || (!hide_headers && nfiles > 1))
-                                       printf("\n==> %s <==\n", argv[optind + i]);
-
-                               do {
-                                       full_write(STDOUT_FILENO, buf, nread);
-                               } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0);
-                       }
-
-                       if (nread < 0) {
-                               perror_msg("read");
-                               status = EXIT_FAILURE;
-                       }
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/coreutils/tee.c b/busybox/coreutils/tee.c
deleted file mode 100644 (file)
index 439cf7d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tee implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <getopt.h>
-#include <stdio.h>
-
-int
-tee_main(int argc, char **argv)
-{
-       char *mode = "w";
-       int c, i, status = 0, nfiles = 0;
-       FILE **files;
-
-       while ((c = getopt(argc, argv, "a")) != EOF) {
-               switch (c) {
-               case 'a': 
-                       mode = "a";
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1));
-       files[nfiles++] = stdout;
-       while (optind < argc) {
-               if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) {
-                       nfiles--;
-                       perror_msg("%s", argv[optind-1]);
-                       status = 1;
-               }
-       }
-
-       while ((c = getchar()) != EOF)
-               for (i = 0; i < nfiles; i++)
-                       putc(c, files[i]);
-
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/coreutils/test.c b/busybox/coreutils/test.c
deleted file mode 100644 (file)
index 9c66cbb..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * test implementation for busybox
- *
- * Copyright (c) by a whole pile of folks: 
- *
- *     test(1); version 7-like  --  author Erik Baalbergen
- *     modified by Eric Gisin to be used as built-in.
- *     modified by Arnold Robbins to add SVR3 compatibility
- *     (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
- *     modified by J.T. Conklin for NetBSD.
- *     modified by Herbert Xu to be used as built-in in ash.
- *     modified by Erik Andersen <andersee@debian.org> to be used 
- *     in busybox.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice states:
- *     "This program is in the Public Domain."
- */
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-/* test(1) accepts the following grammar:
-       oexpr   ::= aexpr | aexpr "-o" oexpr ;
-       aexpr   ::= nexpr | nexpr "-a" aexpr ;
-       nexpr   ::= primary | "!" primary
-       primary ::= unary-operator operand
-               | operand binary-operator operand
-               | operand
-               | "(" oexpr ")"
-               ;
-       unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
-               "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
-
-       binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
-                       "-nt"|"-ot"|"-ef";
-       operand ::= <any legal UNIX file name>
-*/
-
-enum token {
-       EOI,
-       FILRD,
-       FILWR,
-       FILEX,
-       FILEXIST,
-       FILREG,
-       FILDIR,
-       FILCDEV,
-       FILBDEV,
-       FILFIFO,
-       FILSOCK,
-       FILSYM,
-       FILGZ,
-       FILTT,
-       FILSUID,
-       FILSGID,
-       FILSTCK,
-       FILNT,
-       FILOT,
-       FILEQ,
-       FILUID,
-       FILGID,
-       STREZ,
-       STRNZ,
-       STREQ,
-       STRNE,
-       STRLT,
-       STRGT,
-       INTEQ,
-       INTNE,
-       INTGE,
-       INTGT,
-       INTLE,
-       INTLT,
-       UNOT,
-       BAND,
-       BOR,
-       LPAREN,
-       RPAREN,
-       OPERAND
-};
-
-enum token_types {
-       UNOP,
-       BINOP,
-       BUNOP,
-       BBINOP,
-       PAREN
-};
-
-static const struct t_op {
-       const char *op_text;
-       short op_num, op_type;
-} ops [] = {
-       {"-r",  FILRD,  UNOP},
-       {"-w",  FILWR,  UNOP},
-       {"-x",  FILEX,  UNOP},
-       {"-e",  FILEXIST,UNOP},
-       {"-f",  FILREG, UNOP},
-       {"-d",  FILDIR, UNOP},
-       {"-c",  FILCDEV,UNOP},
-       {"-b",  FILBDEV,UNOP},
-       {"-p",  FILFIFO,UNOP},
-       {"-u",  FILSUID,UNOP},
-       {"-g",  FILSGID,UNOP},
-       {"-k",  FILSTCK,UNOP},
-       {"-s",  FILGZ,  UNOP},
-       {"-t",  FILTT,  UNOP},
-       {"-z",  STREZ,  UNOP},
-       {"-n",  STRNZ,  UNOP},
-       {"-h",  FILSYM, UNOP},          /* for backwards compat */
-       {"-O",  FILUID, UNOP},
-       {"-G",  FILGID, UNOP},
-       {"-L",  FILSYM, UNOP},
-       {"-S",  FILSOCK,UNOP},
-       {"=",   STREQ,  BINOP},
-       {"!=",  STRNE,  BINOP},
-       {"<",   STRLT,  BINOP},
-       {">",   STRGT,  BINOP},
-       {"-eq", INTEQ,  BINOP},
-       {"-ne", INTNE,  BINOP},
-       {"-ge", INTGE,  BINOP},
-       {"-gt", INTGT,  BINOP},
-       {"-le", INTLE,  BINOP},
-       {"-lt", INTLT,  BINOP},
-       {"-nt", FILNT,  BINOP},
-       {"-ot", FILOT,  BINOP},
-       {"-ef", FILEQ,  BINOP},
-       {"!",   UNOT,   BUNOP},
-       {"-a",  BAND,   BBINOP},
-       {"-o",  BOR,    BBINOP},
-       {"(",   LPAREN, PAREN},
-       {")",   RPAREN, PAREN},
-       {0,     0,      0}
-};
-
-static char **t_wp;
-static struct t_op const *t_wp_op;
-static gid_t *group_array = NULL;
-static int ngroups;
-
-static enum token t_lex();
-static int oexpr();
-static int aexpr();
-static int nexpr();
-static int binop();
-static int primary();
-static int filstat();
-static int getn();
-static int newerf();
-static int olderf();
-static int equalf();
-static void syntax();
-static int test_eaccess();
-static int is_a_group_member();
-static void initialize_group_array();
-
-extern int
-test_main(int argc, char** argv)
-{
-       int     res;
-
-       if (strcmp(applet_name, "[") == 0) {
-               if (strcmp(argv[--argc], "]"))
-                       error_msg_and_die("missing ]");
-               argv[argc] = NULL;
-       }
-       /* Implement special cases from POSIX.2, section 4.62.4 */
-       switch (argc) {
-       case 1:
-               exit( 1);
-       case 2:
-               exit (*argv[1] == '\0');
-       case 3:
-               if (argv[1][0] == '!' && argv[1][1] == '\0') {
-                       exit (!(*argv[2] == '\0'));
-               }
-               break;
-       case 4:
-               if (argv[1][0] != '!' || argv[1][1] != '\0') {
-                       if (t_lex(argv[2]), 
-                           t_wp_op && t_wp_op->op_type == BINOP) {
-                               t_wp = &argv[1];
-                               exit (binop() == 0);
-                       }
-               }
-               break;
-       case 5:
-               if (argv[1][0] == '!' && argv[1][1] == '\0') {
-                       if (t_lex(argv[3]), 
-                           t_wp_op && t_wp_op->op_type == BINOP) {
-                               t_wp = &argv[2];
-                               exit (!(binop() == 0));
-                       }
-               }
-               break;
-       }
-
-       t_wp = &argv[1];
-       res = !oexpr(t_lex(*t_wp));
-
-       if (*t_wp != NULL && *++t_wp != NULL)
-               syntax(*t_wp, "unknown operand");
-
-       return( res);
-}
-
-static void
-syntax(op, msg)
-       char    *op;
-       char    *msg;
-{
-       if (op && *op)
-               error_msg_and_die("%s: %s", op, msg);
-       else
-               error_msg_and_die("%s", msg);
-}
-
-static int
-oexpr(n)
-       enum token n;
-{
-       int res;
-
-       res = aexpr(n);
-       if (t_lex(*++t_wp) == BOR)
-               return oexpr(t_lex(*++t_wp)) || res;
-       t_wp--;
-       return res;
-}
-
-static int
-aexpr(n)
-       enum token n;
-{
-       int res;
-
-       res = nexpr(n);
-       if (t_lex(*++t_wp) == BAND)
-               return aexpr(t_lex(*++t_wp)) && res;
-       t_wp--;
-       return res;
-}
-
-static int
-nexpr(n)
-       enum token n;                   /* token */
-{
-       if (n == UNOT)
-               return !nexpr(t_lex(*++t_wp));
-       return primary(n);
-}
-
-static int
-primary(n)
-       enum token n;
-{
-       int res;
-
-       if (n == EOI)
-               syntax(NULL, "argument expected");
-       if (n == LPAREN) {
-               res = oexpr(t_lex(*++t_wp));
-               if (t_lex(*++t_wp) != RPAREN)
-                       syntax(NULL, "closing paren expected");
-               return res;
-       }
-       if (t_wp_op && t_wp_op->op_type == UNOP) {
-               /* unary expression */
-               if (*++t_wp == NULL)
-                       syntax(t_wp_op->op_text, "argument expected");
-               switch (n) {
-               case STREZ:
-                       return strlen(*t_wp) == 0;
-               case STRNZ:
-                       return strlen(*t_wp) != 0;
-               case FILTT:
-                       return isatty(getn(*t_wp));
-               default:
-                       return filstat(*t_wp, n);
-               }
-       }
-
-       if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
-               return binop();
-       }         
-
-       return strlen(*t_wp) > 0;
-}
-
-static int
-binop()
-{
-       const char *opnd1, *opnd2;
-       struct t_op const *op;
-
-       opnd1 = *t_wp;
-       (void) t_lex(*++t_wp);
-       op = t_wp_op;
-
-       if ((opnd2 = *++t_wp) == (char *)0)
-               syntax(op->op_text, "argument expected");
-               
-       switch (op->op_num) {
-       case STREQ:
-               return strcmp(opnd1, opnd2) == 0;
-       case STRNE:
-               return strcmp(opnd1, opnd2) != 0;
-       case STRLT:
-               return strcmp(opnd1, opnd2) < 0;
-       case STRGT:
-               return strcmp(opnd1, opnd2) > 0;
-       case INTEQ:
-               return getn(opnd1) == getn(opnd2);
-       case INTNE:
-               return getn(opnd1) != getn(opnd2);
-       case INTGE:
-               return getn(opnd1) >= getn(opnd2);
-       case INTGT:
-               return getn(opnd1) > getn(opnd2);
-       case INTLE:
-               return getn(opnd1) <= getn(opnd2);
-       case INTLT:
-               return getn(opnd1) < getn(opnd2);
-       case FILNT:
-               return newerf (opnd1, opnd2);
-       case FILOT:
-               return olderf (opnd1, opnd2);
-       case FILEQ:
-               return equalf (opnd1, opnd2);
-       }
-       /* NOTREACHED */
-       return 1;
-}
-
-static int
-filstat(nm, mode)
-       char *nm;
-       enum token mode;
-{
-       struct stat s;
-       unsigned int i;
-
-       if (mode == FILSYM) {
-#ifdef S_IFLNK
-               if (lstat(nm, &s) == 0) {
-                       i = S_IFLNK;
-                       goto filetype;
-               }
-#endif
-               return 0;
-       }
-
-       if (stat(nm, &s) != 0) 
-               return 0;
-
-       switch (mode) {
-       case FILRD:
-               return test_eaccess(nm, R_OK) == 0;
-       case FILWR:
-               return test_eaccess(nm, W_OK) == 0;
-       case FILEX:
-               return test_eaccess(nm, X_OK) == 0;
-       case FILEXIST:
-               return 1;
-       case FILREG:
-               i = S_IFREG;
-               goto filetype;
-       case FILDIR:
-               i = S_IFDIR;
-               goto filetype;
-       case FILCDEV:
-               i = S_IFCHR;
-               goto filetype;
-       case FILBDEV:
-               i = S_IFBLK;
-               goto filetype;
-       case FILFIFO:
-#ifdef S_IFIFO
-               i = S_IFIFO;
-               goto filetype;
-#else
-               return 0;
-#endif
-       case FILSOCK:
-#ifdef S_IFSOCK
-               i = S_IFSOCK;
-               goto filetype;
-#else
-               return 0;
-#endif
-       case FILSUID:
-               i = S_ISUID;
-               goto filebit;
-       case FILSGID:
-               i = S_ISGID;
-               goto filebit;
-       case FILSTCK:
-               i = S_ISVTX;
-               goto filebit;
-       case FILGZ:
-               return s.st_size > 0L;
-       case FILUID:
-               return s.st_uid == geteuid();
-       case FILGID:
-               return s.st_gid == getegid();
-       default:
-               return 1;
-       }
-
-filetype:
-       return ((s.st_mode & S_IFMT) == i);
-
-filebit:
-       return ((s.st_mode & i) != 0);
-}
-
-static enum token
-t_lex(s)
-       char *s;
-{
-       struct t_op const *op = ops;
-
-       if (s == 0) {
-               t_wp_op = (struct t_op *)0;
-               return EOI;
-       }
-       while (op->op_text) {
-               if (strcmp(s, op->op_text) == 0) {
-                       t_wp_op = op;
-                       return op->op_num;
-               }
-               op++;
-       }
-       t_wp_op = (struct t_op *)0;
-       return OPERAND;
-}
-
-/* atoi with error detection */
-static int
-getn(s)
-       char *s;
-{
-       char *p;
-       long r;
-
-       errno = 0;
-       r = strtol(s, &p, 10);
-
-       if (errno != 0)
-         error_msg_and_die("%s: out of range", s);
-
-       while (isspace(*p))
-         p++;
-       
-       if (*p)
-         error_msg_and_die("%s: bad number", s);
-
-       return (int) r;
-}
-
-static int
-newerf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_mtime > b2.st_mtime);
-}
-
-static int
-olderf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_mtime < b2.st_mtime);
-}
-
-static int
-equalf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_dev == b2.st_dev &&
-               b1.st_ino == b2.st_ino);
-}
-
-/* Do the same thing access(2) does, but use the effective uid and gid,
-   and don't make the mistake of telling root that any file is
-   executable. */
-static int
-test_eaccess (path, mode)
-char *path;
-int mode;
-{
-       struct stat st;
-       unsigned int euid = geteuid();
-
-       if (stat (path, &st) < 0)
-               return (-1);
-
-       if (euid == 0) {
-               /* Root can read or write any file. */
-               if (mode != X_OK)
-               return (0);
-
-               /* Root can execute any file that has any one of the execute
-                  bits set. */
-               if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
-                       return (0);
-       }
-
-       if (st.st_uid == euid)          /* owner */
-               mode <<= 6;
-       else if (is_a_group_member (st.st_gid))
-               mode <<= 3;
-
-       if (st.st_mode & mode)
-               return (0);
-
-       return (-1);
-}
-
-static void
-initialize_group_array ()
-{
-       ngroups = getgroups(0, NULL);
-       group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
-       getgroups(ngroups, group_array);
-}
-
-/* Return non-zero if GID is one that we have in our groups list. */
-static int
-is_a_group_member (gid)
-gid_t gid;
-{
-       register int i;
-
-       /* Short-circuit if possible, maybe saving a call to getgroups(). */
-       if (gid == getgid() || gid == getegid())
-               return (1);
-
-       if (ngroups == 0)
-               initialize_group_array ();
-
-       /* Search through the list looking for GID. */
-       for (i = 0; i < ngroups; i++)
-               if (gid == group_array[i])
-                       return (1);
-
-       return (0);
-}
diff --git a/busybox/coreutils/touch.c b/busybox/coreutils/touch.c
deleted file mode 100644 (file)
index 1718da7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini touch implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int touch_main(int argc, char **argv)
-{
-       int fd;
-       int create = TRUE;
-
-       /* Parse options */
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 'c':
-                               create = FALSE;
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-
-       if (argc < 1) {
-               show_usage();
-       }
-
-       while (argc > 0) {
-               fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT,
-                               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-               if (fd < 0) {
-                       if (create == FALSE && errno == ENOENT)
-                               return EXIT_SUCCESS;
-                       else {
-                               perror_msg_and_die("%s", *argv);
-                       }
-               }
-               close(fd);
-               if (utime(*argv, NULL)) {
-                       perror_msg_and_die("%s", *argv);
-               }
-               argc--;
-               argv++;
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/tr.c b/busybox/coreutils/tr.c
deleted file mode 100644 (file)
index 5b7b8d0..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tr implementation for busybox
- *
- * Copyright (c) Michiel Huisjes
- *
- * This version of tr is adapted from Minix tr and was modified 
- * by Erik Andersen <andersee@debian.org> to be used in busybox.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
- * enabled, we otherwise get a "storage size isn't constant error. */
-#define ASCII 0377
-
-/* some "globals" shared across this file */
-static char com_fl, del_fl, sq_fl;
-static short in_index, out_index;
-/* these last are pointers to static buffers declared in tr_main */
-static unsigned char *poutput, *pinput;
-static unsigned char *pvector;
-static char *pinvec, *poutvec;
-
-
-static void convert()
-{
-       short read_chars = 0;
-       short c, coded;
-       short last = -1;
-
-       for (;;) {
-               if (in_index == read_chars) {
-                       if ((read_chars = read(0, (char *) pinput, BUFSIZ)) <= 0) {
-                               if (write(1, (char *) poutput, out_index) != out_index)
-                                       error_msg("%s", write_error);
-                               exit(0);
-                       }
-                       in_index = 0;
-               }
-               c = pinput[in_index++];
-               coded = pvector[c];
-               if (del_fl && pinvec[c])
-                       continue;
-               if (sq_fl && last == coded && (pinvec[c] || poutvec[coded]))
-                       continue;
-               poutput[out_index++] = last = coded;
-               if (out_index == BUFSIZ) {
-                       if (write(1, (char *) poutput, out_index) != out_index)
-                               error_msg_and_die("%s", write_error);
-                       out_index = 0;
-               }
-       }
-
-       /* NOTREACHED */
-}
-
-static void map(register unsigned char *string1, unsigned int string1_len,
-               register unsigned char *string2, unsigned int string2_len)
-{
-       unsigned char last = '0';
-       unsigned int i, j;
-
-       for (j = 0, i = 0; i < string1_len; i++) {
-               if (string2_len <= j)
-                       pvector[string1[i]] = last;
-               else
-                       pvector[string1[i]] = last = string2[j++];
-       }
-}
-
-/* supported constructs:
- *   Ranges,  e.g.,  [0-9]  ==>  0123456789
- *   Escapes, e.g.,  \a     ==>  Control-G
- */
-static unsigned int expand(const char *arg, register unsigned char *buffer)
-{
-       unsigned char *buffer_start = buffer;
-       int i, ac;
-
-       while (*arg) {
-               if (*arg == '\\') {
-                       arg++;
-                       *buffer++ = process_escape_sequence(&arg);
-               } else if (*(arg+1) == '-') {
-                       ac = *(arg+2);
-                       if(ac == 0) {
-                               *buffer++ = *arg++;
-                               continue;
-                       }
-                       i = *arg;
-                       while (i <= ac)
-                               *buffer++ = i++;
-                       arg += 3; /* Skip the assumed a-z */
-               } else if (*arg == '[') {
-                       arg++;
-                       i = *arg++;
-                       if (*arg++ != '-') {
-                               *buffer++ = '[';
-                               arg -= 2;
-                               continue;
-                       }
-                       ac = *arg++;
-                       while (i <= ac)
-                               *buffer++ = i++;
-                       arg++;                          /* Skip the assumed ']' */
-               } else
-                       *buffer++ = *arg++;
-       }
-
-       return (buffer - buffer_start);
-}
-
-static int complement(unsigned char *buffer, int buffer_len)
-{
-       register short i, j, ix;
-       char conv[ASCII + 2];
-
-       ix = 0;
-       for (i = 0; i <= ASCII; i++) {
-               for (j = 0; j < buffer_len; j++)
-                       if (buffer[j] == i)
-                               break;
-               if (j == buffer_len)
-                       conv[ix++] = i & ASCII;
-       }
-       memcpy(buffer, conv, ix);
-       return ix;
-}
-
-extern int tr_main(int argc, char **argv)
-{
-       register unsigned char *ptr;
-       int output_length=0, input_length;
-       int idx = 1;
-       int i;
-       RESERVE_BB_BUFFER(output, BUFSIZ);
-       RESERVE_BB_BUFFER(input,  BUFSIZ);
-       RESERVE_BB_UBUFFER(vector, ASCII+1);
-       RESERVE_BB_BUFFER(invec,  ASCII+1);
-       RESERVE_BB_BUFFER(outvec, ASCII+1);
-
-       /* ... but make them available globally */
-       poutput = output;
-       pinput  = input;
-       pvector = vector;
-       pinvec  = invec;
-       poutvec = outvec;
-
-       if (argc > 1 && argv[idx][0] == '-') {
-               for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
-                       switch (*ptr) {
-                       case 'c':
-                               com_fl = TRUE;
-                               break;
-                       case 'd':
-                               del_fl = TRUE;
-                               break;
-                       case 's':
-                               sq_fl = TRUE;
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-               idx++;
-       }
-       for (i = 0; i <= ASCII; i++) {
-               vector[i] = i;
-               invec[i] = outvec[i] = FALSE;
-       }
-
-       if (argv[idx] != NULL) {
-               input_length = expand(argv[idx++], input);
-               if (com_fl)
-                       input_length = complement(input, input_length);
-               if (argv[idx] != NULL) {
-                       if (*argv[idx] == '\0')
-                               error_msg_and_die("STRING2 cannot be empty");
-                       output_length = expand(argv[idx], output);
-                       map(input, input_length, output, output_length);
-               }
-               for (i = 0; i < input_length; i++)
-                       invec[(int)input[i]] = TRUE;
-               for (i = 0; i < output_length; i++)
-                       outvec[(int)output[i]] = TRUE;
-       }
-       convert();
-       return (0);
-}
-
-/*
- * Copyright (c) 1987,1997, Prentice Hall
- * All rights reserved.
- * 
- * Redistribution and use of the MINIX operating system in source and
- * binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- * 
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * 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.
- * 
- * Neither the name of Prentice Hall nor the names of the software
- * authors or contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
diff --git a/busybox/coreutils/tty.c b/busybox/coreutils/tty.c
deleted file mode 100644 (file)
index 4510c29..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tty implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-extern int tty_main(int argc, char **argv)
-{
-       char *tty;
-
-       if (argc > 1) {
-               if (argv[1][0] != '-' || argv[1][1] != 's')
-                       show_usage();
-       } else {
-               tty = ttyname(0);
-               if (tty)
-                       puts(tty);
-               else
-                       puts("not a tty");
-       }
-       return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/busybox/coreutils/uname.c b/busybox/coreutils/uname.c
deleted file mode 100644 (file)
index f7e2291..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* uname -- print system information
-   Copyright (C) 1989-1999 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Option              Example
-
-   -s, --sysname       SunOS
-   -n, --nodename      rocky8
-   -r, --release       4.0
-   -v, --version
-   -m, --machine       sun
-   -a, --all           SunOS rocky8 4.0  sun
-
-   The default behavior is equivalent to `-s'.
-
-   David MacKenzie <djm@gnu.ai.mit.edu> */
-
-/* Busyboxed by Erik Andersen */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-
-#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H)
-# include <sys/systeminfo.h>
-#endif
-#include "busybox.h"
-
-static void print_element(unsigned int mask, char *element);
-
-/* Values that are bitwise or'd into `toprint'. */
-/* Operating system name. */
-static const int PRINT_SYSNAME = 1;
-
-/* Node name on a communications network. */
-static const int PRINT_NODENAME = 2;
-
-/* Operating system release. */
-static const int PRINT_RELEASE = 4;
-
-/* Operating system version. */
-static const int PRINT_VERSION = 8;
-
-/* Machine hardware name. */
-static const int PRINT_MACHINE = 16;
-
- /* Host processor type. */
-static const int PRINT_PROCESSOR = 32;
-
-/* Mask indicating which elements of the name to print. */
-static unsigned char toprint;
-
-
-int uname_main(int argc, char **argv)
-{
-       struct utsname name;
-       char processor[256];
-
-#if defined(__sparc__) && defined(__linux__)
-       char *fake_sparc = getenv("FAKE_SPARC");
-#endif
-
-       toprint = 0;
-
-       /* Parse any options */
-       //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 's':
-                               toprint |= PRINT_SYSNAME;
-                               break;
-                       case 'n':
-                               toprint |= PRINT_NODENAME;
-                               break;
-                       case 'r':
-                               toprint |= PRINT_RELEASE;
-                               break;
-                       case 'v':
-                               toprint |= PRINT_VERSION;
-                               break;
-                       case 'm':
-                               toprint |= PRINT_MACHINE;
-                               break;
-                       case 'p':
-                               toprint |= PRINT_PROCESSOR;
-                               break;
-                       case 'a':
-                               toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
-                                                  PRINT_PROCESSOR | PRINT_VERSION |
-                                                  PRINT_MACHINE);
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-
-       if (toprint == 0)
-               toprint = PRINT_SYSNAME;
-
-       if (uname(&name) == -1)
-               perror_msg("cannot get system name");
-
-#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE)
-       if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1)
-               perror_msg("cannot get processor type");
-}
-
-#else
-       strcpy(processor, "unknown");
-#endif
-
-#if defined(__sparc__) && defined(__linux__)
-       if (fake_sparc != NULL
-               && (fake_sparc[0] == 'y'
-                       || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc");
-#endif
-
-       print_element(PRINT_SYSNAME, name.sysname);
-       print_element(PRINT_NODENAME, name.nodename);
-       print_element(PRINT_RELEASE, name.release);
-       print_element(PRINT_VERSION, name.version);
-       print_element(PRINT_MACHINE, name.machine);
-       print_element(PRINT_PROCESSOR, processor);
-
-       return EXIT_SUCCESS;
-}
-
-/* If the name element set in MASK is selected for printing in `toprint',
-   print ELEMENT; then print a space unless it is the last element to
-   be printed, in which case print a newline. */
-
-static void print_element(unsigned int mask, char *element)
-{
-       if (toprint & mask) {
-               toprint &= ~mask;
-               printf("%s%c", element, toprint ? ' ' : '\n');
-       }
-}
diff --git a/busybox/coreutils/uniq.c b/busybox/coreutils/uniq.c
deleted file mode 100644 (file)
index 53e3c64..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini uniq implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int print_count;
-static int print_uniq = 1;
-static int print_duplicates = 1;
-
-static void print_line(char *line, int count, FILE *fp)
-{
-       if ((print_duplicates && count > 1) || (print_uniq && count == 1)) {
-               if (print_count)
-                       fprintf(fp, "%7d\t%s", count, line);
-               else
-                       fputs(line, fp);
-       }
-}
-
-int uniq_main(int argc, char **argv)
-{
-       FILE *in = stdin, *out = stdout;
-       char *lastline = NULL, *input;
-       int opt, count = 0;
-
-       /* parse argv[] */
-       while ((opt = getopt(argc, argv, "cdu")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               print_count = 1;
-                               break;
-                       case 'd':
-                               print_duplicates = 1;
-                               print_uniq = 0;
-                               break;
-                       case 'u':
-                               print_duplicates = 0;
-                               print_uniq = 1;
-                               break;
-               }
-       }
-
-       if (argv[optind] != NULL) {
-               in = xfopen(argv[optind], "r");
-               if (argv[optind+1] != NULL)
-                       out = xfopen(argv[optind+1], "w");
-       }
-
-       while ((input = get_line_from_file(in)) != NULL) {
-               if (lastline == NULL || strcmp(input, lastline) != 0) {
-                       print_line(lastline, count, out);
-                       free(lastline);
-                       lastline = input;
-                       count = 0;
-               }
-               count++;
-       }
-       print_line(lastline, count, out);
-       free(lastline);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/usleep.c b/busybox/coreutils/usleep.c
deleted file mode 100644 (file)
index 6023bf4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini usleep implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int usleep_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       usleep(atoi(*(++argv)));        /* return void */
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/coreutils/uudecode.c b/busybox/coreutils/uudecode.c
deleted file mode 100644 (file)
index a4059dd..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/* uudecode.c -- uudecode utility.
- * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
- *
- * This product is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This product is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this product; see the file COPYING.  If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-
-
-#include <stdio.h>
-#include <errno.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-#include "pwd_grp/pwd.h"
-#include "pwd_grp/grp.h"
-
-/*struct passwd *getpwnam();*/
-
-/* Single character decode.  */
-#define        DEC(Char) (((Char) - ' ') & 077)
-
-static int read_stduu (const char *inname)
-{
-  char buf[2 * BUFSIZ];
-
-  while (1) {
-    int n;
-    char *p;
-
-    if (fgets (buf, sizeof(buf), stdin) == NULL) {
-      error_msg("%s: Short file", inname);
-      return FALSE;
-    }
-    p = buf;
-
-    /* N is used to avoid writing out all the characters at the end of
-       the file.  */
-    n = DEC (*p);
-    if (n <= 0)
-      break;
-    for (++p; n > 0; p += 4, n -= 3) {
-      char ch;
-
-      if (n >= 3) {
-        ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
-        putchar (ch);
-        ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
-        putchar (ch);
-        ch = DEC (p[2]) << 6 | DEC (p[3]);
-        putchar (ch);
-      } else {
-        if (n >= 1) {
-          ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
-          putchar (ch);
-        }
-        if (n >= 2) {
-          ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
-          putchar (ch);
-        }
-      }
-    }
-  }
-
-  if (fgets (buf, sizeof(buf), stdin) == NULL
-      || strcmp (buf, "end\n")) {
-    error_msg("%s: No `end' line", inname);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static int read_base64 (const char *inname)
-{
-  static const char b64_tab[256] = {
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
-    '\177', '\177', '\177', '\76',  '\177', '\177', '\177', '\77',  /*050-057*/
-    '\64',  '\65',  '\66',  '\67',  '\70',  '\71',  '\72',  '\73',  /*060-067*/
-    '\74',  '\75',  '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
-    '\177', '\0',   '\1',   '\2',   '\3',   '\4',   '\5',   '\6',   /*100-107*/
-    '\7',   '\10',  '\11',  '\12',  '\13',  '\14',  '\15',  '\16',  /*110-117*/
-    '\17',  '\20',  '\21',  '\22',  '\23',  '\24',  '\25',  '\26',  /*120-127*/
-    '\27',  '\30',  '\31',  '\177', '\177', '\177', '\177', '\177', /*130-137*/
-    '\177', '\32',  '\33',  '\34',  '\35',  '\36',  '\37',  '\40',  /*140-147*/
-    '\41',  '\42',  '\43',  '\44',  '\45',  '\46',  '\47',  '\50',  /*150-157*/
-    '\51',  '\52',  '\53',  '\54',  '\55',  '\56',  '\57',  '\60',  /*160-167*/
-    '\61',  '\62',  '\63',  '\177', '\177', '\177', '\177', '\177', /*170-177*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
-  };
-  unsigned char buf[2 * BUFSIZ];
-
-  while (1) {
-    int last_data = 0;
-    unsigned char *p;
-
-    if (fgets (buf, sizeof(buf), stdin) == NULL) {
-      error_msg("%s: Short file", inname);
-      return FALSE;
-    }
-    p = buf;
-
-    if (memcmp (buf, "====", 4) == 0)
-      break;
-    if (last_data != 0) {
-      error_msg("%s: data following `=' padding character", inname);
-      return FALSE;
-    }
-
-    /* The following implementation of the base64 decoding might look
-       a bit clumsy but I only try to follow the POSIX standard:
-       ``All line breaks or other characters not found in the table
-       [with base64 characters] shall be ignored by decoding
-       software.''  */
-    while (*p != '\n') {
-      char c1, c2, c3;
-
-      while ((b64_tab[*p] & '\100') != 0)
-        if (*p == '\n' || *p++ == '=')
-          break;
-      if (*p == '\n')
-        /* This leaves the loop.  */
-        continue;
-      c1 = b64_tab[*p++];
-
-      while ((b64_tab[*p] & '\100') != 0)
-        if (*p == '\n' || *p++ == '=') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      c2 = b64_tab[*p++];
-
-      while (b64_tab[*p] == '\177')
-        if (*p++ == '\n') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      if (*p == '=') {
-        putchar (c1 << 2 | c2 >> 4);
-        last_data = 1;
-        break;
-      }
-      c3 = b64_tab[*p++];
-
-      while (b64_tab[*p] == '\177')
-        if (*p++ == '\n') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      putchar (c1 << 2 | c2 >> 4);
-      putchar (c2 << 4 | c3 >> 2);
-      if (*p == '=') {
-        last_data = 1;
-        break;
-      }
-      else
-        putchar (c3 << 6 | b64_tab[*p++]);
-    }
-  }
-
-  return TRUE;
-}
-
-static int decode (const char *inname,
-                   const char *forced_outname)
-{
-  struct passwd *pw;
-  register char *p;
-  int mode;
-  char buf[2 * BUFSIZ];
-  char *outname;
-  int do_base64 = 0;
-  int res;
-  int dofre;
-
-  /* Search for header line.  */
-
-  while (1) {
-    if (fgets (buf, sizeof (buf), stdin) == NULL) {
-      error_msg("%s: No `begin' line", inname);
-      return FALSE;
-    }
-
-    if (strncmp (buf, "begin", 5) == 0) {
-      if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
-        do_base64 = 1;
-        break;
-      } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
-        break;
-    }
-  }
-
-  /* If the output file name is given on the command line this rules.  */
-  dofre = FALSE;
-  if (forced_outname != NULL)
-    outname = (char *) forced_outname;
-  else {
-    /* Handle ~user/file format.  */
-    if (buf[0] != '~')
-      outname = buf;
-    else {
-      p = buf + 1;
-      while (*p != '/')
-        ++p;
-      if (*p == '\0') {
-        error_msg("%s: Illegal ~user", inname);
-        return FALSE;
-      }
-      *p++ = '\0';
-      pw = getpwnam (buf + 1);
-      if (pw == NULL) {
-        error_msg("%s: No user `%s'", inname, buf + 1);
-        return FALSE;
-      }
-      outname = concat_path_file(pw->pw_dir, p);
-      dofre = TRUE;
-    }
-  }
-
-  /* Create output file and set mode.  */
-  if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
-      && (freopen (outname, "w", stdout) == NULL
-         || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
-         )) {
-    perror_msg("%s", outname); /* */
-    if (dofre)
-       free(outname);
-    return FALSE;
-  }
-
-  /* We differenciate decoding standard UU encoding and base64.  A
-     common function would only slow down the program.  */
-
-  /* For each input line:  */
-  if (do_base64)
-      res = read_base64 (inname);
-  else
-       res = read_stduu (inname);
-  if (dofre)
-      free(outname);
-  return res;
-}
-
-int uudecode_main (int argc,
-                   char **argv)
-{
-  int opt;
-  int exit_status;
-  const char *outname;
-  outname = NULL;
-
-  while ((opt = getopt(argc, argv, "o:")) != EOF) {
-    switch (opt) {
-     case 0:
-      break;
-
-     case 'o':
-      outname = optarg;
-      break;
-
-     default:
-      show_usage();
-    }
-  }
-
-  if (optind == argc)
-    exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-  else {
-    exit_status = EXIT_SUCCESS;
-    do {
-      if (freopen (argv[optind], "r", stdin) != NULL) {
-        if (decode (argv[optind], outname) != 0)
-          exit_status = FALSE;
-      } else {
-        perror_msg("%s", argv[optind]);
-        exit_status = EXIT_FAILURE;
-      }
-      optind++;
-    }
-    while (optind < argc);
-  }
-  return(exit_status);
-}
-
-/* Copyright (c) 1983 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
diff --git a/busybox/coreutils/uuencode.c b/busybox/coreutils/uuencode.c
deleted file mode 100644 (file)
index fc03740..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- *  Copyright (C) 2000 by Glenn McGrath
- *
- *  based on the function base64_encode from http.c in wget v1.6
- *  Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Conversion table.  for base 64 */
-static char tbl_base64[64] = {
-       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-       'w', 'x', 'y', 'z', '0', '1', '2', '3',
-       '4', '5', '6', '7', '8', '9', '+', '/'
-};
-
-static char tbl_std[64] = {
-       '`', '!', '"', '#', '$', '%', '&', '\'',
-       '(', ')', '*', '+', ',', '-', '.', '/',
-       '0', '1', '2', '3', '4', '5', '6', '7',
-       '8', '9', ':', ';', '<', '=', '>', '?',
-       '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
-       'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-       'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-       'X', 'Y', 'Z', '[', '\\', ']', '^', '_'
-};
-
-/*
- * Encode the string S of length LENGTH to base64 format and place it
- * to STORE.  STORE will be 0-terminated, and must point to a writable
- * buffer of at least 1+BASE64_LENGTH(length) bytes.
- * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
- */
-static void uuencode (const char *s, const char *store, const int length, const char *tbl)
-{
-       int i;
-       unsigned char *p = (unsigned char *)store;
-
-       /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
-       for (i = 0; i < length; i += 3) {
-               *p++ = tbl[s[0] >> 2];
-               *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
-               *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
-               *p++ = tbl[s[2] & 0x3f];
-               s += 3;
-       }
-       /* Pad the result if necessary...  */
-       if (i == length + 1) {
-               *(p - 1) = '=';
-       }
-       else if (i == length + 2) {
-               *(p - 1) = *(p - 2) = '=';
-       }
-       /* ...and zero-terminate it.  */
-       *p = '\0';
-}
-
-int uuencode_main(int argc, char **argv)
-{
-       const int src_buf_size = 60;    // This *MUST* be a multiple of 3
-       const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
-       RESERVE_BB_BUFFER(src_buf, src_buf_size + 1);
-       RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1);
-       struct stat stat_buf;
-       FILE *src_stream = stdin;
-       char *tbl = tbl_std;
-       size_t size;
-       mode_t mode;
-       int opt;
-       int column = 0;
-       int write_size = 0;
-       int remaining;
-       int buffer_offset = 0;
-
-       while ((opt = getopt(argc, argv, "m")) != -1) {
-               switch (opt) {
-               case 'm':
-                       tbl = tbl_base64;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       switch (argc - optind) {
-               case 2:
-                       src_stream = xfopen(argv[optind], "r");
-                       stat(argv[optind], &stat_buf);
-                       mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
-                       if (src_stream == stdout) {
-                               printf("NULL\n");
-                       }
-                       break;
-               case 1:
-                       mode = 0666 & ~umask(0666);
-                       break;
-               default:
-                       show_usage();
-       }
-
-       printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
-
-       while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
-               /* Encode the buffer we just read in */
-               uuencode(src_buf, dst_buf, size, tbl);
-
-               /* Write the buffer to stdout, wrapping at 60 chars.
-                * This looks overly complex, but it gets tricky as
-                * the line has to continue to wrap correctly if we
-                * have to refill the buffer
-                *
-                * Improvments most welcome
-                */
-
-               /* Initialise values for the new buffer */
-               remaining = 4 * ((size + 2) / 3);
-               buffer_offset = 0;
-
-               /* Write the buffer to stdout, wrapping at 60 chars
-                * starting from the column the last buffer ran out
-                */
-               do {
-                       if (remaining > (60 - column)) {
-                               write_size = 60 - column;
-                       }
-                       else if (remaining < 60) {
-                               write_size = remaining;
-                       } else {
-                               write_size = 60;
-                       }
-
-                       /* Setup a new row if required */
-                       if (column == 0) {
-                               putchar('\n');
-                               if (tbl == tbl_std) {
-                                       putchar('M');
-                               }
-                       }
-                       /* Write to the 60th column */
-                       if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) {
-                               perror("Couldnt finish writing");
-                       }
-                       /* Update variables based on last write */
-                       buffer_offset += write_size;
-                       remaining -= write_size;
-                       column += write_size;
-                       if (column % 60 == 0) {
-                               column = 0;
-                       }
-               } while (remaining > 0);
-       }
-       printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/coreutils/wc.c b/busybox/coreutils/wc.c
deleted file mode 100644 (file)
index 695e7e7..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini wc implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int total_lines, total_words, total_chars, max_length;
-static int print_lines, print_words, print_chars, print_length;
-
-static void print_counts(int lines, int words, int chars, int length,
-                                                const char *name)
-{
-       char const *space = "";
-
-       if (print_lines) {
-               printf("%7d", lines);
-               space = " ";
-       }
-       if (print_words) {
-               printf("%s%7d", space, words);
-               space = " ";
-       }
-       if (print_chars) {
-               printf("%s%7d", space, chars);
-               space = " ";
-       }
-       if (print_length)
-               printf("%s%7d", space, length);
-       if (*name)
-               printf(" %s", name);
-       putchar('\n');
-}
-
-static void wc_file(FILE * file, const char *name)
-{
-       int lines, words, chars, length;
-       int in_word = 0, linepos = 0;
-       int c;
-
-       lines = words = chars = length = 0;
-       while ((c = getc(file)) != EOF) {
-               chars++;
-               switch (c) {
-               case '\n':
-                       lines++;
-               case '\r':
-               case '\f':
-                       if (linepos > length)
-                               length = linepos;
-                       linepos = 0;
-                       goto word_separator;
-               case '\t':
-                       linepos += 8 - (linepos % 8);
-                       goto word_separator;
-               case ' ':
-                       linepos++;
-               case '\v':
-                 word_separator:
-                       if (in_word) {
-                               in_word = 0;
-                               words++;
-                       }
-                       break;
-               default:
-                       linepos++;
-                       in_word = 1;
-                       break;
-               }
-       }
-       if (linepos > length)
-               length = linepos;
-       if (in_word)
-               words++;
-       print_counts(lines, words, chars, length, name);
-       total_lines += lines;
-       total_words += words;
-       total_chars += chars;
-       if (length > max_length)
-               max_length = length;
-       fclose(file);
-       fflush(stdout);
-}
-
-int wc_main(int argc, char **argv)
-{
-       FILE *file;
-       unsigned int num_files_counted = 0;
-       int opt, status = EXIT_SUCCESS;
-
-       total_lines = total_words = total_chars = max_length = 0;
-       print_lines = print_words = print_chars = print_length = 0;
-
-       while ((opt = getopt(argc, argv, "clLw")) > 0) {
-                       switch (opt) {
-                       case 'c':
-                               print_chars = 1;
-                               break;
-                       case 'l':
-                               print_lines = 1;
-                               break;
-                       case 'L':
-                               print_length = 1;
-                               break;
-                       case 'w':
-                               print_words = 1;
-                               break;
-                       default:
-                               show_usage();
-                       }
-       }
-
-       if (!print_lines && !print_words && !print_chars && !print_length)
-               print_lines = print_words = print_chars = 1;
-
-       if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
-               wc_file(stdin, "");
-               return EXIT_SUCCESS;
-       } else {
-               while (optind < argc) {
-                       if ((file = wfopen(argv[optind], "r")) != NULL)
-                               wc_file(file, argv[optind]);
-                       else
-                               status = EXIT_FAILURE;
-                       num_files_counted++;
-                       optind++;
-               }
-       }
-
-       if (num_files_counted > 1)
-               print_counts(total_lines, total_words, total_chars,
-                                        max_length, "total");
-
-       return status;
-}
diff --git a/busybox/coreutils/whoami.c b/busybox/coreutils/whoami.c
deleted file mode 100644 (file)
index c3b1140..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini whoami implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int whoami_main(int argc, char **argv)
-{
-       char user[9];
-       uid_t uid = geteuid();
-
-       if (argc > 1)
-               show_usage();
-
-       my_getpwuid(user, uid);
-       if (*user) {
-               puts(user);
-               return EXIT_SUCCESS;
-       }
-       error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
-}
diff --git a/busybox/coreutils/yes.c b/busybox/coreutils/yes.c
deleted file mode 100644 (file)
index 7d9596d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini yes implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int yes_main(int argc, char **argv)
-{
-       int i;
-
-       if (argc >= 2 && *argv[1] == '-')
-               show_usage();
-
-       if (argc == 1) {
-               while (1)
-                       if (puts("y") == EOF) {
-                               perror("yes");
-                               return EXIT_FAILURE;
-                       }
-       }
-
-       while (1)
-               for (i = 1; i < argc; i++)
-                       if (fputs(argv[i], stdout) == EOF
-                               || putchar(i == argc - 1 ? '\n' : ' ') == EOF) {
-                               perror("yes");
-                               return EXIT_FAILURE;
-                       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/cp.c b/busybox/cp.c
deleted file mode 100644 (file)
index 82d43ad..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cp implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-extern int cp_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int flags = 0;
-       int i;
-
-       while ((opt = getopt(argc, argv, "adfipR")) != -1)
-               switch (opt) {
-               case 'a':
-                       flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR;
-                       /* fallthrough */
-               case 'd':
-                       flags |= FILEUTILS_PRESERVE_SYMLINKS;
-                       break;
-               case 'f':
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               case 'p':
-                       flags |= FILEUTILS_PRESERVE_STATUS;
-                       break;
-               case 'R':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               default:
-                       show_usage();
-               }
-       
-       if (optind + 2 > argc)
-               show_usage();
-
-       /* If there are only two arguments and...  */
-       if (optind + 2 == argc) {
-               struct stat source_stat;
-               struct stat dest_stat;
-               int source_exists = 1;
-               int dest_exists = 1;
-
-               if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                               lstat(argv[optind], &source_stat) < 0) ||
-                               (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                                stat(argv[optind], &source_stat))) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind]);
-                       source_exists = 0;
-               }
-
-               if (stat(argv[optind + 1], &dest_stat) < 0) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
-                       dest_exists = 0;
-               }
-               
-               /* ...if neither is a directory or...  */
-               if (((!source_exists || !S_ISDIR(source_stat.st_mode)) &&
-                               (!dest_exists || !S_ISDIR(dest_stat.st_mode))) ||
-                               /* ...recursing, the first is a directory, and the
-                                * second doesn't exist, then... */
-                               ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) &&
-                                !dest_exists)) {
-                       /* ...do a simple copy.  */
-                       if (copy_file(argv[optind], argv[optind + 1], flags) < 0)
-                               status = 1;
-                       return status;
-               }
-       }
-
-       for (i = optind; i < argc - 1; i++) {
-               char *dest = concat_path_file(argv[argc - 1],
-                               get_last_path_component(argv[i]));
-               if (copy_file(argv[i], dest, flags) < 0)
-                       status = 1;
-               free(dest);
-       }
-
-       return status;
-}
diff --git a/busybox/cpio.c b/busybox/cpio.c
deleted file mode 100644 (file)
index 7f68715..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cpio implementation for busybox
- *
- * Copyright (C) 2001 by Glenn McGrath 
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Limitations:
- *             Doesn't check CRC's
- *             Only supports new ASCII and CRC formats
- *
- */
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int cpio_main(int argc, char **argv)
-{
-       FILE *src_stream = stdin;
-       char **extract_names = NULL;
-       int extract_function = 0;
-       int num_of_entries = 0;
-       int opt = 0;
-       mode_t oldmask = 0;
-
-       while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
-               switch (opt) {
-               case 'i': // extract
-                       extract_function |= extract_all_to_fs;
-                       break;
-               case 'd': // create _leading_ directories
-                       extract_function |= extract_create_leading_dirs;
-                       oldmask = umask(077); /* Make make_directory act like GNU cpio */
-                       break;
-               case 'm': // preserve modification time
-                       extract_function |= extract_preserve_date;
-                       break;
-               case 'v': // verbosly list files
-                       extract_function |= extract_verbose_list;
-                       break;
-               case 'u': // unconditional
-                       extract_function |= extract_unconditional;
-                       break;
-               case 't': // list files
-                       extract_function |= extract_list;
-                       break;
-               case 'F':
-                       src_stream = xfopen(optarg, "r");
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) {
-               extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
-       }
-
-       if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) {
-               /* The meaning of v changes on extract */
-               extract_function ^= extract_verbose_list;
-               extract_function |= extract_list;
-       }
-
-       while (optind < argc) {
-               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
-               extract_names[num_of_entries] = xstrdup(argv[optind]);
-               num_of_entries++;
-               extract_names[num_of_entries] = NULL;
-               optind++;
-       }
-
-       unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names);
-       if (oldmask) {
-               umask(oldmask); /* Restore umask if we changed it */
-       }
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/cut.c b/busybox/cut.c
deleted file mode 100644 (file)
index 3ed2648..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * cut.c - minimalist version of cut
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h> /* getopt */
-#include <string.h>
-#include <limits.h>
-#include "busybox.h"
-
-
-/* globals from other files */
-extern int optind;
-extern char *optarg;
-
-
-/* option vars */
-static char part = 0; /* (b)yte, (c)har, (f)ields */
-static unsigned int supress_non_delimited_lines = 0;
-static char delim = '\t'; /* delimiter, default is tab */
-
-struct cut_list {
-       int startpos;
-       int endpos;
-};
-
-static const int BOL = 0;
-static const int EOL = INT_MAX;
-static const int NON_RANGE = -1;
-
-static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
-static unsigned int nlists = 0; /* number of elements in above list */
-
-
-static int cmpfunc(const void *a, const void *b)
-{
-       struct cut_list *la = (struct cut_list *)a;
-       struct cut_list *lb = (struct cut_list *)b;
-
-       if (la->startpos > lb->startpos)
-               return 1;
-       if (la->startpos < lb->startpos)
-               return -1;
-       return 0;
-}
-
-
-/*
- * parse_lists() - parses a list and puts values into startpos and endpos.
- * valid list formats: N, N-, N-M, -M 
- * more than one list can be seperated by commas
- */
-static void parse_lists(char *lists)
-{
-       char *ltok = NULL;
-       char *ntok = NULL;
-       char *junk;
-       int s = 0, e = 0;
-
-       /* take apart the lists, one by one (they are seperated with commas */
-       while ((ltok = strsep(&lists, ",")) != NULL) {
-
-               /* it's actually legal to pass an empty list */
-               if (strlen(ltok) == 0)
-                       continue;
-
-               /* get the start pos */
-               ntok = strsep(&ltok, "-");
-               if (ntok == NULL) {
-                       fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
-               } else if (strlen(ntok) == 0) {
-                       s = BOL;
-               } else {
-                       s = strtoul(ntok, &junk, 10);
-                       if(*junk != '\0' || s < 0)
-                               error_msg_and_die("invalid byte or field list");
-                       
-                       /* account for the fact that arrays are zero based, while the user
-                        * expects the first char on the line to be char # 1 */
-                       if (s != 0)
-                               s--;
-               }
-
-               /* get the end pos */
-               ntok = strsep(&ltok, "-");
-               if (ntok == NULL) {
-                       e = NON_RANGE;
-               } else if (strlen(ntok) == 0) {
-                       e = EOL;
-               } else {
-                       e = strtoul(ntok, &junk, 10);
-                       if(*junk != '\0' || e < 0)
-                               error_msg_and_die("invalid byte or field list");
-                       /* if the user specified and end position of 0, that means "til the
-                        * end of the line */
-                       if (e == 0)
-                               e = INT_MAX;
-                       e--; /* again, arrays are zero based, lines are 1 based */
-                       if (e == s)
-                               e = NON_RANGE;
-               }
-
-               /* if there's something left to tokenize, the user past an invalid list */
-               if (ltok)
-                       error_msg_and_die("invalid byte or field list");
-               
-               /* add the new list */
-               cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
-               cut_lists[nlists-1].startpos = s;
-               cut_lists[nlists-1].endpos = e;
-       }
-
-       /* make sure we got some cut positions out of all that */
-       if (nlists == 0)
-               error_msg_and_die("missing list of positions");
-
-       /* now that the lists are parsed, we need to sort them to make life easier
-        * on us when it comes time to print the chars / fields / lines */
-       qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
-
-}
-
-
-static void cut_line_by_chars(const char *line)
-{
-       int c, l;
-       /* set up a list so we can keep track of what's been printed */
-       char *printed = xcalloc(strlen(line), sizeof(char));
-
-       /* print the chars specified in each cut list */
-       for (c = 0; c < nlists; c++) {
-               l = cut_lists[c].startpos;
-               while (l < strlen(line)) {
-                       if (!printed[l]) {
-                               putchar(line[l]);
-                               printed[l] = 'X';
-                       }
-                       l++;
-                       if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
-                               break;
-               }
-       }
-       putchar('\n'); /* cuz we were handed a chomped line */
-       free(printed);
-}
-
-
-static void cut_line_by_fields(char *line)
-{
-       int c, f;
-       int ndelim = -1; /* zero-based / one-based problem */
-       int nfields_printed = 0;
-       char *field = NULL;
-       char d[2] = { delim, 0 };
-       char *printed;
-
-       /* test the easy case first: does this line contain any delimiters? */
-       if (strchr(line, delim) == NULL) {
-               if (!supress_non_delimited_lines)
-                       puts(line);
-               return;
-       }
-
-       /* set up a list so we can keep track of what's been printed */
-       printed = xcalloc(strlen(line), sizeof(char));
-
-       /* process each list on this line, for as long as we've got a line to process */
-       for (c = 0; c < nlists && line; c++) {
-               f = cut_lists[c].startpos;
-               do {
-
-                       /* find the field we're looking for */
-                       while (line && ndelim < f) {
-                               field = strsep(&line, d);
-                               ndelim++;
-                       }
-
-                       /* we found it, and it hasn't been printed yet */
-                       if (field && ndelim == f && !printed[ndelim]) {
-                               /* if this isn't our first time through, we need to print the
-                                * delimiter after the last field that was printed */
-                               if (nfields_printed > 0)
-                                       putchar(delim);
-                               fputs(field, stdout);
-                               printed[ndelim] = 'X';
-                               nfields_printed++;
-                       }
-
-                       f++;
-
-                       /* keep going as long as we have a line to work with, this is a
-                        * list, and we're not at the end of that list */
-               } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
-       }
-
-       /* if we printed anything at all, we need to finish it with a newline cuz
-        * we were handed a chomped line */
-       putchar('\n');
-
-       free(printed);
-}
-
-
-static void cut_file_by_lines(const char *line, unsigned int linenum)
-{
-       static int c = 0;
-       static int l = -1;
-       
-       /* I can't initialize this above cuz the "initializer isn't
-        * constant" *sigh* */
-       if (l == -1)
-               l = cut_lists[c].startpos;
-
-       /* get out if we have no more lists to process or if the lines are lower
-        * than what we're interested in */
-       if (c >= nlists || linenum < l)
-               return;
-
-       /* if the line we're looking for is lower than the one we were passed, it
-        * means we displayed it already, so move on */
-       while (l < linenum) {
-               l++;
-               /* move on to the next list if we're at the end of this one */
-               if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
-                       c++;
-                       /* get out if there's no more lists to process */
-                       if (c >= nlists)
-                               return;
-                       l = cut_lists[c].startpos;
-                       /* get out if the current line is lower than the one we just became
-                        * interested in */
-                       if (linenum < l)
-                               return;
-               }
-       }
-
-       /* If we made it here, it means we've found the line we're looking for, so print it */
-       puts(line);
-}
-
-
-/*
- * snippy-snip
- */
-static void cut_file(FILE *file)
-{
-       char *line = NULL;
-       unsigned int linenum = 0; /* keep these zero-based to be consistent */
-
-       /* go through every line in the file */
-       while ((line = get_line_from_file(file)) != NULL) {
-               chomp(line);
-
-               /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
-               if (part == 'c' || part == 'b')
-                       cut_line_by_chars(line);
-
-               /* cut based on fields */
-               else if (part == 'f') {
-                       if (delim == '\n')
-                               cut_file_by_lines(line, linenum);
-                       else
-                               cut_line_by_fields(line);
-               }
-
-               linenum++;
-               free(line);
-       }
-}
-
-
-extern int cut_main(int argc, char **argv)
-{
-       int opt;
-
-       while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) {
-               switch (opt) {
-                       case 'b':
-                       case 'c':
-                       case 'f':
-                               /* make sure they didn't ask for two types of lists */
-                               if (part != 0) {
-                                       error_msg_and_die("only one type of list may be specified");
-                               }
-                               part = (char)opt;
-                               parse_lists(optarg);
-                               break;
-                       case 'd':
-                               if (strlen(optarg) > 1) {
-                                       error_msg_and_die("the delimiter must be a single character");
-                               }
-                               delim = optarg[0];
-                               break;
-                       case 'n':
-                               /* no-op */
-                               break;
-                       case 's':
-                               supress_non_delimited_lines++;
-                               break;
-               }
-       }
-
-       if (part == 0) {
-               error_msg_and_die("you must specify a list of bytes, characters, or fields");
-       }
-
-       /*  non-field (char or byte) cutting has some special handling */
-       if (part != 'f') {
-               if (supress_non_delimited_lines) {
-                       error_msg_and_die("suppressing non-delimited lines makes sense"
-                                       " only when operating on fields");
-               }
-               if (delim != '\t' && part != 'f') {
-                       error_msg_and_die("a delimiter may be specified only when operating on fields");
-               }
-       }
-
-       /* argv[(optind)..(argc-1)] should be names of file to process. If no
-        * files were specified or '-' was specified, take input from stdin.
-        * Otherwise, we process all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               cut_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       file = wfopen(argv[i], "r");
-                       if(file) {
-                               cut_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/date.c b/busybox/date.c
deleted file mode 100644 (file)
index 6db3e28..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini date implementation for busybox
- *
- * by Matthew Grant <grantma@anathoth.gen.nz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-
-/* This 'date' command supports only 2 time setting formats, 
-   all the GNU strftime stuff (its in libc, lets use it),
-   setting time using UTC and displaying int, as well as
-   an RFC 822 complient date output for shell scripting
-   mail commands */
-
-/* Input parsing code is always bulky - used heavy duty libc stuff as
-   much as possible, missed out a lot of bounds checking */
-
-/* Default input handling to save suprising some people */
-
-static struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
-{
-       int nr;
-
-       nr = sscanf(t_string, "%2d%2d%2d%2d%d",
-                               &(tm_time->tm_mon),
-                               &(tm_time->tm_mday),
-                               &(tm_time->tm_hour),
-                               &(tm_time->tm_min), &(tm_time->tm_year));
-
-       if (nr < 4 || nr > 5) {
-               error_msg_and_die(invalid_date, t_string); 
-       }
-
-       /* correct for century  - minor Y2K problem here? */
-       if (tm_time->tm_year >= 1900)
-               tm_time->tm_year -= 1900;
-       /* adjust date */
-       tm_time->tm_mon -= 1;
-
-       return (tm_time);
-
-}
-
-
-/* The new stuff for LRP */
-
-static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
-{
-       struct tm t;
-
-       /* Parse input and assign appropriately to tm_time */
-
-       if (t=*tm_time,sscanf(t_string, "%d:%d:%d",
-                          &t.tm_hour, &t.tm_min, &t.tm_sec) == 3) {
-                                       /* no adjustments needed */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d:%d",
-                                         &t.tm_hour, &t.tm_min) == 2) {
-                                       /* no adjustments needed */
-
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d:%d",
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour,
-                                         &t.tm_min, &t.tm_sec) == 5) {
-
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d",
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour, &t.tm_min) == 4) {
-
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d:%d",
-                                         &t.tm_year,
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour,
-                                         &t.tm_min, &t.tm_sec) == 6) {
-
-               t.tm_year -= 1900;      /* Adjust years */
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d",
-                                         &t.tm_year,
-                                         &t.tm_mon,
-                                         &t.tm_mday,
-                                         &t.tm_hour, &t.tm_min) == 5) {
-               t.tm_year -= 1900;      /* Adjust years */
-               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
-
-       } else {
-               error_msg_and_die(invalid_date, t_string); 
-       }
-       *tm_time = t;
-       return (tm_time);
-}
-
-
-int date_main(int argc, char **argv)
-{
-       char *date_str = NULL;
-       char *date_fmt = NULL;
-       char *t_buff;
-       int c;
-       int set_time = 0;
-       int rfc822 = 0;
-       int utc = 0;
-       int use_arg = 0;
-       time_t tm;
-       struct tm tm_time;
-
-       /* Interpret command line args */
-       while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
-               switch (c) {
-                       case 'R':
-                               rfc822 = 1;
-                               break;
-                       case 's':
-                               set_time = 1;
-                               if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
-                                       show_usage();
-                               }
-                               break;
-                       case 'u':
-                               utc = 1;
-                               if (putenv("TZ=UTC0") != 0)
-                                       error_msg_and_die(memory_exhausted);
-                               break;
-                       case 'd':
-                               use_arg = 1;
-                               if ((date_str != NULL) || ((date_str = optarg) == NULL))
-                                       show_usage();
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
-               date_fmt = &argv[optind][1];   /* Skip over the '+' */
-       else if (date_str == NULL) {
-               set_time = 1;
-               date_str = argv[optind];
-       } 
-#if 0
-       else {
-               error_msg("date_str='%s'  date_fmt='%s'\n", date_str, date_fmt);
-               show_usage();
-       }
-#endif
-
-       /* Now we have parsed all the information except the date format
-          which depends on whether the clock is being set or read */
-
-       time(&tm);
-       memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
-       /* Zero out fields - take her back to midnight! */
-       if (date_str != NULL) {
-               tm_time.tm_sec = 0;
-               tm_time.tm_min = 0;
-               tm_time.tm_hour = 0;
-       }
-
-       /* Process any date input to UNIX time since 1 Jan 1970 */
-       if (date_str != NULL) {
-
-               if (strchr(date_str, ':') != NULL) {
-                       date_conv_ftime(&tm_time, date_str);
-               } else {
-                       date_conv_time(&tm_time, date_str);
-               }
-
-               /* Correct any day of week and day of year etc. fields */
-               tm = mktime(&tm_time);
-               if (tm < 0)
-                       error_msg_and_die(invalid_date, date_str); 
-               if ( utc ) {
-                       if (putenv("TZ=UTC0") != 0)
-                               error_msg_and_die(memory_exhausted);
-               }
-
-               /* if setting time, set it */
-               if (set_time) {
-                       if (stime(&tm) < 0) {
-                               perror_msg("cannot set date");
-                       }
-               }
-       }
-
-       /* Display output */
-
-       /* Deal with format string */
-       if (date_fmt == NULL) {
-               date_fmt = (rfc822
-                                       ? (utc
-                                          ? "%a, %_d %b %Y %H:%M:%S GMT"
-                                          : "%a, %_d %b %Y %H:%M:%S %z")
-                                       : "%a %b %e %H:%M:%S %Z %Y");
-
-       } else if (*date_fmt == '\0') {
-               /* Imitate what GNU 'date' does with NO format string! */
-               printf("\n");
-               return EXIT_SUCCESS;
-       }
-
-       /* Handle special conversions */
-
-       if (strncmp(date_fmt, "%f", 2) == 0) {
-               date_fmt = "%Y.%m.%d-%H:%M:%S";
-       }
-
-       /* Print OUTPUT (after ALL that!) */
-       t_buff = xmalloc(201);
-       strftime(t_buff, 200, date_fmt, &tm_time);
-       puts(t_buff);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/dc.c b/busybox/dc.c
deleted file mode 100644 (file)
index 8d7a92a..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <math.h>
-#include "busybox.h"
-
-/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
-
-static double stack[100];
-static unsigned int pointer;
-
-static void push(double a)
-{
-       if (pointer >= (sizeof(stack) / sizeof(*stack)))
-               error_msg_and_die("stack overflow");
-       stack[pointer++] = a;
-}
-
-static double pop()
-{
-       if (pointer == 0)
-               error_msg_and_die("stack underflow");
-       return stack[--pointer];
-}
-
-static void add()
-{
-       push(pop() + pop());
-}
-
-static void sub()
-{
-       double subtrahend = pop();
-
-       push(pop() - subtrahend);
-}
-
-static void mul()
-{
-       push(pop() * pop());
-}
-
-static void divide()
-{
-       double divisor = pop();
-
-       push(pop() / divisor);
-}
-
-static void and()
-{
-       push((unsigned int) pop() & (unsigned int) pop());
-}
-
-static void or()
-{
-       push((unsigned int) pop() | (unsigned int) pop());
-}
-
-static void eor()
-{
-       push((unsigned int) pop() ^ (unsigned int) pop());
-}
-
-static void not()
-{
-       push(~(unsigned int) pop());
-}
-
-static void print()
-{
-       printf("%g\n", pop());
-}
-
-struct op {
-       const char *name;
-       void (*function) ();
-};
-
-static const struct op operators[] = {
-       {"+",   add},
-       {"add", add},
-       {"-",   sub},
-       {"sub", sub},
-       {"*",   mul},
-       {"mul", mul},
-       {"/",   divide},
-       {"div", divide},
-       {"and", and},
-       {"or",  or},
-       {"not", not},
-       {"eor", eor},
-       {0,     0}
-};
-
-static void stack_machine(const char *argument)
-{
-       char *endPointer = 0;
-       double d;
-       const struct op *o = operators;
-
-       if (argument == 0) {
-               print();
-               return;
-       }
-
-       d = strtod(argument, &endPointer);
-
-       if (endPointer != argument) {
-               push(d);
-               return;
-       }
-
-       while (o->name != 0) {
-               if (strcmp(o->name, argument) == 0) {
-                       (*(o->function)) ();
-                       return;
-               }
-               o++;
-       }
-       error_msg_and_die("%s: syntax error.", argument);
-}
-
-/* return pointer to next token in buffer and set *buffer to one char
- * past the end of the above mentioned token 
- */
-static char *get_token(char **buffer)
-{
-       char *start   = NULL;
-       char *current = *buffer;
-
-       while (isspace(*current)) { current++; }
-       if (*current != 0) {
-               start = current;
-               while (!isspace(*current) && current != 0) { current++; }
-               *buffer = current;
-       }
-       return start;
-}
-
-/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
-static int number_of_tokens(char *buffer)
-{
-       int   i = 0;
-       char *b = buffer;
-       while (get_token(&b)) { i++; }
-       return i;
-}
-
-int dc_main(int argc, char **argv)
-{
-       /* take stuff from stdin if no args are given */
-       if (argc <= 1) {
-               int i, len;
-               char *line   = NULL;
-               char *cursor = NULL;
-               char *token  = NULL;
-               while ((line = get_line_from_file(stdin))) {
-                       cursor = line;
-                       len = number_of_tokens(line);
-                       for (i = 0; i < len; i++) {
-                               token = get_token(&cursor);
-                               *cursor++ = 0;
-                               stack_machine(token);
-                       }
-                       free(line);
-               }
-       } else {
-               if (*argv[1]=='-')
-                       show_usage();
-               while (argc >= 2) {
-                       stack_machine(argv[1]);
-                       argv++;
-                       argc--;
-               }
-       }
-       stack_machine(0);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/dd.c b/busybox/dd.c
deleted file mode 100644 (file)
index d46db82..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dd implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include "busybox.h"
-
-
-static const struct suffix_mult dd_suffixes[] = {
-       { "c", 1 },
-       { "w", 2 },
-       { "b", 512 },
-       { "kD", 1000 },
-       { "k", 1024 },
-       { "MD", 1000000 },
-       { "M", 1048576 },
-       { "GD", 1000000000 },
-       { "G", 1073741824 },
-       { NULL, 0 }
-};
-
-int dd_main(int argc, char **argv)
-{
-       int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE;
-       size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
-       size_t bs = 512, count = -1;
-       ssize_t n;
-       off_t seek = 0, skip = 0;
-       char *infile = NULL, *outfile = NULL, *buf;
-
-       for (i = 1; i < argc; i++) {
-               if (strncmp("bs=", argv[i], 3) == 0)
-                       bs = parse_number(argv[i]+3, dd_suffixes);
-               else if (strncmp("count=", argv[i], 6) == 0)
-                       count = parse_number(argv[i]+6, dd_suffixes);
-               else if (strncmp("seek=", argv[i], 5) == 0)
-                       seek = parse_number(argv[i]+5, dd_suffixes);
-               else if (strncmp("skip=", argv[i], 5) == 0)
-                       skip = parse_number(argv[i]+5, dd_suffixes);
-               else if (strncmp("if=", argv[i], 3) == 0)
-                       infile = argv[i]+3;
-               else if (strncmp("of=", argv[i], 3) == 0)
-                       outfile = argv[i]+3;
-               else if (strncmp("conv=", argv[i], 5) == 0) {
-                       buf = argv[i]+5;
-                       while (1) {
-                               if (strncmp("notrunc", buf, 7) == 0) {
-                                       trunc = FALSE;
-                                       buf += 7;
-                               } else if (strncmp("sync", buf, 4) == 0) {
-                                       sync_flag = TRUE;
-                                       buf += 4;
-                               } else {
-                                       error_msg_and_die("invalid conversion `%s'", argv[i]+5);
-                               }
-                               if (buf[0] == '\0')
-                                       break;
-                               if (buf[0] == ',')
-                                       buf++;
-                       }
-               } else
-                       show_usage();
-       }
-
-       buf = xmalloc(bs);
-
-       if (infile != NULL) {
-               if ((ifd = open(infile, O_RDONLY)) < 0)
-                       perror_msg_and_die("%s", infile);
-       } else {
-               ifd = STDIN_FILENO;
-               infile = "standard input";
-       }
-
-       if (outfile != NULL) {
-               oflag = O_WRONLY | O_CREAT;
-
-               if (!seek && trunc)
-                       oflag |= O_TRUNC;
-
-               if ((ofd = open(outfile, oflag, 0666)) < 0)
-                       perror_msg_and_die("%s", outfile);
-
-               if (seek && trunc) {
-                       if (ftruncate(ofd, seek * bs) < 0)
-                               perror_msg_and_die("%s", outfile);
-               }
-       } else {
-               ofd = STDOUT_FILENO;
-               outfile = "standard output";
-       }
-
-       if (skip) {
-               if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
-                       perror_msg_and_die("%s", infile);
-       }
-
-       if (seek) {
-               if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
-                       perror_msg_and_die("%s", outfile);
-       }
-
-       while (in_full + in_part != count) {
-               n = safe_read(ifd, buf, bs);
-               if (n < 0)
-                       perror_msg_and_die("%s", infile);
-               if (n == 0)
-                       break;
-               if (n == bs)
-                       in_full++;
-               else
-                       in_part++;
-               if (sync_flag) {
-                       memset(buf + n, '\0', bs - n);
-                       n = bs;
-               }
-               n = full_write(ofd, buf, n);
-               if (n < 0)
-                       perror_msg_and_die("%s", outfile);
-               if (n == bs)
-                       out_full++;
-               else
-                       out_part++;
-       }
-
-       fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part);
-       fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/deallocvt.c b/busybox/deallocvt.c
deleted file mode 100644 (file)
index 15cd0c9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
- * Renamed deallocvt.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/vt.h> */
-static const int VT_DISALLOCATE = 0x5608;  /* free memory associated to vt */
-
-int deallocvt_main(int argc, char *argv[])
-{
-       int fd, num, i;
-
-       //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-')))
-       if (argc > 2)
-               show_usage();
-
-       fd = get_console_fd("/dev/console");
-
-       if (argc == 1) {
-               /* deallocate all unused consoles */
-               if (ioctl(fd, VT_DISALLOCATE, 0))
-                       perror_msg_and_die("VT_DISALLOCATE");
-       } else {
-               for (i = 1; i < argc; i++) {
-                       num = atoi(argv[i]);
-                       if (num == 0)
-                               error_msg("0: illegal VT number");
-                       else if (num == 1)
-                               error_msg("VT 1 cannot be deallocated");
-                       else if (ioctl(fd, VT_DISALLOCATE, num))
-                               perror_msg_and_die("VT_DISALLOCATE");
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/debian/Config.h-deb b/busybox/debian/Config.h-deb
deleted file mode 100644 (file)
index 368b5e9..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* vi: set sw=4 ts=4: */
-// This file defines the feature set to be compiled into busybox.
-// When you turn things off here, they won't be compiled in at all.
-//
-//// This file is parsed by sed.  You MUST use single line comments.
-//   i.e.,  //#define BB_BLAH
-//
-//
-// BusyBox Applications
-//#define BB_ADJTIMEX
-#define BB_AR
-//#define BB_ASH
-//#define BB_BASENAME
-#define BB_CAT
-#define BB_CHGRP
-#define BB_CHMOD
-#define BB_CHOWN
-#define BB_CHROOT
-//#define BB_CHVT
-#define BB_CLEAR
-//#define BB_CMP
-#define BB_CP
-//#define BB_CPIO
-#define BB_CUT
-//#define BB_DATE
-//#define BB_DC
-#define BB_DD
-//#define BB_DEALLOCVT
-#define BB_DF
-#define BB_DIRNAME
-#define BB_DMESG
-//#define BB_DOS2UNIX
-//#define BB_DPKG
-//#define BB_DPKG_DEB
-//#define BB_DUTMP
-//#define BB_DU
-//#define BB_DUMPKMAP
-#define BB_ECHO
-//#define BB_ENV
-#define BB_EXPR
-//#define BB_FBSET
-//#define BB_FDFLUSH
-#define BB_FIND
-#define BB_FREE
-//#define BB_FREERAMDISK
-//#define BB_FSCK_MINIX
-//#define BB_GETOPT
-#define BB_GREP
-#define BB_GUNZIP
-#define BB_GZIP
-#define BB_HALT
-#define BB_HEAD
-//#define BB_HOSTID
-//#define BB_HOSTNAME
-//#define BB_HUSH
-#define BB_ID
-#define BB_IFCONFIG
-#define BB_INIT
-//#define BB_INSMOD
-#define BB_KILL
-#define BB_KILLALL
-#define BB_KLOGD
-//#define BB_LASH
-//#define BB_LENGTH
-#define BB_LN
-//#define BB_LOADACM
-//#define BB_LOADFONT
-#define BB_LOADKMAP
-#define BB_LOGGER
-//#define BB_LOGNAME
-#define BB_LS
-//#define BB_LSMOD
-//#define BB_MAKEDEVS
-#define BB_MD5SUM
-#define BB_MKDIR
-//#define BB_MKFIFO
-//#define BB_MKFS_MINIX
-#define BB_MKNOD
-#define BB_MKSWAP
-//#define BB_MKTEMP
-//#define BB_MODPROBE
-#define BB_MORE
-#define BB_MOUNT
-//#define BB_MSH
-//#define BB_MT
-#define BB_MV
-//#define BB_NC
-//#define BB_NSLOOKUP
-//#define BB_PIDOF
-#define BB_PING
-//#define BB_PIVOT_ROOT
-#define BB_POWEROFF
-//#define BB_PRINTF
-#define BB_PS
-#define BB_PWD
-//#define BB_RDATE
-//#define BB_READLINK
-#define BB_REBOOT
-//#define BB_RENICE
-#define BB_RESET
-#define BB_RM
-#define BB_RMDIR
-//#define BB_RMMOD
-#define BB_ROUTE
-//#define BB_RPM2CPIO
-#define BB_SED
-//#define BB_SETKEYCODES
-#define BB_SLEEP
-#define BB_SORT
-//#define BB_STTY
-#define BB_SWAPONOFF
-#define BB_SYNC
-#define BB_SYSLOGD
-#define BB_TAIL
-#define BB_TAR
-//#define BB_TEE
-#define BB_TEST
-//#define BB_TELNET
-//#define BB_TFTP
-#define BB_TOUCH
-#define BB_TR
-//#define BB_TRACEROUTE
-#define BB_TRUE_FALSE
-#define BB_TTY
-//#define BB_UNIX2DOS
-//#define BB_UUENCODE
-//#define BB_UUDECODE
-#define BB_UMOUNT
-#define BB_UNIQ
-#define BB_UNAME
-//#define BB_UPDATE
-#define BB_UPTIME
-//#define BB_USLEEP
-//#define BB_VI
-//#define BB_WATCHDOG
-#define BB_WC
-#define BB_WGET
-#define BB_WHICH
-#define BB_WHOAMI
-//#define BB_XARGS
-//#define BB_YES
-// End of Applications List
-//
-//
-//
-// ---------------------------------------------------------
-// This is where feature definitions go.  Generally speaking,
-// turning this stuff off makes things a bit smaller (and less 
-// pretty/useful).
-//
-//
-// If you enabled one or more of the shells, you may select which one
-// should be run when sh is invoked:
-//#define BB_FEATURE_SH_IS_ASH
-//#define BB_FEATURE_SH_IS_HUSH
-//#define BB_FEATURE_SH_IS_LASH
-//#define BB_FEATURE_SH_IS_MSH
-//
-// BusyBox will, by default, malloc space for its buffers.  This costs code
-// size for the call to xmalloc.  You can use the following feature to have
-// them put on the stack.  For some very small machines with limited stack
-// space, this can be deadly.  For most folks, this works just fine...
-//#define BB_FEATURE_BUFFERS_GO_ON_STACK
-// The third alternative for buffer allocation is to use BSS.  This works
-// beautifully for computers with a real MMU (and OS support), but wastes
-// runtime RAM for uCLinux.  This behavior was the only one available for
-// BusyBox versions 0.48 and earlier.
-//#define BB_FEATURE_BUFFERS_GO_IN_BSS
-//
-// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
-// thereby eliminating the need for the /proc filesystem and thereby saving
-// lots and lots memory for more important things.  NOTE:  If you enable this
-// feature, you _must_ have patched the kernel to include the devps patch that
-// is included in the busybox/kernel-patches directory.  You will also need to
-// create some device special files in /dev on your embedded system:
-//        mknod /dev/mtab c 10 22
-//        mknod /dev/ps c 10 21
-// I emailed Linus and this patch will not be going into the stock kernel.
-//#define BB_FEATURE_USE_DEVPS_PATCH
-//
-// show verbose usage messages
-//#define BB_FEATURE_VERBOSE_USAGE
-//
-// Use termios to manipulate the screen ('more' is prettier with this on)
-#define BB_FEATURE_USE_TERMIOS
-//
-// calculate terminal & column widths (for more and ls)
-#define BB_FEATURE_AUTOWIDTH
-//
-// show username/groupnames for ls
-#define BB_FEATURE_LS_USERNAME
-//
-// show file timestamps in ls
-#define BB_FEATURE_LS_TIMESTAMPS
-//
-// enable ls -p and -F
-#define BB_FEATURE_LS_FILETYPES
-//
-// sort the file names
-#define BB_FEATURE_LS_SORTFILES
-//
-// enable ls -R
-#define BB_FEATURE_LS_RECURSIVE
-//
-// enable ls -L
-#define BB_FEATURE_LS_FOLLOWLINKS
-//
-// Disable for a smaller (but less functional) ping
-#define BB_FEATURE_FANCY_PING
-//
-// Make init use a simplified /etc/inittab file (recommended).
-#define BB_FEATURE_USE_INITTAB
-//
-//Enable init being called as /linuxrc
-#define BB_FEATURE_LINUXRC
-//
-//Have init enable core dumping for child processes (for debugging only) 
-//#define BB_FEATURE_INIT_COREDUMPS
-//
-//Make sure nothing is printed to the console on boot
-//#define BB_FEATURE_EXTRA_QUIET
-//
-// enable syslogd -R remotehost
-//#define BB_FEATURE_REMOTE_LOG
-//
-// enable syslogd -C
-//#define BB_FEATURE_IPC_SYSLOG
-//
-//Disable for a simple tail implementation (2.34k vs 3k for the full one).
-//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
-//#define BB_FEATURE_FANCY_TAIL
-//
-// Enable support for loop devices in mount
-#define BB_FEATURE_MOUNT_LOOP
-//
-// Enable support for a real /etc/mtab file instead of /proc/mounts
-//#define BB_FEATURE_MTAB_SUPPORT
-//
-// Enable support for mounting remote NFS volumes. 
-// You may need to mount with "-o nolock" if you are
-// not running a local portmapper daemon...
-#define BB_FEATURE_NFSMOUNT
-//
-// Enable support forced filesystem unmounting 
-// (i.e., in case of an unreachable NFS system).
-#define BB_FEATURE_MOUNT_FORCE
-//
-// Enable support for creation of tar files.
-#define BB_FEATURE_TAR_CREATE
-//
-// Enable support for "--exclude" and "-X" for excluding files
-//#define BB_FEATURE_TAR_EXCLUDE
-//
-// Enable support for tar -z option (currently only works for inflating)
-#define BB_FEATURE_TAR_GZIP 
-//
-// Enable reverse sort
-//#define BB_FEATURE_SORT_REVERSE
-//
-// Enable uniqe sort
-//#define BB_FEATURE_SORT_UNIQUE
-//
-// Enable command line editing in the shell.  
-// Only relevant if a shell is enabled. On by default.
-#define BB_FEATURE_COMMAND_EDITING
-//
-// Enable tab completion in the shell.  This is now working quite nicely.
-// This feature adds a bit over 4k. Only relevant if a shell is enabled.
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-//
-// Attempts to match usernames in a ~-prefixed path
-//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-//
-//Allow the shell to invoke all the compiled in BusyBox applets as if they
-//were shell builtins.  Nice for staticly linking an emergency rescue shell,
-//among other things. Off by default.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_STANDALONE_SHELL
-//
-//When this is enabled, busybox shell applets can be called using full path
-//names.  This causes applets (i.e., most busybox commands) to override
-//real commands on the filesystem.  For example, if you run run /bin/cat, it
-//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
-//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
-//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
-// Only relevant if a shell is enabled. Off by default.
-//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-//
-// Uncomment this option for a fancy shell prompt that includes the
-// current username and hostname.  On systems that don't have usernames
-// or hostnames, this can look hideous.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_FANCY_PROMPT
-//
-//Turn on extra fbset options
-//#define BB_FEATURE_FBSET_FANCY
-//
-//Turn on fbset readmode support
-//#define BB_FEATURE_FBSET_READMODE
-//
-// Support insmod/lsmod/rmmod for post 2.1 kernels
-//#define BB_FEATURE_NEW_MODULE_INTERFACE
-//
-// Support insmod/lsmod/rmmod for pre 2.1 kernels
-//#define BB_FEATURE_OLD_MODULE_INTERFACE
-//
-// Support module version checking
-//#define BB_FEATURE_INSMOD_VERSION_CHECKING
-//
-// Support for uClinux memory usage optimization, which will load the image
-// directly into the kernel memory.  This divides memory requrements by three.
-// If you are not running uClinux (i.e., your CPU has an MMU) leave this
-// disabled...
-//#define BB_FEATURE_INSMOD_LOADINKMEM
-//
-// Support for Minix filesystem, version 2
-//#define BB_FEATURE_MINIX2
-//
-// Enable ifconfig status reporting output -- this feature adds 12k.
-#define BB_FEATURE_IFCONFIG_STATUS
-//
-// Enable ifconfig slip-specific options "keepalive" and "outfill"
-//#define BB_FEATURE_IFCONFIG_SLIP
-//
-// Enable ifconfig options "mem_start", "io_addr", and "irq".
-//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-//
-// Enable ifconfig option "hw".  Currently works for only with "ether".
-#define BB_FEATURE_IFCONFIG_HW
-//
-// Enable busybox --install [-s]
-// to create links (or symlinks) for all the commands that are 
-// compiled into the binary.  (needs /proc filesystem)
-#define BB_FEATURE_INSTALLER
-//
-// Enable a nifty progress meter in wget (adds just under 2k)
-#define BB_FEATURE_WGET_STATUSBAR
-//
-// Enable HTTP authentication in wget
-#define BB_FEATURE_WGET_AUTHENTICATION
-//
-// Clean up all memory before exiting -- usually not needed
-// as the OS can clean up...  Don't enable this unless you
-// have a really good reason for cleaning things up manually.
-//#define BB_FEATURE_CLEAN_UP
-//
-// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
-#define BB_FEATURE_HUMAN_READABLE
-//
-// Support for the find -type option.
-#define BB_FEATURE_FIND_TYPE
-//
-// Support for the find -perm option.
-#define BB_FEATURE_FIND_PERM
-//
-// Support for the find -mtine option.
-#define BB_FEATURE_FIND_MTIME
-//
-// Support for the -A -B and -C context flags in grep
-//#define BB_FEATURE_GREP_CONTEXT
-//
-// Support for the EGREP applet (alias to the grep applet)
-//#define BB_FEATURE_GREP_EGREP_ALIAS
-//
-// Tell tftp what commands that should be supported.
-#define BB_FEATURE_TFTP_PUT
-#define BB_FEATURE_TFTP_GET
-//
-// features for vi
-#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
-#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
-#define BB_FEATURE_VI_SEARCH           // search and replace cmds
-#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
-#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
-#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
-#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
-#define BB_FEATURE_VI_SET              // :set
-#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
-//
-// Enable a if you system have setuped locale
-//#define BB_LOCALE_SUPPORT
-//
-// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
-#define BB_FEATURE_TELNET_TTYPE
-//
-// End of Features List
-//
-//
-//
-//
-//
-//
-//---------------------------------------------------
-// Nothing beyond this point should ever be touched by 
-// mere mortals so leave this stuff alone.
-//
-#include <features.h>
-#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
-       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
-       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
-       #undef BB_ASH                   /* Uses fork() */
-       #undef BB_HUSH                  /* Uses fork() */
-       #undef BB_LASH                  /* Uses fork() */
-       #undef BB_INIT                  /* Uses fork() */
-       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
-       #undef BB_SYSLOGD               /* Uses daemon() */
-       #undef BB_KLOGD                 /* Uses daemon() */
-       #undef BB_UPDATE                /* Uses daemon() */
-#endif
-#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
-       #if defined BB_FEATURE_COMMAND_EDITING
-               #define BB_CMDEDIT
-       #else
-               #undef BB_FEATURE_COMMAND_EDITING
-               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
-               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               #undef BB_FEATURE_SH_FANCY_PROMPT
-       #endif
-#else
-       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       #undef BB_FEATURE_SH_STANDALONE_SHELL
-       #undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-//
-#ifdef BB_KILLALL
-       #ifndef BB_KILL
-               #define BB_KILL
-       #endif
-#endif
-//
-#ifndef BB_INIT
-       #undef BB_FEATURE_LINUXRC
-#endif
-//
-#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
-       #define BB_NFSMOUNT
-#endif
-//
-#if defined BB_FEATURE_AUTOWIDTH
-       #ifndef BB_FEATURE_USE_TERMIOS
-               #define BB_FEATURE_USE_TERMIOS
-       #endif
-#endif
-//
-#if defined BB_INSMOD || defined BB_LSMOD
-       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
-               #define BB_FEATURE_NEW_MODULE_INTERFACE
-       #endif
-#endif
-//
-#ifdef BB_UNIX2DOS
-       #define BB_DOS2UNIX
-#endif 
-//
-#ifdef BB_SYSLOGD
-       #if defined BB_FEATURE_IPC_SYSLOG
-               #define BB_LOGREAD
-       #endif
-#endif
-//
-#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
-# define shell_main ash_main
-#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
-# define shell_main hush_main
-#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
-# define shell_main lash_main
-#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
-# define shell_main msh_main
-#endif
diff --git a/busybox/debian/Config.h-static b/busybox/debian/Config.h-static
deleted file mode 100644 (file)
index 094b1f9..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* vi: set sw=4 ts=4: */
-// This file defines the feature set to be compiled into busybox.
-// When you turn things off here, they won't be compiled in at all.
-//
-//// This file is parsed by sed.  You MUST use single line comments.
-//   i.e.,  //#define BB_BLAH
-//
-//
-// BusyBox Applications
-//#define BB_ADJTIMEX
-#define BB_AR
-#define BB_ASH
-#define BB_BASENAME
-#define BB_CAT
-#define BB_CHGRP
-#define BB_CHMOD
-#define BB_CHOWN
-#define BB_CHROOT
-#define BB_CHVT
-#define BB_CLEAR
-#define BB_CMP
-#define BB_CP
-#define BB_CPIO
-#define BB_CUT
-#define BB_DATE
-#define BB_DC
-#define BB_DD
-#define BB_DEALLOCVT
-#define BB_DF
-#define BB_DIRNAME
-#define BB_DMESG
-#define BB_DOS2UNIX
-#define BB_DPKG
-#define BB_DPKG_DEB
-#define BB_DUTMP
-#define BB_DU
-#define BB_DUMPKMAP
-#define BB_ECHO
-#define BB_ENV
-#define BB_EXPR
-#define BB_FBSET
-#define BB_FDFLUSH
-#define BB_FIND
-#define BB_FREE
-#define BB_FREERAMDISK
-#define BB_FSCK_MINIX
-#define BB_GETOPT
-#define BB_GREP
-#define BB_GUNZIP
-#define BB_GZIP
-#define BB_HALT
-#define BB_HEAD
-#define BB_HOSTID
-#define BB_HOSTNAME
-//#define BB_HUSH
-#define BB_ID
-#define BB_IFCONFIG
-#define BB_INIT
-//#define BB_INSMOD
-#define BB_KILL
-#define BB_KILLALL
-#define BB_KLOGD
-//#define BB_LASH
-#define BB_LENGTH
-#define BB_LN
-#define BB_LOADACM
-#define BB_LOADFONT
-#define BB_LOADKMAP
-#define BB_LOGGER
-#define BB_LOGNAME
-#define BB_LS
-#define BB_LSMOD
-#define BB_MAKEDEVS
-#define BB_MD5SUM
-#define BB_MKDIR
-#define BB_MKFIFO
-#define BB_MKFS_MINIX
-#define BB_MKNOD
-#define BB_MKSWAP
-#define BB_MKTEMP
-//#define BB_MODPROBE
-#define BB_MORE
-#define BB_MOUNT
-//#define BB_MSH
-#define BB_MT
-#define BB_MV
-#define BB_NC
-#define BB_NSLOOKUP
-#define BB_PIDOF
-#define BB_PING
-#define BB_PIVOT_ROOT
-#define BB_POWEROFF
-#define BB_PRINTF
-#define BB_PS
-#define BB_PWD
-#define BB_RDATE
-#define BB_READLINK
-#define BB_REBOOT
-#define BB_RENICE
-#define BB_RESET
-#define BB_RM
-#define BB_RMDIR
-#define BB_RMMOD
-#define BB_ROUTE
-#define BB_RPM2CPIO
-#define BB_SED
-#define BB_SETKEYCODES
-#define BB_SLEEP
-#define BB_SORT
-#define BB_STTY
-#define BB_SWAPONOFF
-#define BB_SYNC
-#define BB_SYSLOGD
-#define BB_TAIL
-#define BB_TAR
-#define BB_TEE
-#define BB_TEST
-#define BB_TELNET
-#define BB_TFTP
-#define BB_TOUCH
-#define BB_TR
-#define BB_TRACEROUTE
-#define BB_TRUE_FALSE
-#define BB_TTY
-#define BB_UNIX2DOS
-#define BB_UUENCODE
-#define BB_UUDECODE
-#define BB_UMOUNT
-#define BB_UNIQ
-#define BB_UNAME
-#define BB_UPDATE
-#define BB_UPTIME
-#define BB_USLEEP
-#define BB_VI
-#define BB_WATCHDOG
-#define BB_WC
-#define BB_WGET
-#define BB_WHICH
-#define BB_WHOAMI
-#define BB_XARGS
-#define BB_YES
-// End of Applications List
-//
-//
-//
-// ---------------------------------------------------------
-// This is where feature definitions go.  Generally speaking,
-// turning this stuff off makes things a bit smaller (and less 
-// pretty/useful).
-//
-//
-// If you enabled one or more of the shells, you may select which one
-// should be run when sh is invoked:
-#define BB_FEATURE_SH_IS_ASH
-//#define BB_FEATURE_SH_IS_HUSH
-//#define BB_FEATURE_SH_IS_LASH
-//#define BB_FEATURE_SH_IS_MSH
-//
-// BusyBox will, by default, malloc space for its buffers.  This costs code
-// size for the call to xmalloc.  You can use the following feature to have
-// them put on the stack.  For some very small machines with limited stack
-// space, this can be deadly.  For most folks, this works just fine...
-//#define BB_FEATURE_BUFFERS_GO_ON_STACK
-// The third alternative for buffer allocation is to use BSS.  This works
-// beautifully for computers with a real MMU (and OS support), but wastes
-// runtime RAM for uCLinux.  This behavior was the only one available for
-// BusyBox versions 0.48 and earlier.
-//#define BB_FEATURE_BUFFERS_GO_IN_BSS
-//
-// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
-// thereby eliminating the need for the /proc filesystem and thereby saving
-// lots and lots memory for more important things.  NOTE:  If you enable this
-// feature, you _must_ have patched the kernel to include the devps patch that
-// is included in the busybox/kernel-patches directory.  You will also need to
-// create some device special files in /dev on your embedded system:
-//        mknod /dev/mtab c 10 22
-//        mknod /dev/ps c 10 21
-// I emailed Linus and this patch will not be going into the stock kernel.
-//#define BB_FEATURE_USE_DEVPS_PATCH
-//
-// show verbose usage messages
-#define BB_FEATURE_VERBOSE_USAGE
-//
-// Use termios to manipulate the screen ('more' is prettier with this on)
-#define BB_FEATURE_USE_TERMIOS
-//
-// calculate terminal & column widths (for more and ls)
-#define BB_FEATURE_AUTOWIDTH
-//
-// show username/groupnames for ls
-#define BB_FEATURE_LS_USERNAME
-//
-// show file timestamps in ls
-#define BB_FEATURE_LS_TIMESTAMPS
-//
-// enable ls -p and -F
-#define BB_FEATURE_LS_FILETYPES
-//
-// sort the file names
-#define BB_FEATURE_LS_SORTFILES
-//
-// enable ls -R
-#define BB_FEATURE_LS_RECURSIVE
-//
-// enable ls -L
-#define BB_FEATURE_LS_FOLLOWLINKS
-//
-// Disable for a smaller (but less functional) ping
-#define BB_FEATURE_FANCY_PING
-//
-// Make init use a simplified /etc/inittab file (recommended).
-#define BB_FEATURE_USE_INITTAB
-//
-//Enable init being called as /linuxrc
-#define BB_FEATURE_LINUXRC
-//
-//Have init enable core dumping for child processes (for debugging only) 
-//#define BB_FEATURE_INIT_COREDUMPS
-//
-//Make sure nothing is printed to the console on boot
-//#define BB_FEATURE_EXTRA_QUIET
-//
-// enable syslogd -R remotehost
-#define BB_FEATURE_REMOTE_LOG
-//
-// enable syslogd -C
-//#define BB_FEATURE_IPC_SYSLOG
-//
-//Disable for a simple tail implementation (2.34k vs 3k for the full one).
-//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
-#define BB_FEATURE_FANCY_TAIL
-//
-// Enable support for loop devices in mount
-#define BB_FEATURE_MOUNT_LOOP
-//
-// Enable support for a real /etc/mtab file instead of /proc/mounts
-//#define BB_FEATURE_MTAB_SUPPORT
-//
-// Enable support for mounting remote NFS volumes. 
-// You may need to mount with "-o nolock" if you are
-// not running a local portmapper daemon...
-#define BB_FEATURE_NFSMOUNT
-//
-// Enable support forced filesystem unmounting 
-// (i.e., in case of an unreachable NFS system).
-#define BB_FEATURE_MOUNT_FORCE
-//
-// Enable support for creation of tar files.
-#define BB_FEATURE_TAR_CREATE
-//
-// Enable support for "--exclude" and "-X" for excluding files
-#define BB_FEATURE_TAR_EXCLUDE
-//
-// Enable support for tar -z option (currently only works for inflating)
-#define BB_FEATURE_TAR_GZIP 
-//
-// Enable reverse sort
-#define BB_FEATURE_SORT_REVERSE
-//
-// Enable uniqe sort
-#define BB_FEATURE_SORT_UNIQUE
-//
-// Enable command line editing in the shell.  
-// Only relevant if a shell is enabled. On by default.
-#define BB_FEATURE_COMMAND_EDITING
-//
-// Enable tab completion in the shell.  This is now working quite nicely.
-// This feature adds a bit over 4k. Only relevant if a shell is enabled.
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-//
-// Attempts to match usernames in a ~-prefixed path
-//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-//
-//Allow the shell to invoke all the compiled in BusyBox applets as if they
-//were shell builtins.  Nice for staticly linking an emergency rescue shell,
-//among other things. Off by default.
-// Only relevant if a shell is enabled.
-#define BB_FEATURE_SH_STANDALONE_SHELL
-//
-//When this is enabled, busybox shell applets can be called using full path
-//names.  This causes applets (i.e., most busybox commands) to override
-//real commands on the filesystem.  For example, if you run run /bin/cat, it
-//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
-//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
-//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
-// Only relevant if a shell is enabled. Off by default.
-#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-//
-// Uncomment this option for a fancy shell prompt that includes the
-// current username and hostname.  On systems that don't have usernames
-// or hostnames, this can look hideous.
-// Only relevant if a shell is enabled.
-#define BB_FEATURE_SH_FANCY_PROMPT
-//
-//Turn on extra fbset options
-//#define BB_FEATURE_FBSET_FANCY
-//
-//Turn on fbset readmode support
-//#define BB_FEATURE_FBSET_READMODE
-//
-// Support insmod/lsmod/rmmod for post 2.1 kernels
-#define BB_FEATURE_NEW_MODULE_INTERFACE
-//
-// Support insmod/lsmod/rmmod for pre 2.1 kernels
-//#define BB_FEATURE_OLD_MODULE_INTERFACE
-//
-// Support module version checking
-//#define BB_FEATURE_INSMOD_VERSION_CHECKING
-//
-// Support for uClinux memory usage optimization, which will load the image
-// directly into the kernel memory.  This divides memory requrements by three.
-// If you are not running uClinux (i.e., your CPU has an MMU) leave this
-// disabled...
-//#define BB_FEATURE_INSMOD_LOADINKMEM
-//
-// Support for Minix filesystem, version 2
-//#define BB_FEATURE_MINIX2
-//
-// Enable ifconfig status reporting output -- this feature adds 12k.
-#define BB_FEATURE_IFCONFIG_STATUS
-//
-// Enable ifconfig slip-specific options "keepalive" and "outfill"
-//#define BB_FEATURE_IFCONFIG_SLIP
-//
-// Enable ifconfig options "mem_start", "io_addr", and "irq".
-//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-//
-// Enable ifconfig option "hw".  Currently works for only with "ether".
-#define BB_FEATURE_IFCONFIG_HW
-//
-// Enable busybox --install [-s]
-// to create links (or symlinks) for all the commands that are 
-// compiled into the binary.  (needs /proc filesystem)
-#define BB_FEATURE_INSTALLER
-//
-// Enable a nifty progress meter in wget (adds just under 2k)
-#define BB_FEATURE_WGET_STATUSBAR
-//
-// Enable HTTP authentication in wget
-#define BB_FEATURE_WGET_AUTHENTICATION
-//
-// Clean up all memory before exiting -- usually not needed
-// as the OS can clean up...  Don't enable this unless you
-// have a really good reason for cleaning things up manually.
-//#define BB_FEATURE_CLEAN_UP
-//
-// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
-#define BB_FEATURE_HUMAN_READABLE
-//
-// Support for the find -type option.
-#define BB_FEATURE_FIND_TYPE
-//
-// Support for the find -perm option.
-#define BB_FEATURE_FIND_PERM
-//
-// Support for the find -mtine option.
-#define BB_FEATURE_FIND_MTIME
-//
-// Support for the -A -B and -C context flags in grep
-//#define BB_FEATURE_GREP_CONTEXT
-//
-// Support for the EGREP applet (alias to the grep applet)
-//#define BB_FEATURE_GREP_EGREP_ALIAS
-//
-// Tell tftp what commands that should be supported.
-#define BB_FEATURE_TFTP_PUT
-#define BB_FEATURE_TFTP_GET
-//
-// features for vi
-#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
-#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
-#define BB_FEATURE_VI_SEARCH           // search and replace cmds
-#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
-#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
-#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
-#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
-#define BB_FEATURE_VI_SET              // :set
-#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
-//
-// Enable a if you system have setuped locale
-//#define BB_LOCALE_SUPPORT
-//
-// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
-#define BB_FEATURE_TELNET_TTYPE
-//
-// End of Features List
-//
-//
-//
-//
-//
-//
-//---------------------------------------------------
-// Nothing beyond this point should ever be touched by 
-// mere mortals so leave this stuff alone.
-//
-#include <features.h>
-#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
-       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
-       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
-       #undef BB_ASH                   /* Uses fork() */
-       #undef BB_HUSH                  /* Uses fork() */
-       #undef BB_LASH                  /* Uses fork() */
-       #undef BB_INIT                  /* Uses fork() */
-       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
-       #undef BB_SYSLOGD               /* Uses daemon() */
-       #undef BB_KLOGD                 /* Uses daemon() */
-       #undef BB_UPDATE                /* Uses daemon() */
-#endif
-#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
-       #if defined BB_FEATURE_COMMAND_EDITING
-               #define BB_CMDEDIT
-       #else
-               #undef BB_FEATURE_COMMAND_EDITING
-               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
-               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               #undef BB_FEATURE_SH_FANCY_PROMPT
-       #endif
-#else
-       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       #undef BB_FEATURE_SH_STANDALONE_SHELL
-       #undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-//
-#ifdef BB_KILLALL
-       #ifndef BB_KILL
-               #define BB_KILL
-       #endif
-#endif
-//
-#ifndef BB_INIT
-       #undef BB_FEATURE_LINUXRC
-#endif
-//
-#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
-       #define BB_NFSMOUNT
-#endif
-//
-#if defined BB_FEATURE_AUTOWIDTH
-       #ifndef BB_FEATURE_USE_TERMIOS
-               #define BB_FEATURE_USE_TERMIOS
-       #endif
-#endif
-//
-#if defined BB_INSMOD || defined BB_LSMOD
-       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
-               #define BB_FEATURE_NEW_MODULE_INTERFACE
-       #endif
-#endif
-//
-#ifdef BB_UNIX2DOS
-       #define BB_DOS2UNIX
-#endif 
-//
-#ifdef BB_SYSLOGD
-       #if defined BB_FEATURE_IPC_SYSLOG
-               #define BB_LOGREAD
-       #endif
-#endif
-//
-#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
-# define shell_main ash_main
-#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
-# define shell_main hush_main
-#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
-# define shell_main lash_main
-#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
-# define shell_main msh_main
-#endif
diff --git a/busybox/debian/Config.h-udeb b/busybox/debian/Config.h-udeb
deleted file mode 100644 (file)
index 4fb0597..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* vi: set sw=4 ts=4: */
-// This file defines the feature set to be compiled into busybox.
-// When you turn things off here, they won't be compiled in at all.
-//
-//// This file is parsed by sed.  You MUST use single line comments.
-//   i.e.,  //#define BB_BLAH
-//
-//
-// BusyBox Applications
-//#define BB_ADJTIMEX
-#define BB_AR
-//#define BB_ASH
-#define BB_BASENAME
-#define BB_CAT
-//#define BB_CHGRP
-#define BB_CHMOD
-#define BB_CHOWN
-#define BB_CHROOT
-#define BB_CHVT
-//#define BB_CLEAR
-//#define BB_CMP
-#define BB_CP
-//#define BB_CPIO
-#define BB_CUT
-//#define BB_DATE
-//#define BB_DC
-//#define BB_DD
-//#define BB_DEALLOCVT
-#define BB_DF
-#define BB_DIRNAME
-#define BB_DMESG
-//#define BB_DOS2UNIX
-//#define BB_DPKG
-//#define BB_DPKG_DEB
-//#define BB_DUTMP
-//#define BB_DU
-//#define BB_DUMPKMAP
-#define BB_ECHO
-#define BB_ENV
-#define BB_EXPR
-//#define BB_FBSET
-//#define BB_FDFLUSH
-#define BB_FIND
-#define BB_FREE
-#define BB_FREERAMDISK
-//#define BB_FSCK_MINIX
-//#define BB_GETOPT
-#define BB_GREP
-#define BB_GUNZIP
-//#define BB_GZIP
-//#define BB_HALT
-//#define BB_HEAD
-//#define BB_HOSTID
-//#define BB_HOSTNAME
-//#define BB_HUSH
-//#define BB_ID
-#define BB_IFCONFIG
-#define BB_INIT
-//#define BB_INSMOD
-#define BB_KILL
-//#define BB_KILLALL
-#define BB_KLOGD
-//#define BB_LASH
-//#define BB_LENGTH
-#define BB_LN
-//#define BB_LOADACM
-//#define BB_LOADFONT
-//#define BB_LOADKMAP
-//#define BB_LOGGER
-//#define BB_LOGNAME
-#define BB_LS
-#define BB_LSMOD
-//#define BB_MAKEDEVS
-#define BB_MD5SUM
-#define BB_MKDIR
-//#define BB_MKFIFO
-//#define BB_MKFS_MINIX
-#define BB_MKNOD
-//#define BB_MKSWAP
-//#define BB_MKTEMP
-//#define BB_MODPROBE
-//#define BB_MORE
-#define BB_MOUNT
-//#define BB_MSH
-//#define BB_MT
-#define BB_MV
-//#define BB_NC
-//#define BB_NSLOOKUP
-//#define BB_PIDOF
-#define BB_PING
-#define BB_PIVOT_ROOT
-//#define BB_POWEROFF
-//#define BB_PRINTF
-#define BB_PS
-#define BB_PWD
-//#define BB_RDATE
-//#define BB_READLINK
-#define BB_REBOOT
-//#define BB_RENICE
-//#define BB_RESET
-#define BB_RM
-#define BB_RMDIR
-//#define BB_RMMOD
-#define BB_ROUTE
-//#define BB_RPM2CPIO
-#define BB_SED
-//#define BB_SETKEYCODES
-//#define BB_SLEEP
-//#define BB_SORT
-//#define BB_STTY
-//#define BB_SWAPONOFF
-#define BB_SYNC
-#define BB_SYSLOGD
-#define BB_TAIL
-#define BB_TAR
-//#define BB_TEE
-//#define BB_TEST
-#define BB_TELNET
-//#define BB_TFTP
-//#define BB_TOUCH
-#define BB_TR
-//#define BB_TRACEROUTE
-#define BB_TRUE_FALSE
-//#define BB_TTY
-//#define BB_UNIX2DOS
-//#define BB_UUENCODE
-//#define BB_UUDECODE
-#define BB_UMOUNT
-//#define BB_UNIQ
-//#define BB_UNAME
-//#define BB_UPDATE
-//#define BB_UPTIME
-//#define BB_USLEEP
-//#define BB_VI
-//#define BB_WATCHDOG
-//#define BB_WC
-#define BB_WGET
-//#define BB_WHICH
-//#define BB_WHOAMI
-//#define BB_XARGS
-//#define BB_YES
-// End of Applications List
-//
-//
-//
-// ---------------------------------------------------------
-// This is where feature definitions go.  Generally speaking,
-// turning this stuff off makes things a bit smaller (and less 
-// pretty/useful).
-//
-//
-// If you enabled one or more of the shells, you may select which one
-// should be run when sh is invoked:
-//#define BB_FEATURE_SH_IS_ASH
-//#define BB_FEATURE_SH_IS_HUSH
-//#define BB_FEATURE_SH_IS_LASH
-#define BB_FEATURE_SH_IS_MSH
-//
-// BusyBox will, by default, malloc space for its buffers.  This costs code
-// size for the call to xmalloc.  You can use the following feature to have
-// them put on the stack.  For some very small machines with limited stack
-// space, this can be deadly.  For most folks, this works just fine...
-//#define BB_FEATURE_BUFFERS_GO_ON_STACK
-// The third alternative for buffer allocation is to use BSS.  This works
-// beautifully for computers with a real MMU (and OS support), but wastes
-// runtime RAM for uCLinux.  This behavior was the only one available for
-// BusyBox versions 0.48 and earlier.
-//#define BB_FEATURE_BUFFERS_GO_IN_BSS
-//
-// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
-// thereby eliminating the need for the /proc filesystem and thereby saving
-// lots and lots memory for more important things.  NOTE:  If you enable this
-// feature, you _must_ have patched the kernel to include the devps patch that
-// is included in the busybox/kernel-patches directory.  You will also need to
-// create some device special files in /dev on your embedded system:
-//        mknod /dev/mtab c 10 22
-//        mknod /dev/ps c 10 21
-// I emailed Linus and this patch will not be going into the stock kernel.
-//#define BB_FEATURE_USE_DEVPS_PATCH
-//
-// show verbose usage messages
-//#define BB_FEATURE_VERBOSE_USAGE
-//
-// Use termios to manipulate the screen ('more' is prettier with this on)
-#define BB_FEATURE_USE_TERMIOS
-//
-// calculate terminal & column widths (for more and ls)
-#define BB_FEATURE_AUTOWIDTH
-//
-// show username/groupnames for ls
-#define BB_FEATURE_LS_USERNAME
-//
-// show file timestamps in ls
-#define BB_FEATURE_LS_TIMESTAMPS
-//
-// enable ls -p and -F
-//#define BB_FEATURE_LS_FILETYPES
-//
-// sort the file names
-#define BB_FEATURE_LS_SORTFILES
-//
-// enable ls -R
-//#define BB_FEATURE_LS_RECURSIVE
-//
-// enable ls -L
-//#define BB_FEATURE_LS_FOLLOWLINKS
-//
-// Disable for a smaller (but less functional) ping
-#define BB_FEATURE_FANCY_PING
-//
-// Make init use a simplified /etc/inittab file (recommended).
-#define BB_FEATURE_USE_INITTAB
-//
-//Enable init being called as /linuxrc
-#define BB_FEATURE_LINUXRC
-//
-//Have init enable core dumping for child processes (for debugging only) 
-//#define BB_FEATURE_INIT_COREDUMPS
-//
-//Make sure nothing is printed to the console on boot
-//#define BB_FEATURE_EXTRA_QUIET
-//
-// enable syslogd -R remotehost
-//#define BB_FEATURE_REMOTE_LOG
-//
-// enable syslogd -C
-//#define BB_FEATURE_IPC_SYSLOG
-//
-//Disable for a simple tail implementation (2.34k vs 3k for the full one).
-//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
-//#define BB_FEATURE_FANCY_TAIL
-//
-// Enable support for loop devices in mount
-#define BB_FEATURE_MOUNT_LOOP
-//
-// Enable support for a real /etc/mtab file instead of /proc/mounts
-//#define BB_FEATURE_MTAB_SUPPORT
-//
-// Enable support for mounting remote NFS volumes. 
-// You may need to mount with "-o nolock" if you are
-// not running a local portmapper daemon...
-#define BB_FEATURE_NFSMOUNT
-//
-// Enable support forced filesystem unmounting 
-// (i.e., in case of an unreachable NFS system).
-#define BB_FEATURE_MOUNT_FORCE
-//
-// Enable support for creation of tar files.
-//#define BB_FEATURE_TAR_CREATE
-//
-// Enable support for "--exclude" and "-X" for excluding files
-//#define BB_FEATURE_TAR_EXCLUDE
-//
-// Enable support for tar -z option (currently only works for inflating)
-#define BB_FEATURE_TAR_GZIP 
-//
-// Enable reverse sort
-//#define BB_FEATURE_SORT_REVERSE
-//
-// Enable uniqe sort
-//#define BB_FEATURE_SORT_UNIQUE
-//
-// Enable command line editing in the shell.  
-// Only relevant if a shell is enabled. On by default.
-#define BB_FEATURE_COMMAND_EDITING
-//
-// Enable tab completion in the shell.  This is now working quite nicely.
-// This feature adds a bit over 4k. Only relevant if a shell is enabled.
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-//
-// Attempts to match usernames in a ~-prefixed path
-//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-//
-//Allow the shell to invoke all the compiled in BusyBox applets as if they
-//were shell builtins.  Nice for staticly linking an emergency rescue shell,
-//among other things. Off by default.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_STANDALONE_SHELL
-//
-//When this is enabled, busybox shell applets can be called using full path
-//names.  This causes applets (i.e., most busybox commands) to override
-//real commands on the filesystem.  For example, if you run run /bin/cat, it
-//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
-//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
-//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
-// Only relevant if a shell is enabled. Off by default.
-//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-//
-// Uncomment this option for a fancy shell prompt that includes the
-// current username and hostname.  On systems that don't have usernames
-// or hostnames, this can look hideous.
-// Only relevant if a shell is enabled.
-//#define BB_FEATURE_SH_FANCY_PROMPT
-//
-//Turn on extra fbset options
-//#define BB_FEATURE_FBSET_FANCY
-//
-//Turn on fbset readmode support
-//#define BB_FEATURE_FBSET_READMODE
-//
-// Support insmod/lsmod/rmmod for post 2.1 kernels
-//#define BB_FEATURE_NEW_MODULE_INTERFACE
-//
-// Support insmod/lsmod/rmmod for pre 2.1 kernels
-//#define BB_FEATURE_OLD_MODULE_INTERFACE
-//
-// Support module version checking
-//#define BB_FEATURE_INSMOD_VERSION_CHECKING
-//
-// Support for uClinux memory usage optimization, which will load the image
-// directly into the kernel memory.  This divides memory requrements by three.
-// If you are not running uClinux (i.e., your CPU has an MMU) leave this
-// disabled...
-//#define BB_FEATURE_INSMOD_LOADINKMEM
-//
-// Support for Minix filesystem, version 2
-//#define BB_FEATURE_MINIX2
-//
-// Enable ifconfig status reporting output -- this feature adds 12k.
-#define BB_FEATURE_IFCONFIG_STATUS
-//
-// Enable ifconfig slip-specific options "keepalive" and "outfill"
-//#define BB_FEATURE_IFCONFIG_SLIP
-//
-// Enable ifconfig options "mem_start", "io_addr", and "irq".
-//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-//
-// Enable ifconfig option "hw".  Currently works for only with "ether".
-#define BB_FEATURE_IFCONFIG_HW
-//
-// Enable busybox --install [-s]
-// to create links (or symlinks) for all the commands that are 
-// compiled into the binary.  (needs /proc filesystem)
-//#define BB_FEATURE_INSTALLER
-//
-// Enable a nifty progress meter in wget (adds just under 2k)
-#define BB_FEATURE_WGET_STATUSBAR
-//
-// Enable HTTP authentication in wget
-//#define BB_FEATURE_WGET_AUTHENTICATION
-//
-// Clean up all memory before exiting -- usually not needed
-// as the OS can clean up...  Don't enable this unless you
-// have a really good reason for cleaning things up manually.
-//#define BB_FEATURE_CLEAN_UP
-//
-// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
-//#define BB_FEATURE_HUMAN_READABLE
-//
-// Support for the find -type option.
-#define BB_FEATURE_FIND_TYPE
-//
-// Support for the find -perm option.
-#define BB_FEATURE_FIND_PERM
-//
-// Support for the find -mtine option.
-#define BB_FEATURE_FIND_MTIME
-//
-// Support for the -A -B and -C context flags in grep
-//#define BB_FEATURE_GREP_CONTEXT
-//
-// Support for the EGREP applet (alias to the grep applet)
-//#define BB_FEATURE_GREP_EGREP_ALIAS
-//
-// Tell tftp what commands that should be supported.
-#define BB_FEATURE_TFTP_PUT
-#define BB_FEATURE_TFTP_GET
-//
-// features for vi
-#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
-#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
-#define BB_FEATURE_VI_SEARCH           // search and replace cmds
-#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
-#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
-#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
-#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
-#define BB_FEATURE_VI_SET              // :set
-#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
-//
-// Enable a if you system have setuped locale
-//#define BB_LOCALE_SUPPORT
-//
-// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
-#define BB_FEATURE_TELNET_TTYPE
-//
-// End of Features List
-//
-//
-//
-//
-//
-//
-//---------------------------------------------------
-// Nothing beyond this point should ever be touched by 
-// mere mortals so leave this stuff alone.
-//
-#include <features.h>
-#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__
-       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
-       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
-       #undef BB_ASH                   /* Uses fork() */
-       #undef BB_HUSH                  /* Uses fork() */
-       #undef BB_LASH                  /* Uses fork() */
-       #undef BB_INIT                  /* Uses fork() */
-       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
-       #undef BB_SYSLOGD               /* Uses daemon() */
-       #undef BB_KLOGD                 /* Uses daemon() */
-       #undef BB_UPDATE                /* Uses daemon() */
-#endif
-#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
-       #if defined BB_FEATURE_COMMAND_EDITING
-               #define BB_CMDEDIT
-       #else
-               #undef BB_FEATURE_COMMAND_EDITING
-               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
-               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               #undef BB_FEATURE_SH_FANCY_PROMPT
-       #endif
-#else
-       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       #undef BB_FEATURE_SH_STANDALONE_SHELL
-       #undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-//
-#ifdef BB_KILLALL
-       #ifndef BB_KILL
-               #define BB_KILL
-       #endif
-#endif
-//
-#ifndef BB_INIT
-       #undef BB_FEATURE_LINUXRC
-#endif
-//
-#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
-       #define BB_NFSMOUNT
-#endif
-//
-#if defined BB_FEATURE_AUTOWIDTH
-       #ifndef BB_FEATURE_USE_TERMIOS
-               #define BB_FEATURE_USE_TERMIOS
-       #endif
-#endif
-//
-#if defined BB_INSMOD || defined BB_LSMOD
-       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
-               #define BB_FEATURE_NEW_MODULE_INTERFACE
-       #endif
-#endif
-//
-#ifdef BB_UNIX2DOS
-       #define BB_DOS2UNIX
-#endif 
-//
-#ifdef BB_SYSLOGD
-       #if defined BB_FEATURE_IPC_SYSLOG
-               #define BB_LOGREAD
-       #endif
-#endif
-//
-#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
-# define shell_main ash_main
-#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
-# define shell_main hush_main
-#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
-# define shell_main lash_main
-#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
-# define shell_main msh_main
-#endif
diff --git a/busybox/debian/README.debian b/busybox/debian/README.debian
deleted file mode 100644 (file)
index f210a3e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-BusyBox for Debian
-----------------------
-
-BusyBox is being developed and maintained by Erik Andersen
-<andersee@debian.org>.
-
-If you have a problem with BusyBox, send email to the Debian bug tracking
-system that lives at <submit@bugs.lineo.com> 
-
-Erik Andersen <andersee@debian.org>, Sun, 18 Jun 2000 21:52:00 -0600
diff --git a/busybox/debian/changelog b/busybox/debian/changelog
deleted file mode 100644 (file)
index 4b719e2..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-busybox (1:0.60.2-1) unstable; urgency=low
-
-  * New stable version released.  See changelog for details.
-  * Teaches 'mount -t auto' to ignore usbdevfs, thanks to
-    Ethan Benson <erbenson@alaska.net> (closes: #111055)
-  * Removes all the .o files from the source tarball (oops!)
-    thanks to Matt Kraai, who noticed.
-
- -- Erik Andersen <andersee@debian.org>  Thu, 23 Aug 2001 15:44:14 -0600
-
-busybox (1:0.60.1-1) unstable; urgency=low
-
-  * New stable version released.  See changelog for details.
-  * Enabled 'ar' for the udeb
-
- -- Erik Andersen <andersee@debian.org>  Thu, 23 Aug 2001 15:44:14 -0600
-
-busybox (1:0.60.0-1) unstable; urgency=low
-
-  * New stable version released.  See changelog for details.
-
- -- Erik Andersen <andersee@debian.org>  Thu,  2 Aug 2001 12:12:37 -0600
-
-busybox (1:0.52-1.1) unstable; urgency=high
-
-  * Non-maintainer upload
-  * Fixed wget -P handling (closes: #106223).
-
- -- Matt Kraai <kraai@debian.org>  Wed, 25 Jul 2001 11:01:38 -0600
-
-busybox (1:0.52-1) unstable; urgency=high
-
-  * New version released.  See changelog for details.
-
- -- Erik Andersen <andersee@debian.org>  Sat,  7 Jul 2001 01:23:45 -0600
-
-busybox (1:0.51-10) unstable; urgency=high
-
-  * Fix a compile problem with gcc 3.0 on hppa (closes: #102045)
-
- -- Erik Andersen <andersee@debian.org>  Sat, 23 Jun 2001 23:55:57 -0600
-
-busybox (1:0.51-9) unstable; urgency=high
-
-  * tar was creating leading directories with 0777 permissions as
-    as reult of faulty umask handling.  This fixes it, repairing
-    a grave security problem in the woody the boot floppies.
-    (closes: #101169)
-
- -- Erik Andersen <andersee@debian.org>  Wed, 20 Jun 2001 16:17:38 -0600
-
-busybox (1:0.51-8) unstable; urgency=high
-
-  * Fix cp from /proc, where size=0 (closes: #100369)
-  * Add some padding to struct sysinfo for m68k.
-  * Apparently some bugs failed to be closed when master choked
-    (closes: #99627, #99637, #98571)
-  * Disable the busybox shell for the .deb, since it is not needed
-    for the boot floppies.
-
- -- Erik Andersen <andersee@debian.org>  Mon, 11 Jun 2001 13:26:07 -0600
-
-busybox (1:0.51-7) unstable; urgency=high
-
-  * Fix tar permission setting for existing directories (closes: #99627)
-  * Do not remove the .cvsignore files on 'make release' (closes: #99637)
-
- -- Erik Andersen <andersee@debian.org>  Mon,  4 Jun 2001 10:55:19 -0600
-
-busybox (1:0.51-6) testing unstable; urgency=high
-
-  * Update the version in testing so DHCP in the woody boot-floppies will work.
-  * Enable expr for the boot-floppies (closes: #98433)
-  * It builds on arm just fine now (closes: #97510)
-
- -- Erik Andersen <andersee@debian.org>  Wed, 23 May 2001 14:50:13 -0600
-
-busybox (1:0.51-5) unstable; urgency=low
-
-  * Backport a sed fix from 0.52pre
-  * Backport chroot fix from 0.52pre
-
- -- Erik Andersen <andersee@debian.org>  Wed, 16 May 2001 23:50:33 -0600
-
-busybox (1:0.51-4) unstable; urgency=low
-
-  * Backport from 0.52pre an endianness bugfix for md5sum
-  * Backport some updates to grep and sed
-  * Fix 'wget -O -' so it sets the quiet flag
-
- -- Erik Andersen <andersee@debian.org>  Mon, 14 May 2001 14:17:36 -0600
-
-busybox (1:0.51-3) unstable; urgency=low
-
-  * This is the "I am an idiot" release.
-  * Make cp and mv work again (closes: #97290) 
-  * Fix the version number.
-
- -- Erik Andersen <andersee@debian.org>  Sat, 12 May 2001 17:35:58 -0600
-
-busybox (0.51-2) unstable; urgency=low
-
-  * Backport several release critical fixes into the 0.51 codebase
-    so the boot-floppies will work again.
-  * Fix a link ordering problem. (closes: #93362)
-  * Fixed gunzip (closes: #94331)
-  * Fixed cp permission setting (closes: #94580)
-
- -- Erik Andersen <andersee@debian.org>  Sat, 12 May 2001 11:22:35 -0600
-
-busybox (0.51-1) unstable; urgency=low
-
-  * Fixes several critical bugs (see the busybox changelog
-    for complete details)
-  * Force USE_SYSTEM_PWD_GRP=false, so busybox bypasses
-    the glibc NSS libraries. (closes: #93362)
-  * Fixed a bug in sed's address range handling (closes: #91758) 
-  * Removed irrelevant cruft from the bottem of debian/changelog
-
- -- Erik Andersen <andersee@debian.org>  Tue, 10 Apr 2001 14:07:29 -0600
-
-busybox (0.50-2) unstable; urgency=low
-  
-  * Enabled freeramdisk and pivot_root in the udeb (closes: #91336)
-  * Disabled lash (the busybox shell) in the udeb (closes: #91337)
-  * fixed a bug in syslog, a problem with rebooting when booted as
-    an initrd, and a few other minor problems.
-
- -- Erik Andersen <andersee@debian.org>  Sun, 25 Mar 2001 20:59:44 -0700
-
-
-busybox (0.50-2) unstable; urgency=low
-  
-  * Enabled freeramdisk and pivot_root in the udeb (closes: #91336)
-  * Disabled lash (the busybox shell) in the udeb (closes: #91337)
-  * fixed a bug in syslog, a problem with rebooting when booted as
-    an initrd, and a few other minor problems.
-
- -- Erik Andersen <andersee@debian.org>  Sun, 25 Mar 2001 20:59:44 -0700
-
-busybox (0.50-1) unstable; urgency=low
-
-  * Tons on improvements all around -- See changelog for details.
-  * Fix malformed Build-Depends (closes: #86930)
-  * grep has worked for some time now (closes: #81084)
-  * init compiles with DEBUG_INIT enabled (closes: #85794)
-  * md5sum no longer displays filename when reading stdin (closes: #81283)
-  * lsmod, rmmod, and insmod are no longer enabled (closes: #85642)
-  * busybox and buxybox-static now conflict/replace each other (closes: #80421)
-
- -- Erik Andersen <andersee@debian.org>  Thu, 15 Mar 2001 14:45:00 -0700
-
-busybox (0.49-1) unstable; urgency=low
-
-  * Lots more source updates and bug fixes.  See changelog for details.
-
- -- Erik Andersen <andersee@debian.org>  Sat, 27 Jan 2001 01:45:53 -0700
-
-busybox (0.48-1) unstable; urgency=low
-
-  * Lots more source updates and bug fixes.  See changelog for details.
-  * Now includes .udeb support for the debian-installer.  The .udeb 
-    probably needs some more work, but this should be a good start.
-
- -- Erik Andersen <andersee@debian.org>  Wed, 13 Dec 2000 08:36:07 -0700
-
-busybox (0.47-1) unstable; urgency=low
-
-  * New version released.  See changelog for details.
-
- -- Erik Andersen <andersee@debian.org>  Mon, 25 Sep 2000 23:00:56 -0600
-
-busybox (0.46-1) unstable; urgency=low
-
-  * New version released.  See changelog for details.
-
- -- Erik Andersen <andersee@debian.org>  Tue, 11 Jul 2000 12:15:44 -0600
-
-busybox (0.45-1) unstable; urgency=low
-
-  * First attempt at packaging BusyBox as a .deb.  This has been in 
-    in the Debian boot-floppies CVS tree forever.  Hopefully, having it as a
-    standalone app will make life easier for me, the debian-installer team, and
-    everyone else as well...
-  * I have created a busybox-static that can be used as a rescue shell when you 
-    hose your system.  Just invoke "busybox sh" to fir up the shell.  This has
-    every app provided by busybox staically linked in.  There have been several
-    times in the past that I would have loved to have this sitting on my system
-    (i.e. when libc gets screwed up.)
-
- -- Erik Andersen <andersee@debian.org>  Tue, 27 Jun 2000 12:26:41 -0600
-
diff --git a/busybox/debian/control b/busybox/debian/control
deleted file mode 100644 (file)
index 3626718..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-Source: busybox
-Priority: optional
-Maintainer: Erik Andersen <andersee@debian.org>
-Build-Depends: debhelper (>= 2.1.18), dpkg-dev (>= 1.7.0)
-Standards-Version: 3.2.1.0
-
-Package: busybox
-Architecture: any
-Depends: ${shlibs:Depends}
-Conflicts: busybox-static
-Replaces: busybox-static 
-Section: utils
-Description: Tiny utilities for small and embedded systems. 
- BusyBox combines tiny versions of many common UNIX utilities into a single
- small executable. It provides minimalist replacements for the most common
- utilities you would usually find on your desktop system (i.e., ls, cp, mv,
- mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
- their full-featured GNU cousins; however, the options that are included
- provide the expected functionality and behave very much like their GNU
- counterparts.
- .
- This package installs the BusyBox binary but does not install symlinks
- for any of the supported utilities.  You can use /bin/busybox --install
- to install BusyBox to the current directory (you do not want to do this
- in / on your Debian system!).
-
-Package: busybox-static
-Architecture: any
-Depends: ${shlibs:Depends}
-Conflicts: busybox
-Replaces: busybox
-Section: shells
-Description: Standalone rescue shell with tons of builtin utilities. 
- BusyBox combines tiny versions of many common UNIX utilities into a single
- small executable. It provides minimalist replacements for the most common
- utilities you would usually find on your desktop system (i.e., ls, cp, mv,
- mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
- their full-featured GNU cousins; however, the options that are included
- provide the expected functionality and behave very much like their GNU
- counterparts.
- .
- BusyBox-static provides you with a statically linked simple stand alone shell
- that provides all the utilities available in BusyBox.  This package is
- intended to be used as a rescue shell, in the event that you screw up your
- system.  Invoke "busybox sh" and you have a standalone shell ready to save
- your system from certain destruction.  Invoke "busybox", and it will list the
- available builtin commands.
-
-Package: busybox-udeb
-Architecture: any
-Depends: ${shlibs:Depends}
-Section: debian-installer
-Priority: standard
-Description: Tiny utilities for the debian-installer
- BusyBox combines tiny versions of many common UNIX utilities into a single
- small executable. It provides minimalist replacements for the most common
- utilities you would usually find on your desktop system (i.e., ls, cp, mv,
- mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
- their full-featured GNU cousins; however, the options that are included
- provide the expected functionality and behave very much like their GNU
- counterparts.
- .
- busybox-udeb is used by the debian-installer, so unless you are working
- on the debian-installer, this package is not for you.  Installing this 
- on your Debian system is a very, very bad idea.  You have been warned.
-
diff --git a/busybox/debian/copyright b/busybox/debian/copyright
deleted file mode 100644 (file)
index 68a96e6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-This package was debianized by Erik Andersen <andersee@debian.org> on
-Sun, 18 Jun 2000 23:31:02 -0600
-
-It was downloaded from ftp://ftp.lineo.com/pub/busybox
-HomePage is at: http://busybox.lineo.com/
-
-Copyright: GPL
diff --git a/busybox/debian/rules b/busybox/debian/rules
deleted file mode 100755 (executable)
index 1d7413c..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/make -f
-
-# This is a bit unusual, in that I have to completely recompile everything
-# for each package I build (obviously static and dynamic builds require
-# things to be recompiled...)
-
-# This is the debhelper compatability version to use.
-#export DH_COMPAT=1
-
-bbbd=debian/busybox_builddir
-bb=debian/tmp
-bbsbd=debian/busybox_static_builddir
-bbs=debian/busybox-static
-bbubd=debian/busybox_udeb_builddir
-bbu=debian/busybox-udeb
-
-clean:
-       dh_testdir
-       dh_testroot
-       rm -f debian/build-stamp-busybox debian/build-stamp-busybox-static debian/build-stamp-busybox-udeb
-       -$(MAKE) clean
-       -rm -rf $(bb) $(bbbd) $(bbs) $(bbsbd) $(bbubd) $(bbu)
-       dh_clean
-
-build: debian/build-stamp-busybox
-debian/build-stamp-busybox:
-       dh_testdir
-       mkdir -p $(bbbd)
-       cp Makefile $(bbbd)
-       cp debian/Config.h-deb $(bbbd)/Config.h
-       -(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" applet_source_list)
-       (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
-       touch debian/build-stamp-busybox
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k
-       dh_installdirs
-       # Do not run 'make install', since we do not want all the symlinks. 
-       # This just installes the busybox binary...
-       #(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bb)" install)
-       mkdir -p $(bb)/bin/
-       cp $(bbbd)/busybox $(bb)/bin/busybox
-       mkdir -p $(bb)/usr/share/doc/busybox/busybox.lineo.com
-       cp $(bbbd)/docs/busybox.lineo.com/BusyBox.html $(bb)/usr/share/doc/busybox/busybox.lineo.com/
-       mkdir -p $(bb)/usr/share/man/man1
-       cp $(bbbd)/docs/BusyBox.1 $(bb)/usr/share/man/man1/busybox.1
-
-# Now for the statically linked stuff
-build-static: debian/build-stamp-busybox-static
-debian/build-stamp-busybox-static:
-       dh_testdir
-       mkdir -p $(bbsbd)
-       cp Makefile $(bbsbd)
-       cp debian/Config.h-static $(bbsbd)/Config.h
-       (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
-       touch debian/build-stamp-busybox-static
-
-install-static: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k
-       dh_installdirs
-       # Do not run 'make install', since we do not want all the symlinks. 
-       # This just installes the busybox binary...
-       #(cd $(bbsbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbs)" install)
-       mkdir -p $(bbs)/bin/
-       cp $(bbsbd)/busybox $(bbs)/bin/busybox
-       mkdir -p $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com
-       cp $(bbsbd)/docs/busybox.lineo.com/BusyBox.html $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com/
-       mkdir -p $(bbs)/usr/share/man/man1/
-       cp $(bbsbd)/docs/BusyBox.1 $(bbs)/usr/share/man/man1/busybox.1
-
-half_clean:
-       dh_testdir
-       dh_testroot
-       rm -rf $(bbs) debian/build-stamp-busybox-static
-       -$(MAKE) clean
-
-do_static: half_clean build-static install-static
-
-
-
-# Now for the .udeb stuff
-PACKAGE=busybox-udeb
-VERSION=$(shell dpkg-parsechangelog | grep ^Version: | cut -d ' ' -f 2 | sed -e s/[0-9]://g)
-ARCH=$(shell dpkg --print-architecture)
-FILENAME=$(PACKAGE)_$(VERSION)_$(ARCH).udeb
-
-build-udeb: debian/build-stamp-busybox-udeb
-debian/build-stamp-busybox-udeb:
-       dh_testdir
-       mkdir -p $(bbubd)
-       cp Makefile $(bbubd)
-       cp debian/Config.h-udeb $(bbubd)/Config.h
-       (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
-       touch debian/build-stamp-busybox-udeb
-
-install-udeb: build
-       dh_testdir
-       dh_testroot
-       dh_clean -k
-       dh_installdirs
-       (cd $(bbubd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbu)" install)
-       mkdir -p $(bbu)/usr/share/man/man1/
-       cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1
-
-three_quarter_clean:
-       dh_testdir
-       dh_testroot
-       rm -rf $(bbu) debian/build-stamp-busybox-udeb
-       -$(MAKE) clean
-
-do_udeb: three_quarter_clean build-udeb install-udeb
-
-
-
-# Build architecture-independent files here.
-binary-indep:
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: busybox busybox-static busybox-udeb
-
-busybox: install
-       @echo "--- Building: $@"
-       dh_testdir
-       dh_testroot
-       dh_installdirs
-       dh_installdocs       -p$@  $(bbbd)/docs/BusyBox.txt \
-               $(bbbd)/docs/BusyBox.html docs/style-guide.txt \
-               docs/busybox.lineo.com AUTHORS README TODO
-       rm -rf `find $(bb) -name CVS`
-       rm -f `find $(bb) -name .cvsignore`
-       dh_installchangelogs -p$@ Changelog
-       dh_undocumented      -p$@
-       dh_strip             -p$@
-       dh_compress          -p$@
-       dh_fixperms          -p$@
-       dh_installdeb        -p$@
-       dh_shlibdeps         -p$@
-       dh_gencontrol        -p$@
-       dh_md5sums           -p$@
-       dh_builddeb          -p$@
-
-
-busybox-static: do_static
-       @echo "--- Building: $@"
-       dh_testdir
-       dh_testroot
-       dh_installdirs
-       dh_installdocs       -p$@  $(bbsbd)/docs/BusyBox.txt \
-               $(bbsbd)/docs/BusyBox.html docs/style-guide.txt \
-               docs/busybox.lineo.com AUTHORS README TODO
-       rm -rf `find $(bbs) -name CVS`
-       rm -f `find $(bbs) -name .cvsignore`
-       dh_installchangelogs -p$@ Changelog
-       dh_undocumented      -p$@
-       dh_strip             -p$@
-       dh_compress          -p$@
-       dh_fixperms          -p$@
-       dh_installdeb        -p$@
-       dh_shlibdeps         -p$@
-       dh_gencontrol        -p$@
-       dh_md5sums           -p$@
-       dh_builddeb          -p$@
-
-
-# Note that this builds a .udeb, which is not policy compliant or anything.
-#
-busybox-udeb: do_udeb
-       @echo "--- Building: $@"
-       dh_testdir
-       dh_testroot
-       dh_installdirs
-       dh_strip             -p$@
-       dh_compress          -p$@
-       dh_fixperms          -p$@
-       dh_installdeb        -p$@
-       dh_shlibdeps         -p$@
-       #Make _very_ sure there are no docs lurking about.
-       rm -rf $(bbu)/usr/share/man
-       #dh_gencontrol        -p$@
-       # Don't write your stupid guesses to debian/files.
-       dh_gencontrol        -p$@ -- -fdebian/files~
-       # Register file manually.
-       dpkg-distaddfile $(FILENAME) debian-installer standard
-       dh_md5sums           -p$@
-       dh_builddeb          -p$@ --filename=$(FILENAME)
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff --git a/busybox/df.c b/busybox/df.c
deleted file mode 100644 (file)
index 8cb13fa..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini df implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mntent.h>
-#include <sys/vfs.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern const char mtab_file[]; /* Defined in utility.c */
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long df_disp_hr = KILOBYTE; 
-#endif
-
-static int do_df(char *device, const char *mount_point)
-{
-       struct statfs s;
-       long blocks_used;
-       long blocks_percent_used;
-
-       if (statfs(mount_point, &s) != 0) {
-               perror_msg("%s", mount_point);
-               return FALSE;
-       }
-
-       if (s.f_blocks > 0) {
-               blocks_used = s.f_blocks - s.f_bfree;
-               if(blocks_used == 0)
-                       blocks_percent_used = 0;
-               else {
-                       blocks_percent_used = (long)
-                         (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
-               }
-               if (strcmp(device, "/dev/root") == 0) {
-                       /* Adjusts device to be the real root device,
-                        * or leaves device alone if it can't find it */
-                       device = find_real_root_device_name(device);
-                       if(device==NULL)
-                               return FALSE;
-               }
-#ifdef BB_FEATURE_HUMAN_READABLE
-               printf("%-20s %9s ", device,
-                               make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
-
-               printf("%9s ",
-                               make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr));
-
-               printf("%9s %3ld%% %s\n",
-                               make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
-                               blocks_percent_used, mount_point);
-#else
-               printf("%-20s %9ld %9ld %9ld %3ld%% %s\n",
-                               device,
-                               (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)),
-                               (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)),
-                               (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)),
-                               blocks_percent_used, mount_point);
-#endif
-       }
-
-       return TRUE;
-}
-
-extern int df_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int opt = 0;
-       int i = 0;
-       char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */
-
-       while ((opt = getopt(argc, argv, "k"
-#ifdef BB_FEATURE_HUMAN_READABLE
-       "hm"
-#endif
-)) > 0)
-       {
-               switch (opt) {
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h':
-                               df_disp_hr = 0;
-                               strcpy(disp_units_hdr, "     Size");
-                               break;
-                       case 'm':
-                               df_disp_hr = MEGABYTE;
-                               strcpy(disp_units_hdr, "1M-blocks");
-                               break;
-#endif
-                       case 'k':
-                               /* default display is kilobytes */
-                               break;
-                       default:
-                                         show_usage();
-               }
-       }
-
-       printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr,
-              "Used", "Available", "Use%", "Mounted on");
-
-       if(optind < argc) {
-               struct mntent *mount_entry;
-               for(i = optind; i < argc; i++)
-               {
-                       if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) {
-                               error_msg("%s: can't find mount point.", argv[i]);
-                               status = EXIT_FAILURE;
-                       } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
-                               status = EXIT_FAILURE;
-               }
-       } else {
-               FILE *mount_table;
-               struct mntent *mount_entry;
-
-               mount_table = setmntent(mtab_file, "r");
-               if (mount_table == 0) {
-                       perror_msg("%s", mtab_file);
-                       return EXIT_FAILURE;
-               }
-
-               while ((mount_entry = getmntent(mount_table))) {
-                       if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
-                               status = EXIT_FAILURE;
-               }
-               endmntent(mount_table);
-       }
-
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/dirname.c b/busybox/dirname.c
deleted file mode 100644 (file)
index b534e69..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dirname implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-extern int dirname_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-'))
-               show_usage();
-       argv++;
-
-       puts (dirname (argv[0]));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/dmesg.c b/busybox/dmesg.c
deleted file mode 100644 (file)
index 73de6d1..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* dmesg.c -- Print out the contents of the kernel ring buffer
- * Created: Sat Oct  9 16:19:47 1993
- * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
- * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
- * This program comes with ABSOLUTELY NO WARRANTY.
- * Modifications by Rick Sladkey (jrs@world.std.com)
- * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
- * by Peeter Joot.  This was also suggested by John Hudson.
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- * from util-linux -- adapted for busybox by 
- * Erik Andersen <andersee@debian.org>. I ripped out Native Language 
- * Support, replaced getopt, added some gotos for redundant stuff.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-
-#if __GNU_LIBRARY__ < 5
-# ifdef __alpha__
-#   define klogctl syslog
-# endif
-#else
-# include <sys/klog.h>
-#endif
-
-#include "busybox.h"
-
-int dmesg_main(int argc, char **argv)
-{
-       char *buf;
-       int c;
-       int bufsize = 8196;
-       int i;
-       int n;
-       int level = 0;
-       int lastc;
-       int cmd = 3;
-
-       while ((c = getopt(argc, argv, "cn:s:")) != EOF) {
-               switch (c) {
-               case 'c':
-                       cmd = 4;
-                       break;
-               case 'n':
-                       cmd = 8;
-                       if (optarg == NULL)
-                               show_usage();
-                       level = atoi(optarg);
-                       break;
-               case 's':
-                       if (optarg == NULL)
-                               show_usage();
-                       bufsize = atoi(optarg);
-                       break;
-               default:
-                       show_usage();
-               }
-       }                       
-
-       if (optind < argc) {
-               show_usage();
-       }
-
-       if (cmd == 8) {
-               if (klogctl(cmd, NULL, level) < 0)
-                       perror_msg_and_die("klogctl");
-               return EXIT_SUCCESS;
-       }
-
-       if (bufsize < 4096)
-               bufsize = 4096;
-       buf = (char *) xmalloc(bufsize);
-       if ((n = klogctl(cmd, buf, bufsize)) < 0)
-               perror_msg_and_die("klogctl");
-
-       lastc = '\n';
-       for (i = 0; i < n; i++) {
-               if (lastc == '\n' && buf[i] == '<') {
-                       i++;
-                       while (buf[i] >= '0' && buf[i] <= '9')
-                               i++;
-                       if (buf[i] == '>')
-                               i++;
-               }
-               lastc = buf[i];
-               putchar(lastc);
-       }
-       if (lastc != '\n')
-               putchar('\n');
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/docs/.cvsignore b/busybox/docs/.cvsignore
deleted file mode 100644 (file)
index ec9e94b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-BusyBox.txt
-BusyBox.1
-BusyBox.html
-busybox.txt
-busybox.ps
-busybox.pdf
-busybox
-busybox.pod
diff --git a/busybox/docs/autodocifier.pl b/busybox/docs/autodocifier.pl
deleted file mode 100755 (executable)
index d753300..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-#!/usr/bin/perl -w
-
-use strict;
-use Getopt::Long;
-
-# collect lines continued with a '\' into an array 
-sub continuation {
-       my $fh = shift;
-       my @line;
-
-       while (<$fh>) {
-               my $s = $_;
-               $s =~ s/\\\s*$//;
-               #$s =~ s/#.*$//;
-               push @line, $s;
-               last unless (/\\\s*$/);
-       }
-       return @line;
-}
-
-# regex && eval away unwanted strings from documentation
-sub beautify {
-       my $text = shift;
-       $text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg;
-       $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
-       $text =~ s/"\s*"//sg;
-       my @line = split("\n", $text);
-       $text = join('',
-               map { 
-                       s/^\s*"//;
-                       s/"\s*$//;
-                       s/%/%%/g;
-                       s/\$/\\\$/g;
-                       eval qq[ sprintf(qq{$_}) ]
-               } @line
-       );
-       return $text;
-}
-
-# generate POD for an applet
-sub pod_for_usage {
-       my $name  = shift;
-       my $usage = shift;
-
-       # make options bold
-       my $trivial = $usage->{trivial};
-       $trivial =~ s/(?<!\w)(-\w+)/B<$1>/sxg;
-       my @f0 = 
-               map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/g; $_ }
-               split("\n", $usage->{full});
-
-       # add "\n" prior to certain lines to make indented
-       # lines look right
-       my @f1;
-       my $len = @f0;
-       for (my $i = 0; $i < $len; $i++) {
-               push @f1, $f0[$i];
-               if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) {
-                       next if ($f0[$i] =~ /^$/);
-                       push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s);
-               }
-       }
-       my $full = join("\n", @f1);
-
-       # prepare notes if they exist
-       my $notes = (defined $usage->{notes})
-               ? "$usage->{notes}\n\n"
-               : "";
-
-       # prepare examples if they exist
-       my $example = (defined $usage->{example})
-               ?  
-                       "Example:\n\n" .
-                       join ("\n", 
-                       map  { "\t$_" } 
-                       split("\n", $usage->{example})) . "\n\n"
-               : "";
-
-       return
-               "=item B<$name>".
-               "\n\n"  .
-               "$name $trivial".
-               "\n\n"  .
-               $full   .
-               "\n\n"  .
-               $notes  .
-               $example.
-               "-------------------------------".
-               "\n\n"
-       ;
-}
-
-# FIXME | generate SGML for an applet
-sub sgml_for_usage {
-       my $name  = shift;
-       my $usage = shift;
-       return
-               "<fixme>\n".
-               "  $name\n".
-               "</fixme>\n"
-       ;
-}
-
-# the keys are applet names, and 
-# the values will contain hashrefs of the form:
-#
-# {
-#     trivial => "...",
-#     full    => "...",
-#     notes   => "...",
-#     example => "...",
-# }
-my %docs;
-
-
-# get command-line options
-
-my %opt;
-
-GetOptions(
-       \%opt,
-       "help|h",
-       "sgml|s",
-       "pod|p",
-       "verbose|v",
-);
-
-if (defined $opt{help}) {
-       print
-               "$0 [OPTION]... [FILE]...\n",
-               "\t--help\n",
-               "\t--sgml\n",
-               "\t--pod\n",
-               "\t--verbose\n",
-       ;
-       exit 1;
-}
-
-
-# collect documenation into %docs
-
-foreach (@ARGV) {
-       open(USAGE, $_) || die("$0: $_: $!");
-       my $fh = *USAGE;
-       my ($applet, $type, @line);
-       while (<$fh>) {
-               if (/^#define (\w+)_(\w+)_usage/) {
-                       $applet = $1;
-                       $type   = $2;
-                       @line   = continuation($fh);
-                       my $doc = $docs{$applet} ||= { };
-                       my $text      = join("\n", @line);
-                       $doc->{$type} = beautify($text);
-               }
-       }
-}
-
-
-# generate structured documentation
-
-my $generator = \&pod_for_usage;
-if (defined $opt{sgml}) {
-       $generator = \&sgml_for_usage;
-}
-
-foreach my $applet (sort keys %docs) {
-       print $generator->($applet, $docs{$applet});
-}
-
-exit 0;
-
-__END__
-
-=head1 NAME
-
-autodocifier.pl - generate docs for busybox based on usage.h
-
-=head1 SYNOPSIS
-
-autodocifier.pl [OPTION]... [FILE]...
-
-Example:
-
-    ( cat docs/busybox_header.pod; \
-      docs/autodocifier.pl usage.h; \
-      cat docs/busybox_footer.pod ) > docs/busybox.pod
-
-=head1 DESCRIPTION
-
-The purpose of this script is to automagically generate documentation
-for busybox using its usage.h as the original source for content.
-Currently, the same content has to be duplicated in 3 places in
-slightly different formats -- F<usage.h>, F<docs/busybox.pod>, and
-F<docs/busybox.sgml>.  This is tedious, so Perl has come to the rescue.
-
-This script was based on a script by Erik Andersen <andersen@lineo.com>
-which was in turn based on a script by Mark Whitley <markw@lineo.com>
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<--help>
-
-This displays the help message.
-
-=item B<--pod>
-
-Generate POD (this is the default)
-
-=item B<--sgml>
-
-Generate SGML
-
-=item B<--verbose>
-
-Be verbose (not implemented)
-
-=back
-
-=head1 FORMAT
-
-The following is an example of some data this script might parse.
-
-    #define length_trivial_usage \
-            "STRING"
-    #define length_full_usage \
-            "Prints out the length of the specified STRING."
-    #define length_example_usage \
-            "$ length Hello\n" \
-            "5\n"
-
-Each entry is a cpp macro that defines a string.  The macros are
-named systematically in the form:
-
-    $name_$type_usage
-
-$name is the name of the applet.  $type can be "trivial", "full", "notes",
-or "example".  Every documentation macro must end with "_usage".
-
-The definition of the types is as follows:
-
-=over 4
-
-=item B<trivial>
-
-This should be a brief, one-line description of parameters that
-the command expects.  This will be displayed when B<-h> is issued to
-a command.  I<REQUIRED>
-
-=item B<full>
-
-This should contain descriptions of each option.  This will also
-be displayed along with the trivial help if BB_FEATURE_TRIVIAL_HELP
-is disabled.  I<REQUIRED>
-
-=item B<notes>
-
-This is documentation that is intended to go in the POD or SGML, but
-not be printed when a B<-h> is given to a command.  To see an example
-of notes being used, see init_notes_usage.  I<OPTIONAL>
-
-=item B<example>
-
-This should be an example of how the command is acutally used.
-This will not be printed when a B<-h> is given to a command -- it
-is inteded only for the POD or SGML documentation.  I<OPTIONAL>
-
-=back
-
-=head1 FILES
-
-F<usage.h>
-
-=head1 COPYRIGHT
-
-Copyright (c) 2001 John BEPPU.  All rights reserved.  This program is
-free software; you can redistribute it and/or modify it under the same
-terms as Perl itself.
-
-=head1 AUTHOR
-
-John BEPPU <beppu@lineo.com>
-
-=cut
-
-# $Id: autodocifier.pl,v 1.21 2001/04/17 17:09:34 beppu Exp $
diff --git a/busybox/docs/busybox.net/.cvsignore b/busybox/docs/busybox.net/.cvsignore
deleted file mode 100644 (file)
index 88825af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-BusyBox.html
diff --git a/busybox/docs/busybox.net/busybox-growth.ps b/busybox/docs/busybox.net/busybox-growth.ps
deleted file mode 100644 (file)
index 123f381..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-%!PS-Adobe-2.0
-%%Title: busybox-growth.ps
-%%Creator: gnuplot 3.5 (pre 3.6) patchlevel beta 347
-%%CreationDate: Tue Apr 10 14:03:36 2001
-%%DocumentFonts: (atend)
-%%BoundingBox: 50 40 554 770
-%%Orientation: Landscape
-%%Pages: (atend)
-%%EndComments
-/gnudict 120 dict def
-gnudict begin
-/Color true def
-/Solid true def
-/gnulinewidth 5.000 def
-/userlinewidth gnulinewidth def
-/vshift -46 def
-/dl {10 mul} def
-/hpt_ 31.5 def
-/vpt_ 31.5 def
-/hpt hpt_ def
-/vpt vpt_ def
-/M {moveto} bind def
-/L {lineto} bind def
-/R {rmoveto} bind def
-/V {rlineto} bind def
-/vpt2 vpt 2 mul def
-/hpt2 hpt 2 mul def
-/Lshow { currentpoint stroke M
-  0 vshift R show } def
-/Rshow { currentpoint stroke M
-  dup stringwidth pop neg vshift R show } def
-/Cshow { currentpoint stroke M
-  dup stringwidth pop -2 div vshift R show } def
-/UP { dup vpt_ mul /vpt exch def hpt_ mul /hpt exch def
-  /hpt2 hpt 2 mul def /vpt2 vpt 2 mul def } def
-/DL { Color {setrgbcolor Solid {pop []} if 0 setdash }
- {pop pop pop Solid {pop []} if 0 setdash} ifelse } def
-/BL { stroke gnulinewidth 2 mul setlinewidth } def
-/AL { stroke gnulinewidth 2 div setlinewidth } def
-/UL { gnulinewidth mul /userlinewidth exch def } def
-/PL { stroke userlinewidth setlinewidth } def
-/LTb { BL [] 0 0 0 DL } def
-/LTa { AL [1 dl 2 dl] 0 setdash 0 0 0 setrgbcolor } def
-/LT0 { PL [] 1 0 0 DL } def
-/LT1 { PL [4 dl 2 dl] 0 1 0 DL } def
-/LT2 { PL [2 dl 3 dl] 0 0 1 DL } def
-/LT3 { PL [1 dl 1.5 dl] 1 0 1 DL } def
-/LT4 { PL [5 dl 2 dl 1 dl 2 dl] 0 1 1 DL } def
-/LT5 { PL [4 dl 3 dl 1 dl 3 dl] 1 1 0 DL } def
-/LT6 { PL [2 dl 2 dl 2 dl 4 dl] 0 0 0 DL } def
-/LT7 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 1 0.3 0 DL } def
-/LT8 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 0.5 0.5 0.5 DL } def
-/Pnt { stroke [] 0 setdash
-   gsave 1 setlinecap M 0 0 V stroke grestore } def
-/Dia { stroke [] 0 setdash 2 copy vpt add M
-  hpt neg vpt neg V hpt vpt neg V
-  hpt vpt V hpt neg vpt V closepath stroke
-  Pnt } def
-/Pls { stroke [] 0 setdash vpt sub M 0 vpt2 V
-  currentpoint stroke M
-  hpt neg vpt neg R hpt2 0 V stroke
-  } def
-/Box { stroke [] 0 setdash 2 copy exch hpt sub exch vpt add M
-  0 vpt2 neg V hpt2 0 V 0 vpt2 V
-  hpt2 neg 0 V closepath stroke
-  Pnt } def
-/Crs { stroke [] 0 setdash exch hpt sub exch vpt add M
-  hpt2 vpt2 neg V currentpoint stroke M
-  hpt2 neg 0 R hpt2 vpt2 V stroke } def
-/TriU { stroke [] 0 setdash 2 copy vpt 1.12 mul add M
-  hpt neg vpt -1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt 1.62 mul V closepath stroke
-  Pnt  } def
-/Star { 2 copy Pls Crs } def
-/BoxF { stroke [] 0 setdash exch hpt sub exch vpt add M
-  0 vpt2 neg V  hpt2 0 V  0 vpt2 V
-  hpt2 neg 0 V  closepath fill } def
-/TriUF { stroke [] 0 setdash vpt 1.12 mul add M
-  hpt neg vpt -1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt 1.62 mul V closepath fill } def
-/TriD { stroke [] 0 setdash 2 copy vpt 1.12 mul sub M
-  hpt neg vpt 1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt -1.62 mul V closepath stroke
-  Pnt  } def
-/TriDF { stroke [] 0 setdash vpt 1.12 mul sub M
-  hpt neg vpt 1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt -1.62 mul V closepath fill} def
-/DiaF { stroke [] 0 setdash vpt add M
-  hpt neg vpt neg V hpt vpt neg V
-  hpt vpt V hpt neg vpt V closepath fill } def
-/Pent { stroke [] 0 setdash 2 copy gsave
-  translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
-  closepath stroke grestore Pnt } def
-/PentF { stroke [] 0 setdash gsave
-  translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
-  closepath fill grestore } def
-/Circle { stroke [] 0 setdash 2 copy
-  hpt 0 360 arc stroke Pnt } def
-/CircleF { stroke [] 0 setdash hpt 0 360 arc fill } def
-/C0 { BL [] 0 setdash 2 copy moveto vpt 90 450  arc } bind def
-/C1 { BL [] 0 setdash 2 copy        moveto
-       2 copy  vpt 0 90 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C2 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 90 180 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C3 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 0 180 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C4 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 180 270 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C5 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 0 90 arc
-       2 copy moveto
-       2 copy  vpt 180 270 arc closepath fill
-               vpt 0 360 arc } bind def
-/C6 { BL [] 0 setdash 2 copy moveto
-      2 copy  vpt 90 270 arc closepath fill
-              vpt 0 360 arc closepath } bind def
-/C7 { BL [] 0 setdash 2 copy moveto
-      2 copy  vpt 0 270 arc closepath fill
-              vpt 0 360 arc closepath } bind def
-/C8 { BL [] 0 setdash 2 copy moveto
-      2 copy vpt 270 360 arc closepath fill
-              vpt 0 360 arc closepath } bind def
-/C9 { BL [] 0 setdash 2 copy moveto
-      2 copy  vpt 270 450 arc closepath fill
-              vpt 0 360 arc closepath } bind def
-/C10 { BL [] 0 setdash 2 copy 2 copy moveto vpt 270 360 arc closepath fill
-       2 copy moveto
-       2 copy vpt 90 180 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C11 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 0 180 arc closepath fill
-       2 copy moveto
-       2 copy  vpt 270 360 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C12 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 180 360 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C13 { BL [] 0 setdash  2 copy moveto
-       2 copy  vpt 0 90 arc closepath fill
-       2 copy moveto
-       2 copy  vpt 180 360 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/C14 { BL [] 0 setdash 2 copy moveto
-       2 copy  vpt 90 360 arc closepath fill
-               vpt 0 360 arc } bind def
-/C15 { BL [] 0 setdash 2 copy vpt 0 360 arc closepath fill
-               vpt 0 360 arc closepath } bind def
-/Rec   { newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto
-       neg 0 rlineto closepath } bind def
-/Square { dup Rec } bind def
-/Bsquare { vpt sub exch vpt sub exch vpt2 Square } bind def
-/S0 { BL [] 0 setdash 2 copy moveto 0 vpt rlineto BL Bsquare } bind def
-/S1 { BL [] 0 setdash 2 copy vpt Square fill Bsquare } bind def
-/S2 { BL [] 0 setdash 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def
-/S3 { BL [] 0 setdash 2 copy exch vpt sub exch vpt2 vpt Rec fill Bsquare } bind def
-/S4 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def
-/S5 { BL [] 0 setdash 2 copy 2 copy vpt Square fill
-       exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def
-/S6 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill Bsquare } bind def
-/S7 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill
-       2 copy vpt Square fill
-       Bsquare } bind def
-/S8 { BL [] 0 setdash 2 copy vpt sub vpt Square fill Bsquare } bind def
-/S9 { BL [] 0 setdash 2 copy vpt sub vpt vpt2 Rec fill Bsquare } bind def
-/S10 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt Square fill
-       Bsquare } bind def
-/S11 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt2 vpt Rec fill
-       Bsquare } bind def
-/S12 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill Bsquare } bind def
-/S13 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
-       2 copy vpt Square fill Bsquare } bind def
-/S14 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
-       2 copy exch vpt sub exch vpt Square fill Bsquare } bind def
-/S15 { BL [] 0 setdash 2 copy Bsquare fill Bsquare } bind def
-/D0 { gsave translate 45 rotate 0 0 S0 stroke grestore } bind def
-/D1 { gsave translate 45 rotate 0 0 S1 stroke grestore } bind def
-/D2 { gsave translate 45 rotate 0 0 S2 stroke grestore } bind def
-/D3 { gsave translate 45 rotate 0 0 S3 stroke grestore } bind def
-/D4 { gsave translate 45 rotate 0 0 S4 stroke grestore } bind def
-/D5 { gsave translate 45 rotate 0 0 S5 stroke grestore } bind def
-/D6 { gsave translate 45 rotate 0 0 S6 stroke grestore } bind def
-/D7 { gsave translate 45 rotate 0 0 S7 stroke grestore } bind def
-/D8 { gsave translate 45 rotate 0 0 S8 stroke grestore } bind def
-/D9 { gsave translate 45 rotate 0 0 S9 stroke grestore } bind def
-/D10 { gsave translate 45 rotate 0 0 S10 stroke grestore } bind def
-/D11 { gsave translate 45 rotate 0 0 S11 stroke grestore } bind def
-/D12 { gsave translate 45 rotate 0 0 S12 stroke grestore } bind def
-/D13 { gsave translate 45 rotate 0 0 S13 stroke grestore } bind def
-/D14 { gsave translate 45 rotate 0 0 S14 stroke grestore } bind def
-/D15 { gsave translate 45 rotate 0 0 S15 stroke grestore } bind def
-/DiaE { stroke [] 0 setdash vpt add M
-  hpt neg vpt neg V hpt vpt neg V
-  hpt vpt V hpt neg vpt V closepath stroke } def
-/BoxE { stroke [] 0 setdash exch hpt sub exch vpt add M
-  0 vpt2 neg V hpt2 0 V 0 vpt2 V
-  hpt2 neg 0 V closepath stroke } def
-/TriUE { stroke [] 0 setdash vpt 1.12 mul add M
-  hpt neg vpt -1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt 1.62 mul V closepath stroke } def
-/TriDE { stroke [] 0 setdash vpt 1.12 mul sub M
-  hpt neg vpt 1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt -1.62 mul V closepath stroke } def
-/PentE { stroke [] 0 setdash gsave
-  translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
-  closepath stroke grestore } def
-/CircE { stroke [] 0 setdash 
-  hpt 0 360 arc stroke } def
-/Opaque { gsave closepath 1 setgray fill grestore 0 setgray closepath } def
-/DiaW { stroke [] 0 setdash vpt add M
-  hpt neg vpt neg V hpt vpt neg V
-  hpt vpt V hpt neg vpt V Opaque stroke } def
-/BoxW { stroke [] 0 setdash exch hpt sub exch vpt add M
-  0 vpt2 neg V hpt2 0 V 0 vpt2 V
-  hpt2 neg 0 V Opaque stroke } def
-/TriUW { stroke [] 0 setdash vpt 1.12 mul add M
-  hpt neg vpt -1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt 1.62 mul V Opaque stroke } def
-/TriDW { stroke [] 0 setdash vpt 1.12 mul sub M
-  hpt neg vpt 1.62 mul V
-  hpt 2 mul 0 V
-  hpt neg vpt -1.62 mul V Opaque stroke } def
-/PentW { stroke [] 0 setdash gsave
-  translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
-  Opaque stroke grestore } def
-/CircW { stroke [] 0 setdash 
-  hpt 0 360 arc Opaque stroke } def
-/BoxFill { gsave Rec 1 setgray fill grestore } def
-end
-%%EndProlog
-%%Page: 1 1
-gnudict begin
-gsave
-50 50 translate
-0.100 0.100 scale
-90 rotate
-0 -5040 translate
-0 setgray
-newpath
-(Helvetica) findfont 140 scalefont setfont
-1.000 UL
-LTb
-560 420 M
-63 0 V
-6409 0 R
--63 0 V
-476 420 M
-(0) Rshow
-560 1056 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(100) Rshow
-560 1692 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(200) Rshow
-560 2328 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(300) Rshow
-560 2964 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(400) Rshow
-560 3600 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(500) Rshow
-560 4236 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(600) Rshow
-560 4872 M
-63 0 V
-6409 0 R
--63 0 V
--6493 0 R
-(700) Rshow
-1531 420 M
-0 63 V
-0 4389 R
-0 -63 V
-0 -4529 R
-(400) Cshow
-2825 420 M
-0 63 V
-0 4389 R
-0 -63 V
-0 -4529 R
-(600) Cshow
-4120 420 M
-0 63 V
-0 4389 R
-0 -63 V
-0 -4529 R
-(800) Cshow
-5414 420 M
-0 63 V
-0 4389 R
-0 -63 V
-0 -4529 R
-(1000) Cshow
-6708 420 M
-0 63 V
-0 4389 R
-0 -63 V
-0 -4529 R
-(1200) Cshow
-1.000 UL
-LTb
-560 420 M
-6472 0 V
-0 4452 V
--6472 0 V
-560 420 L
-0 2646 M
-currentpoint gsave translate 90 rotate 0 0 M
-(tar.gz size \(Kb\)) Cshow
-grestore
-3796 140 M
-(time \(days since Jan 1, 1998\)) Cshow
-1.000 UL
-LT0
-696 420 M
-0 593 V
-1255 0 V
-0 15 V
-214 0 V
-0 6 V
-958 0 V
-0 1 V
--84 0 V
-0 37 V
-168 0 V
-0 262 V
-13 0 V
-0 56 V
-91 0 V
-0 33 V
-6 0 V
-0 1 V
-19 0 V
-0 11 V
-20 0 V
-0 13 V
-32 0 V
-0 104 V
-52 0 V
-0 27 V
-65 0 V
-0 15 V
-39 0 V
-0 126 V
-174 0 V
-0 103 V
-52 0 V
-0 49 V
-175 0 V
-0 56 V
-433 0 V
-0 661 V
-415 0 V
-0 857 V
-123 0 V
-0 -291 V
-498 0 V
-0 208 V
-505 0 V
-0 66 V
-291 0 V
-0 115 V
-311 0 V
-0 449 V
-162 0 V
-0 309 V
-stroke
-grestore
-end
-showpage
-%%Trailer
-%%DocumentFonts: Helvetica
-%%Pages: 1
diff --git a/busybox/docs/busybox.net/images/busybox.jpeg b/busybox/docs/busybox.net/images/busybox.jpeg
deleted file mode 100644 (file)
index 37edc96..0000000
Binary files a/busybox/docs/busybox.net/images/busybox.jpeg and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/busybox2.jpg b/busybox/docs/busybox.net/images/busybox2.jpg
deleted file mode 100644 (file)
index abf8f06..0000000
Binary files a/busybox/docs/busybox.net/images/busybox2.jpg and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/fm.mini.png b/busybox/docs/busybox.net/images/fm.mini.png
deleted file mode 100644 (file)
index c0883cd..0000000
Binary files a/busybox/docs/busybox.net/images/fm.mini.png and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/gfx_by_gimp.png b/busybox/docs/busybox.net/images/gfx_by_gimp.png
deleted file mode 100644 (file)
index d583140..0000000
Binary files a/busybox/docs/busybox.net/images/gfx_by_gimp.png and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/ltbutton2.png b/busybox/docs/busybox.net/images/ltbutton2.png
deleted file mode 100644 (file)
index 556f72a..0000000
Binary files a/busybox/docs/busybox.net/images/ltbutton2.png and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/sdsmall.png b/busybox/docs/busybox.net/images/sdsmall.png
deleted file mode 100644 (file)
index b102450..0000000
Binary files a/busybox/docs/busybox.net/images/sdsmall.png and /dev/null differ
diff --git a/busybox/docs/busybox.net/images/written.in.vi.png b/busybox/docs/busybox.net/images/written.in.vi.png
deleted file mode 100644 (file)
index 84f59bc..0000000
Binary files a/busybox/docs/busybox.net/images/written.in.vi.png and /dev/null differ
diff --git a/busybox/docs/busybox.net/index.html b/busybox/docs/busybox.net/index.html
deleted file mode 100644 (file)
index e606238..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
-
-<HTML>
-<HEAD>
-<TITLE>BusyBox</TITLE>
-</HEAD>
-
-<body text="#000000" alink="#660000" link="#660000" bgcolor="#dee2de" vlink="#660000">
-
-<basefont face="lucida, helvetica, arial" size="3">
-
-
-<CENTER>
-      <TABLE BORDER=0 CELLSPACING=1 CELLPADDING=2>
-           <TR>
-               <td bgcolor="#000000">
-                 <FONT FACE="lucida, helvetica" COLOR="#ccccc0">
-                     <B>B&nbsp;u&nbsp;s&nbsp;y&nbsp;B&nbsp;o&nbsp;x</B>
-                 </FONT>
-               </TD>
-           </TR>
-      </TABLE>
-      <a href="/"><IMG SRC="images/busybox2.jpg" alt="BusyBox" border="0" width="360" height="230"></a><BR>
-
-
-<!-- Begin Introduction section -->
-
-
-<TABLE WIDTH="95%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="intro"> <BIG><B>
-    The Swiss Army Knife of Embedded Linux
-    </B></BIG></A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-BusyBox combines tiny versions of many common UNIX utilities into a single
-small executable. It provides minimalist replacements for most of the utilities
-you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
-tar, etc. BusyBox provides a fairly complete POSIX environment for any small or
-embedded system. The utilities in BusyBox generally have fewer options than
-their full featured GNU cousins; however, the options that are included provide
-the expected functionality and behave very much like their GNU counterparts.
-<p>
-BusyBox has been written with size-optimization and limited resources in mind.
-It is also extremely modular so you can easily include or exclude commands (or
-features) at compile time. This makes it easy to customize your embedded
-systems. To create a working system, just add /dev, /etc, and a kernel.
-<p>
-
-BusyBox is now maintained by 
-<a href="http://codepoet.org/andersen/erik/erik.html">
-Erik Andersen</a>, and its ongoing development is being sponsored by 
-<a href="http://www.lineo.com/">Lineo</a>. 
-<p>
-BusyBox is licensed under the 
-<a href="http://www.gnu.org/copyleft/gpl.html">GNU GENERAL PUBLIC LICENSE</a>.
-<p>
-
-
-<h3> Screenshot </h3>
-
-<p> Because everybody loves screenshots, a screenshot of BusyBox 
-is now available <a href="screenshot.html">right here</a>.
-
-
-<H3>Mailing List Information</h3>
-BusyBox now has a <a href="http://opensource.lineo.com/lists/busybox/">mailing list</a>!
-To subscribe, go and visit <a href="http://opensource.lineo.com/mailman/listinfo/busybox">this page</a>.
-
-<!-- Begin Latest News section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="news">
-    <BIG><B>
-    Latest News
-    </B></BIG>
-    </A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-<ul>
-
-    <li> <b>23 August 2001 -- BusyBox 0.60.1 released</b>
-    <br>
-
-            This is a relatively minor bug fixing release that fixes
-            up the bugs that have shown up in the stable release in
-            the last few weeks.  Fortunately, nothing <em>too</em>
-            serious has shown up.  This release only fixes bugs -- no
-            new features, no new applets.  So without further ado,
-            here it is.  Come and get it.
-            <p>
-            The 
-            <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> has all
-            the details.  As usual BusyBox 0.60.1 can be downloaded from 
-            <a href="ftp://oss.lineo.com/busybox">ftp://oss.lineo.com/busybox</a>.
-            <p>Have Fun!
-            <p>
-
-
-    <li> <b>2 August 2001 -- BusyBox 0.60.0 released</b>
-    <br>
-            I am very pleased to announce the immediate availability of
-            BusyBox 0.60.0.  I have personally tested this release with libc5, glibc,
-            and <a href="http://cvs.uclinux.org/uClibc.html">uClibc</a> on
-            x86, ARM, and powerpc using linux 2.2 and 2.4, and I know a number
-            of people using it on everything from ia64 to m68k with great success.
-            Everything seems to be working very nicely now, so getting a nice
-            stable bug-free(tm) release out seems to be in order.   This releases fixes
-            a memory leak in syslogd, a number of bugs in the ash and msh shells, and
-            cleans up a number of things.
-            
-            <p>
-
-            Those wanting an easy way to test the 0.60.0 release with uClibc can 
-            use <a href="http://user-mode-linux.sourceforge.net/">User-Mode Linux</a>
-            to give it a try by downloading and compiling 
-            <a href="ftp://oss.lineo.com/buildroot.tar.gz">buildroot.tar.gz</a>.
-            You don't have to be root or reboot your machine to run test this way.
-            Preconfigured User-Mode Linux kernel source is also on oss.lineo.com. 
-            <p>
-            Another cool thing is the nifty <a href="ftp://oss.lineo.com/busybox/tutorial/index.html">
-            BusyBox Tutorial</a> contributed by K Computing.  This requires 
-            a ShockWave plugin (or standalone viewer), so you may want to grab the 
-            the GPLed shockwave viewer from <a href="http://www.swift-tools.com/Flash/flash-0.4.10.tgz">here</a>
-            to view the tutorial.
-            <p>
-            
-            Finally, In case you didn't notice anything odd about the
-            version number of this release, let me point out that this release
-            is <em>not</em> 0.53, because I bumped the version number up a
-            bit.  This reflects the fact that this release is intended to form
-            a new stable BusyBox release series.  If you need to rely on a
-            stable version of BusyBox, you should plan on using the stable
-            0.60.x series.  If bugs show up then I will release 0.60.1, then
-            0.60.2, etc...  This is also intended to deal with the fact that
-            the BusyBox build system will be getting a major overhaul for the
-            next release and I don't want that to break products that people
-            are shipping.  To avoid that, the new build system will be
-            released as part of a new BusyBox development series that will
-            have some not-yet-decided-on odd version number.  Once things
-            stabilize and the new build system is working for everyone, then
-            I will release that as a new stable release series. 
-
-            <p>
-            The 
-            <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> has all
-            the details.  As usual BusyBox 0.60.0 can be downloaded from 
-            <a href="ftp://oss.lineo.com/busybox">ftp://oss.lineo.com/busybox</a>.
-            <p>Have Fun!
-            <p>
-
-
-    <li> <b>7 July 2001 -- BusyBox 0.52 released</b>
-    <br>
-
-            I am very pleased to announce the immediate availability of
-            BusyBox 0.52 (the "new-and-improved rock-solid release").  This
-            release is the result of <em>many</em> hours of work and has tons
-            of bugfixes, optimizations, and cleanups.  This release adds
-            several new applets, including several new shells (such as hush, msh,
-            and ash).
-
-            <p>
-            The 
-            <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> covers 
-            some of the more obvious details, but there are many many things that
-            are not mentioned, but have been improved in subtle ways.  As usual,
-            BusyBox 0.52 can be downloaded from 
-            <a href="ftp://oss.lineo.com/busybox">ftp://oss.lineo.com/busybox</a>.
-            <p>Have Fun!
-            <p>
-
-
-       <li> <b>10 April 2001 - Graph of Busybox Growth </b>
-       <br> 
-       The illustrious Larry Doolittle has made a PostScript chart of the growth
-       of the Busybox tarball size over time. It is available for downloading /
-       viewing <a href= "busybox-growth.ps"> right here</a>.
-
-       <p> (Note that while the number of applets in Busybox has increased, you
-       can still configure Busybox to be as small as you want by selectively
-       turning off whichever applets you don't need.)
-       <p>
-
-
-
-    <li> <b>Old News</b>
-    <br>
-            For the old news, visit <a href="http://busybox.lineo.com/oldnews.html">the old news page</a>.
-</ul>
-
-
-<!-- Begin Download section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="download"><BIG><B>
-    Download
-    </B></BIG></A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-<ul>
-
-       <li> Source for the latest release can always be downloaded from 
-       <a href="ftp://oss.lineo.com/busybox">ftp://oss.lineo.com/busybox</a>.
-
-       <li> A new snapshot of the source is made daily and is available as a GNU
-       gzipped tarball <a href="busybox.tar.gz"> right here</a>.
-
-       <li> BusyBox now has its own publically browsable
-       <a href="http://opensource.lineo.com/cgi-bin/cvsweb/busybox/">CVS tree</a>,  
-       anonymous
-       <a href="http://opensource.lineo.com/cvs_anon.html">CVS access</a>, and
-       for those that are actively contributing there is even 
-       <a href="http://opensource.lineo.com/cvs_write.html">CVS write access</a>.
-
-</ul>
-
-
-<!-- Begin Docs section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="docs"><BIG><B>
-    Documentation
-    </B></BIG></A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-Current documentation for BusyBox includes: 
-<ul>
-    <li> <a href="ftp://oss.lineo.com/busybox/BusyBox.html">BusyBox.html</a>.
-               This is a list of the all the available commands in BusyBox with 
-               complete usage information and examples of how to use each app.  I 
-               have spent a <em>lot</em> of time updating these docs and trying to 
-               make them fairly comprehensive.  If you find any errors (factual, 
-               grammatical, whatever) please let me know.
-    <li> <a href="ftp://oss.lineo.com/busybox/README">README</a>.
-               This is the README file included in the busybox source release.
-    <li> <a href="http://bugs.lineo.com/db/pa/lbusybox.html">BusyBox Bugs</a>.
-               Need to report a bug?  Need to check if a bug has been filed?
-    <li> If you need more help, the BusyBox
-    <a href="http://opensource.lineo.com/lists/busybox/">mailing list</a> is
-    a good place to start.
-</ul>
-
-
-<!-- Begin Links section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="links">
-    <BIG><B>
-    Important Links
-    </B></BIG>
-    </A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-<ul> 
-
-    <li>  <A HREF="http://perens.com/FreeSoftware/">
-    Free Software from Bruce Perens</A><br>
-    The original idea for BusyBox, and all versions up to 0.26 were written 
-    by <A HREF="mailto:bruce@perens.com">Bruce Perens</a>.  This is his BusyBox website.
-    <p>
-
-    <li>  <A HREF="http://freshmeat.net/projects/busybox/">
-    Freshmeat AppIndex record for BusyBox</A>
-    <p>
-    <li><a href="http://tinylogin.lineo.com/">TinyLogin</a>
-        is a nice embedded tool for handling authentication, changing passwords,
-       and similar tasks which nicely complements BusyBox.
-    <p>
-
-    <li><a href="http://cvs.uclinux.org/uClibc.html">uClibc</a>
-       is a C library for embedded systems.  You can actually statically link
-       a "Hello World" application under x86 that only takes 4k (as opposed to
-       200k under GNU libc).  It can do dynamic linking too and works nicely with
-       BusyBox to create very small embedded systems.
-    <p>
-
-    <li> <a href="http://opensource.lineo.com/software.html">Other cool embedded software</a>.
-    <p>
-
-    <li> <a href="http://opensource.lineo.com/">opensource.lineo.com</a>.
-    <p>
-
-    <li> <A HREF="http://www.lineo.com/">Lineo</A> is sponsoring BusyBox development.
-    <p>
-
-</ul>
-
-
-<!-- Begin Projects section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="projects"><BIG><B>
-    Products/Projects Using BusyBox
-    </B></BIG></A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-<p> I know of the following products and/or projects that use BusyBox --
-listed in the order I happen to add them to the web page:
-
-<ul>
-    <li> <a href="http://www.lineo.com/products/embedix_linux/">Lineo Embedix Linux</a>
-    <li> <a href="http://cvs.debian.org/boot-floppies/">Debian installer (boot floppies) project</a>
-    <li> <a href="http://www.linuxrouter.org/">Linux Router Project </a>
-    <li> <a href="http://linux-embedded.org/">LEM</a>
-    <li> <a href="http://www.toms.net/rb/">tomsrtbt</a>
-    <li> <a href="http://www.stormix.com/">Stormix Installer</a>
-    <li> <a href="http://www.emacinc.com/linux2_sbc.htm">EMAC Linux 2.0 SBC</a>
-    <li> <a href="http://www.trinux.org/">Trinux</a>
-    <li> <a href="http://oddas.sourceforge.net/">ODDAS project</a>
-    <li> <a href="http://www.kerbango.com/">The Kerbango Internet Radio</a>
-    <li> <a href="http://www.linuxmagic.com/vpn/">LinuxMagic VPN Firewall</a>
-    <li> <a href="http://byld.sourceforge.net/">Build Your Linux Disk</a>
-    <li> <a href="http://homepages.ihug.co.nz/~ichi/baslinux.html">BasicLinux</a>
-    <li> <a href="http://ibiblio.org/pub/Linux/system/recovery">Zdisk</a>
-    <li> <a href="http://www.adtran.com">AdTran - VPN/firewall VPN Linux Distribution</a> 
-    <li> <a href="http://mkcdrec.ota.be/">mkCDrec - make CD-ROM recovery</a>
-    <li> <a href="http://recycle.lbl.gov/~ldoolitt/bse/">Linux on nanoEngine</a>
-    <li> <a href="http://www.zelow.no/floppyfw/"> Floppyfw</a>
-
-    <li> <a href="http://midori.transmeta.com/"> Midori Linux</a> - <a href=
-       "http://www.wired.com/news/technology/0,1282,42399,00.html"> Article on
-       Midori Linux</a> on <a href= "http://www.wired.com"> Wired</a>. Quote from
-       Erik at the top of <a href=
-       "http://www.wired.com/news/technology/0,1282,42399-2,00.html"> this
-       page</a>
-
-    <li> <a href="http://www.ltsp.org/">Linux Terminal Server Project</a>
-    <li> <a href="http://www.devil-linux.org/">Devil-Linux</a>
-
-</ul>
-
-<p> Do you use BusyBox?  I'd love to know about it and I'd be happy to link to
-you.
-
-
-
-<!-- End of Table -->
-
-</TD></TR>
-</TABLE>
-
-
-
-<!-- Footer -->
-<HR>
-<TABLE WIDTH="100%">
-    <TR>
-       <TD>
-           <font size="-1" face="arial, helvetica, sans-serif">
-           Mail all comments, insults, suggestions and bribes to 
-           <a href="mailto:andersen@lineo.com">Erik Andersen</a><BR>
-           The Busybox logo is copyright 1999,2000,2001, Erik Andersen.
-           </font>
-       </TD>
-
-       <TD>
-           <a href="http://www.vim.org"><img border=0 width=90 height=36
-           src="images/written.in.vi.png" 
-           alt="This site created with the vi editor"></a>
-       </TD>
-
-       <TD>
-           <a href="http://www.gimp.org/"><img border=0 width=90 height=36
-           src="images/gfx_by_gimp.png" alt="Graphics by GIMP"></a>
-       </TD>
-
-       <TD>
-           <a href="http://www.linuxtoday.com"><img width=90 height=36
-           src="images/ltbutton2.png" alt="Linux Today"></a>
-       </TD>
-
-       <TD>
-           <p><a href="http://slashdot.org"><img width=90 height=36
-           src="images/sdsmall.png" alt="Slashdot"></a>
-       </TD>
-
-       <TD>
-           <a href="http://freshmeat.net"><img width=90 height=36
-           src="images/fm.mini.png" alt="Freshmeat"></a>
-       </TD>
-
-    </TR>
-</TABLE>
-
-
-</CENTER>
-</BODY>
-</HTML>
-
diff --git a/busybox/docs/busybox.net/oldnews.html b/busybox/docs/busybox.net/oldnews.html
deleted file mode 100644 (file)
index d97bb26..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
-
-<HTML>
-<HEAD>
-<TITLE>BusyBox</TITLE>
-</HEAD>
-
-<body text="#000000" alink="#660000" link="#660000" bgcolor="#dee2de" vlink="#660000">
-
-<basefont face="lucida, helvetica, arial" size="3">
-
-
-<CENTER>
-      <TABLE BORDER=0 CELLSPACING=1 CELLPADDING=2>
-           <TR>
-               <td bgcolor="#000000">
-                 <FONT FACE="lucida, helvetica" COLOR="#ccccc0">
-                     <B>B&nbsp;u&nbsp;s&nbsp;y&nbsp;B&nbsp;o&nbsp;x</B>
-                 </FONT>
-               </TD>
-           </TR>
-      </TABLE>
-      <a href="/"><IMG SRC="images/busybox2.jpg" alt="BusyBox" border="0" width="360" height="230"</a><BR>
-
-
-<TABLE WIDTH=95% CELLSPACING=1 CELLPADDING=4 BORDER=1>
-
-<!-- Begin Older News section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="news">
-    <BIG><B>
-    Older BusyBox News</A> 
-    </B></BIG>
-    </A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-<ul>
-
-    <p> <li> <b>Take me back to the <a href="http://busybox.lineo.com/">BusyBox</a> web site.</b>
-    <hr>
-
-    <li> <b>10 April 2001 -- BusyBox 0.51 released</b>
-    <br>
-
-            BusyBox 0.51 (the "rock-solid release") is now out there.  This
-            release adds only 2 new applets: env and vi.  The vi applet,
-            contributed by Sterling Huxley, is very functional, and is only
-            22k.  This release fixes 3 critical bugs in the 0.50 release.
-            There were 2 potential segfaults in lash (the busybox shell) in
-            the 0.50 release which are now fixed.  Another critical bug in
-            0.50 which is now fixed: syslogd from 0.50 could potentially
-            deadlock the init process and thereby break your entire system.
-            <p>
-
-            There are a number of improvements in this release as well.  For
-            one thing, the wget applet is greatly improved.  Dmitry Zakharov
-            added FTP support, and Laurence Anderson make wget fully RFC
-            compliant for HTTP 1.1.  The mechanism for including utility
-            functions in previous releases was clumsy and error prone.  Now
-            all utility functions are part of a new libbb library, which makes
-            maintaining utility functions much simpler.  And BusyBox now
-            compiles on itanium systems (thanks to the Debian itanium porters
-            for letting me use their system!).
-            <p>
-            You can read the 
-            <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> for
-            complete details.  BusyBox 0.51 can be downloaded from 
-            <a href="ftp://oss.lineo.com/busybox">ftp://oss.lineo.com/busybox</a>.
-            <p>Have Fun!
-            <p>
-
-    <li> <b>Busybox Boot-Floppy Image</b>
-
-    <p>Because you asked for it, we have made available a <a href=
-    "ftp://opensource.lineo.com/busybox/busybox.floppy.img"> Busybox boot floppy
-    image</a>. Here's how you use it:
-
-    <ol>
-
-           <li> <a href= "ftp://opensource.lineo.com/busybox/busybox.floppy.img">
-           Download the image</a>
-
-           <li> dd it onto a floppy like so: <tt> dd if=busybox.floppy.img
-           of=/dev/fd0 ; sync </tt>
-
-           <li> Pop it in a machine and boot up.
-
-    </ol>
-
-    <p> If you want to look at the contents of the initrd image, do this:
-
-    <pre>
-           mount ./busybox.floppy.img /mnt -o loop -t msdos        
-           cp /mnt/initrd.gz /tmp                          
-           umount /mnt           
-           gunzip /tmp/initrd.gz
-           mount /tmp/initrd /mnt -o loop -t minix
-    </pre>
-
-
-    <li> <b>15 March 2001 -- BusyBox 0.50 released</b>
-    <br>
-
-            This release adds several new applets including ifconfig, route, pivot_root, stty,
-            and tftp, and also fixes tons of bugs.  Tab completion in the
-            shell is now working very well, and the shell's environment variable
-            expansion was fixed.   Tons of other things were fixed or made
-            smaller.  For a fairly complete overview, see the 
-            <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a>.
-            <p>
-            lash (the busybox shell) is still with us, fixed up a bit so it
-            now behaves itself quite nicely.  It really is quite usable as
-            long as you don't expect it to provide Bourne shell grammer.
-            Standard things like pipes, redirects, command line editing, and
-            environment variable expansion work great.  But we have found that
-            this shell, while very usable, does not provide an extensible
-            framework for adding in full Bourne shell behavior.  So the first order of
-            business as we begin working on the next BusyBox release will be to merge in the new shell
-            currently in progress at 
-            <a href="http://doolittle.faludi.com/~larry/parser.html">Larry Doolittle's website</a>.   
-            <p>
-
-
-    <li> <b>27 January 2001 -- BusyBox 0.49 released</b>
-    <br>
-
-            Several new applets, lots of bug fixes, cleanups, and many smaller 
-            things made nicer.  Several cleanups and improvements to the shell.
-            For a list of the most interesting changes 
-            you might want to look at the <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a>. 
-            <p>
-            Special thanks go out to Matt Kraai and Larry Doolittle for all their
-            work on this release, and for keeping on top of things while I've been 
-            out of town.
-            <p>
-            <em>Special Note</em><br>
-
-            BusyBox 0.49 was supposed to have replaced lash, the BusyBox
-            shell, with a new shell that understands full Bourne shell/Posix shell grammer.
-            Well, that simply didn't happen in time for this release.  A new
-            shell that will eventually replace lash is already under
-            construction.  This new shell is being developed by Larry
-            Doolittle, and could use all of our help.  Please see the work in
-            progress on <a href="http://doolittle.faludi.com/~larry/parser.html">Larry's website</a> 
-            and help out if you can.  This shell will be included in the next 
-            release of BusyBox.
-            <p>
-
-    <li> <b>13 December 2000 -- BusyBox 0.48 released</b>
-    <br>
-
-            This release fixes lots and lots of bugs.  This has had some very
-            rigorous testing, and looks very, very clean.  The usual tar
-            update of course: tar no longer breaks hardlinks, tar -xzf is
-            optionally supported, and the LRP folks will be pleased to know
-            that 'tar -X' and 'tar --exclude' are both now in.  Applets are
-            now looked up using a binary search making lash (the busybox
-            shell) much faster.  For the new debian-installer (for Debian
-            woody) a .udeb can now be generated.  
-            <p>
-            The curious can get a list of some of the more interesting changes by reading 
-            the <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a>. 
-            <p>
-            Many thanks go out to the many many people that have contributed to 
-            this release, especially Matt Kraai, Larry Doolittle, and Kent Robotti.
-            <p>
-    <p> <li> <b>26 September 2000 -- BusyBox 0.47 released</b>
-    <br>
-
-            This release fixes lots of bugs (including an ugly bug in 0.46
-            syslogd that could fork-bomb your system).  Added several new
-            apps: rdate, wget, getopt, dos2unix, unix2dos, reset, unrpm, 
-            renice, xargs, and expr.  syslogd now supports network logging.
-            There are the usual tar updates.  Most apps now use getopt for
-            more correct option parsing.
-            See the <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> 
-            for complete details.
-
-
-    <p> <li> <b>11 July 2000 -- BusyBox 0.46 released</b>
-    <br>
-
-            This release fixes several bugs (including a ugly bug in tar,
-            and fixes for NFSv3 mount support).  Added a dumpkmap to allow 
-            people to dump a binary keymaps for use with 'loadkmap', and a
-            completely reworked 'grep' and 'sed' which should behave better.
-            BusyBox shell can now also be used as a login shell.
-            See the <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> 
-            for complete details.
-
-
-    <p> <li> <b>21 June 2000 -- BusyBox 0.45 released</b>
-    <br>
-
-            This release has been slow in coming, but is very solid at this
-            point.  BusyBox now supports libc5 as well as GNU libc.  This
-            release provides the following new apps: cut, tr, insmod, ar,
-            mktemp, setkeycodes, md5sum, uuencode, uudecode, which, and
-            telnet.  There are bug fixes for just about every app as well (see
-            the <a href="ftp://oss.lineo.com/busybox/Changelog">changelog</a> for
-            details).
-            <p>
-            Also, some exciting infrastructure news!  Busybox now has its own 
-            <a href="http://opensource.lineo.com/lists/busybox/">mailing list</a>, 
-            publically browsable
-            <a href="http://opensource.lineo.com/cgi-bin/cvsweb/busybox/">CVS tree</a>,  
-            anonymous
-            <a href="http://opensource.lineo.com/cvs_anon.html">CVS access</a>, and
-            for those that are actively contributing there is even 
-            <a href="http://opensource.lineo.com/cvs_write.html">CVS write access</a>.
-            I think this will be a huge help to the ongoing development of BusyBox.
-            <p>
-            Also, for the curious, there is no 0.44 release.  Somehow 0.44 got announced
-            a few weeks ago prior to its actually being released.  To avoid any confusion
-            we are just skipping 0.44.
-            <p>
-            Many thanks go out to the many people that have contributed to this release
-            of BusyBox (esp. Pavel Roskin)!
-
-
-    <p> <li> <b>19 April 2000 -- syslogd bugfix</b>
-    <br>
-        Turns out that there was still a bug in busybox syslogd.
-       For example, with the following test app:
-<pre>
-       #include &lt;syslog.h&gt;
-
-       int do_log(char* msg, int delay)
-       {
-           openlog("testlog", LOG_PID, LOG_DAEMON);
-           while(1) {
-               syslog(LOG_ERR, "%s: testing one, two, three\n", msg);
-               sleep(delay);
-           }
-           closelog();
-           return(0);
-       };
-
-       int main(void)
-       {
-           if (fork()==0)
-               do_log("A", 2);
-           do_log("B", 3);
-       }
-</pre>
-       it should be logging stuff from both "A" and "B".  As released in 0.43 only stuff
-       from "A" would have been logged.  This means that if init tries to log something
-       while say ppp has the syslog open, init would block (which is bad, bad, bad).
-       <p>
-       Karl M. Hegbloom has created a 
-       <a href="ftp://ftp.lineo.com/pub/busybox/busybox-0.43-syslog_patch">fix for the problem</a>.
-       Thanks Karl!
-
-
-    <p> <li> <b>18 April 2000 -- BusyBox 0.43 released (finally!)</b>
-    <br>
-        I have finally gotten everything into a state where I feel pretty
-       good about things.  This is definitely the most stable, solid release
-       so far.  A lot of bugs have been fixed, and the following new apps
-       have been added: sh, basename, dirname, killall, uptime, 
-       freeramdisk, tr, echo, test, and usleep.  Tar has been completely
-       rewritten from scratch.  Bss size has also been greatly reduced.
-       More details are available in the 
-       <a href="ftp://ftp.lineo.com/pub/busybox/Changelog">changelog</a>.
-       Oh, and as a special bonus, I wrote some fairly comprehensive
-       <em>documentation</em>, complete with examples and full usage information.
-
-       <p>
-       Many thanks go out to the fine people that have helped by submitting patches
-       and bug reports; particularly instrumental in helping for this release were 
-       Karl Hegbloom, Pavel Roskin, Friedrich Vedder, Emanuele Caratti,
-       Bob Tinsley, Nicolas Pitre, Avery Pennarun, Arne Bernin, John Beppu, and Jim Gleason.
-       There were others so if I somehow forgot to mention you, I'm very sorry.
-       <p>
-
-       You can grab BusyBox 0.43 tarballs <a href="ftp://ftp.lineo.com/pub/busybox/">here</a>.
-
-    <p> <li> <b>9 April 2000 -- BusyBox 0.43 pre release</b>
-    <br>
-        Unfortunately, I have not yet finished all the things I want to
-        do for BusyBox 0.43, so I am posting this pre-release for people
-        to poke at.  This contains my complete rewrite of tar, which now weighs in at
-        5k (7k with all options turned on) and works for reading and writing
-        tarballs (which it does correctly for everything I have been able to throw
-        at it).  Tar also (optionally) supports the "--exclude" option (mainly because
-        the Linux Router Project folks asked for it).  This also has a pre-release
-        of the micro shell I have been writing.  This pre-release should be stable
-        enough for production use -- it just isn't a release since I have some structural
-        changes I still want to make.
-        <p>
-       The pre-release can be found <a href="ftp://ftp.lineo.com/pub/busybox/">here</a>.
-       Please let me know ASAP if you find <em>any</em> bugs.
-    
-    <p> <li> <b>28 March 2000 -- Andersen Baby Boy release</b>
-    <br>
-       I am pleased to announce that on Tuesday March 28th at 5:48pm, weighing in at 7
-       lbs. 12 oz, Micah Erik Andersen was born at LDS Hospital here in Salt Lake City.
-       He was born in the emergency room less then 5 minutes after we arrived -- and
-       it was such a relief that we even made it to the hospital at all.  Despite the
-       fact that I was driving at an amazingly unlawful speed and honking at everybody
-       and thinking decidedly unkind thoughts about the people in our way, my wife
-       (inconsiderate of my feelings and complete lack of medical training) was lying
-       down in the back seat saying things like "I think I need to start pushing now"
-       (which she then proceeded to do despite my best encouraging statements to the
-       contrary).
-       <p>
-       Anyway, I'm glad to note that despite the much-faster-than-we-were-expecting
-       labor, both Shaunalei and our new baby boy are doing wonderfully.
-       <p>
-       So now that I am done with my excuse for the slow release cycle...
-       Progress on the next release of BusyBox has been slow but steady.  I expect
-       to have a release sometime during the first week of April.  This release will
-       include a number of important changes, including the addition of a shell, a 
-       re-write of tar (to accommodate the Linux Router Project), and syslogd can now
-       accept multiple concurrent connections, fixing lots of unexpected blocking 
-       problems.
-
-
-    <p> <li> <b>11 February 2000 -- BusyBox 0.42 released</b>
-    <br>
-
-            This is the most solid BusyBox release so far.  Many, many
-               bugs have been fixed.   See the 
-<a href="ftp://ftp.lineo.com/pub/busybox/Changelog">changelog</a> for details.
-
-               Of particular interest, init will now cleanly unmount 
-               filesystems on reboot, cp and mv have been rewritten and 
-               behave much better, and mount and umount no longer leak 
-               loop devices.  Many thanks go out to Randolph Chung, 
-               Karl M. Hegbloom, Taketoshi Sano, and Pavel Roskin for 
-               their hard work on this release of BusyBox.  Please pound 
-               on it and let me know if you find any bugs.
-
-    <p> <li> <b>19 January 2000 -- BusyBox 0.41 released</b>
-    <br>
-
-            This release includes bugfixes to cp, mv, logger, true, false,
-               mkdir, syslogd, and init.  New apps include wc, hostid, 
-               logname, tty, whoami, and yes.  New features include loop device
-               support in mount and umount, and better TERM handling by init.
-               The changelog can be found <a href="ftp://ftp.lineo.com/pub/busybox/Changelog">here</a>.
-
-    <p> <li> <b>7 January 2000 -- BusyBox 0.40 released</b>
-    <br>
-
-            This release includes bugfixes to init (now includes inittab support),
-            syslogd, head, logger, du, grep, cp, mv, sed, dmesg, ls, kill, gunzip, and mknod.
-            New apps include sort, uniq, lsmod, rmmod, fbset, and loadacm.
-            In particular, this release fixes an important bug in tar which 
-            in some cases produced serious security problems.
-            As always, the changelog can be found <a href="ftp://ftp.lineo.com/pub/busybox/Changelog">here</a>.
-
-    <p> <li> <b>11 December 1999 -- BusyBox Website</b>
-    <br>
-            I have received permission from Bruce Perens (the original author of BusyBox)
-               to set up this site as the new primary website for BusyBox.  This website
-               will always contain pointers to the latest and greatest, and will also 
-               contain the latest documentation on how to use BusyBox, what it can do,
-               what arguments its apps support, etc.
-
-    <p> <li> <b>10 December 1999 -- BusyBox 0.39 released</b>
-    <br>
-            This release includes fixes to init, reboot, halt, kill, and ls, and contains 
-            the new apps ping, hostname, mkfifo, free, tail, du, tee, and head.  A full
-            changelog can be found <a href="ftp://ftp.lineo.com/pub/busybox/Changelog">here</a>.
-    <p> <li> <b>5 December 1999 -- BusyBox 0.38 released</b>
-    <br>
-            This release includes fixes to tar, cat, ls, dd, rm, umount, find, df, 
-               and make install, and includes new apps syslogd/klogd and logger. 
-</ul>
-
-
-<!-- Begin Links section -->
-
-<TR><TD BGCOLOR="#ccccc0" ALIGN=center>
-    <A NAME="links">
-    <BIG><B>
-    Important Links</A> 
-    </B></BIG>
-    </A>
-</TD></TR>
-<TR><TD BGCOLOR="#eeeee0">
-
-<ul> 
-
-    <li> <a href="http://busybox.lineo.com/">Take me back to http://busybox.lineo.com/</a>.
-    <p>
-
-    <li>  <A HREF="http://perens.com/FreeSoftware/">
-    Free Software from Bruce Perens</A><br>
-    The original idea for BusyBox, and all versions up to 0.26 were written 
-    by <A HREF="mailto:bruce@perens.com">Bruce Perens</a>.  This is his BusyBox website.
-    <p>
-
-    <li>  <A HREF="http://freshmeat.net/appindex/1999/04/11/923859921.html">
-    Freshmeat AppIndex record for BusyBox</A>
-    <p>
-
-    <li> <a href="http://opensource.lineo.com/software.html">Other cool embedded software</a>.
-    <p>
-
-    <li> <a href="http://opensource.lineo.com/">opensource.lineo.com</a>.
-    <p>
-
-    <li> <A HREF="http://www.lineo.com/">Lineo</A> is sponsoring BusyBox development.
-    <p>
-
-</ul>
-
-
-<!-- End of Table -->
-
-</TD></TR>
-</TABLE>
-</P>
-
-
-
-<!-- Footer -->
-<HR>
-<TABLE WIDTH="100%">
-    <TR>
-       <TD>
-           <font size="-1" face="arial, helvetica, sans-serif">
-           Mail all comments, insults, suggestions and bribes to 
-           <a href="mailto:andersen@lineo.com">Erik Andersen</a><BR>
-           The Busybox logo is copyright 1999,2000, Erik Andersen.
-           </font>
-       </TD>
-
-       <TD>
-           <a href="http://www.vim.org"><img border=0 width=88 height=32
-           src="images/anim.written.in.vi.gif" 
-           alt="This site created with the vi editor"></a>
-       </TD>
-
-       <TD>
-           <a href="http://www.gimp.org/"><img border=0 width=88 height=38
-           src="images/gfx_by_gimp.gif" alt="Graphics by GIMP"></a>
-       </TD>
-
-       <TD>
-           <a href="http://www.linuxtoday.com"><img width=90 height=36
-           src="images/ltbutton2.jpg" alt="Linux Today"></a>
-       </TD>
-
-       <TD>
-           <p><a href="http://slashdot.org"><img width=90 height=36
-           src="images/sdsmall.gif" alt="Slashdot"></a>
-       </TD>
-
-       <TD>
-           <a href="http://freshmeat.net"><img width=90 height=36
-           src="images/fm.mini.jpg" alt="Freshmeat"></a>
-       </TD>
-
-    </TR>
-</TABLE>
-
-
-</BODY>
-</HTML>
-
diff --git a/busybox/docs/busybox.net/screenshot.html b/busybox/docs/busybox.net/screenshot.html
deleted file mode 100644 (file)
index 8424fce..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<html>
-
-<head>
-
-<title> Busybox Screenshot! </title>
-
-<meta name="Author" content="Mark Whitley">
-<meta name="Description" content="A screenshot of Busybox">
-
-</head>
-
-<body text="#000000" alink="#660000" link="#660000" bgcolor="#dee2de" vlink="#660000">
-
-<h1> Busybox Screenshot! </h1>
-
-<TABLE WIDTH="80%" CELLSPACING=1 CELLPADDING=4 BORDER=1>
-<TR><TD BGCOLOR="#000000">
-
-
-<pre style="background-color: black; color: lightgreen; padding: 5px;
-font-family: monospace; font-size: smaller;" width="80%">
-
-
-$ ./busybox
-BusyBox v0.49 (2001.01.30-17:35+0000) multi-call binary -- GPL2
-
-Usage: busybox [function] [arguments]...
-   or: [function] [arguments]...
-
-        BusyBox is a multi-call binary that combines many common Unix
-        utilities into a single executable.  Most people will create a
-        link to busybox for each function they wish to use, and BusyBox
-        will act like whatever it was invoked as.
-
-Currently defined functions:
-        basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear,
-        cp, cut, date, dd, df, dirname, dmesg, du, echo, false, find,
-        free, grep, gunzip, gzip, halt, head, id, init, kill, killall,
-        ln, logger, ls, lsmod, mkdir, mknod, mkswap, more, mount, mv,
-        poweroff, ps, pwd, reboot, reset, rm, rmdir, sed, sh, sleep, sort,
-        swapoff, swapon, sync, syslogd, tail, tar, touch, true, tty, umount,
-        uname, uniq, uptime, wc, which, whoami, xargs, yes, zcat
-
-$ <blink>_</blink>
-
-</pre>
-
-</TD></TR>
-</TABLE>
-
-</body>
-
-</html>
-
diff --git a/busybox/docs/busybox.sgml b/busybox/docs/busybox.sgml
deleted file mode 100644 (file)
index 2d37250..0000000
+++ /dev/null
@@ -1,3974 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [ ]>
-<book id="BusyBoxDocumentation">
- <bookinfo>
-  <title>BusyBox - The Swiss Army Knife of Embedded Linux</title>
-  
-  <legalnotice>
-   <para>
-     This documentation is free software; you can redistribute
-     it and/or modify it under the terms of the GNU General Public
-     License as published by the Free Software Foundation; either
-     version 2 of the License, or (at your option) any later
-     version.
-   </para>
-      
-   <para>
-     This program is distributed in the hope that it will be
-     useful, but WITHOUT ANY WARRANTY; without even the implied
-     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-     See the GNU General Public License for more details.
-   </para>
-      
-   <para>
-     You should have received a copy of the GNU General Public
-     License along with this program; if not, write to the Free
-     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-     MA 02111-1307 USA
-   </para>
-      
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
- </bookinfo>
-
-<toc></toc>
-  <chapter id="Introduction">
-     <title>Introduction</title>
-
-       <para>
-       BusyBox combines tiny versions of many common UNIX utilities into a single
-       small executable. It provides minimalist replacements for most of the
-       utilities you usually find in fileutils, shellutils, findutils, textutils,
-       grep, gzip, tar, etc. BusyBox provides a fairly complete POSIX environment
-       for any small or embedded system. The utilities in BusyBox generally have
-       fewer options than their full-featured GNU cousins; however, the options
-       that are included provide the expected functionality and behave very much
-       like their GNU counterparts. 
-       </para>
-
-       <para>
-       BusyBox has been written with size-optimization and limited resources in
-       mind. It is also extremely modular so you can easily include or exclude
-       commands (or features) at compile time. This makes it easy to customize
-       your embedded systems. To create a working system, just add a kernel, a
-       shell (such as ash), and an editor (such as elvis-tiny or ae).
-       </para>
-  </chapter>
-
-  <chapter id="Syntax">
-     <title>How to use BusyBox</title>
-       <sect1 id="How-to-use-BusyBox">
-           <title>Syntax</title>
-
-           <para>
-           <screen>
-            BusyBox &lt;function&gt; [arguments...]  # or
-           </screen>
-           </para>
-
-           <para>
-           <screen>
-            &lt;function&gt; [arguments...]          # if symlinked
-           </screen>
-           </para>
-       </sect1>
-
-       <sect1 id="Invoking-BusyBox">
-           <title>Invoking BusyBox</title>
-
-           <para>
-           When you create a link to BusyBox for the function you wish to use, when
-           BusyBox is called using that link it will behave as if the command itself
-           has been invoked.
-           </para>
-
-           <para>
-           For example, entering
-           </para>
-
-           <para>
-           <screen>
-                   ln -s ./BusyBox ls
-                   ./ls
-           </screen>
-           </para>
-
-           <para>
-           will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled
-           into BusyBox). 
-           </para>
-
-           <para>
-           You can also invoke BusyBox by issuing the command as an argument on the
-           command line. For example, entering
-           </para>
-
-           <para>
-           <screen>
-                   ./BusyBox ls
-           </screen>
-           </para>
-
-           <para>
-           will also cause BusyBox to behave as 'ls'. 
-           </para>
-
-       </sect1>
-
-       <sect1 id="Common-options">
-           <title>Common options</title>
-
-           <para>
-           Most BusyBox commands support the <emphasis>--help</emphasis> option to provide 
-           a terse runtime description of their behavior. 
-           </para>
-       </sect1>
-  </chapter>
-
-  <chapter id="Commands">
-     <title>BusyBox Commands</title>
-       <sect1 id="Available-BusyBox-Commands">
-           <title>Available BusyBox Commands</title>
-               <para>
-               Currently defined functions include:
-               </para>
-
-               <para>
-               ar, basename, cat, chgrp, chmod, chown, chroot, chvt, clear,
-               cp, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dpkg-deb,
-               du, dumpkmap, dutmp, echo, false, fbset, fdflush, find, free,
-               freeramdisk, fsck.minix, grep, gunzip, gzip, halt, head,
-               hostid, hostname, id, init, insmod, kill, killall, length, ln,
-               loadacm, loadfont, loadkmap, logger, logname, ls, lsmod,
-               makedevs, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp,
-               more, mount, mt, mv, nc, nslookup, ping, poweroff, printf, ps,
-               pwd, reboot, renice, reset, rm, rmdir, rmmod, sed, setkeycodes, sh, sleep,
-               sort, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet,
-               test, touch, tr, true, tty, umount, uname, uniq, update,
-               uptime, usleep, uudecode, uuencode, wc, which, whoami, yes,
-               zcat, [
-               </para>
-       </sect1>
-
-       <sect1 id="ar">
-           <title>ar</title>
-
-               <para>
-               Usage: ar [OPTION] archive [FILENAME]...
-               </para>
-
-               <para>
-               Extract or list files from an ar archive.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       o       Preserve original dates
-                       p       Extract to stdout
-                       t       List
-                       x       Extract
-                       v       Verbosely list files processed
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="basename">
-           <title>basename</title>
-               <para>
-               Usage: basename FILE [SUFFIX]
-               </para>
-
-               <para>
-               Strip directory path and suffixes from FILE. If specified, also removes
-               any trailing SUFFIX.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ basename /usr/local/bin/foo
-                       foo
-                       $ basename /usr/local/bin/
-                       bin
-                       $ basename /foo/bar.txt .txt
-                       bar
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="cat">
-           <title>cat</title>
-
-               <para>
-               Usage: cat [FILE]...
-               </para>
-
-               <para>
-               Concatenate <literal>FILE(s)</literal> and prints them to the standard
-               output.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ cat /proc/uptime
-                       110716.72 17.67
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="chgrp">
-           <title>chgrp</title>
-
-               <para>
-               Usage: chgrp [OPTION]... GROUP FILE...
-               </para>
-
-               <para>
-               Change the group membership of each FILE to GROUP.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -R      Change files and directories recursively
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -l /tmp/foo
-                       -r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo
-                       $ chgrp root /tmp/foo
-                       $ ls -l /tmp/foo
-                       -r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="chmod">
-           <title>chmod</title>
-
-               <para>
-               Usage: chmod [<emphasis>-R</emphasis>] MODE[,MODE]... FILE...
-               </para>
-
-               <para>
-               Change file access permissions for the specified
-               <literal>FILE(s)</literal> (or directories). Each MODE is defined by
-               combining the letters for WHO has access to the file, an OPERATOR for
-               selecting how the permissions should be changed, and a PERMISSION for
-               <literal>FILE(s)</literal> (or directories).
-               </para>
-
-               <para>
-               WHO may be chosen from
-               </para>
-
-               <para>
-               <screen>
-                       u       User who owns the file
-                       g       Users in the file's Group
-                       o       Other users not in the file's group
-                       a       All users
-               </screen>
-               </para>
-
-               <para>
-               OPERATOR may be chosen from
-               </para>
-
-               <para>
-               <screen>
-                       +       Add a permission
-                       -       Remove a permission
-                       =       Assign a permission
-               </screen>
-               </para>
-
-               <para>
-               PERMISSION may be chosen from
-               </para>
-
-               <para>
-               <screen>
-                       r       Read
-                       w       Write
-                       x       Execute (or access for directories)
-                       s       Set user (or group) ID bit
-                       t       Sticky bit (for directories prevents removing files by non-owners)
-               </screen>
-               </para>
-
-               <para>
-               Alternately, permissions can be set numerically where the first three
-               numbers are calculated by adding the octal values, such as
-               </para>
-
-               <para>
-               <screen>
-                       4       Read
-                       2       Write
-                       1       Execute
-               </screen>
-               </para>
-
-               <para>
-               An optional fourth digit can also be used to specify
-               </para>
-
-               <para>
-               <screen>
-                       4       Set user ID
-                       2       Set group ID
-                       1       Sticky bit
-               </screen>
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -R      Change files and directories recursively.
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -l /tmp/foo
-                       -rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo
-                       $ chmod u+x /tmp/foo
-                       $ ls -l /tmp/foo
-                       -rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*
-                       $ chmod 444 /tmp/foo
-                       $ ls -l /tmp/foo
-                       -r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-       
-       <sect1 id="chown">
-           <title>chown</title>
-               <para>
-               Usage: chown [OPTION]... OWNER[&lt;.|:&gt;[GROUP] FILE...
-               </para>
-
-               <para>
-               Change the owner and/or group of each FILE to OWNER and/or GROUP.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -R      Change files and directories recursively
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -l /tmp/foo
-                       -r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo
-                       $ chown root /tmp/foo
-                       $ ls -l /tmp/foo
-                       -r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo
-                       $ chown root.root /tmp/foo
-                       ls -l /tmp/foo
-                       -r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="chroot">
-           <title>chroot</title>
-               <para>
-               Usage: chroot NEWROOT [COMMAND...]
-               </para>
-
-               <para>
-               Run COMMAND with root directory set to NEWROOT.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -l /bin/ls
-                       lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -&gt; /BusyBox
-                       $ mount /dev/hdc1 /mnt -t minix
-                       $ chroot /mnt
-                       $ ls -l /bin/ls
-                       -rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="chvt">
-           <title>chvt</title>
-               <para>
-               Usage: chvt N
-               </para>
-
-               <para>
-               Change the foreground virtual terminal to /dev/ttyN
-               </para>
-       </sect1>
-
-       <sect1 id="clear">
-           <title>clear</title>
-
-               <para>
-               Usage: clear
-               </para>
-
-               <para>
-               Clear the screen.
-               </para>
-       </sect1>
-
-       <sect1 id="cp">
-           <title>cp</title>
-
-               <para>
-               Usage: cp [OPTION]... SOURCE DEST
-               </para>
-
-               <para>
-               <screen>
-                  or: cp [OPTION]... SOURCE... DIRECTORY
-               </screen>
-               </para>
-
-               <para>
-               Copy SOURCE to DEST, or multiple <literal>SOURCE(s)</literal> to
-               DIRECTORY.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Same as -dpR
-                       -d      Preserve links
-                       -p      Preserve file attributes if possible
-                       -R      Copy directories recursively
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="cut">
-           <title>cut</title>
-
-               <para>
-               Usage: cut [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               Print selected fields from each input FILE to standard output.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                               -b LIST Output only bytes from LIST
-                               -c LIST Output only characters from LIST
-                               -d CHAR Use CHAR instead of tab as the field delimiter
-                               -s      Output only the lines containing delimiter
-                               -f N    Print only these fields
-                               -n      Ignored
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo "Hello world" | cut -f 1 -d ' '
-                       Hello
-                       $ echo "Hello world" | cut -f 2 -d ' '
-                       world
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="date">
-           <title>date</title>
-
-               <para>
-               Usage: date [OPTION]... [+FORMAT]
-               </para>
-
-               <para>
-               <screen>
-                 or:  date [OPTION] [MMDDhhmm[[CC]YY][.ss]]
-               </screen>
-               </para>
-
-               <para>
-               Display the current time in the given FORMAT, or set the system date.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -R      Output RFC-822 compliant date string
-                       -s      Set time described by STRING
-                       -u      Print or set Coordinated Universal Time
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ date
-                       Wed Apr 12 18:52:41 MDT 2000
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dc">
-           <title>dc</title>
-
-               <para>
-               Usage: dc [EXPRESSION]
-               </para>
-
-               <para>
-               This is a Tiny RPN calculator that understands the
-               following operations: +, -, /, *, and, or, not, eor. If
-               no arguments are given, dc will process input from
-               stdin.
-               </para>
-
-               <para>
-               The behaviour of BusyBox/dc deviates (just a little ;-)
-               from GNU/dc, but this will be remedied in the future.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dc 2 2 +
-                       4
-                       $ dc 8 8 \* 2 2 + /
-                       16
-                       $ dc 0 1 and
-                       0
-                       $ dc 0 1 or
-                       1
-                       $ echo 72 9 div 8 mul | dc
-                       64
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dd">
-           <title>dd</title>
-
-               <para>
-               Usage: dd [OPTION]...
-               </para>
-
-               <para>
-               Copy a file, converting and formatting according to
-               options.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       if=FILE Read from FILE instead of stdin
-                       of=FILE Write to FILE instead of stdout
-                       bs=N    Read and write N bytes at a time
-                       count=N Copy only N input blocks
-                       skip=N  Skip N input blocks
-                       seek=N  Skip N output blocks
-               </screen>
-               </para>
-
-               <para>
-               Numbers may be suffixed by w (x2), k (x1024), b (x512),
-               or M (x1024^2).
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dd if=/dev/zero of=/dev/ram1 bs=1M count=4
-                       4+0 records in
-                       4+0 records out
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="deallocvt">
-           <title>deallocvt</title>
-
-               <para>
-               Usage: deallocvt N
-               </para>
-
-               <para>
-               Deallocate unused virtual terminal /dev/ttyN.
-               </para>
-       </sect1>
-
-       <sect1 id="df">
-           <title>df</title>
-
-               <para>
-               Usage: df [FILE]...
-               </para>
-
-               <para>
-               Print the filesystem space used and space available.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ df
-                       Filesystem           1k-blocks      Used Available Use% Mounted on
-                       /dev/sda3              8690864   8553540    137324  98% /
-                       /dev/sda1                64216     36364     27852  57% /boot
-                       $ df /dev/sda3
-                       Filesystem           1k-blocks      Used Available Use% Mounted on
-                       /dev/sda3              8690864   8553540    137324  98% /
-               </screen>
-               </para>
-       </sect1>
-       
-       <sect1 id="dirname">
-           <title>dirname</title>
-
-               <para>
-               Usage: dirname NAME
-               </para>
-
-               <para>
-               Strip non-directory suffix from NAME.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dirname /tmp/foo
-                       /tmp
-                       $ dirname /tmp/foo/
-                       /tmp
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dmesg">
-           <title>dmesg</title>
-
-               <para>
-               Usage: dmesg [OPTION]...
-               </para>
-
-               <para>
-               Print or control the kernel ring buffer.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c              Clear the ring buffer after printing
-                       -n LEVEL        Set the console logging level to LEVEL
-                       -s BUFSIZE      Query ring buffer using a buffer of BUFSIZE
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dos2unix">
-           <title>dos2unix</title>
-
-               <para>
-               Usage: dos2unix < dosfile > unixfile
-               </para>
-
-               <para>
-               Converts a text file from dos format to unix format.
-               </para>
-
-       </sect1>
-
-       <sect1 id="dpkg-deb">
-           <title>dpkg-deb</title>
-
-               <para>
-               Usage: dpkg-deb [OPTION] archive [directory] 
-               </para>
-
-               <para>
-               Debian package archive (.deb) manipulation tool 
-               </para>
-
-               <para>
-               Options:
-               </para>
-               
-               <para>
-               <screen>
-                       -c      List the contents of the filesystem tree archive portion of the package 
-                       -e      Extracts the control information files from a package archive into the specified directory.
-                               If  no  directory  is specified then a subdirectory DEBIAN in the current directory is used.
-                       -x      Silently extracts the filesystem tree from a package archive into the specified directory.
-                       -X      Extracts the filesystem tree from a package archive into the specified directory, listing the files as it goes. 
-                       If required the specified directory (but not its parents) will be created.
-               </screen>
-               <para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       dpkg-deb -e ./busybox_0.48-1_i386.deb
-                       dpkg-deb -x ./busybox_0.48-1_i386.deb ./unpack_dir
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="du">
-           <title>du</title>
-
-               <para>
-               Usage: du [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               Summarize the disk space used for each FILE or current
-               directory.  Disk space printed in units of 1k (i.e.,
-               1024 bytes).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -l      Count sizes many times if hard linked
-                       -s      Display only a total for each argument
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ du
-                       16      ./CVS
-                       12      ./kernel-patches/CVS
-                       80      ./kernel-patches
-                       12      ./tests/CVS
-                       36      ./tests
-                       12      ./scripts/CVS
-                       16      ./scripts
-                       12      ./docs/CVS
-                       104     ./docs
-                       2417    .
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dumpkmap">
-           <title>dumpkmap</title>
-
-               <para>
-               Usage: dumpkmap
-               </para>
-
-               <para>
-               Prints out a binary keyboard translation table to standard output.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dumpkmap &lt; keymap
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="dutmp">
-           <title>dutmp</title>
-
-               <para>
-               Usage: dutmp [FILE]
-               </para>
-
-               <para>
-               Dump utmp file format (pipe delimited) from FILE or
-               stdin to stdout.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dutmp /var/run/utmp
-                       8|7||si|||0|0|0|955637625|760097|0
-                       2|0|~|~~|reboot||0|0|0|955637625|782235|0
-                       1|20020|~|~~|runlevel||0|0|0|955637625|800089|0
-                       8|125||l4|||0|0|0|955637629|998367|0
-                       6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0
-                       6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0
-                       7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="echo">
-           <title>echo</title>
-
-               <para>
-               Usage: echo [OPTION]... [ARG]...
-               </para>
-
-               <para>
-               Print ARGs to stdout.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -n      Suppress trailing newline
-                       -e      Enable interpretation of escaped characters
-                       -E      Disable interpretation of escaped characters
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo "Erik is cool"
-                       Erik is cool
-                       $ echo -e "Erik\nis\ncool"
-                       Erik
-                       is
-                       cool
-                       $ echo "Erik\nis\ncool"
-                       Erik\nis\ncool
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="expr">
-           <title>expr</title>
-
-               <para>
-               Usage: expr EXPRESSION
-               </para>
-
-               <para>
-               Prints the value of EXPRESSION to standard output.
-               </para>
-
-               <para>
-               EXPRESSION may be:
-               </para>
-
-               <para>
-               <screen>
-                       ARG1 |  ARG2    ARG1 if it is neither null nor 0, otherwise ARG2
-                       ARG1 &  ARG2    ARG1 if neither argument is null or 0, otherwise 0
-                       ARG1 &lt  ARG2    ARG1 is less than ARG2
-                       ARG1 &lt= ARG2    ARG1 is less than or equal to ARG2
-                       ARG1 =  ARG2    ARG1 is equal to ARG2
-                       ARG1 != ARG2    ARG1 is unequal to ARG2
-                       ARG1 &gt= ARG2    ARG1 is greater than or equal to ARG2
-                       ARG1 &gt  ARG2    ARG1 is greater than ARG2
-                       ARG1 +  ARG2    arithmetic sum of ARG1 and ARG2
-                       ARG1 -  ARG2    arithmetic difference of ARG1 and ARG2
-                       ARG1 *  ARG2    arithmetic product of ARG1 and ARG2
-                       ARG1 /  ARG2    arithmetic quotient of ARG1 divided by ARG2
-                       ARG1 %  ARG2    arithmetic remainder of ARG1 divided by ARG2
-                       STRING : REGEXP             anchored pattern match of REGEXP in STRING
-                       match STRING REGEXP         same as STRING : REGEXP
-                       substr STRING POS LENGTH    substring of STRING, POS counted from 1
-                       index STRING CHARS          index in STRING where any CHARS is found, or 0
-                       length STRING               length of STRING
-                       quote TOKEN                 interpret TOKEN as a string, even if it is a
-                                                       keyword like `match' or an operator like `/'
-                       ( EXPRESSION )              value of EXPRESSION
-               </screen>
-               </para>
-
-               <para>
-               Beware that many operators need to be escaped or quoted for shells.
-               Comparisons are arithmetic if both ARGs are numbers, else
-               lexicographical.  Pattern matches return the string matched between
-               \( and \) or null; if \( and \) are not used, they return the number
-               of characters matched or 0.
-               </para>
-
-       </sect1>
-
-
-       <sect1 id="false">
-           <title>false</title>
-
-               <para>
-               Usage: false
-               </para>
-
-               <para>
-               Return an exit code of FALSE (1).
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ false
-                       $ echo $?
-                       1
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="fbset">
-           <title>fbset</title>
-
-               <para>
-               Usage: fbset [OPTION]... [MODE]
-               </para>
-
-               <para>
-               Show and modify frame buffer device settings.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -h                                              Display option summary
-                       -fb DEVICE                                      Operate on DEVICE
-                       -db FILE                                        Use FILE for mode database
-                       -g XRES YRES VXRES VYRES DEPTH                  Set all geometry parameters
-                       -t PIXCLOCK LEFT RIGHT UPPER LOWER HSLEN VSLEN  Set all timing parameters
-                       -xres RES                                       Set visible horizontal resolution
-                       -yres RES                                       Set visible vertical resolution
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ fbset
-                       mode "1024x768-76"
-                                       # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz
-                                       geometry 1024 768 1024 768 16
-                                       timings 12714 128 32 16 4 128 4
-                                       accel false
-                                       rgba 5/11,6/5,5/0,0/0
-                       endmode
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="fdflush">
-           <title>fdflush</title>
-
-               <para>
-               Usage: fdflush DEVICE
-               </para>
-
-               <para>
-               Force floppy disk drive to detect disk change on DEVICE.
-               </para>
-       </sect1>
-
-       <sect1 id="find">
-           <title>find</title>
-
-               <para>
-               Usage: find [PATH]... [EXPRESSION]
-               </para>
-
-               <para>
-               Search for files in a directory hierarchy. The default
-               PATH is the current directory; default EXPRESSION is
-               '-print'.
-               </para>
-
-               <para>
-               EXPRESSION may consist of:
-               </para>
-
-               <para>
-               <screen>
-                       -follow         Dereference symbolic links
-                       -name PATTERN   File name (leading directories removed) matches PATTERN
-                       -type X         Filetype matches X (where X is one of: f,d,l,b,c,...)
-                       -perm PERMS     Permissions match any of (+NNN); all of (-NNN); or exactly (NNN)
-                       -mtime TIME     Modified time is greater than (+N); less than (-N); or exactly (N) days
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ find / -name /etc/passwd
-                       /etc/passwd
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="free">
-           <title>free</title>
-
-               <para>
-               Usage: free
-               </para>
-
-               <para>
-               Displays the amount of free and used system memory.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ free
-                       total         used         free       shared      buffers
-                         Mem:       257628       248724         8904        59644        93124
-                        Swap:       128516         8404       120112
-                       Total:       386144       257128       129016
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="freeramdisk">
-           <title>freeramdisk</title>
-
-               <para>
-               Usage: freeramdisk DEVICE
-               </para>
-
-               <para>
-               Free all memory used by the ramdisk DEVICE.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ freeramdisk /dev/ram2
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="fsck.minix">
-           <title>fsck.minix</title>
-
-               <para>
-               Usage: fsck.minix [OPTION]... DEVICE
-               </para>
-
-               <para>
-               Perform a consistency check on the MINIX filesystem on
-               DEVICE.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -l      List all filenames
-                       -r      Perform interactive repairs
-                       -a      Perform automatic repairs
-                       -v      Verbose
-                       -s      Output super-block information
-                       -m      Activate MINIX-like "mode not cleared" warnings
-                       -f      Force file system check.
-               </screen>
-               </para>
-       </sect1>
-       
-       <sect1 id="getopt">
-           <title>getopt</title>
-
-               <para>
-               Usage: getopt [OPTIONS]...
-               </para>
-
-               <para>
-               Parse command options
-               </para>
-
-               <para>
-               <screen>
-                  -a, --alternative            Allow long options starting with single -\n"
-                  -l, --longoptions=longopts   Long options to be recognized\n"
-                  -n, --name=progname          The name under which errors are reported\n"
-                  -o, --options=optstring      Short options to be recognized\n"
-                  -q, --quiet                  Disable error reporting by getopt(3)\n"
-                  -Q, --quiet-output           No normal output\n"
-                  -s, --shell=shell            Set shell quoting conventions\n"
-                  -T, --test                   Test for getopt(1) version\n"
-                  -u, --unqote                 Do not quote the output\n"
-               </screen>
-               </para>
-
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ cat getopt.test
-                       #!/bin/sh
-                       GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
-                               -n 'example.busybox' -- "$@"`
-                       if [ $? != 0 ] ; then  exit 1 ; fi
-                       eval set -- "$GETOPT"
-                       while true ; do
-                         case $1 in
-                           -a|--a-long) echo "Option a" ; shift ;;
-                           -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
-                           -c|--c-long)
-                             case "$2" in
-                               "") echo "Option c, no argument"; shift 2 ;;
-                               *)  echo "Option c, argument \`$2'" ; shift 2 ;;
-                             esac ;;
-                           --) shift ; break ;;
-                           *) echo "Internal error!" ; exit 1 ;;
-                         esac
-                       done
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="grep">
-           <title>grep</title>
-
-               <para>
-               Usage: grep [OPTIONS]... PATTERN [FILE]...
-               </para>
-
-               <para>
-               Search for PATTERN in each FILE or stdin.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -h      Suppress the prefixing filename on output
-                       -i      Ignore case distinctions
-                       -n      Print line number with output lines
-                       -q      Be quiet. Returns 0 if result was found, 1 otherwise
-                       -v      Select non-matching lines
-               </screen>
-               </para>
-
-               <para>
-               This version of grep matches full regular expressions.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ grep root /etc/passwd
-                       root:x:0:0:root:/root:/bin/bash
-                       $ grep ^[rR]oo. /etc/passwd
-                       root:x:0:0:root:/root:/bin/bash
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="gunzip">
-           <title>gunzip</title>
-
-               <para>
-               Usage: gunzip [OPTION]... FILE
-               </para>
-
-               <para>
-               Uncompress FILE (or stdin if FILE is '-').
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Write output to standard output
-                       -t      Test compressed file integrity
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -la /tmp/BusyBox*
-                       -rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz
-                       $ gunzip /tmp/BusyBox-0.43.tar.gz
-                       $ ls -la /tmp/BusyBox*
-                       -rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="gzip">
-           <title>gzip</title>
-
-               <para>
-               Usage: gzip [OPTION]... FILE
-               </para>
-
-               <para>
-               Compress FILE (or stdin if FILE is '-') with maximum
-               compression to FILE.gz (or stdout if FILE is '-').
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Write output to standard output
-                       -d      decompress
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -la /tmp/BusyBox*
-                       -rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar
-                       $ gzip /tmp/BusyBox-0.43.tar
-                       $ ls -la /tmp/BusyBox*
-                       -rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/BusyBox-0.43.tar.gz
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="halt">
-           <title>halt</title>
-
-               <para>
-               Usage: halt
-               </para>
-
-               <para>
-               Halt the system.
-               </para>
-       </sect1>
-
-       <sect1 id="head">
-           <title>head</title>
-
-               <para>
-               Usage: head [OPTION] FILE...
-               </para>
-
-               <para>
-               Print first 10 lines of each FILE to standard output.
-               With more than one FILE, precede each with a header
-               giving the file name. With no FILE, or when FILE is -,
-               read standard input.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -n NUM  Print first NUM lines instead of first 10
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ head -n 2 /etc/passwd
-                       root:x:0:0:root:/root:/bin/bash
-                       daemon:x:1:1:daemon:/usr/sbin:/bin/sh
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="hostid">
-           <title>hostid</title>
-
-               <para>
-               Usage: hostid
-               </para>
-
-               <para>
-               Prints out a unique 32-bit identifier for the current
-               machine. The 32-bit identifier is intended to be unique
-               among all UNIX systems in existence. 
-               </para>
-       </sect1>
-
-       <sect1 id="hostname">
-           <title>hostname</title>
-
-               <para>
-               Usage: hostname [OPTION]... [HOSTNAME|-F FILE]
-               </para>
-
-               <para>
-               Get or set the hostname or DNS domain name. If a
-               hostname is given (or a file with the -F parameter), the
-               host name will be set.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -s              Short
-                       -i              Addresses for the hostname
-                       -d              DNS domain name
-                       -F, --file FILE Use the contents of FILE to specify the hostname
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ hostname
-                       slag
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="id">
-           <title>id</title>
-
-               <para>
-               Usage: id [OPTION]... [USERNAME]
-               </para>
-
-               <para>
-               Print information for USERNAME or the current user.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -g      Print only the group ID
-                       -u      Print only the user ID
-                       -n      print a name instead of a number (with for -ug)
-                       -r      Print the real user ID instead of the effective ID (with -ug)
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ id
-                       uid=1000(andersen) gid=1000(andersen)
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="init">
-           <title>init</title>
-
-               <para>
-               Usage: init
-               </para>
-
-               <para>
-               Init is the parent of all processes.
-               </para>
-
-               <para>
-               This version of init is designed to be run only by the
-               kernel.
-               </para>
-
-               <para>
-               BusyBox init doesn't support multiple runlevels. The
-               runlevels field of the /etc/inittab file is completely
-               ignored by BusyBox init. If you want runlevels, use
-               sysvinit.
-               </para>
-
-               <para>
-               BusyBox init works just fine without an inittab. If no
-               inittab is found, it has the following default behavior:
-               </para>
-
-               <para>
-               <screen>
-                       ::sysinit:/etc/init.d/rcS
-                       ::askfirst:/bin/sh
-               </screen>
-               </para>
-
-               <para>
-               If it detects that /dev/console is _not_ a serial
-               console, it will also run:
-               </para>
-
-               <para>
-               <screen>
-                       tty2::askfirst:/bin/sh
-               </screen>
-               </para>
-
-               <para>
-               If you choose to use an /etc/inittab file, the inittab
-               entry format is as follows:
-               </para>
-
-               <para>
-               <screen>
-                       &lt;id&gt;:&lt;runlevels&gt;:&lt;action&gt;:&lt;process&gt;
-               </screen>
-               </para>
-
-               <sect2>
-                   <title>id</title>
-                       <para>
-
-                       WARNING: This field has a non-traditional meaning for BusyBox init!
-                       The id field is used by BusyBox init to specify the controlling tty
-                       for the specified process to run on.  The contents of this field
-                       are appended to "/dev/" and used as-is.  There is no need for this
-                       field to be unique, although if it isn't you may have strange
-                       results.  If this field is left blank, the controlling tty is set
-                       to the console.  Also note that if BusyBox detects that a serial
-                       console is in use, then only entries whose controlling tty is
-                       either the serial console or /dev/null will be run.  BusyBox init
-                       does nothing with utmp.  We don't need no stinkin' utmp.
-
-                       </para>
-               </sect2>
-
-               <sect2>
-                   <title>runlevels</title>
-
-                       <para>
-                       The runlevels field is completely ignored.
-                       </para>
-               </sect2>
-
-               <sect2>
-                   <title>action</title>
-
-
-                       <para>
-                       Valid actions include: sysinit, respawn, askfirst, wait, 
-                       once, and ctrlaltdel.
-                       </para>
-
-
-                       <para>
-                       The available actions can be classified into two groups: actions
-                       that are run only once, and actions that are re-run when the specified
-                       process exits.
-                       </para>
-
-                       <para>
-                       Run only-once actions:
-                       </para>
-
-                       <para>
-                       'sysinit' is the first item run on boot.  init waits until all
-                       sysinit actions are completed before continuing.  Following the
-                       completion of all sysinit actions, all 'wait' actions are run.
-                       'wait' actions, like  'sysinit' actions, cause init to wait until
-                       the specified task completes.  'once' actions are asyncronous,
-                       therefore, init does not wait for them to complete.  'ctrlaltdel'
-                       actions are run immediately before init causes the system to reboot
-                       (unmounting filesystems with a 'ctrlaltdel' action is a very good
-                        idea).
-                       </para>
-
-                       <para>
-                       Run repeatedly actions:
-                       </para>
-
-                       <para>
-                       'respawn' actions are run after the 'once' actions.  When a process
-                       started with a 'respawn' action exits, init automatically restarts
-                       it.  Unlike sysvinit, BusyBox init does not stop processes from
-                       respawning out of control.  The 'askfirst' actions acts just like
-                       respawn, except that before running the specified process it
-                       displays the line "Please press Enter to activate this console."
-                       and then waits for the user to press enter before starting the
-                       specified process.  
-                       </para>
-
-                       <para>
-                       Unrecognized actions (like initdefault) will cause init to emit an
-                       error message, and then go along with its business.  All actions are
-                       run in the reverse order from how they appear in /etc/inittab.
-                       </para>
-
-               </sect2>
-
-               <sect2>
-                   <title>process</title>
-
-                       <para>
-                       Specifies the process to be executed and its
-                       command line.
-                       </para>
-               </sect2>
-
-               <sect2>
-                   <title>Example /etc/inittab file</title>
-
-                   <para>
-                   <screen>
-                           # This is run first except when booting in single-user mode.
-                           #
-                           ::sysinit:/etc/init.d/rcS
-
-                           # /bin/sh invocations on selected ttys
-                           #
-                           # Start an "askfirst" shell on the console (whatever that may be)
-                           ::askfirst:-/bin/sh
-                           # Start an "askfirst" shell on /dev/tty2-4
-                           tty2::askfirst:-/bin/sh
-                           tty2::askfirst:-/bin/sh
-                           tty2::askfirst:-/bin/sh
-
-                           # /sbin/getty invocations for selected ttys
-                           #
-                           tty4::respawn:/sbin/getty 38400 tty5
-                           tty5::respawn:/sbin/getty 38400 tty6
-
-                           # Example of how to put a getty on a serial line (for a terminal)
-                           #
-                           #::respawn:/sbin/getty -L ttyS0 9600 vt100
-                           #::respawn:/sbin/getty -L ttyS1 9600 vt100
-                           #
-                           # Example how to put a getty on a modem line.
-                           #::respawn:/sbin/getty 57600 ttyS2
-
-                           # Stuff to do before rebooting
-                           ::ctrlaltdel:/bin/umount -a -r
-                           ::ctrlaltdel:/sbin/swapoff
-                   </screen>
-                   </para>
-               </sect2>
-       </sect1>
-
-       <sect1 id="insmod">
-           <title>insmod</title>
-
-               <para>
-               Usage: insmod [OPTION]... MODULE [symbol=value]...
-               </para>
-
-               <para>
-               Load MODULE into the kernel.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -f      Force module to load into the wrong kernel version.
-                       -k      Make module autoclean-able.
-                       -v      Verbose output
-                       -x      Do not export externs
-                       -L      Prevent simultaneous loads of the same module
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="kill">
-           <title>kill</title>
-
-               <para>
-               Usage: kill [OPTION] PID...
-               </para>
-
-               <para>
-               Send a signal (default is SIGTERM) to the specified
-               PID(s).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -l      List all signal names and numbers
-                       -SIG    Send signal SIG
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ps | grep apache
-                       252 root     root     S [apache]
-                       263 www-data www-data S [apache]
-                       264 www-data www-data S [apache]
-                       265 www-data www-data S [apache]
-                       266 www-data www-data S [apache]
-                       267 www-data www-data S [apache]
-                       $ kill 252
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="killall">
-           <title>killall</title>
-
-               <para>
-               Usage: killall [OPTION] NAME...
-               </para>
-
-               <para>
-               Send a signal (default is SIGTERM) to the specified
-               NAME(s).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -l      List all signal names and numbers
-                       -SIG    Send signal SIG
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ killall apache
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="length">
-           <title>length</title>
-
-               <para>
-               Usage: length STRING
-               </para>
-
-               <para>
-               Print the length of STRING.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ length "Hello"
-                       5
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="ln">
-           <title>ln</title>
-
-               <para>
-               Usage: ln [OPTION]... TARGET FILE|DIRECTORY
-               </para>
-
-               <para>
-               Create a link named FILE or DIRECTORY to the specified
-               TARGET.  You may use '--' to indicate that all following
-               arguments are non-options.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -s      Make symbolic link instead of hard link
-                       -f      Remove existing destination file
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ln -s BusyBox /tmp/ls
-                       $ ls -l /tmp/ls
-                       lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -&gt; BusyBox*
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="loadacm">
-           <title>loadacm</title>
-
-               <para>
-               Usage: loadacm
-               </para>
-
-               <para>
-               Load an acm from stdin.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ loadacm &lt; /etc/i18n/acmname
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="loadfont">
-           <title>loadfont</title>
-
-               <para>
-               Usage: loadfont
-               </para>
-
-               <para>
-               Load a console font from stdin.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ loadfont &lt; /etc/i18n/fontname
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="loadkmap">
-           <title>loadkmap</title>
-
-               <para>
-               Usage: loadkmap
-               </para>
-
-               <para>
-               Load a binary keyboard translation table from stdin.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ loadkmap &lt; /etc/i18n/lang-keymap
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="logger">
-           <title>logger</title>
-
-               <para>
-               Usage: logger [OPTION]... [MESSAGE]
-               </para>
-
-               <para>
-               Write MESSAGE to the system log.  If MESSAGE is omitted, log
-               stdin.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -s      Log to stderr as well as the system log
-                       -t      Log using the specified tag (defaults to user name)
-                       -p      Enter the message with the specified priority
-                               This may be numerical or a ``facility.level'' pair
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ logger "hello"
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="logname">
-           <title>logname</title>
-
-               <para>
-               Usage: logname
-               </para>
-
-               <para>
-               Print the name of the current user.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ logname
-                       root
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="ls">
-           <title>ls</title>
-
-               <para>
-               Usage: ls [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Do not hide entries starting with .
-                       -c      With  -l:  show ctime (the time of last
-                               modification of file status information)
-                       -d      List directory entries instead of contents
-                       -e      List both full date and full time
-                       -l      Use a long listing format
-                       -n      List numeric UIDs and GIDs instead of names
-                       -p      Append indicator (one of /=@|) to entries
-                       -u      With -l: show access time (the time of last
-                               access of the file)
-                       -x      List entries by lines instead of by columns
-                       -A      Do not list implied . and ..
-                       -C      List entries by columns
-                       -F      Append indicator (one of */=@|) to entries
-                       -L      list entries pointed to by symbolic links
-                       -R      List subdirectories recursively
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="lsmod">
-           <title>lsmod</title>
-
-               <para>
-               Usage: lsmod
-               </para>
-
-               <para>
-               List currently loaded kernel modules.
-               </para>
-       </sect1>
-
-       <sect1 id="makedevs">
-           <title>makedevs</title>
-
-               <para>
-               Usage: makedevsf NAME TYPE MAJOR MINOR FIRST LAST [s]
-               </para>
-
-               <para>
-               Create a range of block or character special files.
-               </para>
-
-               <para>
-               TYPE may be:
-               </para>
-
-               <para>
-               <screen>
-                       b       Make a block (buffered) device
-                       c or u  Make a character (un-buffered) device
-                       p       Make a named pipe. MAJOR and MINOR are ignored for named pipes
-               </screen>
-               </para>
-
-               <para>
-               FIRST specifies the number appended to NAME to create
-               the first device.  LAST specifies the number of the last
-               item that should be created. If 's' is the last
-               argument, the base device is created as well.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ makedevs /dev/ttyS c 4 66 2 63
-                       [creates ttyS2-ttyS63]
-                       $ makedevs /dev/hda b 3 0 0 8 s
-                       [creates hda,hda1-hda8]
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="md5sum">
-           <title>md5sum</title>
-
-               <para>
-               Usage: md5sum [OPTION]... FILE...
-               </para>
-
-               <para>
-               Print or check MD5 checksums.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -b      Read files in binary mode
-                       -c      Check MD5 sums against given list
-                       -t      Read files in text mode (default)
-                       -g      Read a string
-               </screen>
-               </para>
-
-               <para>
-               The following two options are useful only when verifying
-               checksums:
-               </para>
-
-               <para>
-               <screen>
-                       -s      Don't output anything, status code shows success
-                       -w      Warn about improperly formated MD5 checksum lines
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ md5sum busybox
-                       6fd11e98b98a58f64ff3398d7b324003  busybox
-                       $ md5sum -c
-                       6fd11e98b98a58f64ff3398d7b324003  busybox
-                       6fd11e98b98a58f64ff3398d7b324002  busybox
-                       md5sum: MD5 check failed for 'busybox'
-                       ^D
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mkdir">
-           <title>mkdir</title>
-
-               <para>
-               Usage: mkdir [OPTION]... DIRECTORY...
-               </para>
-
-               <para>
-               Create the DIRECTORY(s), if they do not already exist.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -m      Set permission mode (as in chmod), not rwxrwxrwx - umask
-                       -p      No error if directory exists, make parent directories as needed
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ mkdir /tmp/foo
-                       $ mkdir /tmp/foo
-                       /tmp/foo: File exists
-                       $ mkdir /tmp/foo/bar/baz
-                       /tmp/foo/bar/baz: No such file or directory
-                       $ mkdir -p /tmp/foo/bar/baz
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mkfifo">
-           <title>mkfifo</title>
-
-               <para>
-               Usage: mkfifo [OPTION] NAME
-               </para>
-
-               <para>
-               Create a named pipe (identical to 'mknod NAME p').
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -m MODE Create the pipe using the specified mode (default a=rw)
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mkfs.minix">
-           <title>mkfs.minix</title>
-
-               <para>
-               Usage: mkfs.minix [OPTION]... NAME [BLOCKS]
-               </para>
-
-               <para>
-               Make a MINIX filesystem.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c              Check the device for bad blocks
-                       -n [14|30]      Specify the maximum length of filenames
-                       -i              Specify the number of inodes for the filesystem
-                       -l FILENAME     Read the bad blocks list from FILENAME
-                       -v              Make a Minix version 2 filesystem
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mknod">
-           <title>mknod</title>
-
-               <para>
-               Usage: mknod [OPTION]... NAME TYPE MAJOR MINOR
-               </para>
-
-               <para>
-               Create a special file (block, character, or pipe).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -m      Create the special file using the specified mode (default a=rw)
-               </screen>
-               </para>
-
-               <para>
-               TYPE may be:
-               </para>
-
-               <para>
-               <screen>
-                       b       Make a block (buffered) device
-                       c or u  Make a character (un-buffered) device
-                       p       Make a named pipe. MAJOR and MINOR are ignored for named pipes
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ mknod /dev/fd0 b 2 0 
-                       $ mknod -m 644 /tmp/pipe p
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mkswap">
-           <title>mkswap</title>
-
-               <para>
-               Usage: mkswap [OPTION]... DEVICE [BLOCKS]
-               </para>
-
-               <para>
-               Prepare a disk partition to be used as a swap partition.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Check for read-ability.
-                       -v0     Make version 0 swap [max 128 Megs].
-                       -v1     Make version 1 swap [big!] (default for kernels &gt; 2.1.117).
-                       BLOCKS  Number of block to use (default is entire partition).
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mktemp">
-           <title>mktemp</title>
-
-               <para>
-               Usage: mktemp TEMPLATE
-               </para>
-
-               <para>
-               Creates a temporary file with its name based on
-               TEMPLATE.  TEMPLATE is any name with six `Xs' (i.e.,
-               /tmp/temp.XXXXXX).
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ mktemp /tmp/temp.XXXXXX
-                       /tmp/temp.mWiLjM
-                       $ ls -la /tmp/temp.mWiLjM
-                       -rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="more">
-           <title>more</title>
-
-               <para>
-               Usage: more [FILE]...
-               </para>
-
-               <para>
-               Page through text one screenful at a time.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ dmesg | more
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mount">
-           <title>mount</title>
-
-               <para>
-               Usage: mount [OPTION]...
-               </para>
-
-               <para>
-               <screen>
-                  or: mount [OPTION]... DEVICE DIRECTORY
-               </screen>
-               </para>
-
-               <para>
-               Mount filesystems.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Mount all filesystems in /etc/fstab
-                       -o      One of the many filesystem options listed below
-                       -r      Mount the filesystem read-only
-                       -t TYPE Specify the filesystem type
-                       -w      Mount the filesystem read-write
-               </screen>
-               </para>
-
-               <para>
-               Options for use with the -o flag:
-               </para>
-
-               <para>
-               <screen>
-                       async/sync      Writes are asynchronous / synchronous
-                       atime/noatime   Enable / disable updates to inode access times
-                       dev/nodev       Allow / disallow use of special device files
-                       exec/noexec     Allow / disallow use of executable files
-                       loop            Mount a file via loop device
-                       suid/nosuid     Allow / disallow set-user-id-root programs
-                       remount         Remount a currently mounted filesystem
-                       ro/rw           Mount filesystem read-only / read-write
-               </screen>
-               </para>
-
-               <para>
-               There are even more flags that are filesystem specific.
-               You'll have to see the written documentation for those.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ mount
-                       /dev/hda3 on / type minix (rw)
-                       proc on /proc type proc (rw)
-                       devpts on /dev/pts type devpts (rw)
-                       $ mount /dev/fd0 /mnt -t msdos -o ro
-                       $ mount /tmp/diskimage /opt -t ext2 -o loop
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mt">
-           <title>mt</title>
-
-               <para>
-               Usage: mt [OPTION] OPCODE VALUE
-               </para>
-
-               <para>
-               Control magnetic tape drive operation.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -f DEVICE       Control DEVICE
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="mv">
-           <title>mv</title>
-
-               <para>
-               Usage: mv SOURCE DEST
-               </para>
-
-               <para>
-               <screen>
-                  or: mv SOURCE... DIRECTORY
-               </screen>
-               </para>
-
-               <para>
-               Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ mv /tmp/foo /bin/bar
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="nc">
-           <title>nc</title>
-
-               <para>
-               Usage: nc HOST PORT
-               </para>
-
-               <para>
-                  or: nc -p PORT -l
-               </para>
-
-
-               <para>
-               Open a pipe to HOST:PORT or listen for a connection on PORT.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ nc foobar.somedomain.com 25
-                       220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600
-                       help
-                       214-Commands supported:
-                       214-    HELO EHLO MAIL RCPT DATA AUTH
-                       214     NOOP QUIT RSET HELP
-                       quit
-                       221 foobar closing connection
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="nslookup">
-           <title>nslookup</title>
-
-               <para>
-               Usage: nslookup [HOST]
-               </para>
-
-               <para>
-               Query the nameserver for the IP address of the given
-               HOST.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ nslookup localhost
-                       Server:     default
-                       Address:    default
-
-                       Name:       debian
-                       Address:    127.0.0.1
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="ping">
-           <title>ping</title>
-
-               <para>
-               Usage: ping [OPTION]... HOST
-               </para>
-
-               <para>
-               Send ICMP ECHO_REQUEST packets to HOST.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c COUNT        Send only COUNT pings
-                       -s SIZE         Send SIZE data bytes in packets (default=56)
-                       -q              Quiet mode, only displays output at start and when finished
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ping localhost
-                       PING slag (127.0.0.1): 56 data bytes
-                       64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms
-
-                       --- debian ping statistics ---
-                       1 packets transmitted, 1 packets received, 0% packet loss
-                       round-trip min/avg/max = 20.1/20.1/20.1 ms
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="poweroff">
-           <title>poweroff</title>
-
-               <para>
-               Usage: poweroff
-               </para>
-
-               <para>
-               Shut down the system, and request that the kernel turn
-               off power upon halting.
-               </para>
-       </sect1>
-
-       <sect1 id="printf">
-           <title>printf</title>
-
-               <para>
-               Usage: printf FORMAT [ARGUMENT]...
-               </para>
-
-               <para>
-               Format and print the given data in a manner similar to
-               the C printf command.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ printf "Val=%d\n" 5
-                       Val=5
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="ps">
-           <title>ps</title>
-
-               <para>
-               Usage: ps
-               </para>
-
-               <para>
-               Report process status.  This version of ps accepts no
-               options.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ps
-                         PID  Uid      Gid State Command
-                           1 root     root     S init
-                           2 root     root     S [kflushd]
-                           3 root     root     S [kupdate]
-                           4 root     root     S [kpiod]
-                           5 root     root     S [kswapd]
-                         742 andersen andersen S [bash]
-                         743 andersen andersen S -bash
-                         745 root     root     S [getty]
-                        2990 andersen andersen R ps
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="pwd">
-           <title>pwd</title>
-
-               <para>
-               Usage: pwd
-               </para>
-
-               <para>
-               Print the full filename of the current working
-               directory.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ pwd
-                       /root
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="rdate">
-           <title>rdate</title>
-
-               <para>
-               Usage: rdate [OPTION] HOST
-               </para>
-
-               <para>
-               Get and possibly set the system date and time from a remote HOST.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -s      Set the system date and time (default).
-                       -p      Print the date and time.
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="reboot">
-           <title>reboot</title>
-
-               <para>
-               Usage: reboot
-               </para>
-
-               <para>
-               Reboot the system.
-               </para>
-       </sect1>
-
-       <sect1 id="renice">
-           <title>renice</title>
-
-               <para>
-               Usage: renice priority pid [pid ...]
-               </para>
-
-               <para>
-               Changes priority of running processes. Allowed priorities range
-               from 20 (the process runs only when nothing else is running) to 0
-               (default priority) to -20 (almost nothing else ever gets to run).
-               </para>
-       </sect1>
-
-       <sect1 id="reset">
-           <title>reset</title>
-
-               <para>
-               Usage: reset
-               </para>
-
-               <para>
-               Resets the screen.
-               </para>
-       </sect1>
-
-       <sect1 id="rm">
-           <title>rm</title>
-
-               <para>
-               Usage: rm [OPTION]... FILE...
-               </para>
-
-               <para>
-               Remove (unlink) the FILE(s).  You may use '--' to
-               indicate that all following arguments are non-options.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -i              Always prompt before removing each destinations
-                       -f              Remove existing destinations, never prompt
-                       -r or -R        Remove the contents of directories recursively
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ rm -rf /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="rmdir">
-           <title>rmdir</title>
-
-               <para>
-               Usage: rmdir DIRECTORY...
-               </para>
-
-               <para>
-               Remove DIRECTORY(s) if they are empty.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ rmdir /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="rmmod">
-           <title>rmmod</title>
-
-               <para>
-               Usage: rmmod [OPTION]... [MODULE]...
-               </para>
-
-               <para>
-               Unload MODULE(s) from the kernel.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Try to remove all unused kernel modules
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ rmmod tulip
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="sed">
-           <title>sed</title>
-
-               <para>
-               Usage: sed [OPTION]... SCRIPT [FILE]...
-               </para>
-
-               <para>
-               Allowed sed scripts come in the following form:
-               </para>
-
-               <para>
-               <screen>
-               ADDR [!] COMMAND
-               </screen>
-               </para>
-
-               <para>
-               ADDR can be:
-               </para>
-
-               <para>
-               <screen>
-                       NUMBER    Match specified line number
-                       $         Match last line
-                       /REGEXP/  Match specified regexp
-               </screen>
-               </para>
-
-               <para>
-               ! inverts the meaning of the match
-               </para>
-
-               <para>
-               COMMAND can be:
-               </para>
-
-               <para>
-               <screen>
-                       s/regexp/replacement/[igp]
-                               which attempt to match regexp against the pattern space
-                               and if successful replaces the matched portion with replacement.
-                       aTEXT
-                               which appends TEXT after the pattern space
-               </screen>
-               </para>
-
-               <para>
-               This version of sed matches full regular expressions.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -e      Add the script to the commands to be executed
-                       -n      Suppress automatic printing of pattern space
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'
-                       bar
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="setkeycodes">
-           <title>setkeycodes</title>
-
-               <para>
-               Usage: setkeycodes SCANCODE KEYCODE ...
-               </para>
-
-               <para>
-               Set entries into the kernel's scancode-to-keycode map,
-               allowing unusual keyboards to generate usable keycodes.
-               </para>
-
-               <para>
-               SCANCODE may be either xx or e0xx (hexadecimal), and
-               KEYCODE is given in decimal.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ setkeycodes e030 127
-               </screen>
-               </para>
-       </sect1>
-
-
-       <sect1 id="sh">
-           <title>sh</title>
-
-               <para>
-               Usage: sh
-               </para>
-
-               <para>
-               lash -- the BusyBox LAme SHell (command interpreter)
-               </para>
-
-               <para>
-               This command does not yet have proper documentation.  
-               </para>
-
-               <para>
-               Use lash just as you would use any other shell. It
-               properly handles pipes, redirects, job control, can be
-               used as the shell for scripts (#!/bin/sh), and has a
-               sufficient set of builtins to do what is needed. It does
-               not (yet) support Bourne Shell syntax. If you need
-               things like ``if-then-else'', ``while'', and such, use
-               ash or bash. If you just need a very simple and
-               extremely small shell, this will do the job.
-               </para>
-       </sect1>
-
-       <sect1 id="sleep">
-           <title>sleep</title>
-
-               <para>
-               Usage: sleep N
-               </para>
-
-               <para>
-               Pause for N seconds.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ sleep 2
-                       [2 second delay results]
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="sort">
-           <title>sort</title>
-
-               <para>
-               Usage: sort [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               Sort lines of text in FILE(s).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -n      Compare numerically
-                       -r      Reverse after sorting
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo -e "e\nf\nb\nd\nc\na" | sort
-                       a
-                       b
-                       c
-                       d
-                       e
-                       f
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="swapoff">
-           <title>swapoff</title>
-
-               <para>
-               Usage: swapoff [OPTION] [DEVICE]
-               </para>
-
-               <para>
-               Stop swapping virtual memory pages on DEVICE.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Stop swapping on all swap devices
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="swapon">
-           <title>swapon</title>
-
-               <para>
-               Usage: swapon [OPTION] [DEVICE]
-               </para>
-
-               <para>
-               Start swapping virtual memory pages on the given device.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Start swapping on all swap devices
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="sync">
-           <title>sync</title>
-
-               <para>
-               Usage: sync
-               </para>
-
-               <para>
-               Write all buffered filesystem blocks to disk.
-               </para>
-       </sect1>
-
-       <sect1 id="syslogd">
-           <title>syslogd</title>
-
-               <para>
-               Usage: syslogd [OPTION]...
-               </para>
-
-               <para>
-               Linux system and kernel (provides klogd) logging
-               utility. Note that this version of syslogd/klogd ignores
-               /etc/syslog.conf.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -m NUM  Interval between MARK lines (default=20min, 0=off)
-                       -n      Run as a foreground process
-                       -K      Do not start up the klogd process
-                       -O FILE Use an alternate log file (default=/var/log/messages)
-                       -R HOST[:PORT] Log remotely to IP or hostname on PORT (default PORT=514/UDP)
-                       -L      Log locally as well as network logging (default is network only)
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-               $ syslogd -R masterlog:514
-               $ syslogd -R 192.168.1.1:601
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="tail">
-           <title>tail</title>
-
-               <para>
-               Usage: tail [OPTION] [FILE]...
-               </para>
-
-               <para>
-               Print last 10 lines of each FILE to standard output.
-               With more than one FILE, precede each with a header
-               giving the file name. With no FILE, or when FILE is -,
-               read stdin.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -n NUM  Print last NUM lines instead of last 10
-                       -f      Output data as the file grows.  This version
-                               of 'tail -f' supports only one file at a time.
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ tail -n 1 /etc/resolv.conf
-                       nameserver 10.0.0.1
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="tar">
-           <title>tar</title>
-
-               <para>
-               Usage: tar [MODE] [OPTION] [FILE]...
-               </para>
-
-               <para>
-               
-               </para>
-
-               <para>
-               MODE may be chosen from
-               </para>
-
-               <para>
-               <screen>
-                       c       Create
-                       x       Extract
-                       t       List
-               </screen>
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       f FILE                  Use FILE for tarfile (or stdin if '-')
-                       O                               Extract to stdout
-                       exclude FILE    File to exclude
-                       v                               List files processed
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ zcat /tmp/tarball.tar.gz | tar -xf -
-                       $ tar -cf /tmp/tarball.tar /usr/local
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="tee">
-           <title>tee</title>
-
-               <para>
-               Usage: tee [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               Copy stdin to FILE(s), and also to stdout.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Append to the given FILEs, do not overwrite
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo "Hello" | tee /tmp/foo
-                       Hello
-                       $ cat /tmp/foo
-                       Hello
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="telnet">
-           <title>telnet</title>
-
-               <para>
-               Usage: telnet HOST [PORT]
-               </para>
-
-               <para>
-               Establish interactive communication with another
-               computer over a network using the TELNET protocol.
-               </para>
-       </sect1>
-
-       <sect1 id="test">
-           <title>test, [</title>
-
-               <para>
-               Usage: test EXPRESSION
-               </para>
-
-               <para>
-                  or: [ EXPRESSION ]
-               </para>
-
-               <para>
-               Check file types and compare values returning an exit
-               code determined by the value of EXPRESSION.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ test 1 -eq 2
-                       $ echo $?
-                       1
-                       $ test 1 -eq 1
-                       $ echo $?
-                       0
-                       $ [ -d /etc ]
-                       $ echo $?
-                       0
-                       $ [ -d /junk ]
-                       $ echo $?
-                       1
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="touch">
-           <title>touch</title>
-
-               <para>
-               Usage: touch [OPTION]... FILE...
-               </para>
-
-               <para>
-               Update the last-modified date on (or create) FILE(s).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Do not create files
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls -l /tmp/foo
-                       /bin/ls: /tmp/foo: No such file or directory
-                       $ touch /tmp/foo
-                       $ ls -l /tmp/foo
-                       -rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="tr">
-           <title>tr</title>
-
-               <para>
-               Usage: tr [OPTION]... STRING1 [STRING2]
-               </para>
-
-               <para>
-               Translate, squeeze, and/or delete characters from stdin,
-               writing to stdout.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Take complement of STRING1
-                       -d      Delete input characters coded STRING1
-                       -s      Squeeze multiple output characters of STRING2 into one character
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo "gdkkn vnqkc" | tr [a-y] [b-z]
-                       hello world
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="true">
-           <title>true</title>
-
-               <para>
-               Usage: true
-               </para>
-
-               <para>
-               Return an exit code of TRUE (1).
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ true
-                       $ echo $?
-                       0
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="tty">
-           <title>tty</title>
-
-               <para>
-               Usage: tty
-               </para>
-
-               <para>
-               Print the file name of the terminal connected to stdin.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -s      Print nothing, only return an exit status
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ tty
-                       /dev/tty2
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="umount">
-           <title>umount</title>
-
-               <para>
-               Usage: umount [OPTION]... DEVICE|DIRECTORY
-               </para>
-
-               <para>
-               
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Unmount all file systems
-                       -r      Try to remount devices as read-only if mount is busy
-                       -f      Force filesystem umount (i.e., unreachable NFS server)
-                       -l      Do not free loop device (if a loop device has been used)
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ umount /dev/hdc1 
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="uname">
-           <title>uname</title>
-
-               <para>
-               Usage: uname [OPTION]...
-               </para>
-
-               <para>
-               Print certain system information. With no OPTION, same
-               as -s.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -a      Print all information
-                       -m      Print the machine (hardware) type
-                       -n      Print the machine's network node hostname
-                       -r      Print the operating system release
-                       -s      Print the operating system name
-                       -p      Print the host processor type
-                       -v      Print the operating system version
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ uname -a
-                       Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="uniq">
-           <title>uniq</title>
-
-               <para>
-               Usage: uniq [INPUT [OUTPUT]]
-               </para>
-
-               <para>
-               Discard all but one of successive identical lines from
-               INPUT (or stdin), writing to OUTPUT (or stdout).
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-               -c              prefix lines by the number of occurrences
-               -d              only print duplicate lines
-               -u              only print unique lines
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ echo -e "a\na\nb\nc\nc\na" | sort | uniq
-                       a
-                       b
-                       c
-               </screen>
-               </para>
-       </sect1>
-       
-       <sect1 id="unix2dos">
-           <title>unix2dos</title>
-
-               <para>
-               Usage: unix2dos < unixfile > dosfile
-               </para>
-
-               <para>
-               Converts a text file from unix format to dos format.
-               </para>
-
-       </sect1>
-
-       <sect1 id="unrpm">
-           <title>unrpm</title>
-
-               <para>
-               Usage: unrpm < package.rpm | gzip -d | cpio -idmuv
-               </para>
-
-               <para>
-               Extracts an rpm archive.
-               </para>
-
-       </sect1>
-
-       <sect1 id="update">
-           <title>update</title>
-
-               <para>
-               Usage: update [OPTION]...
-               </para>
-
-               <para>
-               Periodically flush filesystem buffers.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -S      Force use of sync(2) instead of flushing
-                       -s SECS Call sync this often (default 30)
-                       -f SECS Flush some buffers this often (default 5)
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="uptime">
-           <title>uptime</title>
-
-               <para>
-               Usage: uptime
-               </para>
-
-               <para>
-               Display how long the system has been running since boot.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ uptime
-                         1:55pm  up  2:30, load average: 0.09, 0.04, 0.00
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="usleep">
-           <title>usleep</title>
-
-               <para>
-               Usage: usleep N
-               </para>
-
-               <para>
-               Pause for N microseconds.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ usleep 1000000
-                       [pauses for 1 second]
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="uudecode">
-           <title>uudecode</title>
-
-               <para>
-               Usage: uudecode [OPTION] [FILE]
-               </para>
-
-               <para>
-               Uudecode a uuencoded file.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -o FILE Direct output to FILE
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ uudecode -o busybox busybox.uu
-                       $ ls -l busybox
-                       -rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="uuencode">
-           <title>uuencode</title>
-
-               <para>
-               Usage: uuencode [OPTION] [INFILE] OUTFILE
-               </para>
-
-               <para>
-               Uuencode a file.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -m      Use base64 encoding as of RFC1521
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ uuencode busybox busybox
-                       begin 755 busybox
-                       M?T5,1@$!`0````````````(``P`!````L+@$"#0```!0N@,``````#0`(``&amp;
-                       .....
-                       $ uudecode busybox busybox &gt; busybox.uu
-                       $
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="watchdog">
-           <title>watchdog</title>
-
-               <para>
-               Usage: watchdog device
-               </para>
-
-               <para>
-               Periodically writes to watchdog device B<device>.
-               </para>
-       </sect1>
-
-       <sect1 id="wc">
-           <title>wc</title>
-
-               <para>
-               Usage: wc [OPTION]... [FILE]...
-               </para>
-
-               <para>
-               Print line, word, and byte counts for each FILE, and a
-               total line if more than one FILE is specified. With no
-               FILE, read stdin.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -c      Print the byte counts
-                       -l      Print the newline counts
-                       -L      Print the length of the longest line
-                       -w      Print the word counts
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ wc /etc/passwd
-                            31      46    1365 /etc/passwd
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="which">
-           <title>which</title>
-
-               <para>
-               Usage: which [COMMAND]...
-               </para>
-
-               <para>
-               Locate COMMAND(s).
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ which login
-                       /bin/login
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="whoami">
-           <title>whoami</title>
-
-               <para>
-               Usage: whoami
-               </para>
-
-               <para>
-               Print the user name associated with the current
-               effective user id.
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ whoami
-                       andersen
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="xargs">
-           <title>xargs</title>
-
-               <para>
-               Usage: xargs [OPTIONS] [COMMAND] [ARGS...]
-               </para>
-
-               <para>
-               Executes COMMAND on every item given by standard input.
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -t      Print the command just before it is run
-               </screen>
-               </para>
-
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-                       $ ls | xargs gzip
-                       $ find . -name '*.c' -print | xargs rm
-               </screen>
-               </para>
-       </sect1>
-
-       <sect1 id="yes">
-           <title>yes</title>
-
-               <para>
-               Usage: yes [STRING]...
-               </para>
-
-               <para>
-               Repeatedly output a line with all specified STRING(s),
-               or `y'.
-               </para>
-       </sect1>
-
-       <sect1 id="zcat">
-           <title>zcat</title>
-
-               <para>
-               Usage: zcat [OPTION]... FILE
-               </para>
-
-               <para>
-               Uncompress FILE (or stdin if FILE is '-') to stdout.  
-               </para>
-
-               <para>
-               Options:
-               </para>
-
-               <para>
-               <screen>
-                       -t      Test compressed file integrity
-               </screen>
-               </para>
-
-               <para>
-               Example:
-               </para>
-
-               <para>
-               <screen>
-               </screen>
-               </para>
-       </sect1>
-  </chapter>
-
-  <chapter id="LIBC-NSS">
-    <title>LIBC NSS</title>
-
-       <para>
-       GNU Libc uses the Name Service Switch (NSS) to configure the
-       behavior of the C library for the local environment, and to
-       configure how it reads system data, such as passwords and group
-       information. BusyBox has made it Policy that it will never use
-       NSS, and will never use libc calls that make use of NSS. This
-       allows you to run an embedded system without the need for
-       installing an /etc/nsswitch.conf file and without /lib/libnss_*
-       libraries installed.
-       </para>
-
-       <para>
-       If you are using a system that is using a remote LDAP server for
-       authentication via GNU libc NSS, and you want to use BusyBox,
-       then you will need to adjust the BusyBox source. Chances are
-       though, that if you have enough space to install of that stuff
-       on your system, then you probably want the full GNU utilities.
-       </para>
-  </chapter>
-
-  <chapter id="SEE-ALSO">
-    <title>SEE ALSO</title>
-
-       <para>
-       <literal>textutils(1),</literal>
-       <literal>shellutils(1),</literal>
-       etc...
-       </para>
-  </chapter>
-
-  <chapter id="MAINTAINER">
-    <title>MAINTAINER</title>
-
-       <para>
-       Erik Andersen &lt;andersee@debian.org&gt; &lt;andersen@lineo.com&gt;
-       </para>
-  </chapter>
-
-  <chapter id="AUTHORS">
-    <title>AUTHORS</title>
-
-       <para>
-       The following people have made significant contributions to 
-       BusyBox -- whether they know it or not.
-       </para>
-
-       <para>
-       Erik Andersen &lt;andersee@debian.org&gt;
-       </para>
-
-       <para>
-       Edward Betts &lt;edward@debian.org&gt;
-       </para>
-
-       <para>
-       John Beppu &lt;beppu@lineo.com&gt;
-       </para>
-
-       <para>
-       Brian Candler &lt;B.Candler@pobox.com&gt;
-       </para>
-
-       <para>
-       Randolph Chung &lt;tausq@debian.org&gt;
-       </para>
-
-       <para>
-       Dave Cinege &lt;dcinege@psychosis.com&gt;       
-       </para>
-
-       <para>
-       Karl M. Hegbloom &lt;karlheg@debian.org&gt;
-       </para>
-
-       <para>
-       Daniel Jacobowitz &lt;dan@debian.org&gt;
-       </para>
-
-       <para>
-       Matt Kraai &lt;kraai@alumni.carnegiemellon.edu&gt;
-       </para>
-
-       <para>
-       John Lombardo &lt;john@deltanet.com&gt; 
-       </para>
-
-       <para>
-       Glenn McGrath &lt;bug1@netconnect.com.au&gt;
-       </para>
-
-       <para>
-       Bruce Perens &lt;bruce@perens.com&gt;
-       </para>
-
-       <para>
-       Chip Rosenthal &lt;chip@unicom.com&gt;, &lt;crosenth@covad.com&gt;
-       </para>
-
-       <para>
-       Pavel Roskin &lt;proski@gnu.org&gt;
-       </para>
-
-       <para>
-       Gyepi Sam &lt;gyepi@praxis-sw.com&gt;
-       </para>
-
-       <para>
-       Linus Torvalds &lt;torvalds@transmeta.com&gt;
-       </para>
-
-        <para>
-        Mark Whitley &lt;markw@lineo.com&gt;
-        </para>
-
-       <para>
-       Charles P. Wright &lt;cpwright@villagenet.com&gt;
-       </para>
-
-       <para>
-       Enrique Zanardi &lt;ezanardi@ull.es&gt;
-       </para>
-
-
-  </chapter>
-</book>    <!-- End of the book -->
diff --git a/busybox/docs/busybox_footer.pod b/busybox/docs/busybox_footer.pod
deleted file mode 100644 (file)
index 2ab4e16..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-=back
-
-=head1 LIBC NSS
-
-GNU Libc uses the Name Service Switch (NSS) to configure the behavior of the C
-library for the local environment, and to configure how it reads system data,
-such as passwords and group information.  BusyBox has made it Policy that it
-will never use NSS, and will never use and libc calls that make use of NSS.
-This allows you to run an embedded system without the need for installing an
-/etc/nsswitch.conf file and without and /lib/libnss_* libraries installed.
-
-If you are using a system that is using a remote LDAP server for authentication
-via GNU libc NSS, and you want to use BusyBox, then you will need to adjust the
-BusyBox source.  Chances are though, that if you have enough space to install
-of that stuff on your system, then you probably want the full GNU utilities.
-
-=head1 SEE ALSO
-
-textutils(1), shellutils(1), etc...
-
-=head1 MAINTAINER
-
-Erik Andersen <andersee@debian.org> <andersen@lineo.com>
-
-=head1 AUTHORS
-
-The following people have contributed code to BusyBox whether
-they know it or not.
-
-
-=for html <br>
-
-Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
-
-    Tons of new stuff, major rewrite of most of the
-    core apps, tons of new apps as noted in header files.
-
-=for html <br>
-
-John Beppu <beppu@lineo.com>
-
-    du, head, nslookup, sort, tee, uniq (so Kraai could rewrite them ;-),
-    documentation
-
-=for html <br>
-
-Edward Betts <edward@debian.org>
-
-    expr, hostid, logname, tty, wc, whoami, yes
-=for html <br>
-
-Brian Candler <B.Candler@pobox.com>
-
-    tiny-ls(ls)
-
-=for html <br>
-
-Randolph Chung <tausq@debian.org>
-
-    fbset, ping, hostname, and mkfifo
-
-=for html <br>
-
-Dave Cinege <dcinege@psychosis.com>    
-
-    more(v2), makedevs, dutmp, modularization, auto links file, 
-    various fixes, Linux Router Project maintenance
-
-=for html <br>
-
-Larry Doolittle <ldoolitt@recycle.lbl.gov>
-
-    various fixes, shell rewrite
-
-=for html <br>
-
-Karl M. Hegbloom <karlheg@debian.org>
-
-    cp_mv.c, the test suite, various fixes to utility.c, &c.
-
-=for html <br>
-
-Sterling Huxley <sterling@europa.com>
-
-    vi (!!!)
-
-=for html <br>
-
-Daniel Jacobowitz <dan@debian.org>
-
-    mktemp.c
-
-=for html <br>
-
-Matt Kraai <kraai@alumni.carnegiemellon.edu>
-
-    documentation, bugfixes
-
-=for html <br>
-
-John Lombardo <john@deltanet.com>      
-
-    dirname, tr
-
-=for html <br>
-
-Glenn McGrath <bug1@netconnect.com.au>
-
-    ar.c
-
-=for html <br>
-
-Vladimir Oleynik <dzo@simtreas.ru>
-
-    cmdedit, stty-port, locale, various fixes 
-    and irreconcilable critic of everything not perfect.
-
-=for html <br>
-
-Bruce Perens <bruce@pixar.com>
-
-    Original author of BusyBox. His code is still in many apps.
-
-=for html <br>
-
-Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
-
-    wget - Contributed by permission of Covad Communications
-
-=for html <br>
-
-Pavel Roskin <proski@gnu.org>
-
-    Lots of bugs fixes and patches.
-
-=for html <br>
-
-Gyepi Sam <gyepi@praxis-sw.com>
-
-    Remote logging feature for syslogd
-
-=for html <br>
-
-Linus Torvalds <torvalds@transmeta.com>
-
-    mkswap, fsck.minix, mkfs.minix
-
-=for html <br>
-
-Mark Whitley <markw@lineo.com>
-
-    sed remix, bug fixes, style-guide, etc.
-
-=for html <br>
-
-Charles P. Wright <cpwright@villagenet.com>
-
-    gzip, mini-netcat(nc)
-
-=for html <br>
-
-Enrique Zanardi <ezanardi@ull.es>
-
-    tarcat (since removed), loadkmap, various fixes, Debian maintenance
-
-=cut
-
-# $Id: busybox_footer.pod,v 1.4 2001/04/17 17:09:34 beppu Exp $
diff --git a/busybox/docs/busybox_header.pod b/busybox/docs/busybox_header.pod
deleted file mode 100644 (file)
index b80b631..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# vi: set sw=4 ts=4:
-
-=head1 NAME
-
-BusyBox - The Swiss Army Knife of Embedded Linux
-
-=head1 SYNTAX
-
- BusyBox <function> [arguments...]  # or
-
- <function> [arguments...]         # if symlinked
-
-=head1 DESCRIPTION
-
-BusyBox combines tiny versions of many common UNIX utilities into a single
-small executable. It provides minimalist replacements for most of the utilities
-you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
-tar, etc.  BusyBox provides a fairly complete POSIX environment for any small
-or embedded system.  The utilities in BusyBox generally have fewer options than
-their full-featured GNU cousins; however, the options that are included provide
-the expected functionality and behave very much like their GNU counterparts. 
-
-BusyBox has been written with size-optimization and limited resources in mind.
-It is also extremely modular so you can easily include or exclude commands (or
-features) at compile time.  This makes it easy to customize your embedded
-systems.  To create a working system, just add a kernel, a shell (such as ash),
-and an editor (such as elvis-tiny or ae).
-
-=head1 USAGE
-
-When you create a link to BusyBox for the function you wish to use, when BusyBox
-is called using that link it will behave as if the command itself has been invoked.
-
-For example, entering
-
-       ln -s ./BusyBox ls
-       ./ls
-
-will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled
-into BusyBox). 
-
-You can also invoke BusyBox by issuing the command as an argument on the
-command line.  For example, entering
-
-       ./BusyBox ls
-
-will also cause BusyBox to behave as 'ls'. 
-
-=head1 COMMON OPTIONS
-
-Most BusyBox commands support the B<-h> option to provide a
-terse runtime description of their behavior. 
-
-=head1 COMMANDS
-
-Currently defined functions include:
-
-adjtimex, ar, basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear,
-cmp, cp, cpio, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dos2unix, dpkg,
-dpkg-deb, du, dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find, free,
-freeramdisk, fsck.minix, getopt, grep, gunzip, gzip, halt, head, hostid,
-hostname, id, ifconfig, init, insmod, kill, killall, klogd, length, ln,
-loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs, md5sum,
-mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc,
-nslookup, ping, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, reboot,
-renice, reset, rm, rmdir, rmmod, route, rpm2cpio, sed, setkeycodes,
-sh, sleep, sort, stty, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet,
-test, tftp, touch, tr, true, tty, umount, uname, uniq, unix2dos, update, uptime,
-usleep, uudecode, uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat,
-[
-
-=over 4
-
diff --git a/busybox/docs/contributing.txt b/busybox/docs/contributing.txt
deleted file mode 100644 (file)
index 2e00492..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-Contributing To Busybox
-=======================
-
-This document describes what you need to do to contribute to Busybox, where
-you can help, guidelines on testing, and how to submit a well-formed patch
-that is more likely to be accepted.
-
-The Busybox home page is at: http://busybox.lineo.com
-
-
-
-Pre-Contribution Checklist
---------------------------
-
-So you want to contribute to Busybox, eh? Great, wonderful, glad you want to
-help. However, before you dive in, headlong and hotfoot, there are some things
-you need to do:
-
-
-Checkout the Latest Code from CVS
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This is a necessary first step. Please do not try to work with the last
-released version, as there is a good chance that somebody has already fixed
-the bug you found. Somebody might have even added the feature you had in mind.
-Don't make your work obsolete before you start!
-
-For information on how to check out Busybox from CVS, please look at the
-following links:
-
-       http://oss.lineo.com/cvs_anon.html
-       http://oss.lineo.com/cvs_howto.html
-
-
-Read the Mailing List
-~~~~~~~~~~~~~~~~~~~~~
-
-No one is required to read the entire archives of the mailing list, but you
-should at least read up on what people have been talking about lately. If
-you've recently discovered a problem, chances are somebody else has too. If
-you're the first to discover a problem, post a message and let the rest of us
-know.
-
-Archives can be found here:
-
-       http://opensource.lineo.com/lists/busybox/
-
-If you have a serious interest in Busybox, i.e., you are using it day-to-day or
-as part of an embedded project, it would be a good idea to join the mailing
-list.
-
-A web-based sign-up form can be found here:
-
-       http://opensource.lineo.com/mailman/listinfo/busybox
-
-
-Coordinate with the Applet Maintainer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some (not all) of the applets in Busybox are "owned" by a maintainer who has
-put significant effort into it and is probably more familiar with it than
-others. To find the maintainer of an applet, look at the top of the .c file
-for a name following the word 'Copyright' or 'Written by' or 'Maintainer'.
-
-Before plunging ahead, it's a good idea to send a message to the mailing list
-that says: "Hey, I was thinking about adding the 'transmogrify' feature to the
-'foo' applet.  Would this be useful? Is anyone else working on it?" You might
-want to CC the maintainer (if any) with your question.
-
-
-
-Areas Where You Can Help
-------------------------
-
-Busybox can always use improvement! If you're looking for ways to help, there
-there are a variety of areas where you could help.
-
-
-What Busybox Doesn't Need
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Before listing the areas where you _can_ help, it's worthwhile to mention the
-areas where you shouldn't bother. While Busybox strives to be the "Swiss Army
-Knife" of embedded Linux, there are some applets that will not be accepted:
-
- - Any filesystem manipulation tools: Busybox is filesystem independent and
-   we do not want to start adding mkfs/fsck tools for every (or any)
-   filesystem under the sun. (fsck_minix.c and mkfs_minix.c are living on
-   borrowed time.) There are far too many of these tools out there.  Use
-   the upstream version. Not everything has to be part of Busybox.
-
- - Any partitioning tools: Partitioning a device is typically done once and
-   only once, and tools which do this generally do not need to reside on the
-   target device (esp a flash device). If you need a partitioning tool, grab
-   one (such as fdisk, sfdisk, or cfdisk from util-linux) and use that, but
-   don't try to merge it into busybox. These are nasty and complex and we
-   don't want to maintain them.
-
- - Any disk, device, or media-specific tools: Use the -utils or -tools package
-   that was designed for your device; don't try to shoehorn them into Busybox.
-
- - Any architecture specific tools: Busybox is (or should be) architecture
-   independent. Do not send us tools that cannot be used across multiple
-   platforms / arches.
-
- - Any daemons that are not essential to basic system operation. To date, only
-   syslogd and klogd meet this requirement. We do not need a web server, an
-   ftp daemon, a dhcp server, a mail transport agent or a dns resolver. If you
-   need one of those, you are welcome to ask the folks on the mailing list for
-   recommendations, but please don't bloat up Busybox with any of these.
-
-
-Bug Reporting
-~~~~~~~~~~~~~
-
-If you find a bug in Busybox, you can send a bug report to our bug tracking
-system (homepage: http://bugs.lineo.com). Instructions on how to send a bug
-report to the tracking system can be found at:
-
-       http://bugs.lineo.com/Reporting.html
-       
-The README file that comes with Busybox also describes how to submit a bug.
-
-A well-written bug report should include a transcript of a shell session that
-demonstrates the bad behavior and enables anyone else to duplicate the bug on
-their own machine. The following is such an example:
-
-       When I execute Busybox 'date' it produces unexpected results.
-
-       This is using GNU date:
-       $ date
-       Wed Mar 21 14:19:41 MST 2001
-
-       This is using Busybox date:
-       $ date
-       codswaddle
-
-
-Bug Triage
-~~~~~~~~~~
-
-Validating and confirming bugs is nearly as important as reporting them in the
-first place. It is valuable to know if a bug can be duplicated on a different
-machine, on a different filesystem, on a different architecture, with a
-different C library, and so forth.
-
-To see a listing of all the bugs currently filed against Busybox, look here:
-
-       http://bugs.lineo.com/db/pa/lbusybox.html
-
-If you have comments to add to a bug (can / can't duplicate, think a bug
-should be closed / reopened), please send it to [bugnumber]@bugs.lineo.com.
-The message you send will automatically be forwarded to the mailing list for
-all to see.
-
-
-Write Documentation
-~~~~~~~~~~~~~~~~~~~
-
-Chances are, documentation in Busybox is either missing or needs improvement.
-Either way, help is welcome.
-
-Work is being done to automatically generate documentation from sources,
-especially from the usage.h file. If you want to correct the documentation,
-please make changes to the pre-generation parts, rather than the generated
-documentation. [More to come on this later...]
-
-It is preferred that modifications to documentation be submitted in patch
-format (more on this below), but we're a little more lenient when it comes to
-docs. You could, for example, just say "after the listing of the mount
-options, the following example would be helpful..."
-
-
-Consult Existing Sources
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-For a quick listing of "needs work" spots in the sources, cd into the Busybox
-directory and run the following:
-
-       for i in TODO FIXME XXX; do grep $i *.[ch]; done
-
-This will show all of the trouble spots or 'questionable' code. Pick a spot,
-any spot, these are all invitations for you to contribute.
-
-
-Consult The Bug-Tracking System
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Head to: http://bugs.lineo.com/db/pa/lBusybox.html and look at the bugs on
-there. Pick one you think you can fix, and fix it. If it's a wishlist item and
-someone's requesting a new feature, take a stab at adding it. Everything
-previously said about "reading the mailing list" and "coordinating with the
-applet maintainer" still applies.
-
-
-Add a New Applet
-~~~~~~~~~~~~~~~~
-
-If you want to add a new applet to Busybox, we'd love to see it. However,
-before you write any code, please ask beforehand on the mailing list something
-like "Do you think applet 'foo' would be useful in Busybox?" or "Would you
-guys accept applet 'foo' into Busybox if I were to write it?" If the answer is
-"no" by the folks on the mailing list, then you've saved yourself some time.
-Conversely, you could get some positive responses from folks who might be
-interested in helping you implement it, or can recommend the best approach.
-Perhaps most importantly, this is your way of calling "dibs" on something and
-avoiding duplication of effort.
-
-Also, before you write a line of code, please read the 'new-applet-HOWTO.txt'
-file in the docs/ directory.
-
-
-Janitorial Work
-~~~~~~~~~~~~~~~
-
-These are dirty jobs, but somebody's gotta do 'em.
-
- - Converting applets to use getopt() for option processing. Type 'grep -L
-   getopt *.c' to get a listing of the applets that currently don't use
-   getopt. If a .c file processes no options, it should have a line that
-   reads: /* no options, no getopt */ somewhere in the file.
-
- - Replace any "naked" calls to malloc, calloc, realloc, str[n]dup, fopen with
-   the x* equivalents found in utility.c.
-
- - Security audits:
-   http://www.securityfocus.com/frames/?content=/forums/secprog/secure-programming.html
-
- - Synthetic code removal: http://www.perl.com/pub/2000/06/commify.html - This
-   is very Perl-specific, but the advice given in here applies equally well to
-   C.
-
- - C library funciton use audits: Verifying that functions are being used
-   properly (called with the right args), replacing unsafe library functions
-   with safer versions, making sure return codes are being checked, etc.
-
- - Where appropriate, replace preprocessor defined macros and values with
-   compile-time equivalents.
-
- - Style guide compliance. See: docs/style-guide.txt
-
- - Add testcases to tests/testcases.
-
- - Makefile improvements:
-   http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html
-   (I think the recursive problems are pretty much taken care of at this point, non?)
-
- - "Ten Commandments" compliance: (this is a "maybe", certainly not as
-   important as any of the previous items.)
-    http://web.onetelnet.ch/~twolf/tw/c/ten_commandments.html
-
-Other useful links:
-
- - the comp.lang.c FAQ: http://web.onetelnet.ch/~twolf/tw/c/index.html#Sources
-
-
-
-Submitting Patches To Busybox
------------------------------
-
-Here are some guidelines on how to submit a patch to Busybox.
-
-
-Making A Patch
-~~~~~~~~~~~~~~
-
-If you've got anonymous CVS access set up, making a patch is simple. Just make
-sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'.
-You can send the resulting .patch file to the mailing list with a description
-of what it does. (But not before you test it! See the next section for some
-guidelines.) It is preferred that patches be sent as attachments, but it is
-not required.
-
-Also, feel free to help test other people's patches and reply to them with
-comments. You can apply a patch by saving it into your busybox/ directory and
-typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test
-if it works as advertised, and post your findings to the mailing list.
-
-NOTE: Please do not include extraneous or irrelevant changes in your patches.
-Please do not try to "bundle" two patches together into one. Make single,
-discreet changes on a per-patch basis. Sometimes you need to make a patch that
-touches code in many places, but these kind of patches are rare and should be
-coordinated with a maintainer.
-
-
-Testing Guidelines
-~~~~~~~~~~~~~~~~~~
-
-It's considered good form to test your new feature before you submit a patch
-to the mailing list, and especially before you commit a change to CVS. Here
-are some guidelines on how to test your changes.
-
- - Always test Busybox applets against GNU counterparts and make sure the
-   behavior / output is identical between the two.
-
- - Try several different permutations and combinations of the features you're
-   adding (i.e., different combinations of command-line switches) and make sure
-   they all work; make sure one feature does not interfere with another.
-
- - Make sure you test compiling against the source both with the feature
-   turned on and turned off in Config.h and make sure Busybox compiles cleanly
-   both ways.
-
- - Run the multibuild.pl script in the tests directory and make sure
-   everything checks out OK. (Do this from within the busybox/ directory by
-   typing: 'tests/multibuild.pl'.)
-
-
-Making Sure Your Patch Doesn't Get Lost
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you don't want your patch to be lost or forgotten, send it to the bug
-tracking system (http://bugs.lineo.com). You do this by emailing your patch in
-a message to submit@bugs.lineo.com with a subject line something like this:
-
-       [PATCH] - Adds "transmogrify" feature to "foo"
-
-In the body, you should have a pseudo-header that looks like the following:
-
-    Package: busybox
-    Version: v0.50pre (or whatever the current version is)
-    Severity: wishlist
-
-The remainder of the body should read along these lines:
-
-       This patch adds the "transmogrify" feature to the "foo" applet. I have
-       tested this on [arch] system(s) and it works. I have tested it against the
-       GNU counterparts and the outputs are identical. I have run the scripts in
-       the 'tests' directory and nothing breaks.
-
-Detailed instructions on how to submit a bug to the tracking system are at:
-
-       http://bugs.lineo.com/Reporting.html
-
-If you have a patch that will fix and close a reported bug, please send a
-message to [bugnumber]@bugs.lineo.com with your patch attached. It will catch
-people's attention if you have a subject line like the following:
-
-       [PATCH INCLUDED] - Fix attached, please apply and close this bug
-
-
-
-Improving Your Chances of Patch Acceptance
-------------------------------------------
-
-Even after you send a brilliant patch to the mailing list, sometimes it can go
-unnoticed, un-replied-to, and sometimes (sigh) even lost. This is an
-unfortunate fact of life, but there are steps you can take to help your patch
-get noticed and convince a maintainer that it should be added:
-
-
-Be Succinct
-~~~~~~~~~~~
-
-A patch that includes small, isolated, obvious changes is more likely to be
-accepted than a patch that touches code in lots of different places or makes
-sweeping, dubious changes.
-
-
-Back It Up
-~~~~~~~~~~
-
-Hard facts on why your patch is better than the existing code will go a long
-way toward convincing maintainers that your patch should be included.
-Specifically, patches are more likely to be accepted if they are provably more
-correct, smaller, faster, simpler, or more maintainable than the existing
-code.
-
-Conversely, any patch that is supported with nothing more than "I think this
-would be cool" or "this patch is good because I say it is and I've got a Phd
-in Computer Science" will likely be ignored.
-
-
-Follow The Style Guide
-~~~~~~~~~~~~~~~~~~~~~~
-
-It's considered good form to abide by the established coding style used in a
-project; Busybox is no exception. We have gone so far as to delineate the
-"elements of Busybox style" in the file docs/style-guide.txt. Please follow
-them.
-
-
-Work With Someone Else
-~~~~~~~~~~~~~~~~~~~~~~
-
-Working on a patch in isolation is less effective than working with someone
-else for a variety of reasons. If another Busybox user is interested in what
-you're doing, then it's two (or more) voices instead of one that can petition
-for inclusion of the patch. You'll also have more people that can test your
-changes, or even offer suggestions on better approaches you could take.
-
-Getting other folks interested follows as a natural course if you've received
-responses from queries to applet maintainer or positive responses from folks
-on the mailing list.
-
-We've made strident efforts to put a useful "collaboration" infrastructure in
-place in the form of mailing lists, the bug tracking system, and CVS. Please
-use these resources.
-
-
-Send Patches to the Bug Tracking System
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This was mentioned above in the "Making Sure Your Patch Doesn't Get Lost"
-section, but it is worth mentioning again. A patch sent to the mailing list
-might be unnoticed and forgotten. A patch sent to the bug tracking system will
-be stored and closely connected to the bug it fixes.
-
-
-Be Polite
-~~~~~~~~~
-
-The old saying "You'll catch more flies with honey than you will with vinegar"
-applies when submitting patches to the mailing list for approval. The way you
-present your patch is sometimes just as important as the actual patch itself
-(if not more so). Being rude to the maintainers is not an effective way to
-convince them that your patch should be included; it will likely have the
-opposite effect.
-
-
-
-Committing Changes to CVS
--------------------------
-
-If you submit several patches that demonstrate that you are a skilled and wise
-coder, you may be invited to become a committer, thus enabling you to commit
-changes directly to CVS. This is nice because you don't have to wait for
-someone else to commit your change for you, you can just do it yourself.
-
-But note that this is a priviledge that comes with some responsibilities. You
-should test your changes before you commit them. You should also talk to an
-applet maintainer before you make any kind of sweeping changes to somebody
-else's code. Big changes should still go to the mailing list first. Remember,
-being wise, polite, and discreet is more important than being clever.
-
-
-When To Commit
-~~~~~~~~~~~~~~
-
-Generally, you should feel free to commit a change if:
-
- - Your changes are small and don't touch many files
- - You are fixing a bug
- - Somebody has told you that it's okay
- - It's obviously the Right Thing
-
-The more of the above are true, the better it is to just commit a change
-directly to CVS.
-
-
-When Not To Commit
-~~~~~~~~~~~~~~~~~~
-
-Even if you have commit rights, you should probably still post a patch to the
-mailing list if:
-
- - Your changes are broad and touch many different files
- - You are adding a feature
- - Your changes are speculative or experimental (i.e., trying a new algorithm)
- - You are not the maintainer and your changes make the maintainer cringe
-
-The more of the above are true, the better it is to post a patch to the
-mailing list instead of committing.
-
-
-
-Final Words
------------
-
-If all of this seems complicated, don't panic, it's really not that tough. If
-you're having difficulty following some of the steps outlined in this
-document don't worry, the folks on the Busybox mailing list are a fairly
-good-natured bunch and will work with you to help get your patches into shape
-or help you make contributions.
-
-
diff --git a/busybox/docs/new-applet-HOWTO.txt b/busybox/docs/new-applet-HOWTO.txt
deleted file mode 100644 (file)
index 1f5c3eb..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-How to Add a New Applet to BusyBox
-==================================
-
-This document details the steps you must take to add a new applet to BusyBox.
-
-Credits:
-Matt Kraai - initial writeup
-Mark Whitley - the remix
-
-
-Initial Write
--------------
-
-First, write your applet.  Be sure to include copyright information at the
-top, such as who you stole the code from and so forth. Also include the
-mini-GPL boilerplate. Be sure to name the main function <applet>_main instead
-of main.  And be sure to put it in <applet>.c.  For a new applet mu, here is
-the code that would go in mu.c:
-
-----begin example code------
-
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mu implementation for busybox
- *
- *
- * Copyright (C) [YEAR] by [YOUR NAME] <YOUR EMAIL>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-
-int mu_main(int argc, char **argv)
-{
-       int fd;
-       char mu;
-
-       if ((fd = open("/dev/random", O_RDONLY)) < 0)
-               perror_msg_and_die("/dev/random");
-
-       if ((n = safe_read(fd, &mu, 1)) < 1)
-               perror_msg_and_die("/dev/random");
-
-       return mu;
-}
-
-----end example code------
-
-
-Coding Style
-------------
-
-Before you submit your applet for inclusion in BusyBox, (or better yet, before
-you _write_ your applet) please read through the style guide in the docs
-directory and make your program compliant.
-
-
-Some Words on libbb
--------------------
-
-As you are writing your applet, please be aware of the body of pre-existing
-useful functions in libbb. Use these instead of reinventing the wheel.
-
-Additionally, if you have any useful, general-purpose functions in your
-program that could be useful in another program, consider putting them in
-libbb.
-
-
-Usage String(s)
----------------
-
-Next, add usage information for you applet to usage.h. This should look like
-the following:
-
-       #define mu_trivial_usage \
-               "-[abcde] FILES"
-       #define mu_full_usage \
-               "Returns an indeterminate value.\n\n" \
-               "Options:\n" \
-               "\t-a\t\tfirst function\n" \
-               "\t-b\t\tsecond function\n" \
-
-If your program supports flags, the flags should be mentioned on the first
-line (-[abcde]) and a detailed description of each flag should go in the
-mu_full_usage section, one flag per line. (Numerous examples of this
-currently exist in usage.h.)
-
-
-Header Files
-------------
-
-Next, add an entry to applets.h.  Be *sure* to keep the list in alphabetical
-order, or else it will break the binary-search lookup algorithm in busybox.c
-and the Gods of BusyBox smite you. Yea, verily:
-
-       /* all programs above here are alphabetically "less than" 'mu' */
-       #ifdef BB_MU
-               APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage)
-       #endif
-       /* all programs below here are alphabetically "greater than" 'mu' */
-
-
-Finally, add a define for your applet to Config.h:
-
-       #define BB_MU
-
-
-Documentation
--------------
-
-If you're feeling especially nice, you should also document your applet in the
-docs directory (but nobody ever does that).
-
-
-The Grand Announcement
-----------------------
-
-Then create a diff -urN of the files you added (<applet>.c, usage.c,
-applets.h, Config.h) and send it to the mailing list:
-busybox@opensource.lineo.com. Sending patches as attachments is preferred, but
-not required.
-
-
diff --git a/busybox/docs/style-guide.txt b/busybox/docs/style-guide.txt
deleted file mode 100644 (file)
index c71f1e6..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-Busybox Style Guide
-===================
-
-This document describes the coding style conventions used in Busybox. If you
-add a new file to Busybox or are editing an existing file, please format your
-code according to this style. If you are the maintainer of a file that does
-not follow these guidelines, please -- at your own convenience -- modify the
-file(s) you maintain to bring them into conformance with this style guide.
-Please note that this is a low priority task.
-
-To help you format the whitespace of your programs, an ".indent.pro" file is
-included in the main Busybox source directory that contains option flags to
-format code as per this style guide. This way you can run GNU indent on your
-files by typing 'indent myfile.c myfile.h' and it will magically apply all the
-right formatting rules to your file. Please _do_not_ run this on all the files
-in the directory, just your own.
-
-
-
-Declaration Order
------------------
-
-Here is the order in which code should be laid out in a file:
-
- - commented program name and one-line description
- - commented author name and email address(es)
- - commented GPL boilerplate
- - commented longer description / notes for the program (if needed)
- - #includes of .h files with angle brackets (<>) around them
- - #includes of .h files with quotes ("") around them
- - #defines (if any, note the section below titled "Avoid the Preprocessor")
- - const and global variables
- - function declarations (if necessary)
- - function implementations
-
-
-
-Whitespace and Formatting
--------------------------
-
-This is everybody's favorite flame topic so let's get it out of the way right
-up front.
-
-
-Tabs vs. Spaces in Line Indentation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The preference in Busybox is to indent lines with tabs. Do not indent lines
-with spaces and do not indents lines using a mixture of tabs and spaces. (The
-indentation style in the Apache and Postfix source does this sort of thing:
-\s\s\s\sif (expr) {\n\tstmt; --ick.) The only exception to this rule is
-multi-line comments that use an asterisk at the beginning of each line, i.e.:
-
-       /t/*
-       /t * This is a block comment.
-       /t * Note that it has multiple lines
-       /t * and that the beginning of each line has a tab plus a space
-       /t * except for the opening '/*' line where the slash
-       /t * is used instead of a space.
-       /t */
-
-Furthermore, The preference is that tabs be set to display at four spaces
-wide, but the beauty of using only tabs (and not spaces) at the beginning of
-lines is that you can set your editor to display tabs at *whatever* number of
-spaces is desired and the code will still look fine.
-
-
-Operator Spacing
-~~~~~~~~~~~~~~~~
-
-Put spaces between terms and operators. Example:
-
-       Don't do this:
-
-               for(i=0;i<num_items;i++){
-
-       Do this instead:
-
-               for (i = 0; i < num_items; i++) {
-
-       While it extends the line a bit longer, the spaced version is more
-       readable. An allowable exception to this rule is the situation where
-       excluding the spacing makes it more obvious that we are dealing with a
-       single term (even if it is a compound term) such as:
-
-               if (str[idx] == '/' && str[idx-1] != '\\')
-
-       or
-
-               if ((argc-1) - (optind+1) > 0)
-
-
-Bracket Spacing
-~~~~~~~~~~~~~~~
-
-If an opening bracket starts a function, it should be on the
-next line with no spacing before it. However, if a bracket follows an opening
-control block, it should be on the same line with a single space (not a tab)
-between it and the opening control block statement. Examples:
-
-       Don't do this:
-
-               while (!done)
-               {
-
-               do
-               {
-
-       Don't do this either:
-
-               while (!done){
-
-               do{
-
-       And for heaven's sake, don't do this:
-
-               while (!done)
-                 {
-
-               do
-                 {
-
-       Do this instead:
-
-               while (!done) {
-
-               do {
-
-
-Spacing around Parentheses
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Put a space between C keywords and left parens, but not between function names
-and the left paren that starts it's parameter list (whether it is being
-declared or called). Examples:
-
-       Don't do this:
-
-               while(foo) {
-               for(i = 0; i < n; i++) {
-
-       Do this instead:
-
-               while (foo) {
-               for (i = 0; i < n; i++) {
-
-       But do functions like this:
-
-               static int my_func(int foo, char bar)
-               ...
-               baz = my_func(1, 2);
-
-Also, don't put a space between the left paren and the first term, nor between
-the last arg and the right paren.
-
-       Don't do this:
-
-               if ( x < 1 )
-               strcmp( thisstr, thatstr )
-
-       Do this instead:
-
-               if (x < 1)
-               strcmp(thisstr, thatstr)
-
-
-Cuddled Elses
-~~~~~~~~~~~~~
-
-Also, please "cuddle" your else statements by putting the else keyword on the
-same line after the right bracket that closes an 'if' statement.
-
-       Don't do this:
-
-       if (foo) {
-               stmt;
-       }
-       else {
-               stmt;
-       }
-
-       Do this instead:
-
-       if (foo) {
-               stmt;
-       } else {
-               stmt;
-       }
-
-The exception to this rule is if you want to include a comment before the else
-block. Example:
-
-       if (foo) {
-               stmts...
-       }
-       /* otherwise, we're just kidding ourselves, so re-frob the input */
-       else {
-               other_stmts...
-       }
-
-
-
-Variable and Function Names
----------------------------
-
-Use the K&R style with names in all lower-case and underscores occasionally
-used to separate words (e.g., "variable_name" and "numchars" are both
-acceptable). Using underscores makes variable and function names more readable
-because it looks like whitespace; using lower-case is easy on the eyes.
-
-       Frowned upon:
-
-               hitList
-               TotalChars
-               szFileName
-               pf_Nfol_TriState
-
-       Preferred:
-
-               hit_list
-               total_chars
-               file_name
-               sensible_name
-
-Exceptions:
-
- - Enums, macros, and constant variables are occasionally written in all
-   upper-case with words optionally seperatedy by underscores (i.e. FIFOTYPE,
-   ISBLKDEV()).
-
- - Nobody is going to get mad at you for using 'pvar' as the name of a
-   variable that is a pointer to 'var'.
-
-
-Converting to K&R
-~~~~~~~~~~~~~~~~~
-
-The Busybox codebase is very much a mixture of code gathered from a variety of
-sources. This explains why the current codebase contains such a hodge-podge of
-different naming styles (Java, Pascal, K&R, just-plain-weird, etc.). The K&R
-guideline explained above should therefore be used on new files that are added
-to the repository. Furthermore, the maintainer of an existing file that uses
-alternate naming conventions should, at his own convenience, convert those
-names over to K&R style. Converting variable names is a very low priority
-task.
-
-If you want to do a search-and-replace of a single variable name in different
-files, you can do the following in the busybox directory:
-
-       $ perl -pi -e 's/\bOldVar\b/new_var/g' *.[ch]
-
-If you want to convert all the non-K&R vars in your file all at once, follow
-these steps:
-
- - In the busybox directory type 'scripts/mk2knr.pl files-to-convert'. This
-   does not do the actual conversion, rather, it generates a script called
-   'convertme.pl' that shows what will be converted, giving you a chance to
-   review the changes beforehand.
-
- - Review the 'convertme.pl' script that gets generated in the busybox
-   directory and remove / edit any of the substitutions in there. Please
-   especially check for false positives (strings that should not be
-   converted).
-
- - Type './convertme.pl same-files-as-before' to perform the actual
-   conversion.
-
- - Compile and see if everything still works.
-Please be aware of changes that have cascading effects into other files. For
-example, if you're changing the name of something in, say utility.c, you
-should probably run 'scripts/mk2knr.pl utility.c' at first, but when you run
-the 'convertme.pl' script you should run it on _all_ files like so:
-'./convertme.pl *.[ch]'.
-
-
-
-Avoid The Preprocessor
-----------------------
-
-At best, the preprocessor is a necessary evil, helping us account for platform
-and architecture differences. Using the preprocessor unnecessarily is just
-plain evil.
-
-
-The Folly of #define
-~~~~~~~~~~~~~~~~~~~~
-
-Use 'const <type> var' for declaring constants.
-
-       Don't do this:
-
-               #define var 80
-
-       Do this instead, when the variable is in a header file and will be used in
-       several source files: 
-
-               const int var = 80; 
-
-       Or do this when the variable is used only in a single source file:
-
-               static const int var = 80; 
-
-Declaring variables as '[static] const' gives variables an actual type and
-makes the compiler do type checking for you; the preprocessor does _no_ type
-checking whatsoever, making it much more error prone. Declaring variables with
-'[static] const' also makes debugging programs much easier since the value of
-the variable can be easily queried and displayed.
-
-
-The Folly of Macros
-~~~~~~~~~~~~~~~~~~~
-
-Use 'static inline' instead of a macro.
-
-       Don't do this:
-
-               #define mini_func(param1, param2) (param1 << param2)
-
-       Do this instead:
-
-               static inline int mini_func(int param1, param2)
-               {
-                       return (param1 << param2);
-               }
-
-Static inline functions are greatly preferred over macros. They provide type
-safety, have no length limitations, no formatting limitations, have an actual
-return value, and under gcc they are as cheap as macros. Besides, really long
-macros with backslashes at the end of each line are ugly as sin.
-
-
-The Folly of #ifdef
-~~~~~~~~~~~~~~~~~~~
-
-Code cluttered with ifdefs is difficult to read and maintain. Don't do it.
-Instead, put your ifdefs at the top of your .c file (or in a header), and
-conditionally define 'static inline' functions, (or *maybe* macros), which are
-used in the code.  
-
-       Don't do this:
-
-               ret = my_func(bar, baz);
-               if (!ret)
-                       return -1;
-               #ifdef BB_FEATURE_FUNKY
-                       maybe_do_funky_stuff(bar, baz);
-               #endif
-
-       Do this instead:
-
-       (in .h header file)
-
-               #ifdef BB_FEATURE_FUNKY
-               static inline void maybe_do_funky_stuff (int bar, int baz)
-               {
-                       /* lotsa code in here */
-               }
-               #else
-               static inline void maybe_do_funky_stuff (int bar, int baz) {}
-               #endif
-
-       (in the .c source file)
-
-               ret = my_func(bar, baz);
-               if (!ret)
-                       return -1;
-               maybe_do_funky_stuff(bar, baz);
-
-The great thing about this approach is that the compiler will optimize away
-the "no-op" case (the empty function) when the feature is turned off.
-
-Note also the use of the word 'maybe' in the function name to indicate
-conditional execution.
-
-
-
-Notes on Strings
-----------------
-
-Strings in C can get a little thorny. Here's some guidelines for dealing with
-strings in Busybox. (There is surely more that could be added to this
-section.)
-
-
-String Files
-~~~~~~~~~~~~
-
-Put all help/usage messages in usage.c. Put other strings in messages.c.
-Putting these strings into their own file is a calculated decision designed to
-confine spelling errors to a single place and aid internationalization
-efforts, if needed. (Side Note: we might want to use a single file - maybe
-called 'strings.c' - instead of two, food for thought).
-
-
-Testing String Equivalence
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There's a right way and a wrong way to test for sting equivalence with
-strcmp():
-
-       The wrong way:
-
-               if (!strcmp(string, "foo")) {
-                       ...
-
-       The right way:
-
-               if (strcmp(string, "foo") == 0){
-                       ...
-
-The use of the "equals" (==) operator in the latter example makes it much more
-obvious that you are testing for equivalence. The former example with the
-"not" (!) operator makes it look like you are testing for an error. In a more
-perfect world, we would have a streq() function in the string library, but
-that ain't the world we're living in.
-
-
-Avoid Dangerous String Functions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Unfortunately, the way C handles strings makes them prone to overruns when
-certain library functions are (mis)used. The following table  offers a summary
-of some of the more notorious troublemakers:
-
-function     overflows         preferred
-----------------------------------------
-strcpy       dest string       strncpy
-strcat       dest string       strncat
-gets         string it gets    fgets
-getwd        buf string        getcwd
-[v]sprintf   str buffer        [v]snprintf
-realpath     path buffer       use with pathconf
-[vf]scanf    its arguments     just avoid it
-
-
-The above is by no means a complete list. Be careful out there.
-
-
-
-Avoid Big Static Buffers
-------------------------
-
-First, some background to put this discussion in context: Static buffers look
-like this in code:
-
-       /* in a .c file outside any functions */
-       static char *buffer[BUFSIZ]; /* happily used by any function in this file,
-                                       but ick! big! */
-
-The problem with these is that any time any busybox app is run, you pay a
-memory penalty for this buffer, even if the applet that uses said buffer is
-not run. This can be fixed, thusly:
-
-       static char *buffer;
-       ...
-       other_func()
-       {
-               strcpy(buffer, lotsa_chars); /* happily uses global *buffer */
-       ...
-       foo_main()
-       {
-               buffer = xmalloc(sizeof(char)*BUFSIZ);
-       ...
-
-However, this approach trades bss segment for text segment. Rather than
-mallocing the buffers (and thus growing the text size), buffers can be
-declared on the stack in the *_main() function and made available globally by
-assigning them to a global pointer thusly:
-
-       static char *pbuffer;
-       ...
-       other_func()
-       {
-               strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */
-       ...
-       foo_main()
-       {
-               char *buffer[BUFSIZ]; /* declared locally, on stack */
-               pbuffer = buffer;     /* but available globally */
-       ...
-
-This last approach has some advantages (low code size, space not used until
-it's needed), but can be a problem in some low resource machines that have
-very limited stack space (e.g., uCLinux).
-
-A macro is declared in busybox.h that implements compile-time selection
-between xmalloc() and stack creation, so you can code the line in question as
-
-               RESERVE_BB_BUFFER(buffer, BUFSIZ);
-
-and the right thing will happen, based on your configuration.
-
-
-
-Miscellaneous Coding Guidelines
--------------------------------
-
-The following are important items that don't fit into any of the above
-sections.
-
-
-Model Busybox Applets After GNU Counterparts
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When in doubt about the proper behavior of a Busybox program (output,
-formatting, options, etc.), model it after the equivalent GNU program.
-Doesn't matter how that program behaves on some other flavor of *NIX; doesn't
-matter what the POSIX standard says or doesn't say, just model Busybox
-programs after their GNU counterparts and it will make life easier on (nearly)
-everyone.
-
-The only time we deviate from emulating the GNU behavior is when:
-
-       - We are deliberately not supporting a feature (such as a command line
-         switch)
-       - Emulating the GNU behavior is prohibitively expensive (lots more code
-         would be required, lots more memory would be used, etc.)
-       - The difference is minor or cosmetic
-
-A note on the 'cosmetic' case: Output differences might be considered
-cosmetic, but if the output is significant enough to break other scripts that
-use the output, it should really be fixed.
-
-
-Scope
-~~~~~
-
-If a const variable is used only in a single source file, put it in the source
-file and not in a header file. Likewise, if a const variable is used in only
-one function, do not make it global to the file. Instead, declare it inside
-the function body. Bottom line: Make a conscious effort to limit declarations
-to the smallest scope possible.
-
-Inside applet files, all functions should be declared static so as to keep the
-global name space clean. The only exception to this rule is the "applet_main"
-function which must be declared extern.
-
-If you write a function that performs a task that could be useful outside the
-immediate file, turn it into a general-purpose function with no ties to any
-applet and put it in the utility.c file instead.
-
-
-Brackets Are Your Friends
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Please use brackets on all if and else statements, even if it is only one
-line. Example:
-
-       Don't do this:
-
-               if (foo)
-                       stmt1;
-               stmt2
-               stmt3;
-
-       Do this instead:
-
-               if (foo) {
-                       stmt1;
-               }
-               stmt2
-               stmt3;
-
-The "bracketless" approach is error prone because someday you might add a line
-like this:
-
-               if (foo)
-                       stmt1;
-                       new_line();
-               stmt2
-               stmt3;
-
-And the resulting behavior of your program would totally bewilder you. (Don't
-laugh, it happens to us all.) Remember folks, this is C, not Python.
-
-
-Function Declarations
-~~~~~~~~~~~~~~~~~~~~~
-
-Do not use old-style function declarations that declare variable types between
-the parameter list and opening bracket. Example:
-
-       Don't do this:
-
-               int foo(parm1, parm2)
-                       char parm1;
-                       float parm2;
-               {
-                       ....
-
-       Do this instead:
-
-               int foo(char parm1, float parm2)
-               {
-                       ....
-
-The only time you would ever need to use the old declaration syntax is to
-support ancient, antediluvian compilers. To our good fortune, we have access
-to more modern compilers and the old declaration syntax is neither necessary
-nor desired.
-
-
-Emphasizing Logical Blocks
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Organization and readability are improved by putting extra newlines around
-blocks of code that perform a single task. These are typically blocks that
-begin with a C keyword, but not always.
-
-Furthermore, you should put a single comment (not necessarily one line, just
-one comment) before the block, rather than commenting each and every line.
-There is an optimal ammount of commenting that a program can have; you can
-comment too much as well as too little.
-
-A picture is really worth a thousand words here, the following example
-illustrates how to emphasize logical blocks:
-
-       while (line = get_line_from_file(fp)) {
-
-               /* eat the newline, if any */
-               chomp(line);
-
-               /* ignore blank lines */
-               if (strlen(file_to_act_on) == 0) {
-                       continue;
-               }
-
-               /* if the search string is in this line, print it,
-                * unless we were told to be quiet */
-               if (strstr(line, search) && !be_quiet) {
-                       puts(line);
-               }
-
-               /* clean up */
-               free(line);
-       }
-
-
-Processing Options with getopt
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If your applet needs to process  command-line switches, please use getopt() to
-do so. Numerous examples can be seen in many of the existing applets, but
-basically it boils down to two things: at the top of the .c file, have this
-line in the midst of your #includes:
-
-       #include <getopt.h>
-
-And a code block similar to the following near the top of your applet_main()
-routine:
-
-    while ((opt = getopt(argc, argv, "abc")) > 0) { 
-            switch (opt) {
-            case 'a':
-                do_a_opt = 1;
-                break;
-            case 'b':
-                do_b_opt = 1;
-                break;
-            case 'c':
-                do_c_opt = 1;
-                break;
-            default:
-                show_usage();    /* in utility.c */
-            }
-    }
-
-If your applet takes no options (such as 'init'), there should be a line
-somewhere in the file reads:
-
-       /* no options, no getopt */
-
-That way, when people go grepping to see which applets need to be converted to
-use getopt, they won't get false positives.
-
-Additional Note: Do not use the getopt_long library function and do not try to
-hand-roll your own long option parsing. Busybox applets should only support
-short options. Explanations and examples of the short options should be
-documented in usage.h.
diff --git a/busybox/dos2unix.c b/busybox/dos2unix.c
deleted file mode 100644 (file)
index cb30c56..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * dos2unix for BusyBox
- *
- * dos2unix '\n' convertor 0.5.0
- *   based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
- * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
- * All rights reserved.
- *
- * dos2unix filters reading input from stdin and writing output to stdout.
- * Without arguments it reverts the format (e.i. if source is in UNIX format,
- * output is in DOS format and vice versa).
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- * See the COPYING file for license information.
- */
-
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include "busybox.h"
-
-
-/* We are making a lame pseudo-random string generator here.  in
- * convert(), each pass through the while loop will add more and more
- * stuff into value, which is _supposed_ to wrap.  We don't care about
- * it being accurate.  We care about it being messy, since we then mod
- * it by the sizeof(letters) and then use that as an index into letters
- * to pick a random letter to add to out temporary file. */
-typedef unsigned long int bb_uint64_t;
-
-static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-// if fn is NULL then input is stdin and output is stdout
-static int convert(char *fn, int ConvType) 
-{
-       int c, fd;
-       struct timeval tv;
-       char tempFn[BUFSIZ];
-       static bb_uint64_t value=0;
-       FILE *in = stdin, *out = stdout;
-
-       if (fn != NULL) {
-               if ((in = wfopen(fn, "rw")) == NULL) {
-                       return -1;
-               }
-               strcpy(tempFn, fn);
-               c = strlen(tempFn);
-               tempFn[c] = '.';
-               while(1) {
-                   if (c >=BUFSIZ)
-                       error_msg_and_die("unique name not found");
-                   /* Get some semi random stuff to try and make a
-                    * random filename based (and in the same dir as)
-                    * the input file... */
-                   gettimeofday (&tv, NULL);
-                   value += ((bb_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
-                   tempFn[++c] = letters[value % 62];
-                   tempFn[c+1] = '\0';
-                   value /= 62;
-
-                   if ((fd = open(tempFn, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 ) {
-                       continue;
-                   }
-                   out = fdopen(fd, "w+");
-                   if (!out) {
-                       close(fd);
-                       remove(tempFn);
-                       continue;
-                   }
-                   break;
-               }
-       }
-
-       while ((c = fgetc(in)) != EOF) {
-               if (c == '\r') {
-                       if ((ConvType == CT_UNIX2DOS) && (fn != NULL)) {
-                               // file is alredy in DOS format so it is not necessery to touch it
-                               remove(tempFn);
-                               if (fclose(in) < 0 || fclose(out) < 0) {
-                                       perror_msg(NULL);
-                                       return -2;
-                               }
-                               return 0;
-                       }
-                       if (!ConvType)
-                               ConvType = CT_DOS2UNIX;
-                       break;
-               }
-               if (c == '\n') {
-                       if ((ConvType == CT_DOS2UNIX) && (fn != NULL)) {
-                               // file is alredy in UNIX format so it is not necessery to touch it
-                               remove(tempFn);
-                               if ((fclose(in) < 0) || (fclose(out) < 0)) {
-                                       perror_msg(NULL);
-                                       return -2;
-                               }
-                               return 0;
-                       }
-                       if (!ConvType) {
-                               ConvType = CT_UNIX2DOS;
-                       }
-                       if (ConvType == CT_UNIX2DOS) {
-                               fputc('\r', out);
-                       }
-                       fputc('\n', out);
-                       break;
-               }
-               fputc(c, out);
-       }
-       if (c != EOF)
-               while ((c = fgetc(in)) != EOF) {
-                       if (c == '\r')
-                               continue;
-                       if (c == '\n') {
-                               if (ConvType == CT_UNIX2DOS)
-                                       fputc('\r', out);
-                               fputc('\n', out);
-                               continue;
-                       }
-               fputc(c, out);
-       }
-
-       if (fn != NULL) {
-           if (fclose(in) < 0 || fclose(out) < 0) {
-               perror_msg(NULL);
-               remove(tempFn);
-               return -2;
-           }
-
-           /* Assume they are both on the same filesystem (which
-            * should be true since we put them into the same directory
-            * so we _should_ be ok, but you never know... */
-           if (rename(tempFn, fn) < 0) {
-               perror_msg("unable to rename '%s' as '%s'", tempFn, fn);
-               return -1;
-           }
-       }
-
-       return 0;
-}
-
-int dos2unix_main(int argc, char *argv[]) 
-{
-       int ConvType = CT_AUTO;
-       int o;
-
-       //See if we are supposed to be doing dos2unix or unix2dos 
-       if (argv[0][0]=='d') {
-           ConvType = CT_DOS2UNIX;
-       }
-       if (argv[0][0]=='u') {
-           ConvType = CT_UNIX2DOS;
-       }
-
-       // process parameters
-       while ((o = getopt(argc, argv, "du")) != EOF) {
-               switch (o) {
-               case 'd':
-                       ConvType = CT_UNIX2DOS;
-                       break;
-               case 'u':
-                       ConvType = CT_DOS2UNIX;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if (optind < argc) {
-               while(optind < argc)
-                       if ((o = convert(argv[optind++], ConvType)) < 0)
-                               break;
-       }
-       else
-               o = convert(NULL, ConvType);
-
-       return o;
-}
-
diff --git a/busybox/dpkg.c b/busybox/dpkg.c
deleted file mode 100644 (file)
index 48c3928..0000000
+++ /dev/null
@@ -1,1445 +0,0 @@
-/*
- *  Mini dpkg implementation for busybox.
- *  This is not meant as a replacemnt for dpkg
- *
- *  Copyright (C) 2001 by Glenn McGrath
- *             
- *  Started life as a busybox implementation of udpkg
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Known difference between busybox dpkg and the official dpkg that i dont
- * consider important, its worth keeping a note of differences anyway, just to
- * make it easier to maintain.
- *  - The first value for the Confflile: field isnt placed on a new line.
- *  - The <package>.control file is extracted and kept in the info dir.
- *  - When installing a package the Status: field is placed at the end of the
- *      section, rather than just after the Package: field.
- *  - Packages with previously unknown status are inserted at the begining of
- *      the status file
- *
- * Bugs that need to be fixed
- *  - (unknown, please let me know when you find any)
- *
- */
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* NOTE: If you vary HASH_PRIME sizes be aware,
- * 1) Tweaking these will have a big effect on how much memory this program uses.
- * 2) For computational efficiency these hash tables should be at least 20%
- *    larger than the maximum number of elements stored in it.
- * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking
- *    for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
- * 4) If you go bigger than 15 bits you may get into trouble (untested) as its
- *    sometimes cast to an unsigned int, if you go to 16 bit you will overlap
- *    int's and chaos is assured, 16381 is the max prime for 14 bit field
- */
-
-/* NAME_HASH_PRIME, Stores package names and versions, 
- * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
- * as there a lot of duplicate version numbers */
-#define NAME_HASH_PRIME 16381
-char *name_hashtable[NAME_HASH_PRIME + 1];
-
-/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
- * It must not be smaller than STATUS_HASH_PRIME,
- * Currently only packages from status_hashtable are stored in here, but in
- * future this may be used to store packages not only from a status file,
- * but an available_hashtable, and even multiple packages files.
- * Package can be stored more than once if they have different versions.
- * e.g. The same package may have different versions in the status file
- *      and available file */
-#define PACKAGE_HASH_PRIME 10007
-typedef struct edge_s {
-       unsigned int operator:3;
-       unsigned int type:4;
-       unsigned int name:14;
-       unsigned int version:14;
-} edge_t;
-
-typedef struct common_node_s {
-       unsigned int name:14;
-       unsigned int version:14;
-       unsigned int num_of_edges:14;
-       edge_t **edge;
-} common_node_t;
-common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
-
-/* Currently it doesnt store packages that have state-status of not-installed
- * So it only really has to be the size of the maximum number of packages
- * likely to be installed at any one time, so there is a bit of leaway here */
-#define STATUS_HASH_PRIME 8191
-typedef struct status_node_s {
-       unsigned int package:14;        /* has to fit PACKAGE_HASH_PRIME */
-       unsigned int status:14;         /* has to fit STATUS_HASH_PRIME */
-} status_node_t;
-status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
-
-/* Even numbers are for 'extras', like ored dependecies or null */
-enum edge_type_e {
-       EDGE_NULL = 0,
-       EDGE_PRE_DEPENDS = 1,
-       EDGE_OR_PRE_DEPENDS = 2,
-       EDGE_DEPENDS = 3,
-       EDGE_OR_DEPENDS = 4,
-       EDGE_REPLACES = 5,
-       EDGE_PROVIDES = 7,
-       EDGE_CONFLICTS = 9,
-       EDGE_SUGGESTS = 11,
-       EDGE_RECOMMENDS = 13,
-       EDGE_ENHANCES = 15
-};
-enum operator_e {
-       VER_NULL = 0,
-       VER_EQUAL = 1,
-       VER_LESS = 2,
-       VER_LESS_EQUAL = 3,
-       VER_MORE = 4,
-       VER_MORE_EQUAL = 5,
-       VER_ANY = 6
-};
-
-enum dpkg_opt_e {
-       dpkg_opt_purge = 1,
-       dpkg_opt_remove = 2,
-       dpkg_opt_unpack = 4,
-       dpkg_opt_configure = 8,
-       dpkg_opt_install = 16,
-       dpkg_opt_package_name = 32,
-       dpkg_opt_filename = 64,
-       dpkg_opt_list_installed = 128,
-       dpkg_opt_force_ignore_depends = 256
-};
-
-typedef struct deb_file_s {
-       char *control_file;
-       char *filename;
-       unsigned int package:14;
-} deb_file_t;
-
-
-void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
-{
-       unsigned long int hash_num = key[0];
-       int len = strlen(key);
-       int i;
-
-       /* Maybe i should have uses a "proper" hashing algorithm here instead
-        * of making one up myself, seems to be working ok though. */
-       for(i = 1; i < len; i++) {
-               /* shifts the ascii based value and adds it to previous value
-                * shift amount is mod 24 because long int is 32 bit and data
-                * to be shifted is 8, dont want to shift data to where it has
-                * no effect*/
-               hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); 
-       }
-       *start = (unsigned int) hash_num % hash_prime;
-       *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1));
-}
-
-/* this adds the key to the hash table */
-int search_name_hashtable(const char *key)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-//     char *temp;
-
-       make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
-       while(name_hashtable[probe_address] != NULL) {
-               if (strcmp(name_hashtable[probe_address], key) == 0) {
-                       return(probe_address);
-               } else {
-                       probe_address -= probe_decrement;
-                       if ((int)probe_address < 0) {
-                               probe_address += NAME_HASH_PRIME;
-                       }
-               }
-       }
-       name_hashtable[probe_address] = xstrdup(key);
-       return(probe_address);
-}
-
-/* this DOESNT add the key to the hashtable
- * TODO make it consistent with search_name_hashtable
- */
-unsigned int search_status_hashtable(const char *key)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-
-       make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
-       while(status_hashtable[probe_address] != NULL) {
-               if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
-                       break;
-               } else {
-                       probe_address -= probe_decrement;
-                       if ((int)probe_address < 0) {
-                               probe_address += STATUS_HASH_PRIME;
-                       }
-               }
-       }
-       return(probe_address);
-}
-
-/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
-int version_compare_part(const char *version1, const char *version2)
-{
-       int upstream_len1 = 0;
-       int upstream_len2 = 0;
-       char *name1_char;
-       char *name2_char;
-       int len1 = 0;
-       int len2 = 0;
-       int tmp_int;
-       int ver_num1;
-       int ver_num2;
-       int ret;
-
-       if (version1 == NULL) {
-               version1 = xstrdup("");
-       }
-       if (version2 != NULL) {
-               version2 = xstrdup("");
-       }
-       upstream_len1 = strlen(version1);
-       upstream_len2 = strlen(version2);
-
-       while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
-               /* Compare non-digit section */
-               tmp_int = strcspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strcspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               tmp_int = strcmp(name1_char, name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (tmp_int != 0) {
-                       ret = tmp_int;
-                       goto cleanup_version_compare_part;
-               }
-
-               /* Compare digits */
-               tmp_int = strspn(&version1[len1], "0123456789");
-               name1_char = xstrndup(&version1[len1], tmp_int);
-               len1 += tmp_int;
-               tmp_int = strspn(&version2[len2], "0123456789");
-               name2_char = xstrndup(&version2[len2], tmp_int);
-               len2 += tmp_int;
-               ver_num1 = atoi(name1_char);
-               ver_num2 = atoi(name2_char);
-               free(name1_char);
-               free(name2_char);
-               if (ver_num1 < ver_num2) {
-                       ret = -1;
-                       goto cleanup_version_compare_part;
-               }
-               else if (ver_num1 > ver_num2) {
-                       ret = 1;
-                       goto cleanup_version_compare_part;
-               }
-       }
-       ret = 0;
-cleanup_version_compare_part:
-       return(ret);
-}
-
-/* if ver1 < ver2 return -1,
- * if ver1 = ver2 return 0,
- * if ver1 > ver2 return 1,
- */
-int version_compare(const unsigned int ver1, const unsigned int ver2)
-{
-       char *ch_ver1 = name_hashtable[ver1];
-       char *ch_ver2 = name_hashtable[ver2];
-
-       char epoch1, epoch2;
-       char *deb_ver1, *deb_ver2;
-       char *ver1_ptr, *ver2_ptr;
-       char *upstream_ver1;
-       char *upstream_ver2;
-       int result;
-
-       /* Compare epoch */
-       if (ch_ver1[1] == ':') {
-               epoch1 = ch_ver1[0];
-               ver1_ptr = strchr(ch_ver1, ':') + 1;
-       } else {
-               epoch1 = '0';
-               ver1_ptr = ch_ver1;
-       }
-       if (ch_ver2[1] == ':') {
-               epoch2 = ch_ver2[0];
-               ver2_ptr = strchr(ch_ver2, ':') + 1;
-       } else {
-               epoch2 = '0';
-               ver2_ptr = ch_ver2;
-       }
-       if (epoch1 < epoch2) {
-               return(-1);
-       }
-       else if (epoch1 > epoch2) {
-               return(1);
-       }
-
-       /* Compare upstream version */
-       upstream_ver1 = xstrdup(ver1_ptr);
-       upstream_ver2 = xstrdup(ver2_ptr);
-
-       /* Chop off debian version, and store for later use */
-       deb_ver1 = strrchr(upstream_ver1, '-');
-       deb_ver2 = strrchr(upstream_ver2, '-');
-       if (deb_ver1) {
-               deb_ver1[0] = '\0';
-               deb_ver1++;
-       }
-       if (deb_ver2) {
-               deb_ver2[0] = '\0';
-               deb_ver2++;
-       }
-       result = version_compare_part(upstream_ver1, upstream_ver2);
-
-       free(upstream_ver1);
-       free(upstream_ver2);
-
-       if (result != 0) {
-               return(result);
-       }
-
-       /* Compare debian versions */
-       return(version_compare_part(deb_ver1, deb_ver2));
-}
-
-int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
-{
-       const int version_result = version_compare(version1, version2);
-       switch(operator) {
-               case (VER_ANY):
-                       return(TRUE);
-               case (VER_EQUAL):
-                       if (version_result == 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_LESS):
-                       if (version_result < 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_LESS_EQUAL):
-                       if (version_result <= 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_MORE):
-                       if (version_result > 0) {
-                               return(TRUE);
-                       }
-                       break;
-               case (VER_MORE_EQUAL):
-                       if (version_result >= 0) {
-                               return(TRUE);
-                       }
-                       break;
-       }
-       return(FALSE);
-}
-
-
-int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
-{
-       unsigned int probe_address = 0;
-       unsigned int probe_decrement = 0;
-
-       make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
-       while(package_hashtable[probe_address] != NULL) {
-               if (package_hashtable[probe_address]->name == name) {
-                       if (operator == VER_ANY) {
-                               return(probe_address);
-                       }
-                       if (test_version(package_hashtable[probe_address]->version, version, operator)) {
-                               return(probe_address);
-                       }
-               }
-               probe_address -= probe_decrement;
-               if ((int)probe_address < 0) {
-                       probe_address += PACKAGE_HASH_PRIME;
-               }
-       }
-       return(probe_address);
-}
-
-/*
- * Create one new node and one new edge for every dependency.
- */
-void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
-{
-       char *line = xstrdup(whole_line);
-       char *line2;
-       char *line_ptr1 = NULL;
-       char *line_ptr2 = NULL;
-       char *field;
-       char *field2;
-       char *version;
-       edge_t *edge;
-       int offset_ch;
-       int type;
-
-       field = strtok_r(line, ",", &line_ptr1);
-       do {
-               line2 = xstrdup(field);
-               field2 = strtok_r(line2, "|", &line_ptr2);
-               if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) {
-                       type = EDGE_OR_DEPENDS;
-               }
-               else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) {
-                       type = EDGE_OR_PRE_DEPENDS;
-               } else {
-                       type = edge_type;
-               }
-
-               do {
-                       edge = (edge_t *) xmalloc(sizeof(edge_t));
-                       edge->type = type;
-
-                       /* Skip any extra leading spaces */
-                       field2 += strspn(field2, " ");
-
-                       /* Get dependency version info */
-                       version = strchr(field2, '(');
-                       if (version == NULL) {
-                               edge->operator = VER_ANY;
-                               /* Get the versions hash number, adding it if the number isnt already in there */
-                               edge->version = search_name_hashtable("ANY");
-                       } else {
-                               /* Skip leading ' ' or '(' */
-                               version += strspn(field2, " ");
-                               version += strspn(version, "(");
-                               /* Calculate length of any operator charactors */
-                               offset_ch = strspn(version, "<=>");
-                               /* Determine operator */
-                               if (offset_ch > 0) {
-                                       if (strncmp(version, "=", offset_ch) == 0) {
-                                               edge->operator = VER_EQUAL;
-                                       }
-                                       else if (strncmp(version, "<<", offset_ch) == 0) {
-                                               edge->operator = VER_LESS;
-                                       }
-                                       else if (strncmp(version, "<=", offset_ch) == 0) {
-                                               edge->operator = VER_LESS_EQUAL;
-                                       }
-                                       else if (strncmp(version, ">>", offset_ch) == 0) {
-                                               edge->operator = VER_MORE;
-                                       }
-                                       else if (strncmp(version, ">=", offset_ch) == 0) {
-                                               edge->operator = VER_MORE_EQUAL;
-                                       } else {
-                                               error_msg_and_die("Illegal operator\n");
-                                       }
-                               }
-                               /* skip to start of version numbers */
-                               version += offset_ch;
-                               version += strspn(version, " ");
-
-                               /* Truncate version at trailing ' ' or ')' */
-                               version[strcspn(version, " )")] = '\0';
-                               /* Get the versions hash number, adding it if the number isnt already in there */
-                               edge->version = search_name_hashtable(version);
-                       }
-
-                       /* Get the dependency name */
-                       field2[strcspn(field2, " (")] = '\0';
-                       edge->name = search_name_hashtable(field2);
-       
-                       /* link the new edge to the current node */
-                       parent_node->num_of_edges++;
-                       parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1));
-                       parent_node->edge[parent_node->num_of_edges - 1] = edge;
-               } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL);
-               free(line2);
-       } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL);
-       free(line);
-
-       return;
-}
-
-void free_package(common_node_t *node)
-{
-       int i;
-       if (node != NULL) {
-               for (i = 0; i < node->num_of_edges; i++) {
-                       if (node->edge[i] != NULL) {
-                               free(node->edge[i]);
-                       }
-               }
-               if (node->edge != NULL) {
-                       free(node->edge);
-               }
-               if (node != NULL) {
-                       free(node);
-               }
-       }
-}
-
-unsigned int fill_package_struct(char *control_buffer)
-{
-       common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t));
-
-       char **field_name = xmalloc(sizeof(char *));
-       char **field_value = xmalloc(sizeof(char *));
-       int field_start = 0;
-       int num = -1;
-       int buffer_length = strlen(control_buffer);
-
-       new_node->version = search_name_hashtable("unknown");
-       while (field_start < buffer_length) {
-               field_start += read_package_field(&control_buffer[field_start], field_name, field_value);
-
-               if (*field_name == NULL) {
-                       goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !!
-               }
-
-               if (strcmp(*field_name, "Package") == 0) {
-                       new_node->name = search_name_hashtable(*field_value);
-               }
-               else if (strcmp(*field_name, "Version") == 0) {
-                       new_node->version = search_name_hashtable(*field_value);
-               }
-               else if (strcmp(*field_name, "Pre-Depends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS);
-               }
-               else if (strcmp(*field_name, "Depends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_DEPENDS);
-               }
-               else if (strcmp(*field_name, "Replaces") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_REPLACES);
-               }
-               else if (strcmp(*field_name, "Provides") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_PROVIDES);
-               }
-               else if (strcmp(*field_name, "Conflicts") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS);
-               }
-               else if (strcmp(*field_name, "Suggests") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS);
-               }
-               else if (strcmp(*field_name, "Recommends") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS);
-               }
-               else if (strcmp(*field_name, "Enhances") == 0) {
-                       add_split_dependencies(new_node, *field_value, EDGE_ENHANCES);
-               }
-fill_package_struct_cleanup:
-               if (*field_name) {
-                       free(*field_name);
-               }
-               if (*field_value) {
-                       free(*field_value);
-               }
-       }
-       free(field_name);
-       free(field_value);
-
-       if (new_node->version == search_name_hashtable("unknown")) {
-               free_package(new_node);
-               return(-1);
-       }
-       num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
-       if (package_hashtable[num] == NULL) {
-               package_hashtable[num] = new_node;
-       } else {
-               free_package(new_node);
-       }
-       return(num);
-}
-
-/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
-unsigned int get_status(const unsigned int status_node, const int num)
-{
-       char *status_string = name_hashtable[status_hashtable[status_node]->status];
-       char *state_sub_string;
-       unsigned int state_sub_num;
-       int len;
-       int i;
-
-       /* set tmp_string to point to the start of the word number */
-       for (i = 1; i < num; i++) {
-               /* skip past a word */
-               status_string += strcspn(status_string, " ");
-               /* skip past the seperating spaces */
-               status_string += strspn(status_string, " ");
-       }
-       len = strcspn(status_string, " \n\0");
-       state_sub_string = xstrndup(status_string, len);
-       state_sub_num = search_name_hashtable(state_sub_string);
-       free(state_sub_string);
-       return(state_sub_num);
-}
-
-void set_status(const unsigned int status_node_num, const char *new_value, const int position)
-{
-       const unsigned int new_value_len = strlen(new_value);
-       const unsigned int new_value_num = search_name_hashtable(new_value);
-       unsigned int want = get_status(status_node_num, 1);
-       unsigned int flag = get_status(status_node_num, 2);
-       unsigned int status = get_status(status_node_num, 3);
-       int want_len = strlen(name_hashtable[want]);
-       int flag_len = strlen(name_hashtable[flag]);
-       int status_len = strlen(name_hashtable[status]);
-       char *new_status;
-
-       switch (position) {
-               case (1):
-                       want = new_value_num;
-                       want_len = new_value_len;
-                       break;
-               case (2):
-                       flag = new_value_num;
-                       flag_len = new_value_len;
-                       break;
-               case (3):
-                       status = new_value_num;
-                       status_len = new_value_len;
-                       break;
-               default:
-                       error_msg_and_die("DEBUG ONLY: this shouldnt happen");
-       }
-
-       new_status = (char *) xmalloc(want_len + flag_len + status_len + 3);
-       sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
-       status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
-       free(new_status);
-       return;
-}
-
-void index_status_file(const char *filename)
-{
-       FILE *status_file;
-       char *control_buffer;
-       char *status_line;
-       status_node_t *status_node = NULL;
-       unsigned int status_num;
-
-       status_file = xfopen(filename, "r");
-       while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) {
-               const unsigned int package_num = fill_package_struct(control_buffer);
-               if (package_num != -1) {
-                       status_node = xmalloc(sizeof(status_node_t));
-                       /* fill_package_struct doesnt handle the status field */
-                       status_line = strstr(control_buffer, "Status:");
-                       if (status_line != NULL) {
-                               status_line += 7;
-                               status_line += strspn(status_line, " \n\t");
-                               status_line = xstrndup(status_line, strcspn(status_line, "\n\0"));
-                               status_node->status = search_name_hashtable(status_line);
-                               free(status_line);
-                       }
-                       status_node->package = package_num;
-                       status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
-                       status_hashtable[status_num] = status_node;
-               }
-               free(control_buffer);
-       }
-       fclose(status_file);
-       return;
-}
-
-
-char *get_depends_field(common_node_t *package, const int depends_type)
-{
-       char *depends = NULL;
-       char *old_sep = (char *)xcalloc(1, 3);
-       char *new_sep = (char *)xcalloc(1, 3);
-       int line_size = 0;
-       int depends_size;
-
-       int i;
-
-       for (i = 0; i < package->num_of_edges; i++) {
-               if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) ||
-                       (package->edge[i]->type == EDGE_OR_DEPENDS)) {
-               }
-
-               if ((package->edge[i]->type == depends_type) ||
-                       (package->edge[i]->type == depends_type + 1)) {
-                       /* Check if its the first time through */
-
-                       depends_size = 8 + strlen(name_hashtable[package->edge[i]->name])
-                               + strlen(name_hashtable[package->edge[i]->version]);
-                       line_size += depends_size;
-                       depends = (char *) xrealloc(depends, line_size + 1);
-
-                       /* Check to see if this dependency is the type we are looking for
-                        * +1 to check for 'extra' types, e.g. ored dependecies */
-                       strcpy(old_sep, new_sep);
-                       if (package->edge[i]->type == depends_type) {
-                               strcpy(new_sep, ", ");
-                       }
-                       else if (package->edge[i]->type == depends_type + 1) {
-                               strcpy(new_sep, "| ");
-                       }
-
-                       if (depends_size == line_size) {
-                               strcpy(depends, "");
-                       } else {
-                               if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) {
-                                       strcat(depends, " | ");
-                               } else {
-                                       strcat(depends, ", ");
-                               }
-                       }
-
-                       strcat(depends, name_hashtable[package->edge[i]->name]);
-                       if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) {
-                               if (package->edge[i]->operator == VER_EQUAL) {
-                                       strcat(depends, " (= ");
-                               }
-                               else if (package->edge[i]->operator == VER_LESS) {
-                                       strcat(depends, " (<< ");
-                               }
-                               else if (package->edge[i]->operator == VER_LESS_EQUAL) {
-                                       strcat(depends, " (<= ");
-                               }
-                               else if (package->edge[i]->operator == VER_MORE) {
-                                       strcat(depends, " (>> ");
-                               }
-                               else if (package->edge[i]->operator == VER_MORE_EQUAL) {
-                                       strcat(depends, " (>= ");
-                               } else {
-                                       strcat(depends, " (");
-                               }
-                               strcat(depends, name_hashtable[package->edge[i]->version]);
-                               strcat(depends, ")");
-                       }
-               }
-       }
-       return(depends);
-}
-
-void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
-{
-       char *name;
-       char *value;
-       int start = 0;
-       while (1) {
-               start += read_package_field(&control_buffer[start], &name, &value);
-               if (name == NULL) {
-                       break;
-               }
-               if (strcmp(name, "Status") != 0) {
-                       fprintf(new_status_file, "%s: %s\n", name, value);
-               }
-       }
-       return;
-}
-
-/* This could do with a cleanup */
-void write_status_file(deb_file_t **deb_file)
-{
-       FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
-       FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
-       char *package_name;
-       char *status_from_file;
-       char *control_buffer = NULL;
-       char *tmp_string;
-       int status_num;
-       int field_start = 0;
-       int write_flag;
-       int i = 0;
-
-       /* Update previously known packages */
-       while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) {
-               tmp_string = strstr(control_buffer, "Package:") + 8;
-               tmp_string += strspn(tmp_string, " \n\t");
-               package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0"));
-               write_flag = FALSE;
-               tmp_string = strstr(control_buffer, "Status:");
-               if (tmp_string != NULL) {
-                       /* Seperate the status value from the control buffer */
-                       tmp_string += 7;
-                       tmp_string += strspn(tmp_string, " \n\t");
-                       status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
-               } else {
-                       status_from_file = NULL;
-               }
-
-               /* Find this package in the status hashtable */
-               status_num = search_status_hashtable(package_name);
-               if (status_hashtable[status_num] != NULL) {
-                       const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
-                       if (strcmp(status_from_file, status_from_hashtable) != 0) {
-                               /* New status isnt exactly the same as old status */
-                               const int state_status = get_status(status_num, 3);
-                               if ((strcmp("installed", name_hashtable[state_status]) == 0) ||
-                                       (strcmp("unpacked", name_hashtable[state_status]) == 0)) {
-                                       /* We need to add the control file from the package */
-                                       i = 0;
-                                       while(deb_file[i] != NULL) {
-                                               if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
-                                                       /* Write a status file entry with a modified status */
-                                                       /* remove trailing \n's */
-                                                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
-                                                       set_status(status_num, "ok", 2);
-                                                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
-                                                       write_flag = TRUE;
-                                                       break;
-                                               }
-                                               i++;
-                                       }
-                                       /* This is temperary, debugging only */
-                                       if (deb_file[i] == NULL) {
-                                               error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name);
-                                       }
-                               }
-                               else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
-                                       /* Only write the Package, Status, Priority and Section lines */
-                                       fprintf(new_status_file, "Package: %s\n", package_name);
-                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
-
-                                       while (1) {
-                                               char *field_name;
-                                               char *field_value;
-                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
-                                               if (field_name == NULL) {
-                                                       break;
-                                               }
-                                               if ((strcmp(field_name, "Priority") == 0) ||
-                                                       (strcmp(field_name, "Section") == 0)) {
-                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
-                                               }
-                                       }
-                                       write_flag = TRUE;
-                                       fputs("\n", new_status_file);
-                               }
-                               else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
-                                       /* only change the status line */
-                                       while (1) {
-                                               char *field_name;
-                                               char *field_value;
-                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
-                                               if (field_name == NULL) {
-                                                       break;
-                                               }
-                                               /* Setup start point for next field */
-                                               if (strcmp(field_name, "Status") == 0) {
-                                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
-                                               } else {
-                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
-                                               }
-                                       }
-                                       write_flag = TRUE;
-                                       fputs("\n", new_status_file);
-                               }
-                       }
-               }
-               /* If the package from the status file wasnt handle above, do it now*/
-               if (write_flag == FALSE) {
-                       fprintf(new_status_file, "%s\n\n", control_buffer);
-               }
-
-               if (status_from_file != NULL) {
-                       free(status_from_file);
-               }
-               free(package_name);
-               free(control_buffer);
-       }
-
-       /* Write any new packages */
-       for(i = 0; deb_file[i] != NULL; i++) {
-               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
-               if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
-                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
-                       set_status(status_num, "ok", 2);
-                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
-               }
-       }
-       fclose(old_status_file);
-       fclose(new_status_file);
-
-
-       /* Create a seperate backfile to dpkg */
-       if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
-               struct stat stat_buf;   
-               if (stat("/var/lib/dpkg/status", &stat_buf) == 0) {
-                       error_msg_and_die("Couldnt create backup status file");
-               }
-               /* Its ok if renaming the status file fails becasue status 
-                * file doesnt exist, maybe we are starting from scratch */
-               error_msg("No status file found, creating new one");
-       }
-
-       if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) {
-               error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file");
-       }
-}
-
-int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
-{
-       int *conflicts = NULL;
-       int conflicts_num = 0;
-       int state_status;
-       int state_flag;
-       int state_want;
-       unsigned int status_package_num;
-       int i = deb_start;
-       int j, k;
-
-       /* Check for conflicts
-        * TODO: TEST if conflicts with other packages to be installed
-        *
-        * Add install packages and the packages they provide
-        * to the list of files to check conflicts for
-        */
-
-       /* Create array of package numbers to check against
-        * installed package for conflicts*/
-       while (deb_file[i] != NULL) {
-               const unsigned int package_num = deb_file[i]->package;
-               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
-               conflicts[conflicts_num] = package_num;
-               conflicts_num++;
-               /* add provides to conflicts list */
-               for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
-                       if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
-                               const int conflicts_package_num = search_package_hashtable(
-                                       package_hashtable[package_num]->edge[j]->name,
-                                       package_hashtable[package_num]->edge[j]->version,
-                                       package_hashtable[package_num]->edge[j]->operator);
-                               if (package_hashtable[conflicts_package_num] == NULL) {
-                                       /* create a new package */
-                                       common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t));
-                                       new_node->name = package_hashtable[package_num]->edge[j]->name;
-                                       new_node->version = package_hashtable[package_num]->edge[j]->version;
-                                       new_node->num_of_edges = 0;
-                                       new_node->edge = NULL;
-                                       package_hashtable[conflicts_package_num] = new_node;
-                               }
-                               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
-                               conflicts[conflicts_num] = conflicts_package_num;
-                               conflicts_num++;
-                       }
-               }
-               i++;
-       }
-
-       /* Check conflicts */
-       for (i = 0; i < conflicts_num; i++) {
-               /* Check for conflicts */
-               for (j = 0; j < STATUS_HASH_PRIME; j++) {
-                       if (status_hashtable[j] == NULL) {
-                               continue;
-                       }
-                       state_flag = get_status(j, 2);
-                       state_status = get_status(j, 3);
-                       if ((state_status != search_name_hashtable("installed"))
-                               && (state_flag != search_name_hashtable("want-install"))) {
-                               continue;
-                       }
-                       status_package_num = status_hashtable[j]->package;
-                       for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) {
-                               const edge_t *package_edge = package_hashtable[status_package_num]->edge[k];
-                               if (package_edge->type != EDGE_CONFLICTS) {
-                                       continue;
-                               }
-                               if (package_edge->name != package_hashtable[conflicts[i]]->name) {
-                                       continue;
-                               }
-                               /* There is a conflict against the package name
-                                * check if version conflict as well */
-                               if (test_version(package_hashtable[deb_file[i]->package]->version,
-                                               package_edge->version, package_edge->operator)) {
-                                       error_msg_and_die("Package %s conflict with %s",
-                                               name_hashtable[package_hashtable[deb_file[i]->package]->name],
-                                               name_hashtable[package_hashtable[status_package_num]->name]);
-                               }
-                       }
-               }
-       }
-
-       /* Check dependendcies */
-       i = 0;
-       while (deb_file[i] != NULL) {
-               const common_node_t *package_node = package_hashtable[deb_file[i]->package];
-               int status_num = 0;
-
-               for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) {
-                       const edge_t *package_edge = package_node->edge[j];
-                       const unsigned int package_num = search_package_hashtable(package_edge->name,
-                               package_edge->version, package_edge->operator);
-
-                       status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
-                       state_status = get_status(status_num, 3);
-                       state_want = get_status(status_num, 1);
-                       switch (package_edge->type) {
-                               case(EDGE_PRE_DEPENDS):
-                               case(EDGE_OR_PRE_DEPENDS):
-                                       /* It must be already installed */
-                                       /* NOTE: This is untested, nothing apropriate in my status file */
-                                       if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) {
-                                               error_msg_and_die("Package %s pre-depends on %s, but it is not installed",
-                                                       name_hashtable[package_node->name],
-                                                       name_hashtable[package_edge->name]);
-                                       }
-                                       break;
-                               case(EDGE_DEPENDS):
-                               case(EDGE_OR_DEPENDS):
-                                       /* It must be already installed, or to be installed */
-                                       if ((package_hashtable[package_num] == NULL) ||
-                                               ((state_status != search_name_hashtable("installed")) &&
-                                               (state_want != search_name_hashtable("want_install")))) {
-                                               error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
-                                                       name_hashtable[package_node->name],
-                                                       name_hashtable[package_edge->name]);
-                                       }
-                                       break;
-                       }
-               }
-               i++;
-       }
-       free(conflicts);
-       return(TRUE);
-}
-
-char **create_list(const char *filename)
-{
-       FILE *list_stream;
-       char **file_list = xmalloc(sizeof(char *));
-       char *line = NULL;
-       char *last_char;
-       int length = 0;
-       int count = 0;
-
-       /* dont use [xw]fopen here, handle error ourself */
-       list_stream = fopen(filename, "r");
-       if (list_stream == NULL) {
-               *file_list = NULL;
-               return(file_list);
-       }
-       while (getline(&line, &length, list_stream) != -1) {
-               file_list = xrealloc(file_list, sizeof(char *) * (length + 1));
-               last_char = last_char_is(line, '\n');
-               if (last_char) {
-                       *last_char = '\0';
-               }
-               file_list[count] = xstrdup(line);
-               free(line);
-               count++;
-               length = 0;
-       }
-       fclose(list_stream);
-
-       if (count == 0) {
-               return(NULL);
-       } else {
-               file_list[count] = NULL;
-               return(file_list);
-       }
-}
-
-/* maybe i should try and hook this into remove_file.c somehow */
-int remove_file_array(char **remove_names, char **exclude_names)
-{
-       struct stat path_stat;
-       int match_flag;
-       int remove_flag = FALSE;
-       int i,j;
-
-       if (remove_names == NULL) {
-               return(FALSE);
-       }
-       for (i = 0; remove_names[i] != NULL; i++) {
-               match_flag = FALSE;
-               if (exclude_names != NULL) {
-                       for (j = 0; exclude_names[j] != 0; j++) {
-                               if (strcmp(remove_names[i], exclude_names[j]) == 0) {
-                                       match_flag = TRUE;
-                                       break;
-                               }
-                       }
-               }
-               if (!match_flag) {
-                       if (lstat(remove_names[i], &path_stat) < 0) {
-                               continue;
-                       }
-                       if (S_ISDIR(path_stat.st_mode)) {
-                               if (rmdir(remove_names[i]) != -1) {
-                                       remove_flag = TRUE;
-                               }
-                       } else {
-                               if (unlink(remove_names[i]) != -1) {
-                                       remove_flag = TRUE;
-                               }
-                       }
-               }
-       }
-       return(remove_flag);
-}
-
-int run_package_script(const char *package_name, const char *script_type)
-{
-       struct stat path_stat;
-       char *script_path;
-
-       script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21);
-       sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type);
-
-       /* If the file doesnt exist is isnt a fatal */
-       if (lstat(script_path, &path_stat) < 0) {
-               free(script_path);
-               return(EXIT_SUCCESS);
-       } else {
-               free(script_path);
-               return(system(script_path));
-       }
-}
-
-void all_control_list(char **remove_files, const char *package_name)
-{
-       const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm",
-               "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL };
-       int i;
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       for(i = 0; i < 10; i++) {
-               remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21);
-               sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]);
-       }
-       remove_files[10] = NULL;
-}
-
-void remove_package(const unsigned int package_num)
-{
-       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       const int package_name_length = strlen(package_name);
-       char **remove_files;
-       char **exclude_files;
-       char list_name[package_name_length + 25];
-       char conffile_name[package_name_length + 30];
-       int return_value;
-
-       printf("Removing %s ...\n", package_name);
-
-       /* run prerm script */
-       return_value = run_package_script(package_name, "prem");
-       if (return_value == -1) {
-               error_msg_and_die("script failed, prerm failure");
-       }
-
-       /* Create a list of files to remove, and a seperate list of those to keep */
-       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
-       remove_files = create_list(list_name);
-
-       sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name);
-       exclude_files = create_list(conffile_name);
-
-       /* Some directories cant be removed straight away, so do multiple passes */
-       while (remove_file_array(remove_files, exclude_files) == TRUE);
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       remove_files = xmalloc(11);
-       all_control_list(remove_files, package_name);
-
-       /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep  */
-       exclude_files = xmalloc(sizeof(char*) * 3);
-       exclude_files[0] = xstrdup(conffile_name);
-       exclude_files[1] = xmalloc(package_name_length + 27);
-       sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name);
-       exclude_files[2] = NULL;
-
-       remove_file_array(remove_files, exclude_files);
-
-       /* rename <package>.conffile to <package>.list */
-       rename(conffile_name, list_name);
-
-       /* Change package status */
-       set_status(status_num, "deinstall", 1);
-       set_status(status_num, "config-files", 3);
-}
-
-void purge_package(const unsigned int package_num)
-{
-       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       char **remove_files;
-       char **exclude_files;
-       char list_name[strlen(package_name) + 25];
-
-       /* run prerm script */
-       if (run_package_script(package_name, "prerm") == -1) {
-               error_msg_and_die("script failed, prerm failure");
-       }
-
-       /* Create a list of files to remove */
-       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
-       remove_files = create_list(list_name);
-
-       exclude_files = xmalloc(1);
-       exclude_files[0] = NULL;
-
-       /* Some directories cant be removed straight away, so do multiple passes */
-       while (remove_file_array(remove_files, exclude_files) == TRUE);
-
-       /* Create a list of all /var/lib/dpkg/info/<package> files */
-       remove_files = xmalloc(11);
-       all_control_list(remove_files, package_name);
-       remove_file_array(remove_files, exclude_files);
-
-       /* run postrm script */
-       if (run_package_script(package_name, "postrm") == -1) {
-               error_msg_and_die("postrm fialure.. set status to what?");
-       }
-
-       /* Change package status */
-       set_status(status_num, "purge", 1);
-       set_status(status_num, "not-installed", 3);
-}
-
-void unpack_package(deb_file_t *deb_file)
-{
-       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
-       const unsigned int status_num = search_status_hashtable(package_name);
-       const unsigned int status_package_num = status_hashtable[status_num]->status;
-
-       FILE *out_stream;
-       char *info_prefix;
-
-       /* If existing version, remove it first */
-       if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
-               /* Package is already installed, remove old version first */
-               printf("Preparing to replace %s %s (using %s) ...\n", package_name,
-                       name_hashtable[package_hashtable[status_package_num]->version],
-                       deb_file->filename);
-               remove_package(status_package_num);
-       } else {
-               printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename);
-       }
-
-       /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
-       info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1);
-       sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name);
-       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL);
-
-       /* Extract data.tar.gz to the root directory */
-       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL);
-
-       /* Create the list file */
-       strcat(info_prefix, "list");
-       out_stream = xfopen(info_prefix, "w");                  
-       deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL);
-       fclose(out_stream);
-
-       /* change status */
-       set_status(status_num, "install", 1);
-       set_status(status_num, "unpacked", 3);
-
-       free(info_prefix);
-}
-
-void configure_package(deb_file_t *deb_file)
-{
-       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
-       const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
-       const int status_num = search_status_hashtable(package_name);
-       int return_value;
-
-       printf("Setting up %s (%s)\n", package_name, package_version);
-
-       /* Run the preinst prior to extracting */
-       return_value = run_package_script(package_name, "postinst");
-       if (return_value == -1) {
-               /* TODO: handle failure gracefully */
-               error_msg_and_die("postrm failure.. set status to what?");
-       }
-       /* Change status to reflect success */
-       set_status(status_num, "install", 1);
-       set_status(status_num, "installed", 3);
-}
-
-extern int dpkg_main(int argc, char **argv)
-{
-       deb_file_t **deb_file = NULL;
-       status_node_t *status_node;
-       char opt = 0;
-       int package_num;
-       int dpkg_opt = 0;
-       int deb_count = 0;
-       int state_status;
-       int status_num;
-       int i;
-
-       while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) {
-               switch (opt) {
-                       case 'C': // equivalent to --configure in official dpkg
-                               dpkg_opt |= dpkg_opt_configure;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'F': // equivalent to --force in official dpkg
-                               if (strcmp(optarg, "depends") == 0) {
-                                       dpkg_opt |= dpkg_opt_force_ignore_depends;
-                               }                               
-                       case 'i':
-                               dpkg_opt |= dpkg_opt_install;
-                               dpkg_opt |= dpkg_opt_filename;
-                               break;
-                       case 'l':
-                               dpkg_opt |= dpkg_opt_list_installed;
-                       case 'P':
-                               dpkg_opt |= dpkg_opt_purge;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'r':
-                               dpkg_opt |= dpkg_opt_remove;
-                               dpkg_opt |= dpkg_opt_package_name;
-                               break;
-                       case 'u':       /* Equivalent to --unpack in official dpkg */
-                               dpkg_opt |= dpkg_opt_unpack;
-                               dpkg_opt |= dpkg_opt_filename;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((argc == optind) || (dpkg_opt == 0)) {
-               show_usage();
-       } 
-
-       puts("(Reading database ... xxxxx files and directories installed.)");
-       index_status_file("/var/lib/dpkg/status");
-
-       /* Read arguments and store relevant info in structs */
-       deb_file = xmalloc(sizeof(deb_file_t));
-       while (optind < argc) {
-               deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t));
-               if (dpkg_opt & dpkg_opt_filename) {
-                       deb_file[deb_count]->filename = xstrdup(argv[optind]);
-                       deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control");
-                       if (deb_file[deb_count]->control_file == NULL) {
-                               error_msg_and_die("Couldnt extract control file");
-                       }
-                       package_num = fill_package_struct(deb_file[deb_count]->control_file);
-
-                       if (package_num == -1) {
-                               error_msg("Invalid control file in %s", argv[optind]);
-                               continue;
-                       }
-                       deb_file[deb_count]->package = (unsigned int) package_num;
-                       /* Add the package to the status hashtable */
-                       if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) {
-                               status_node = (status_node_t *) xmalloc(sizeof(status_node_t));
-                               status_node->package = deb_file[deb_count]->package;
-                               /* use reinstreq isnt changed to "ok" until the package control info
-                                * is written to the status file*/
-                               status_node->status = search_name_hashtable("install reinstreq not-installed");
-
-                               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               status_hashtable[status_num] = status_node;
-                       }
-               }
-               else if (dpkg_opt & dpkg_opt_package_name) {
-                       deb_file[deb_count]->filename = NULL;
-                       deb_file[deb_count]->control_file = NULL;
-                       deb_file[deb_count]->package = search_package_hashtable(
-                               search_name_hashtable(argv[optind]),
-                               search_name_hashtable("ANY"), VER_ANY);
-                       if (package_hashtable[deb_file[deb_count]->package] == NULL) {
-                               error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]);
-                       }
-                       state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3);
-
-                       /* check package status is "installed" */
-                       if (dpkg_opt & dpkg_opt_remove) {
-                               if ((strcmp(name_hashtable[state_status], "not-installed") == 0) ||
-                                       (strcmp(name_hashtable[state_status], "config-files") == 0)) {
-                                       error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               }
-                       }
-                       else if (dpkg_opt & dpkg_opt_purge) {
-                               /* if package status is "conf-files" then its ok */
-                               if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
-                                       error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
-                               }
-                       }
-               }
-               deb_count++;
-               optind++;
-       }
-       deb_file[deb_count] = NULL;
-
-       /* Check that the deb file arguments are installable */
-       /* TODO: check dependencies before removing */
-       if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) {
-               if (!check_deps(deb_file, 0, deb_count)) {
-                       error_msg_and_die("Dependency check failed");
-               }
-       }
-
-       for (i = 0; i < deb_count; i++) {
-               /* Remove or purge packages */
-               if (dpkg_opt & dpkg_opt_remove) {
-                       remove_package(deb_file[i]->package);
-               }
-               else if (dpkg_opt & dpkg_opt_purge) {
-                       purge_package(deb_file[i]->package);
-               }
-               else if (dpkg_opt & dpkg_opt_unpack) {
-                       unpack_package(deb_file[i]);
-               }
-               else if (dpkg_opt & dpkg_opt_install) {
-                       unpack_package(deb_file[i]);
-                       configure_package(deb_file[i]);
-               }
-               else if (dpkg_opt & dpkg_opt_configure) {
-                       configure_package(deb_file[i]);
-               }
-       }
-
-       write_status_file(deb_file);
-
-       for (i = 0; i < deb_count; i++) {
-               free(deb_file[i]->control_file);
-               free(deb_file[i]->filename);
-               free(deb_file[i]);
-       }
-       free(deb_file);
-
-       for (i = 0; i < NAME_HASH_PRIME; i++) {
-               if (name_hashtable[i] != NULL) {
-                       free(name_hashtable[i]);
-               }
-       }
-
-       for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
-               free_package(package_hashtable[i]);
-       }
-
-       for (i = 0; i < STATUS_HASH_PRIME; i++) {
-               if (status_hashtable[i] != NULL) {
-                       free(status_hashtable[i]);
-               }
-       }
-
-       return(EXIT_FAILURE);
-}
-
diff --git a/busybox/dpkg_deb.c b/busybox/dpkg_deb.c
deleted file mode 100644 (file)
index a933c69..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int dpkg_deb_main(int argc, char **argv)
-{
-       char *prefix = NULL;
-       char *filename = NULL;
-       char *output_buffer = NULL;
-       int opt = 0;
-       int arg_type = 0;
-       int deb_extract_funct = extract_create_leading_dirs | extract_unconditional;    
-       
-       const int arg_type_prefix = 1;
-       const int arg_type_field = 2;
-       const int arg_type_filename = 4;
-//     const int arg_type_un_ar_gz = 8;
-
-       while ((opt = getopt(argc, argv, "ceftXxI")) != -1) {
-               switch (opt) {
-                       case 'c':
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_verbose_list;
-                               break;
-                       case 'e':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               break;
-                       case 'f':
-                               arg_type = arg_type_field;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_one_to_buffer;
-                               filename = xstrdup("./control");
-                               break;
-                       case 't': /* --fsys-tarfile, i just made up this short name */
-                               /* Integrate the functionality needed with some code from ar.c */
-                               error_msg_and_die("Option disabled");
-//                             arg_type = arg_type_un_ar_gz;
-                               break;
-                       case 'X':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               deb_extract_funct |= extract_list;
-                       case 'x':
-                               arg_type = arg_type_prefix;
-                               deb_extract_funct |= extract_data_tar_gz;
-                               deb_extract_funct |= extract_all_to_fs;
-                               break;
-                       case 'I':
-                               arg_type = arg_type_filename;
-                               deb_extract_funct |= extract_control_tar_gz;
-                               deb_extract_funct |= extract_one_to_buffer;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)  {
-               show_usage();
-       }
-
-       /* Workout where to extract the files */
-       if (arg_type == arg_type_prefix) {
-               /* argument is a dir name */
-               if ((optind + 1) == argc ) {
-                       prefix = xstrdup("./DEBIAN/");
-               } else {
-                       prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2);
-                       strcpy(prefix, argv[optind + 1]);
-                       /* Make sure the directory has a trailing '/' */
-                       if (last_char_is(prefix, '/') == NULL) {
-                               strcat(prefix, "/");
-                       }
-               }
-               mkdir(prefix, 0777);
-       }
-
-       if (arg_type == arg_type_filename) {
-               if ((optind + 1) != argc) {
-                       filename = xstrdup(argv[optind + 1]);
-               } else {
-                       error_msg_and_die("-I currently requires a filename to be specified");
-               }
-       }
-
-       output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename);
-
-       if ((arg_type == arg_type_filename) && (output_buffer != NULL)) {
-               puts(output_buffer);
-       }
-       else if (arg_type == arg_type_field) {
-               char *field = NULL;
-               char *name;
-               char *value;
-               int field_start = 0;
-
-               while (1) {
-                       field_start += read_package_field(&output_buffer[field_start], &name, &value);
-                       if (name == NULL) {
-                               break;
-                       }
-                       if (strcmp(name, argv[optind + 1]) == 0) {
-                               puts(value);
-                       }
-                       free(field);
-               }
-       }
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/du.c b/busybox/du.c
deleted file mode 100644 (file)
index fb649ae..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini du implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-#include <errno.h>
-#include "busybox.h"
-
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long disp_hr = KILOBYTE;
-#endif
-
-typedef void (Display) (long, char *);
-
-static int du_depth = 0;
-static int count_hardlinks = 0;
-
-static Display *print;
-
-static void print_normal(long size, char *filename)
-{
-#ifdef BB_FEATURE_HUMAN_READABLE
-       printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
-#else
-       printf("%ld\t%s\n", size, filename);
-#endif
-}
-
-static void print_summary(long size, char *filename)
-{
-       if (du_depth == 1) {
-               print_normal(size, filename);
-       }
-}
-
-#define HASH_SIZE       311             /* Should be prime */
-#define hash_inode(i)   ((i) % HASH_SIZE)
-
-typedef struct ino_dev_hash_bucket_struct {
-  struct ino_dev_hash_bucket_struct *next;
-  ino_t ino;
-  dev_t dev;
-  char name[1];
-} ino_dev_hashtable_bucket_t;
-
-static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
-
-/*
- * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
- * `ino_dev_hashtable', else return 0
- *
- * If NAME is a non-NULL pointer to a character pointer, and there is
- * a match, then set *NAME to the value of the name slot in that
- * bucket.
- */
-static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
-{
-       ino_dev_hashtable_bucket_t *bucket;
-
-       bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
-       while (bucket != NULL) {
-         if ((bucket->ino == statbuf->st_ino) &&
-                 (bucket->dev == statbuf->st_dev))
-         {
-               if (name) *name = bucket->name;
-               return 1;
-         }
-         bucket = bucket->next;
-       }
-       return 0;
-}
-
-/* Add statbuf to statbuf hash table */
-static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
-{
-       int i;
-       size_t s;
-       ino_dev_hashtable_bucket_t *bucket;
-
-       i = hash_inode(statbuf->st_ino);
-       s = name ? strlen(name) : 0;
-       bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
-       bucket->ino = statbuf->st_ino;
-       bucket->dev = statbuf->st_dev;
-       if (name)
-               strcpy(bucket->name, name);
-       else
-               bucket->name[0] = '\0';
-       bucket->next = ino_dev_hashtable[i];
-       ino_dev_hashtable[i] = bucket;
-}
-
-/* Clear statbuf hash table */
-static void reset_ino_dev_hashtable(void)
-{
-       int i;
-       ino_dev_hashtable_bucket_t *bucket;
-
-       for (i = 0; i < HASH_SIZE; i++) {
-               while (ino_dev_hashtable[i] != NULL) {
-                       bucket = ino_dev_hashtable[i]->next;
-                       free(ino_dev_hashtable[i]);
-                       ino_dev_hashtable[i] = bucket;
-               }
-       }
-}
-
-/* tiny recursive du */
-static long du(char *filename)
-{
-       struct stat statbuf;
-       long sum;
-
-       if ((lstat(filename, &statbuf)) != 0) {
-               perror_msg("%s", filename);
-               return 0;
-       }
-
-       du_depth++;
-       sum = (statbuf.st_blocks >> 1);
-
-       /* Don't add in stuff pointed to by symbolic links */
-       if (S_ISLNK(statbuf.st_mode)) {
-               sum = 0L;
-               if (du_depth == 1) {
-               }
-       }
-       if (S_ISDIR(statbuf.st_mode)) {
-               DIR *dir;
-               struct dirent *entry;
-               char *newfile;
-
-               dir = opendir(filename);
-               if (!dir) {
-                       du_depth--;
-                       return 0;
-               }
-
-               newfile = last_char_is(filename, '/');
-               if (newfile)
-                       *newfile = '\0';
-
-               while ((entry = readdir(dir))) {
-                       char *name = entry->d_name;
-
-                       if ((strcmp(name, "..") == 0)
-                               || (strcmp(name, ".") == 0)) {
-                               continue;
-                       }
-                       newfile = concat_path_file(filename, name);
-                       sum += du(newfile);
-                       free(newfile);
-               }
-               closedir(dir);
-               print(sum, filename);
-       }
-       else if (statbuf.st_nlink > 1 && !count_hardlinks) {
-               /* Add files with hard links only once */
-               if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
-                       sum = 0L;
-                       if (du_depth == 1)
-                               print(sum, filename);
-               }
-               else {
-                       add_to_ino_dev_hashtable(&statbuf, NULL);
-               }
-       }
-       du_depth--;
-       return sum;
-}
-
-int du_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int i;
-       int c;
-
-       /* default behaviour */
-       print = print_normal;
-
-       /* parse argv[] */
-       while ((c = getopt(argc, argv, "sl"
-#ifdef BB_FEATURE_HUMAN_READABLE
-"hm"
-#endif
-"k")) != EOF) {
-                       switch (c) {
-                       case 's':
-                                       print = print_summary;
-                                       break;
-                       case 'l':
-                                       count_hardlinks = 1;
-                                       break;
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h': disp_hr = 0;        break;
-                       case 'm': disp_hr = MEGABYTE; break;
-#endif
-                       case 'k': break;
-                       default:
-                                       show_usage();
-                       }
-       }
-
-       /* go through remaining args (if any) */
-       if (optind >= argc) {
-               if (du(".") == 0)
-                       status = EXIT_FAILURE;
-       } else {
-               long sum;
-
-               for (i=optind; i < argc; i++) {
-                       sum = du(argv[i]);
-                       if(is_directory(argv[i], FALSE, NULL)==FALSE) {
-                               print_normal(sum, argv[i]);
-                       }
-                       reset_ino_dev_hashtable();
-               }
-       }
-
-       return status;
-}
-
-/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/dumpkmap.c b/busybox/dumpkmap.c
deleted file mode 100644 (file)
index 22652a5..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dumpkmap implementation for busybox
- *
- * Copyright (C) Arne Bernin <arne@matrix.loopback.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-/* From <linux/kd.h> */
-struct kbentry {
-       unsigned char kb_table;
-       unsigned char kb_index;
-       unsigned short kb_value;
-};
-static const int KDGKBENT = 0x4B46;  /* gets one entry in translation table */
-
-/* From <linux/keyboard.h> */
-static const int NR_KEYS = 128;
-static const int MAX_NR_KEYMAPS = 256;
-
-int dumpkmap_main(int argc, char **argv)
-{
-       struct kbentry ke;
-       int i, j, fd;
-       char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap";
-
-       if (argc>=2 && *argv[1]=='-') {
-               show_usage();
-       }
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0) {
-               perror_msg("Error opening " CURRENT_VC);
-               return EXIT_FAILURE;
-       }
-
-       write(1, magic, 7);
-
-       for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0;
-       flags[0]=1; 
-       flags[1]=1;
-       flags[2]=1;
-       flags[4]=1;
-       flags[5]=1;
-       flags[6]=1;
-       flags[8]=1;
-       flags[9]=1;
-       flags[10]=1;
-       flags[12]=1;
-       
-       /* dump flags */
-       for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); 
-
-       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
-               if (flags[i] == 1) {
-                       for (j = 0; j < NR_KEYS; j++) {
-                               ke.kb_index = j;
-                               ke.kb_table = i;
-                               if (ioctl(fd, KDGKBENT, &ke) < 0) {
-                               
-                                       error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value);
-                                       }
-                               else {
-                                       write(1,(void*)&ke.kb_value,2); 
-                                       }       
-                               
-                       }
-               }
-       }
-       close(fd);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/dutmp.c b/busybox/dutmp.c
deleted file mode 100644 (file)
index df7f64d..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- * 
- * dutmp
- * Takes utmp formated file on stdin and dumps it's contents 
- * out in colon delimited fields. Easy to 'cut' for shell based 
- * versions of 'who', 'last', etc. IP Addr is output in hex, 
- * little endian on x86.
- * 
- * Modified to support all sorts of libcs by 
- * Erik Andersen <andersen@lineo.com>
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <errno.h>
-#include <utmp.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int dutmp_main(int argc, char **argv)
-{
-
-       int file;
-       struct utmp ut;
-
-       if (argc<2) {
-               file = fileno(stdin);
-       } else if (*argv[1] == '-' ) {
-               show_usage();
-       } else  {
-               file = open(argv[1], O_RDONLY);
-               if (file < 0) {
-                       perror_msg_and_die(io_error, argv[1]);
-               }
-       }
-
-/* Kludge around the fact that the binary format for utmp has changed. */
-#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__
-       /* Linux libc5 */
-       while (read(file, (void*)&ut, sizeof(struct utmp))) {
-               printf("%d|%d|%s|%s|%s|%s|%s|%lx\n",
-                               ut.ut_type, ut.ut_pid, ut.ut_line,
-                               ut.ut_id, ut.ut_user, ut.ut_host,
-                               ctime(&(ut.ut_time)), 
-                               (long)ut.ut_addr);
-       }
-#else
-       /* Glibc, uClibc, etc. */
-       while (read(file, (void*)&ut, sizeof(struct utmp))) {
-               printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
-               ut.ut_type, ut.ut_pid, ut.ut_line,
-               ut.ut_id, ut.ut_user,   ut.ut_host,
-               ut.ut_exit.e_termination, ut.ut_exit.e_exit,
-               ut.ut_session,
-               ut.ut_tv.tv_sec, ut.ut_tv.tv_usec,
-               ut.ut_addr);
-       }
-#endif
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/echo.c b/busybox/echo.c
deleted file mode 100644 (file)
index 31c0315..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * echo implementation for busybox
- *
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int 
-echo_main(int argc, char** argv)
-{
-       int nflag = 0;
-       int eflag = 0;
-
-       /* Skip argv[0]. */
-       argc--;
-       argv++;
-
-       while (argc > 0 && *argv[0] == '-')
-       {
-               register char *temp;
-               register int ix;
-
-               /*
-                * If it appears that we are handling options, then make sure
-                * that all of the options specified are actually valid.
-                * Otherwise, the string should just be echoed.
-                */
-               temp = argv[0] + 1;
-
-               for (ix = 0; temp[ix]; ix++)
-               {
-                       if (strrchr("neE", temp[ix]) == 0)
-                               goto just_echo;
-               }
-
-               if (!*temp)
-                       goto just_echo;
-
-               /*
-                * All of the options in temp are valid options to echo.
-                * Handle them.
-                */
-               while (*temp)
-               {
-                       if (*temp == 'n')
-                               nflag = 1;
-                       else if (*temp == 'e')
-                               eflag = 1;
-                       else if (*temp == 'E')
-                               eflag = 0;
-                       else
-                               goto just_echo;
-
-                       temp++;
-               }
-               argc--;
-               argv++;
-       }
-
-just_echo:
-       while (argc > 0) {
-               const char *arg = argv[0];
-               register int c;
-
-               while ((c = *arg++)) {
-
-                       /* Check for escape sequence. */
-                       if (c == '\\' && eflag && *arg) {
-                               if (*arg == 'c') {
-                                       /* '\c' means cancel newline. */
-                                       nflag = 1;
-                                       arg++;
-                                       continue;
-                               } else {
-                                       c = process_escape_sequence(&arg);
-                               }
-                       }
-
-                       putchar(c);
-               }
-               argc--;
-               argv++;
-               if (argc > 0)
-                       putchar(' ');
-       }
-       if (!nflag)
-               putchar('\n');
-       fflush(stdout);
-
-       return EXIT_SUCCESS;
-}
-
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- *     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.
- *
- *     @(#)echo.c      8.1 (Berkeley) 5/31/93
- */
diff --git a/busybox/editors/sed.c b/busybox/editors/sed.c
deleted file mode 100644 (file)
index 709fb13..0000000
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * sed.c - very minimalist version of sed
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/*
-       Supported features and commands in this version of sed:
-
-        - comments ('#')
-        - address matching: num|/matchstr/[,num|/matchstr/|$]command
-        - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
-        - edit commands: (a)ppend, (i)nsert, (c)hange
-        - file commands: (r)ead
-        - backreferences in substitution expressions (\1, \2...\9)
-        
-        (Note: Specifying an address (range) to match is *optional*; commands
-        default to the whole pattern space if no specific address match was
-        requested.)
-
-       Unsupported features:
-
-        - transliteration (y/source-chars/dest-chars/) (use 'tr')
-        - no pattern space hold space storing / swapping (x, etc.)
-        - no labels / branching (: label, b, t, and friends)
-        - and lots, lots more.
-*/
-
-#include <stdio.h>
-#include <unistd.h> /* for getopt() */
-#include <regex.h>
-#include <string.h> /* for strdup() */
-#include <errno.h>
-#include <ctype.h> /* for isspace() */
-#include <stdlib.h>
-#include "busybox.h"
-
-/* externs */
-extern void xregcomp(regex_t *preg, const char *regex, int cflags);
-extern int optind; /* in unistd.h */
-extern char *optarg; /* ditto */
-
-/* options */
-static int be_quiet = 0;
-
-
-struct sed_cmd {
-
-
-       /* GENERAL FIELDS */
-       char delimiter;     /* The delimiter used to separate regexps */
-
-       /* address storage */
-       int beg_line; /* 'sed 1p'   0 == no begining line, apply commands to all lines */
-       int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */
-       regex_t *beg_match; /* sed -e '/match/cmd' */
-       regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
-
-       /* the command */
-       char cmd; /* p,d,s (add more at your leisure :-) */
-
-
-       /* SUBSTITUTION COMMAND SPECIFIC FIELDS */
-
-       /* sed -e 's/sub_match/replace/' */
-       regex_t *sub_match;
-       char *replace;
-       unsigned int num_backrefs:4; /* how many back references (\1..\9) */
-                       /* Note:  GNU/POSIX sed does not save more than nine backrefs, so
-                        * we only use 4 bits to hold the number */
-       unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
-       unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */
-
-
-       /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */
-
-       char *editline;
-
-
-       /* FILE COMMAND (r) SPEICIFIC FIELDS */
-
-       char *filename;
-};
-
-/* globals */
-static struct sed_cmd *sed_cmds = NULL; /* growable arrary holding a sequence of sed cmds */
-static int ncmds = 0; /* number of sed commands */
-
-/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */
-
-#ifdef BB_FEATURE_CLEAN_UP
-static void destroy_cmd_strs()
-{
-       if (sed_cmds == NULL)
-               return;
-
-       /* destroy all the elements in the array */
-       while (--ncmds >= 0) {
-
-               if (sed_cmds[ncmds].beg_match) {
-                       regfree(sed_cmds[ncmds].beg_match);
-                       free(sed_cmds[ncmds].beg_match);
-               }
-               if (sed_cmds[ncmds].end_match) {
-                       regfree(sed_cmds[ncmds].end_match);
-                       free(sed_cmds[ncmds].end_match);
-               }
-               if (sed_cmds[ncmds].sub_match) {
-                       regfree(sed_cmds[ncmds].sub_match);
-                       free(sed_cmds[ncmds].sub_match);
-               }
-               if (sed_cmds[ncmds].replace)
-                       free(sed_cmds[ncmds].replace);
-       }
-
-       /* destroy the array */
-       free(sed_cmds);
-       sed_cmds = NULL;
-}
-#endif
-
-
-/*
- * index_of_next_unescaped_regexp_delim - walks left to right through a string
- * beginning at a specified index and returns the index of the next regular
- * expression delimiter (typically a forward * slash ('/')) not preceeded by 
- * a backslash ('\').
- */
-static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const char *str, int idx)
-{
-       int bracket = -1;
-       int escaped = 0;
-
-       for ( ; str[idx]; idx++) {
-               if (bracket != -1) {
-                       if (str[idx] == ']' && !(bracket == idx - 1 ||
-                                                                        (bracket == idx - 2 && str[idx-1] == '^')))
-                               bracket = -1;
-               } else if (escaped)
-                       escaped = 0;
-               else if (str[idx] == '\\')
-                       escaped = 1;
-               else if (str[idx] == '[')
-                       bracket = idx;
-               else if (str[idx] == sed_cmd->delimiter)
-                       return idx;
-       }
-
-       /* if we make it to here, we've hit the end of the string */
-       return -1;
-}
-
-/*
- * returns the index in the string just past where the address ends.
- */
-static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
-{
-       char *my_str = strdup(str);
-       int idx = 0;
-       char olddelimiter;
-       olddelimiter = sed_cmd->delimiter;
-       sed_cmd->delimiter = '/';
-
-       if (isdigit(my_str[idx])) {
-               do {
-                       idx++;
-               } while (isdigit(my_str[idx]));
-               my_str[idx] = 0;
-               *linenum = atoi(my_str);
-       }
-       else if (my_str[idx] == '$') {
-               *linenum = -1;
-               idx++;
-       }
-       else if (my_str[idx] == '/') {
-               idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx);
-               if (idx == -1)
-                       error_msg_and_die("unterminated match expression");
-               my_str[idx] = '\0';
-               *regex = (regex_t *)xmalloc(sizeof(regex_t));
-               xregcomp(*regex, my_str+1, REG_NEWLINE);
-               idx++; /* so it points to the next character after the last '/' */
-       }
-       else {
-               error_msg("get_address: no address found in string\n"
-                               "\t(you probably didn't check the string you passed me)");
-               idx = -1;
-       }
-
-       free(my_str);
-       sed_cmd->delimiter = olddelimiter;
-       return idx;
-}
-
-static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
-{
-       int oldidx, cflags = REG_NEWLINE;
-       char *match;
-       int idx = 0;
-       int j;
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *    s/match/replace/gIp
-        *    ||     |        |||
-        *    mandatory       optional
-        *
-        *    (all three of the '/' slashes are mandatory)
-        */
-
-       /* verify that the 's' is followed by something.  That something
-        * (typically a 'slash') is now our regexp delimiter... */
-       if (!substr[++idx])
-               error_msg_and_die("bad format in substitution expression");
-       else
-           sed_cmd->delimiter=substr[idx];
-
-       /* save the match string */
-       oldidx = idx+1;
-       idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
-       if (idx == -1)
-               error_msg_and_die("bad format in substitution expression");
-       match = xstrndup(substr + oldidx, idx - oldidx);
-
-       /* determine the number of back references in the match string */
-       /* Note: we compute this here rather than in the do_subst_command()
-        * function to save processor time, at the expense of a little more memory
-        * (4 bits) per sed_cmd */
-       
-       /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ 
-       for (j = 0; match[j]; j++) {
-               /* GNU/POSIX sed does not save more than nine backrefs */
-               if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9)
-                       sed_cmd->num_backrefs++;
-       }
-
-       /* save the replacement string */
-       oldidx = idx+1;
-       idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
-       if (idx == -1)
-               error_msg_and_die("bad format in substitution expression");
-       sed_cmd->replace = xstrndup(substr + oldidx, idx - oldidx);
-
-       /* process the flags */
-       while (substr[++idx]) {
-               switch (substr[idx]) {
-                       case 'g':
-                               sed_cmd->sub_g = 1;
-                               break;
-                       case 'I':
-                               cflags |= REG_ICASE;
-                               break;
-                       case 'p':
-                               sed_cmd->sub_p = 1;
-                               break;
-                       default:
-                               /* any whitespace or semicolon trailing after a s/// is ok */
-                               if (strchr("; \t\v\n\r", substr[idx]))
-                                       goto out;
-                               /* else */
-                               error_msg_and_die("bad option in substitution expression");
-               }
-       }
-
-out:   
-       /* compile the match string into a regex */
-       sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
-       xregcomp(sed_cmd->sub_match, match, cflags);
-       free(match);
-
-       return idx;
-}
-
-static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
-{
-       int idx = 0;
-       int slashes_eaten = 0;
-       char *ptr; /* shorthand */
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *
-        *    need one of these 
-        *    |
-        *    |    this backslash (immediately following the edit command) is mandatory
-        *    |    |
-        *    [aic]\
-        *    TEXT1\
-        *    TEXT2\
-        *    TEXTN
-        *
-        * as soon as we hit a TEXT line that has no trailing '\', we're done.
-        * this means a command like:
-        *
-        * i\
-        * INSERTME
-        *
-        * is a-ok.
-        *
-        */
-
-       if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r'))
-               error_msg_and_die("bad format in edit expression");
-
-       /* store the edit line text */
-       /* make editline big enough to accomodate the extra '\n' we will tack on
-        * to the end */
-       sed_cmd->editline = xmalloc(strlen(&editstr[3]) + 2);
-       strcpy(sed_cmd->editline, &editstr[3]);
-       ptr = sed_cmd->editline;
-
-       /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */
-       while (ptr[idx]) {
-               while (ptr[idx] != '\\' || (ptr[idx+1] != '\n' && ptr[idx+1] != '\r')) {
-                       idx++;
-                       if (!ptr[idx]) {
-                               goto out;
-                       }
-               }
-               /* move the newline over the '\' before it (effectively eats the '\') */
-               memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1]));
-               ptr[strlen(ptr)-1] = 0;
-               slashes_eaten++;
-               /* substitue \r for \n if needed */
-               if (ptr[idx] == '\r')
-                       ptr[idx] = '\n';
-       }
-
-out:
-       /* this accounts for discrepancies between the modified string and the
-        * original string passed in to this function */
-       idx += slashes_eaten;
-
-       /* figure out if we need to add a newline */
-       if (ptr[idx-1] != '\n') {
-               ptr[idx] = '\n';
-               idx++;
-       }
-
-       /* terminate string */
-       ptr[idx]= 0;
-       /* adjust for opening 2 chars [aic]\ */
-       idx += 2;
-
-       return idx;
-}
-
-
-static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr)
-{
-       int idx = 0;
-       int filenamelen = 0;
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *    '[ ]filename'
-        *      |  |
-        *      |  a filename
-        *      |
-        *     optional whitespace
-
-        *   re: the file to be read, the GNU manual says the following: "Note that
-        *   if filename cannot be read, it is treated as if it were an empty file,
-        *   without any error indication." Thus, all of the following commands are
-        *   perfectly leagal:
-        *
-        *   sed -e '1r noexist'
-        *   sed -e '1r ;'
-        *   sed -e '1r'
-        */
-
-       /* the file command may be followed by whitespace; move past it. */
-       while (isspace(filecmdstr[++idx]))
-               { ; }
-               
-       /* the first non-whitespace we get is a filename. the filename ends when we
-        * hit a normal sed command terminator or end of string */
-       filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0");
-       sed_cmd->filename = xmalloc(filenamelen + 1);
-       safe_strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen + 1);
-
-       return idx + filenamelen;
-}
-
-
-static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
-{
-       int idx = 0;
-
-       /* parse the command
-        * format is: [addr][,addr]cmd
-        *            |----||-----||-|
-        *            part1 part2  part3
-        */
-
-       /* first part (if present) is an address: either a number or a /regex/ */
-       if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
-               idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
-
-       /* second part (if present) will begin with a comma */
-       if (cmdstr[idx] == ',')
-               idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match);
-
-       /* last part (mandatory) will be a command */
-       if (cmdstr[idx] == '\0')
-               error_msg_and_die("missing command");
-       sed_cmd->cmd = cmdstr[idx];
-
-       /* if it was a single-letter command that takes no arguments (such as 'p'
-        * or 'd') all we need to do is increment the index past that command */
-       if (strchr("pd", cmdstr[idx])) {
-               idx++;
-       }
-       /* handle (s)ubstitution command */
-       else if (sed_cmd->cmd == 's') {
-               idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
-       else if (strchr("aic", sed_cmd->cmd)) {
-               if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
-                       error_msg_and_die("only a beginning address can be specified for edit commands");
-               idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       /* handle file cmds: (r)ead */
-       else if (sed_cmd->cmd == 'r') {
-               if (sed_cmd->end_line || sed_cmd->end_match)
-                       error_msg_and_die("Command only uses one address");
-               idx += parse_file_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       else {
-               error_msg_and_die("invalid command");
-       }
-
-       /* give back whatever's left over */
-       return (char *)&cmdstr[idx];
-}
-
-static void add_cmd_str(const char *cmdstr)
-{
-       char *mystr = (char *)cmdstr;
-
-       do {
-
-               /* trim leading whitespace and semicolons */
-               memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
-               /* if we ate the whole thing, that means there was just trailing
-                * whitespace or a final / no-op semicolon. either way, get out */
-               if (strlen(mystr) == 0)
-                       return;
-               /* if this is a comment, jump past it and keep going */
-               if (mystr[0] == '#') {
-                       mystr = strpbrk(mystr, ";\n\r");
-                       continue;
-               }
-               /* grow the array */
-               sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));
-               /* zero new element */
-               memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));
-               /* load command string into new array element, get remainder */
-               mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);
-
-       } while (mystr && strlen(mystr));
-}
-
-
-static void load_cmd_file(char *filename)
-{
-       FILE *cmdfile;
-       char *line;
-       char *nextline;
-
-       cmdfile = xfopen(filename, "r");
-
-       while ((line = get_line_from_file(cmdfile)) != NULL) {
-               /* if a line ends with '\' it needs the next line appended to it */
-               while (line[strlen(line)-2] == '\\' &&
-                               (nextline = get_line_from_file(cmdfile)) != NULL) {
-                       line = xrealloc(line, strlen(line) + strlen(nextline) + 1);
-                       strcat(line, nextline);
-                       free(nextline);
-               }
-               /* eat trailing newline (if any) --if I don't do this, edit commands
-                * (aic) will print an extra newline */
-               chomp(line);
-               add_cmd_str(line);
-               free(line);
-       }
-}
-
-#define PIPE_MAGIC 0x7f
-#define PIPE_GROW 64  
-#define pipeputc(c) \
-{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \
-       pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \
-       memset(pipeline+pipeline_len, 0, PIPE_GROW); \
-       pipeline_len += PIPE_GROW; \
-       pipeline[pipeline_len-1] = PIPE_MAGIC; } \
-       pipeline[pipeline_idx++] = (c); }
-
-static void print_subst_w_backrefs(const char *line, const char *replace, 
-       regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, 
-       int *pipeline_len_p, int matches)
-{
-       char *pipeline = *pipeline_p;
-       int pipeline_idx = *pipeline_idx_p;
-       int pipeline_len = *pipeline_len_p;
-       int i;
-
-       /* go through the replacement string */
-       for (i = 0; replace[i]; i++) {
-               /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
-               if (replace[i] == '\\' && isdigit(replace[i+1])) {
-                       int j;
-                       char tmpstr[2];
-                       int backref;
-                       ++i; /* i now indexes the backref number, instead of the leading slash */
-                       tmpstr[0] = replace[i];
-                       tmpstr[1] = 0;
-                       backref = atoi(tmpstr);
-                       /* print out the text held in regmatch[backref] */
-                       if (backref <= matches && regmatch[backref].rm_so != -1)
-                               for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++)
-                                       pipeputc(line[j]);
-               }
-
-               /* if we find a backslash escaped character, print the character */
-               else if (replace[i] == '\\') {
-                       ++i;
-                       pipeputc(replace[i]);
-               }
-
-               /* if we find an unescaped '&' print out the whole matched text.
-                * fortunately, regmatch[0] contains the indicies to the whole matched
-                * expression (kinda seems like it was designed for just such a
-                * purpose...) */
-               else if (replace[i] == '&' && replace[i-1] != '\\') {
-                       int j;
-                       for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++)
-                               pipeputc(line[j]);
-               }
-               /* nothing special, just print this char of the replacement string to stdout */
-               else
-                       pipeputc(replace[i]);
-       }
-       *pipeline_p = pipeline;
-       *pipeline_idx_p = pipeline_idx;
-       *pipeline_len_p = pipeline_len;
-}
-
-static int do_subst_command(const struct sed_cmd *sed_cmd, char **line)
-{
-       char *hackline = *line;
-       char *pipeline = 0;
-       int pipeline_idx = 0;
-       int pipeline_len = 0;
-       int altered = 0;
-       regmatch_t *regmatch = NULL;
-
-       /* we only proceed if the substitution 'search' expression matches */
-       if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH)
-               return 0;
-
-       /* whaddaya know, it matched. get the number of back references */
-       regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1));
-
-       /* allocate more PIPE_GROW bytes
-          if replaced string is larger than original */
-       pipeline_len = strlen(hackline)+PIPE_GROW;
-       pipeline = xmalloc(pipeline_len);
-       memset(pipeline, 0, pipeline_len);
-       /* buffer magic */
-       pipeline[pipeline_len-1] = PIPE_MAGIC;
-
-       /* and now, as long as we've got a line to try matching and if we can match
-        * the search string, we make substitutions */
-       while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline,
-                                       sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) {
-               int i;
-
-               /* print everything before the match */
-               for (i = 0; i < regmatch[0].rm_so; i++)
-                       pipeputc(hackline[i]);
-
-               /* then print the substitution string */
-               print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, 
-                               &pipeline, &pipeline_idx, &pipeline_len,
-                               sed_cmd->num_backrefs);
-
-               /* advance past the match */
-               hackline += regmatch[0].rm_eo;
-               /* flag that something has changed */
-               altered++;
-
-               /* if we're not doing this globally, get out now */
-               if (!sed_cmd->sub_g)
-                       break;
-       }
-
-       for (; *hackline; hackline++) pipeputc(*hackline);
-       if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0;
-
-       /* cleanup */
-       free(regmatch);
-
-       free(*line);
-       *line = pipeline;
-       return altered;
-}
-
-
-static void process_file(FILE *file)
-{
-       char *line = NULL;
-       static int linenum = 0; /* GNU sed does not restart counting lines at EOF */
-       unsigned int still_in_range = 0;
-       int altered;
-       int i;
-
-       /* go through every line in the file */
-       while ((line = get_line_from_file(file)) != NULL) {
-
-               chomp(line);
-               linenum++;
-               altered = 0;
-
-               /* for every line, go through all the commands */
-               for (i = 0; i < ncmds; i++) {
-
-
-                       /*
-                        * entry point into sedding...
-                        */
-                       if (
-                                       /* no range necessary */
-                                       (sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 &&
-                                        sed_cmds[i].beg_match == NULL &&
-                                        sed_cmds[i].end_match == NULL) ||
-                                       /* this line number is the first address we're looking for */
-                                       (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||
-                                       /* this line matches our first address regex */
-                                       (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||
-                                       /* we are currently within the beginning & ending address range */
-                                       still_in_range
-                          ) {
-
-                               /*
-                                * actual sedding
-                                */
-                               switch (sed_cmds[i].cmd) {
-
-                                       case 'p':
-                                               puts(line);
-                                               break;
-
-                                       case 'd':
-                                               altered++;
-                                               break;
-
-                                       case 's':
-
-                                               /*
-                                                * Some special cases for 's' printing to make it compliant with
-                                                * GNU sed printing behavior (aka "The -n | s///p Matrix"):
-                                                *
-                                                *    -n ONLY = never print anything regardless of any successful
-                                                *    substitution
-                                                *
-                                                *    s///p ONLY = always print successful substitutions, even if
-                                                *    the line is going to be printed anyway (line will be printed
-                                                *    twice).
-                                                *
-                                                *    -n AND s///p = print ONLY a successful substitution ONE TIME;
-                                                *    no other lines are printed - this is the reason why the 'p'
-                                                *    flag exists in the first place.
-                                                */
-
-                                               /* if the user specified that they didn't want anything printed (i.e., a -n
-                                                * flag and no 'p' flag after the s///), then there's really no point doing
-                                                * anything here. */
-                                               if (be_quiet && !sed_cmds[i].sub_p)
-                                                       break;
-
-                                               /* we print the line once, unless we were told to be quiet */
-                                               if (!be_quiet)
-                                                       altered |= do_subst_command(&sed_cmds[i], &line);
-
-                                               /* we also print the line if we were given the 'p' flag
-                                                * (this is quite possibly the second printing) */
-                                               if (sed_cmds[i].sub_p)
-                                                       altered |= do_subst_command(&sed_cmds[i], &line);
-                                               if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's'))
-                                                       puts(line);
-
-                                               break;
-
-                                       case 'a':
-                                               puts(line);
-                                               fputs(sed_cmds[i].editline, stdout);
-                                               altered++;
-                                               break;
-
-                                       case 'i':
-                                               fputs(sed_cmds[i].editline, stdout);
-                                               break;
-
-                                       case 'c':
-                                               /* single-address case */
-                                               if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {
-                                                       fputs(sed_cmds[i].editline, stdout);
-                                               }
-                                               /* multi-address case */
-                                               else {
-                                                       /* matching text */
-                                                       if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
-                                                               fputs(sed_cmds[i].editline, stdout);
-                                                       /* matching line numbers */
-                                                       if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)
-                                                               fputs(sed_cmds[i].editline, stdout);
-                                               }
-                                               altered++;
-
-                                               break;
-
-                                       case 'r': {
-                                                                 FILE *outfile;
-                                                                 puts(line);
-                                                                 outfile = fopen(sed_cmds[i].filename, "r");
-                                                                 if (outfile)
-                                                                         print_file(outfile);
-                                                                 /* else if we couldn't open the output file,
-                                                                  * no biggie, just don't print anything */
-                                                                 altered++;
-                                                         }
-                                                         break;
-                               }
-
-                               /*
-                                * exit point from sedding...
-                                */
-                               if (
-                                       /* this is a single-address command or... */
-                                       (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (
-                                               /* we were in the middle of our address range (this
-                                                * isn't the first time through) and.. */
-                                               (still_in_range == 1) && (
-                                                       /* this line number is the last address we're looking for or... */
-                                                       (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||
-                                                       /* this line matches our last address regex */
-                                                       (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
-                                               )
-                                       )
-                               ) {
-                                       /* we're out of our address range */
-                                       still_in_range = 0;
-                               }
-
-                               /* didn't hit the exit? then we're still in the middle of an address range */
-                               else {
-                                       still_in_range = 1;
-                               }
-                       }
-               }
-
-               /* we will print the line unless we were told to be quiet or if the
-                * line was altered (via a 'd'elete or 's'ubstitution), in which case
-                * the altered line was already printed */
-               if (!be_quiet && !altered)
-                       puts(line);
-
-               free(line);
-       }
-}
-
-extern int sed_main(int argc, char **argv)
-{
-       int opt;
-
-#ifdef BB_FEATURE_CLEAN_UP
-       /* destroy command strings on exit */
-       if (atexit(destroy_cmd_strs) == -1)
-               perror_msg_and_die("atexit");
-#endif
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
-               switch (opt) {
-                       case 'n':
-                               be_quiet++;
-                               break;
-                       case 'e':
-                               add_cmd_str(optarg);
-                               break;
-                       case 'f': 
-                               load_cmd_file(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a pattern from a -e and no command file was specified,
-        * argv[optind] should be the pattern. no pattern, no worky */
-       if (ncmds == 0) {
-               if (argv[optind] == NULL)
-                       show_usage();
-               else {
-                       add_cmd_str(argv[optind]);
-                       optind++;
-               }
-       }
-
-
-       /* argv[(optind)..(argc-1)] should be names of file to process. If no
-        * files were specified or '-' was specified, take input from stdin.
-        * Otherwise, we process all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               process_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       file = fopen(argv[i], "r");
-                       if (file == NULL) {
-                               perror_msg("%s", argv[i]);
-                       } else {
-                               process_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-       
-       return 0;
-}
diff --git a/busybox/editors/vi.c b/busybox/editors/vi.c
deleted file mode 100644 (file)
index 8d7506d..0000000
+++ /dev/null
@@ -1,3947 +0,0 @@
-/* vi: set sw=8 ts=8: */
-/*
- * tiny vi.c: A small 'vi' clone
- * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-static const char vi_Version[] =
-       "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $";
-
-/*
- * To compile for standalone use:
- *     gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
- *       or
- *     gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c                # include testing features
- *     strip vi
- */
-
-/*
- * Things To Do:
- *     EXINIT
- *     $HOME/.exrc  and  ./.exrc
- *     add magic to search     /foo.*bar
- *     add :help command
- *     :map macros
- *     how about mode lines:   vi: set sw=8 ts=8:
- *     if mark[] values were line numbers rather than pointers
- *        it would be easier to change the mark when add/delete lines
- *     More intelligence in refresh()
- *     ":r !cmd"  and  "!cmd"  to filter text through an external command
- *     A true "undo" facility
- *     An "ex" line oriented mode- maybe using "cmdedit"
- */
-
-//----  Feature --------------  Bytes to immplement
-#ifdef STANDALONE
-#define vi_main                        main
-#define BB_FEATURE_VI_COLON    // 4288
-#define BB_FEATURE_VI_YANKMARK // 1408
-#define BB_FEATURE_VI_SEARCH   // 1088
-#define BB_FEATURE_VI_USE_SIGNALS      // 1056
-#define BB_FEATURE_VI_DOT_CMD  //  576
-#define BB_FEATURE_VI_READONLY //  128
-#define BB_FEATURE_VI_SETOPTS  //  576
-#define BB_FEATURE_VI_SET      //  224
-#define BB_FEATURE_VI_WIN_RESIZE       //  256  WIN_RESIZE
-// To test editor using CRASHME:
-//    vi -C filename
-// To stop testing, wait until all to text[] is deleted, or
-//    Ctrl-Z and kill -9 %1
-// while in the editor Ctrl-T will toggle the crashme function on and off.
-//#define BB_FEATURE_VI_CRASHME                // randomly pick commands to execute
-#endif                                                 /* STANDALONE */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <regex.h>
-#include <ctype.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#ifndef STANDALONE
-#include "busybox.h"
-#endif                                                 /* STANDALONE */
-
-#ifndef TRUE
-#define TRUE                   ((int)1)
-#define FALSE                  ((int)0)
-#endif                                                 /* TRUE */
-#define MAX_SCR_COLS           BUFSIZ
-
-// Misc. non-Ascii keys that report an escape sequence
-#define VI_K_UP                        128     // cursor key Up
-#define VI_K_DOWN              129     // cursor key Down
-#define VI_K_RIGHT             130     // Cursor Key Right
-#define VI_K_LEFT              131     // cursor key Left
-#define VI_K_HOME              132     // Cursor Key Home
-#define VI_K_END               133     // Cursor Key End
-#define VI_K_INSERT            134     // Cursor Key Insert
-#define VI_K_PAGEUP            135     // Cursor Key Page Up
-#define VI_K_PAGEDOWN          136     // Cursor Key Page Down
-#define VI_K_FUN1              137     // Function Key F1
-#define VI_K_FUN2              138     // Function Key F2
-#define VI_K_FUN3              139     // Function Key F3
-#define VI_K_FUN4              140     // Function Key F4
-#define VI_K_FUN5              141     // Function Key F5
-#define VI_K_FUN6              142     // Function Key F6
-#define VI_K_FUN7              143     // Function Key F7
-#define VI_K_FUN8              144     // Function Key F8
-#define VI_K_FUN9              145     // Function Key F9
-#define VI_K_FUN10             146     // Function Key F10
-#define VI_K_FUN11             147     // Function Key F11
-#define VI_K_FUN12             148     // Function Key F12
-
-static const int YANKONLY = FALSE;
-static const int YANKDEL = TRUE;
-static const int FORWARD = 1;  // code depends on "1"  for array index
-static const int BACK = -1;    // code depends on "-1" for array index
-static const int LIMITED = 0;  // how much of text[] in char_search
-static const int FULL = 1;     // how much of text[] in char_search
-
-static const int S_BEFORE_WS = 1;      // used in skip_thing() for moving "dot"
-static const int S_TO_WS = 2;          // used in skip_thing() for moving "dot"
-static const int S_OVER_WS = 3;                // used in skip_thing() for moving "dot"
-static const int S_END_PUNCT = 4;      // used in skip_thing() for moving "dot"
-static const int S_END_ALNUM = 5;      // used in skip_thing() for moving "dot"
-
-typedef unsigned char Byte;
-
-
-static int editing;            // >0 while we are editing a file
-static int cmd_mode;           // 0=command  1=insert
-static int file_modified;      // buffer contents changed
-static int err_method;         // indicate error with beep or flash
-static int fn_start;           // index of first cmd line file name
-static int save_argc;          // how many file names on cmd line
-static int cmdcnt;             // repetition count
-static fd_set rfds;            // use select() for small sleeps
-static struct timeval tv;      // use select() for small sleeps
-static char erase_char;                // the users erase character
-static int rows, columns;      // the terminal screen is this size
-static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
-static char *SOs, *SOn;                // terminal standout start/normal ESC sequence
-static char *bell;             // terminal bell sequence
-static char *Ceol, *Ceos;      // Clear-end-of-line and Clear-end-of-screen ESC sequence
-static char *CMrc;             // Cursor motion arbitrary destination ESC sequence
-static char *CMup, *CMdown;    // Cursor motion up and down ESC sequence
-static Byte *status_buffer;    // mesages to the user
-static Byte last_input_char;   // last char read from user
-static Byte last_forward_char; // last char searched for with 'f'
-static Byte *cfn;              // previous, current, and next file name
-static Byte *text, *end, *textend;     // pointers to the user data in memory
-static Byte *screen;           // pointer to the virtual screen buffer
-static int screensize;         //            and its size
-static Byte *screenbegin;      // index into text[], of top line on the screen
-static Byte *dot;              // where all the action takes place
-static int tabstop;
-static struct termios term_orig, term_vi;      // remember what the cooked mode was
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-static int last_row;           // where the cursor was last moved to
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static jmp_buf restart;                // catch_sig()
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-static struct winsize winsize; // remember the window size
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-#ifdef BB_FEATURE_VI_DOT_CMD
-static int adding2q;           // are we currently adding user input to q
-static Byte *last_modifying_cmd;       // last modifying cmd for "."
-static Byte *ioq, *ioq_start;  // pointer to string for get_one_char to "read"
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#if    defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)
-static Byte *modifying_cmds;   // cmds that modify text[]
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_READONLY
-static int vi_readonly, readonly;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SETOPTS
-static int autoindent;
-static int showmatch;
-static int ignorecase;
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
-static int YDreg, Ureg;                // default delete register and orig line for "U"
-static Byte *mark[28];         // user marks points somewhere in text[]-  a-z and previous context ''
-static Byte *context_start, *context_end;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-static Byte *last_search_pattern;      // last pattern from a '/' or '?' search
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-
-static void edit_file(Byte *); // edit one file
-static void do_cmd(Byte);      // execute a command
-static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot
-static Byte *begin_line(Byte *);       // return pointer to cur line B-o-l
-static Byte *end_line(Byte *); // return pointer to cur line E-o-l
-static Byte *dollar_line(Byte *);      // return pointer to just before NL
-static Byte *prev_line(Byte *);        // return pointer to prev line B-o-l
-static Byte *next_line(Byte *);        // return pointer to next line B-o-l
-static Byte *end_screen(void); // get pointer to last char on screen
-static int count_lines(Byte *, Byte *);        // count line from start to stop
-static Byte *find_line(int);   // find begining of line #li
-static Byte *move_to_col(Byte *, int); // move "p" to column l
-static int isblnk(Byte);       // is the char a blank or tab
-static void dot_left(void);    // move dot left- dont leave line
-static void dot_right(void);   // move dot right- dont leave line
-static void dot_begin(void);   // move dot to B-o-l
-static void dot_end(void);     // move dot to E-o-l
-static void dot_next(void);    // move dot to next line B-o-l
-static void dot_prev(void);    // move dot to prev line B-o-l
-static void dot_scroll(int, int);      // move the screen up or down
-static void dot_skip_over_ws(void);    // move dot pat WS
-static void dot_delete(void);  // delete the char at 'dot'
-static Byte *bound_dot(Byte *);        // make sure  text[0] <= P < "end"
-static Byte *new_screen(int, int);     // malloc virtual screen memory
-static Byte *new_text(int);    // malloc memory for text[] buffer
-static Byte *char_insert(Byte *, Byte);        // insert the char c at 'p'
-static Byte *stupid_insert(Byte *, Byte);      // stupidly insert the char c at 'p'
-static Byte find_range(Byte **, Byte **, Byte);        // return pointers for an object
-static int st_test(Byte *, int, int, Byte *);  // helper for skip_thing()
-static Byte *skip_thing(Byte *, int, int, int);        // skip some object
-static Byte *find_pair(Byte *, Byte);  // find matching pair ()  []  {}
-static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole
-static Byte *text_hole_make(Byte *, int);      // at "p", make a 'size' byte hole
-static Byte *yank_delete(Byte *, Byte *, int, int);    // yank text[] into register then delete
-static void show_help(void);   // display some help info
-static void print_literal(Byte *, Byte *);     // copy s to buf, convert unprintable
-static void rawmode(void);     // set "raw" mode on tty
-static void cookmode(void);    // return to "cooked" mode on tty
-static int mysleep(int);       // sleep for 'h' 1/100 seconds
-static Byte readit(void);      // read (maybe cursor) key from stdin
-static Byte get_one_char(void);        // read 1 char from stdin
-static int file_size(Byte *);  // what is the byte size of "fn"
-static int file_insert(Byte *, Byte *, int);
-static int file_write(Byte *, Byte *, Byte *);
-static void place_cursor(int, int, int);
-static void screen_erase();
-static void clear_to_eol(void);
-static void clear_to_eos(void);
-static void standout_start(void);      // send "start reverse video" sequence
-static void standout_end(void);        // send "end reverse video" sequence
-static void flash(int);                // flash the terminal screen
-static void beep(void);                // beep the terminal
-static void indicate_error(char);      // use flash or beep to indicate error
-static void show_status_line(void);    // put a message on the bottom line
-static void psb(char *, ...);  // Print Status Buf
-static void psbs(char *, ...); // Print Status Buf in standout mode
-static void ni(Byte *);                // display messages
-static void edit_status(void); // show file status on status line
-static void redraw(int);       // force a full screen refresh
-static void format_line(Byte*, Byte*, int);
-static void refresh(int);      // update the terminal from screen[]
-
-#ifdef BB_FEATURE_VI_SEARCH
-static Byte *char_search(Byte *, Byte *, int, int);    // search for pattern starting at p
-static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-#ifdef BB_FEATURE_VI_COLON
-static void Hit_Return(void);
-static Byte *get_one_address(Byte *, int *);   // get colon addr, if present
-static Byte *get_address(Byte *, int *, int *);        // get two colon addrs, if present
-static void colon(Byte *);     // execute the "colon" mode cmds
-#endif                                                 /* BB_FEATURE_VI_COLON */
-static Byte *get_input_line(Byte *);   // get input line- use "status line"
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static void winch_sig(int);    // catch window size changes
-static void suspend_sig(int);  // catch ctrl-Z
-static void alarm_sig(int);    // catch alarm time-outs
-static void catch_sig(int);    // catch ctrl-C
-static void core_sig(int);     // catch a core dump signal
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_DOT_CMD
-static void start_new_cmd_q(Byte);     // new queue for command
-static void end_cmd_q();       // stop saving input chars
-#else                                                  /* BB_FEATURE_VI_DOT_CMD */
-#define end_cmd_q()
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-static void window_size_get(int);      // find out what size the window is
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-#ifdef BB_FEATURE_VI_SETOPTS
-static void showmatching(Byte *);      // show the matching pair ()  []  {}
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
-static Byte *string_insert(Byte *, Byte *);    // insert the string at 'p'
-#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *text_yank(Byte *, Byte *, int);   // save copy of "p" into a register
-static Byte what_reg(void);            // what is letter of current YDreg
-static void check_context(Byte);       // remember context for '' command
-static Byte *swap_context(Byte *);     // goto new context for '' command
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_CRASHME
-static void crash_dummy();
-static void crash_test();
-static int crashme = 0;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-
-
-extern int vi_main(int argc, char **argv)
-{
-       int c;
-
-#ifdef BB_FEATURE_VI_YANKMARK
-       int i;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       CMrc= "\033[%d;%dH";    // Terminal Crusor motion ESC sequence
-       CMup= "\033[A";         // move cursor up one line, same col
-       CMdown="\n";            // move cursor down one line, same col
-       Ceol= "\033[0K";        // Clear from cursor to end of line
-       Ceos= "\033[0J";        // Clear from cursor to end of screen
-       SOs = "\033[7m";        // Terminal standout mode on
-       SOn = "\033[0m";        // Terminal standout mode off
-       bell= "\007";           // Terminal bell sequence
-#ifdef BB_FEATURE_VI_CRASHME
-       (void) srand((long) getpid());
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       status_buffer = (Byte *) malloc(200);   // hold messages to user
-#ifdef BB_FEATURE_VI_READONLY
-       vi_readonly = readonly = FALSE;
-       if (strncmp(argv[0], "view", 4) == 0) {
-               readonly = TRUE;
-               vi_readonly = TRUE;
-       }
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SETOPTS
-       autoindent = 1;
-       ignorecase = 1;
-       showmatch = 1;
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_YANKMARK
-       for (i = 0; i < 28; i++) {
-               reg[i] = 0;
-       }                                       // init the yank regs
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_DOT_CMD
-       modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~";      // cmds modifying text[]
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-
-       //  1-  process $HOME/.exrc file
-       //  2-  process EXINIT variable from environment
-       //  3-  process command line args
-       while ((c = getopt(argc, argv, "hCR")) != -1) {
-               switch (c) {
-#ifdef BB_FEATURE_VI_CRASHME
-               case 'C':
-                       crashme = 1;
-                       break;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-#ifdef BB_FEATURE_VI_READONLY
-               case 'R':               // Read-only flag
-                       readonly = TRUE;
-                       break;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       //case 'r':     // recover flag-  ignore- we don't use tmp file
-                       //case 'x':     // encryption flag- ignore
-                       //case 'c':     // execute command first
-                       //case 'h':     // help -- just use default
-               default:
-                       show_help();
-                       return 1;
-               }
-       }
-
-       // The argv array can be used by the ":next"  and ":rewind" commands
-       // save optind.
-       fn_start = optind;      // remember first file name for :next and :rew
-       save_argc = argc;
-
-       //----- This is the main file handling loop --------------
-       if (optind >= argc) {
-               editing = 1;    // 0= exit,  1= one file,  2= multiple files
-               edit_file(0);
-       } else {
-               for (; optind < argc; optind++) {
-                       editing = 1;    // 0=exit, 1=one file, 2+ =many files
-                       if (cfn != 0)
-                               free(cfn);
-                       cfn = (Byte *) strdup(argv[optind]);
-                       edit_file(cfn);
-               }
-       }
-       //-----------------------------------------------------------
-
-       return (0);
-}
-
-static void edit_file(Byte * fn)
-{
-       char c;
-       int cnt, size, ch;
-
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       char *msg;
-       int sig;
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_YANKMARK
-       static Byte *cur_line;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       rawmode();
-       rows = 24;
-       columns = 80;
-       ch= -1;
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       new_screen(rows, columns);      // get memory for virtual screen
-
-       cnt = file_size(fn);    // file size
-       size = 2 * cnt;         // 200% of file size
-       new_text(size);         // get a text[] buffer
-       screenbegin = dot = end = text;
-       if (fn != 0) {
-               ch= file_insert(fn, text, cnt);
-       }
-       if (ch < 1) {
-               (void) char_insert(text, '\n'); // start empty buf with dummy line
-       }
-       file_modified = FALSE;
-#ifdef BB_FEATURE_VI_YANKMARK
-       YDreg = 26;                     // default Yank/Delete reg
-       Ureg = 27;                      // hold orig line for "U" cmd
-       for (cnt = 0; cnt < 28; cnt++) {
-               mark[cnt] = 0;
-       }                                       // init the marks
-       mark[26] = mark[27] = text;     // init "previous context"
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       err_method = 1;         // flash
-       last_forward_char = last_input_char = '\0';
-       crow = 0;
-       ccol = 0;
-       edit_status();
-
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       signal(SIGHUP, catch_sig);
-       signal(SIGINT, catch_sig);
-       signal(SIGALRM, alarm_sig);
-       signal(SIGTERM, catch_sig);
-       signal(SIGQUIT, core_sig);
-       signal(SIGILL, core_sig);
-       signal(SIGTRAP, core_sig);
-       signal(SIGIOT, core_sig);
-       signal(SIGABRT, core_sig);
-       signal(SIGFPE, core_sig);
-       signal(SIGBUS, core_sig);
-       signal(SIGSEGV, core_sig);
-#ifdef SIGSYS
-       signal(SIGSYS, core_sig);
-#endif 
-       signal(SIGWINCH, winch_sig);
-       signal(SIGTSTP, suspend_sig);
-       sig = setjmp(restart);
-       if (sig != 0) {
-               msg = "";
-               if (sig == SIGWINCH)
-                       msg = "(window resize)";
-               if (sig == SIGHUP)
-                       msg = "(hangup)";
-               if (sig == SIGINT)
-                       msg = "(interrupt)";
-               if (sig == SIGTERM)
-                       msg = "(terminate)";
-               if (sig == SIGBUS)
-                       msg = "(bus error)";
-               if (sig == SIGSEGV)
-                       msg = "(I tried to touch invalid memory)";
-               if (sig == SIGALRM)
-                       msg = "(alarm)";
-
-               psbs("-- caught signal %d %s--", sig, msg);
-               screenbegin = dot = text;
-       }
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-
-       editing = 1;
-       cmd_mode = 0;           // 0=command  1=insert  2='R'eplace
-       cmdcnt = 0;
-       tabstop = 8;
-       offset = 0;                     // no horizontal offset
-       c = '\0';
-#ifdef BB_FEATURE_VI_DOT_CMD
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
-       if (ioq_start != NULL)
-               free(ioq_start);
-       ioq = ioq_start = last_modifying_cmd = 0;
-       adding2q = 0;
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-       redraw(FALSE);                  // dont force every col re-draw
-       show_status_line();
-
-       //------This is the main Vi cmd handling loop -----------------------
-       while (editing > 0) {
-#ifdef BB_FEATURE_VI_CRASHME
-               if (crashme > 0) {
-                       if ((end - text) > 1) {
-                               crash_dummy();  // generate a random command
-                       } else {
-                               crashme = 0;
-                               dot =
-                                       string_insert(text, (Byte *) "\n\n#####  Ran out of text to work on.  #####\n\n");      // insert the string
-                               refresh(FALSE);
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-               last_input_char = c = get_one_char();   // get a cmd from user
-#ifdef BB_FEATURE_VI_YANKMARK
-               // save a copy of the current line- for the 'U" command
-               if (begin_line(dot) != cur_line) {
-                       cur_line = begin_line(dot);
-                       text_yank(begin_line(dot), end_line(dot), Ureg);
-               }
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_DOT_CMD
-               // These are commands that change text[].
-               // Remember the input for the "." command
-               if (!adding2q && ioq_start == 0
-                       && strchr((char *) modifying_cmds, c) != NULL) {
-                       start_new_cmd_q(c);
-               }
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               do_cmd(c);              // execute the user command
-               //
-               // poll to see if there is input already waiting. if we are
-               // not able to display output fast enough to keep up, skip
-               // the display update until we catch up with input.
-               if (mysleep(0) == 0) {
-                       // no input pending- so update output
-                       refresh(FALSE);
-                       show_status_line();
-               }
-#ifdef BB_FEATURE_VI_CRASHME
-               if (crashme > 0)
-                       crash_test();   // test editor variables
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       }
-       //-------------------------------------------------------------------
-
-       place_cursor(rows, 0, FALSE);   // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
-       cookmode();
-}
-
-static Byte readbuffer[BUFSIZ];
-
-#ifdef BB_FEATURE_VI_CRASHME
-static int totalcmds = 0;
-static int Mp = 85;            // Movement command Probability
-static int Np = 90;            // Non-movement command Probability
-static int Dp = 96;            // Delete command Probability
-static int Ip = 97;            // Insert command Probability
-static int Yp = 98;            // Yank command Probability
-static int Pp = 99;            // Put command Probability
-static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
-char chars[20] = "\t012345 abcdABCD-=.$";
-char *words[20] = { "this", "is", "a", "test",
-       "broadcast", "the", "emergency", "of",
-       "system", "quick", "brown", "fox",
-       "jumped", "over", "lazy", "dogs",
-       "back", "January", "Febuary", "March"
-};
-char *lines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-char *multilines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-
-// create a random command to execute
-static void crash_dummy()
-{
-       static int sleeptime;   // how long to pause between commands
-       char c, cm, *cmd, *cmd1;
-       int i, cnt, thing, rbi, startrbi, percent;
-
-       // "dot" movement commands
-       cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
-
-       // is there already a command running?
-       if (strlen((char *) readbuffer) > 0)
-               goto cd1;
-  cd0:
-       startrbi = rbi = 0;
-       sleeptime = 0;          // how long to pause between commands
-       memset(readbuffer, '\0', BUFSIZ - 1);   // clear the read buffer
-       // generate a command by percentages
-       percent = (int) lrand48() % 100;        // get a number from 0-99
-       if (percent < Mp) {     //  Movement commands
-               // available commands
-               cmd = cmd1;
-               M++;
-       } else if (percent < Np) {      //  non-movement commands
-               cmd = "mz<>\'\"";       // available commands
-               N++;
-       } else if (percent < Dp) {      //  Delete commands
-               cmd = "dx";             // available commands
-               D++;
-       } else if (percent < Ip) {      //  Inset commands
-               cmd = "iIaAsrJ";        // available commands
-               I++;
-       } else if (percent < Yp) {      //  Yank commands
-               cmd = "yY";             // available commands
-               Y++;
-       } else if (percent < Pp) {      //  Put commands
-               cmd = "pP";             // available commands
-               P++;
-       } else {
-               // We do not know how to handle this command, try again
-               U++;
-               goto cd0;
-       }
-       // randomly pick one of the available cmds from "cmd[]"
-       i = (int) lrand48() % strlen(cmd);
-       cm = cmd[i];
-       if (strchr(":\024", cm))
-               goto cd0;               // dont allow colon or ctrl-T commands
-       readbuffer[rbi++] = cm; // put cmd into input buffer
-
-       // now we have the command-
-       // there are 1, 2, and multi char commands
-       // find out which and generate the rest of command as necessary
-       if (strchr("dmryz<>\'\"", cm)) {        // 2-char commands
-               cmd1 = " \n\r0$^-+wWeEbBhjklHL";
-               if (cm == 'm' || cm == '\'' || cm == '\"') {    // pick a reg[]
-                       cmd1 = "abcdefghijklmnopqrstuvwxyz";
-               }
-               thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-               c = cmd1[thing];
-               readbuffer[rbi++] = c;  // add movement to input buffer
-       }
-       if (strchr("iIaAsc", cm)) {     // multi-char commands
-               if (cm == 'c') {
-                       // change some thing
-                       thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-                       c = cmd1[thing];
-                       readbuffer[rbi++] = c;  // add movement to input buffer
-               }
-               thing = (int) lrand48() % 4;    // what thing to insert
-               cnt = (int) lrand48() % 10;     // how many to insert
-               for (i = 0; i < cnt; i++) {
-                       if (thing == 0) {       // insert chars
-                               readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
-                       } else if (thing == 1) {        // insert words
-                               strcat((char *) readbuffer, words[(int) lrand48() % 20]);
-                               strcat((char *) readbuffer, " ");
-                               sleeptime = 0;  // how fast to type
-                       } else if (thing == 2) {        // insert lines
-                               strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       } else {        // insert multi-lines
-                               strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       }
-               }
-               strcat((char *) readbuffer, "\033");
-       }
-  cd1:
-       totalcmds++;
-       if (sleeptime > 0)
-               (void) mysleep(sleeptime);      // sleep 1/100 sec
-}
-
-// test to see if there are any errors
-static void crash_test()
-{
-       static time_t oldtim;
-       time_t tim;
-       char d[2], buf[BUFSIZ], msg[BUFSIZ];
-
-       msg[0] = '\0';
-       if (end < text) {
-               strcat((char *) msg, "end<text ");
-       }
-       if (end > textend) {
-               strcat((char *) msg, "end>textend ");
-       }
-       if (dot < text) {
-               strcat((char *) msg, "dot<text ");
-       }
-       if (dot > end) {
-               strcat((char *) msg, "dot>end ");
-       }
-       if (screenbegin < text) {
-               strcat((char *) msg, "screenbegin<text ");
-       }
-       if (screenbegin > end - 1) {
-               strcat((char *) msg, "screenbegin>end-1 ");
-       }
-
-       if (strlen(msg) > 0) {
-               alarm(0);
-               sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
-                       totalcmds, last_input_char, msg, SOs, SOn);
-               write(1, buf, strlen(buf));
-               while (read(0, d, 1) > 0) {
-                       if (d[0] == '\n' || d[0] == '\r')
-                               break;
-               }
-               alarm(3);
-       }
-       tim = (time_t) time((time_t *) 0);
-       if (tim >= (oldtim + 3)) {
-               sprintf((char *) status_buffer,
-                               "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
-                               totalcmds, M, N, I, D, Y, P, U, end - text + 1);
-               oldtim = tim;
-       }
-       return;
-}
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-
-//---------------------------------------------------------------------
-//----- the Ascii Chart -----------------------------------------------
-//
-//  00 nul   01 soh   02 stx   03 etx   04 eot   05 enq   06 ack   07 bel
-//  08 bs    09 ht    0a nl    0b vt    0c np    0d cr    0e so    0f si
-//  10 dle   11 dc1   12 dc2   13 dc3   14 dc4   15 nak   16 syn   17 etb
-//  18 can   19 em    1a sub   1b esc   1c fs    1d gs    1e rs    1f us
-//  20 sp    21 !     22 "     23 #     24 $     25 %     26 &     27 '
-//  28 (     29 )     2a *     2b +     2c ,     2d -     2e .     2f /
-//  30 0     31 1     32 2     33 3     34 4     35 5     36 6     37 7
-//  38 8     39 9     3a :     3b ;     3c <     3d =     3e >     3f ?
-//  40 @     41 A     42 B     43 C     44 D     45 E     46 F     47 G
-//  48 H     49 I     4a J     4b K     4c L     4d M     4e N     4f O
-//  50 P     51 Q     52 R     53 S     54 T     55 U     56 V     57 W
-//  58 X     59 Y     5a Z     5b [     5c \     5d ]     5e ^     5f _
-//  60 `     61 a     62 b     63 c     64 d     65 e     66 f     67 g
-//  68 h     69 i     6a j     6b k     6c l     6d m     6e n     6f o
-//  70 p     71 q     72 r     73 s     74 t     75 u     76 v     77 w
-//  78 x     79 y     7a z     7b {     7c |     7d }     7e ~     7f del
-//---------------------------------------------------------------------
-
-//----- Execute a Vi Command -----------------------------------
-static void do_cmd(Byte c)
-{
-       Byte c1, *p, *q, *msg, buf[9], *save_dot;
-       int cnt, i, j, dir, yf;
-
-       c1 = c;                         // quiet the compiler
-       cnt = yf = dir = 0;     // quiet the compiler
-       p = q = save_dot = msg = buf;   // quiet the compiler
-       memset(buf, '\0', 9);   // clear buf
-       if (cmd_mode == 2) {
-               // we are 'R'eplacing the current *dot with new char
-               if (*dot == '\n') {
-                       // don't Replace past E-o-l
-                       cmd_mode = 1;   // convert to insert
-               } else {
-                       if (1 <= c && c <= 127) {       // only ASCII chars
-                               if (c != 27)
-                                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
-                               dot = char_insert(dot, c);      // insert new char
-                       }
-                       goto dc1;
-               }
-       }
-       if (cmd_mode == 1) {
-               //  hitting "Insert" twice means "R" replace mode
-               if (c == VI_K_INSERT) goto dc5;
-               // insert the char c at "dot"
-               if (1 <= c && c <= 127) {
-                       dot = char_insert(dot, c);      // only ASCII chars
-               }
-               goto dc1;
-       }
-
-       switch (c) {
-               //case 0x01:    // soh
-               //case 0x09:    // ht
-               //case 0x0b:    // vt
-               //case 0x0e:    // so
-               //case 0x0f:    // si
-               //case 0x10:    // dle
-               //case 0x11:    // dc1
-               //case 0x13:    // dc3
-#ifdef BB_FEATURE_VI_CRASHME
-       case 0x14:                      // dc4  ctrl-T
-               crashme = (crashme == 0) ? 1 : 0;
-               break;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-               //case 0x16:    // syn
-               //case 0x17:    // etb
-               //case 0x18:    // can
-               //case 0x1c:    // fs
-               //case 0x1d:    // gs
-               //case 0x1e:    // rs
-               //case 0x1f:    // us
-               //case '!':     // !- 
-               //case '#':     // #- 
-               //case '&':     // &- 
-               //case '(':     // (- 
-               //case ')':     // )- 
-               //case '*':     // *- 
-               //case ',':     // ,- 
-               //case '=':     // =- 
-               //case '@':     // @- 
-               //case 'F':     // F- 
-               //case 'K':     // K- 
-               //case 'Q':     // Q- 
-               //case 'S':     // S- 
-               //case 'T':     // T- 
-               //case 'V':     // V- 
-               //case '[':     // [- 
-               //case '\\':    // \- 
-               //case ']':     // ]- 
-               //case '_':     // _- 
-               //case '`':     // `- 
-               //case 'g':     // g- 
-               //case 'u':     // u- FIXME- there is no undo
-               //case 'v':     // v- 
-       default:                        // unrecognised command
-               buf[0] = c;
-               buf[1] = '\0';
-               if (c <= ' ') {
-                       buf[0] = '^';
-                       buf[1] = c + '@';
-                       buf[2] = '\0';
-               }
-               ni((Byte *) buf);
-               end_cmd_q();    // stop adding to q
-       case 0x00:                      // nul- ignore
-               break;
-       case 2:                 // ctrl-B  scroll up   full screen
-       case VI_K_PAGEUP:       // Cursor Key Page Up
-               dot_scroll(rows - 2, -1);
-               break;
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       case 0x03:                      // ctrl-C   interrupt
-               longjmp(restart, 1);
-               break;
-       case 26:                        // ctrl-Z suspend
-               suspend_sig(SIGTSTP);
-               break;
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-       case 4:                 // ctrl-D  scroll down half screen
-               dot_scroll((rows - 2) / 2, 1);
-               break;
-       case 5:                 // ctrl-E  scroll down one line
-               dot_scroll(1, 1);
-               break;
-       case 6:                 // ctrl-F  scroll down full screen
-       case VI_K_PAGEDOWN:     // Cursor Key Page Down
-               dot_scroll(rows - 2, 1);
-               break;
-       case 7:                 // ctrl-G  show current status
-               edit_status();
-               break;
-       case 'h':                       // h- move left
-       case VI_K_LEFT: // cursor key Left
-       case 8:                 // ctrl-H- move left    (This may be ERASE char)
-       case 127:                       // DEL- move left   (This may be ERASE char)
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_left();
-               break;
-       case 10:                        // Newline ^J
-       case 'j':                       // j- goto next line, same col
-       case VI_K_DOWN: // cursor key Down
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_next();             // go to next B-o-l
-               dot = move_to_col(dot, ccol + offset);  // try stay in same col
-               break;
-       case 12:                        // ctrl-L  force redraw whole screen
-       case 18:                        // ctrl-R  force redraw
-               place_cursor(0, 0, FALSE);      // put cursor in correct place
-               clear_to_eos(); // tel terminal to erase display
-               (void) mysleep(10);
-               screen_erase(); // erase the internal screen buffer
-               refresh(TRUE);  // this will redraw the entire display
-               break;
-       case 13:                        // Carriage Return ^M
-       case '+':                       // +- goto next line
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_next();
-               dot_skip_over_ws();
-               break;
-       case 21:                        // ctrl-U  scroll up   half screen
-               dot_scroll((rows - 2) / 2, -1);
-               break;
-       case 25:                        // ctrl-Y  scroll up one line
-               dot_scroll(1, -1);
-               break;
-       case 27:                        // esc
-               if (cmd_mode == 0)
-                       indicate_error(c);
-               cmd_mode = 0;   // stop insrting
-               end_cmd_q();
-               *status_buffer = '\0';  // clear status buffer
-               break;
-       case ' ':                       // move right
-       case 'l':                       // move right
-       case VI_K_RIGHT:        // Cursor Key Right
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_right();
-               break;
-#ifdef BB_FEATURE_VI_YANKMARK
-       case '"':                       // "- name a register to use for Delete/Yank
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       YDreg = c1 - 'a';
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case '\'':                      // '- goto a specific mark
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
-                       // get the b-o-l
-                       q = mark[(int) c1];
-                       if (text <= q && q < end) {
-                               dot = q;
-                               dot_begin();    // go to B-o-l
-                               dot_skip_over_ws();
-                       }
-               } else if (c1 == '\'') {        // goto previous context
-                       dot = swap_context(dot);        // swap current and previous context
-                       dot_begin();    // go to B-o-l
-                       dot_skip_over_ws();
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case 'm':                       // m- Mark a line
-               // this is really stupid.  If there are any inserts or deletes
-               // between text[0] and dot then this mark will not point to the
-               // correct location! It could be off by many lines!
-               // Well..., at least its quick and dirty.
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
-                       // remember the line
-                       mark[(int) c1] = dot;
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case 'P':                       // P- Put register before
-       case 'p':                       // p- put register after
-               p = reg[YDreg];
-               if (p == 0) {
-                       psbs("Nothing in register %c", what_reg());
-                       break;
-               }
-               // are we putting whole lines or strings
-               if (strchr((char *) p, '\n') != NULL) {
-                       if (c == 'P') {
-                               dot_begin();    // putting lines- Put above
-                       }
-                       if (c == 'p') {
-                               // are we putting after very last line?
-                               if (end_line(dot) == (end - 1)) {
-                                       dot = end;      // force dot to end of text[]
-                               } else {
-                                       dot_next();     // next line, then put before
-                               }
-                       }
-               } else {
-                       if (c == 'p')
-                               dot_right();    // move to right, can move to NL
-               }
-               dot = string_insert(dot, p);    // insert the string
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'U':                       // U- Undo; replace current line with original version
-               if (reg[Ureg] != 0) {
-                       p = begin_line(dot);
-                       q = end_line(dot);
-                       p = text_hole_delete(p, q);     // delete cur line
-                       p = string_insert(p, reg[Ureg]);        // insert orig line
-                       dot = p;
-                       dot_skip_over_ws();
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       case '$':                       // $- goto end of line
-       case VI_K_END:          // Cursor Key End
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot = end_line(dot + 1);
-               break;
-       case '%':                       // %- find matching char of pair () [] {}
-               for (q = dot; q < end && *q != '\n'; q++) {
-                       if (strchr("()[]{}", *q) != NULL) {
-                               // we found half of a pair
-                               p = find_pair(q, *q);
-                               if (p == NULL) {
-                                       indicate_error(c);
-                               } else {
-                                       dot = p;
-                               }
-                               break;
-                       }
-               }
-               if (*q == '\n')
-                       indicate_error(c);
-               break;
-       case 'f':                       // f- forward to a user specified char
-               last_forward_char = get_one_char();     // get the search char
-               //
-               // dont seperate these two commands. 'f' depends on ';'
-               //
-               //**** fall thru to ... 'i'
-       case ';':                       // ;- look at rest of line for last forward char
-               if (cmdcnt-- > 1) {
-                       do_cmd(';');
-               }                               // repeat cnt
-               if (last_forward_char == 0) break;
-               q = dot + 1;
-               while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
-                       q++;
-               }
-               if (*q == last_forward_char)
-                       dot = q;
-               break;
-       case '-':                       // -- goto prev line
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_prev();
-               dot_skip_over_ws();
-               break;
-#ifdef BB_FEATURE_VI_DOT_CMD
-       case '.':                       // .- repeat the last modifying command
-               // Stuff the last_modifying_cmd back into stdin
-               // and let it be re-executed.
-               if (last_modifying_cmd != 0) {
-                       ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd);
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_SEARCH
-       case '?':                       // /- search for a pattern
-       case '/':                       // /- search for a pattern
-               buf[0] = c;
-               buf[1] = '\0';
-               q = get_input_line(buf);        // get input line- use "status line"
-               if (strlen((char *) q) == 1)
-                       goto dc3;       // if no pat re-use old pat
-               if (strlen((char *) q) > 1) {   // new pat- save it and find
-                       // there is a new pat
-                       if (last_search_pattern != 0) {
-                               free(last_search_pattern);
-                       }
-                       last_search_pattern = (Byte *) strdup((char *) q);
-                       goto dc3;       // now find the pattern
-               }
-               // user changed mind and erased the "/"-  do nothing
-               break;
-       case 'N':                       // N- backward search for last pattern
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = BACK;             // assume BACKWARD search
-               p = dot - 1;
-               if (last_search_pattern[0] == '?') {
-                       dir = FORWARD;
-                       p = dot + 1;
-               }
-               goto dc4;               // now search for pattern
-               break;
-       case 'n':                       // n- repeat search for last pattern
-               // search rest of text[] starting at next char
-               // if search fails return orignal "p" not the "p+1" address
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-         dc3:
-               if (last_search_pattern == 0) {
-                       msg = (Byte *) "No previous regular expression";
-                       goto dc2;
-               }
-               if (last_search_pattern[0] == '/') {
-                       dir = FORWARD;  // assume FORWARD search
-                       p = dot + 1;
-               }
-               if (last_search_pattern[0] == '?') {
-                       dir = BACK;
-                       p = dot - 1;
-               }
-         dc4:
-               q = char_search(p, last_search_pattern + 1, dir, FULL);
-               if (q != NULL) {
-                       dot = q;        // good search, update "dot"
-                       msg = (Byte *) "";
-                       goto dc2;
-               }
-               // no pattern found between "dot" and "end"- continue at top
-               p = text;
-               if (dir == BACK) {
-                       p = end - 1;
-               }
-               q = char_search(p, last_search_pattern + 1, dir, FULL);
-               if (q != NULL) {        // found something
-                       dot = q;        // found new pattern- goto it
-                       msg = (Byte *) "search hit BOTTOM, continuing at TOP";
-                       if (dir == BACK) {
-                               msg = (Byte *) "search hit TOP, continuing at BOTTOM";
-                       }
-               } else {
-                       msg = (Byte *) "Pattern not found";
-               }
-         dc2:
-               psbs("%s", msg);
-               break;
-       case '{':                       // {- move backward paragraph
-               q = char_search(dot, (Byte *) "\n\n", BACK, FULL);
-               if (q != NULL) {        // found blank line
-                       dot = next_line(q);     // move to next blank line
-               }
-               break;
-       case '}':                       // }- move forward paragraph
-               q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL);
-               if (q != NULL) {        // found blank line
-                       dot = next_line(q);     // move to next blank line
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       case '0':                       // 0- goto begining of line
-       case '1':                       // 1- 
-       case '2':                       // 2- 
-       case '3':                       // 3- 
-       case '4':                       // 4- 
-       case '5':                       // 5- 
-       case '6':                       // 6- 
-       case '7':                       // 7- 
-       case '8':                       // 8- 
-       case '9':                       // 9- 
-               if (c == '0' && cmdcnt < 1) {
-                       dot_begin();    // this was a standalone zero
-               } else {
-                       cmdcnt = cmdcnt * 10 + (c - '0');       // this 0 is part of a number
-               }
-               break;
-       case ':':                       // :- the colon mode commands
-               p = get_input_line((Byte *) ":");       // get input line- use "status line"
-#ifdef BB_FEATURE_VI_COLON
-               colon(p);               // execute the command
-#else                                                  /* BB_FEATURE_VI_COLON */
-               if (*p == ':')
-                       p++;                            // move past the ':'
-               cnt = strlen((char *) p);
-               if (cnt <= 0)
-                       break;
-               if (strncasecmp((char *) p, "quit", cnt) == 0 ||
-                       strncasecmp((char *) p, "q!", cnt) == 0) {      // delete lines
-                       if (file_modified == TRUE && p[1] != '!') {
-                               psbs("No write since last change (:quit! overrides)");
-                       } else {
-                               editing = 0;
-                       }
-               } else if (strncasecmp((char *) p, "write", cnt) == 0 ||
-                                  strncasecmp((char *) p, "wq", cnt) == 0) {
-                       cnt = file_write(cfn, text, end - 1);
-                       file_modified = FALSE;
-                       psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
-                       if (p[1] == 'q') {
-                               editing = 0;
-                       }
-               } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
-                       edit_status();                  // show current file status
-               } else if (sscanf((char *) p, "%d", &j) > 0) {
-                       dot = find_line(j);             // go to line # j
-                       dot_skip_over_ws();
-               } else {                // unrecognised cmd
-                       ni((Byte *) p);
-               }
-#endif                                                 /* BB_FEATURE_VI_COLON */
-               break;
-       case '<':                       // <- Left  shift something
-       case '>':                       // >- Right shift something
-               cnt = count_lines(text, dot);   // remember what line we are on
-               c1 = get_one_char();    // get the type of thing to delete
-               find_range(&p, &q, c1);
-               (void) yank_delete(p, q, 1, YANKONLY);  // save copy before change
-               p = begin_line(p);
-               q = end_line(q);
-               i = count_lines(p, q);  // # of lines we are shifting
-               for ( ; i > 0; i--, p = next_line(p)) {
-                       if (c == '<') {
-                               // shift left- remove tab or 8 spaces
-                               if (*p == '\t') {
-                                       // shrink buffer 1 char
-                                       (void) text_hole_delete(p, p);
-                               } else if (*p == ' ') {
-                                       // we should be calculating columns, not just SPACE
-                                       for (j = 0; *p == ' ' && j < tabstop; j++) {
-                                               (void) text_hole_delete(p, p);
-                                       }
-                               }
-                       } else if (c == '>') {
-                               // shift right -- add tab or 8 spaces
-                               (void) char_insert(p, '\t');
-                       }
-               }
-               dot = find_line(cnt);   // what line were we on
-               dot_skip_over_ws();
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'A':                       // A- append at e-o-l
-               dot_end();              // go to e-o-l
-               //**** fall thru to ... 'a'
-       case 'a':                       // a- append after current char
-               if (*dot != '\n')
-                       dot++;
-               goto dc_i;
-               break;
-       case 'B':                       // B- back a blank-delimited Word
-       case 'E':                       // E- end of a blank-delimited word
-       case 'W':                       // W- forward a blank-delimited word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = FORWARD;
-               if (c == 'B')
-                       dir = BACK;
-               if (c == 'W' || isspace(dot[dir])) {
-                       dot = skip_thing(dot, 1, dir, S_TO_WS);
-                       dot = skip_thing(dot, 2, dir, S_OVER_WS);
-               }
-               if (c != 'W')
-                       dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
-               break;
-       case 'C':                       // C- Change to e-o-l
-       case 'D':                       // D- delete to e-o-l
-               save_dot = dot;
-               dot = dollar_line(dot); // move to before NL
-               // copy text into a register and delete
-               dot = yank_delete(save_dot, dot, 0, YANKDEL);   // delete to e-o-l
-               if (c == 'C')
-                       goto dc_i;      // start inserting
-#ifdef BB_FEATURE_VI_DOT_CMD
-               if (c == 'D')
-                       end_cmd_q();    // stop adding to q
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               break;
-       case 'G':               // G- goto to a line number (default= E-O-F)
-               dot = end - 1;                          // assume E-O-F
-               if (cmdcnt > 0) {
-                       dot = find_line(cmdcnt);        // what line is #cmdcnt
-               }
-               dot_skip_over_ws();
-               break;
-       case 'H':                       // H- goto top line on screen
-               dot = screenbegin;
-               if (cmdcnt > (rows - 1)) {
-                       cmdcnt = (rows - 1);
-               }
-               if (cmdcnt-- > 1) {
-                       do_cmd('+');
-               }                               // repeat cnt
-               dot_skip_over_ws();
-               break;
-       case 'I':                       // I- insert before first non-blank
-               dot_begin();    // 0
-               dot_skip_over_ws();
-               //**** fall thru to ... 'i'
-       case 'i':                       // i- insert before current char
-       case VI_K_INSERT:       // Cursor Key Insert
-         dc_i:
-               cmd_mode = 1;   // start insrting
-               psb("-- Insert --");
-               break;
-       case 'J':                       // J- join current and next lines together
-               if (cmdcnt-- > 2) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_end();              // move to NL
-               if (dot < end - 1) {    // make sure not last char in text[]
-                       *dot++ = ' ';   // replace NL with space
-                       while (isblnk(*dot)) {  // delete leading WS
-                               dot_delete();
-                       }
-               }
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'L':                       // L- goto bottom line on screen
-               dot = end_screen();
-               if (cmdcnt > (rows - 1)) {
-                       cmdcnt = (rows - 1);
-               }
-               if (cmdcnt-- > 1) {
-                       do_cmd('-');
-               }                               // repeat cnt
-               dot_begin();
-               dot_skip_over_ws();
-               break;
-       case 'M':                       // M- goto middle line on screen
-               dot = screenbegin;
-               for (cnt = 0; cnt < (rows-1) / 2; cnt++)
-                       dot = next_line(dot);
-               break;
-       case 'O':                       // O- open a empty line above
-               //    0i\n ESC -i
-               p = begin_line(dot);
-               if (p[-1] == '\n') {
-                       dot_prev();
-       case 'o':                       // o- open a empty line below; Yes, I know it is in the middle of the "if (..."
-                       dot_end();
-                       dot = char_insert(dot, '\n');
-               } else {
-                       dot_begin();    // 0
-                       dot = char_insert(dot, '\n');   // i\n ESC
-                       dot_prev();     // -
-               }
-               goto dc_i;
-               break;
-       case 'R':                       // R- continuous Replace char
-         dc5:
-               cmd_mode = 2;
-               psb("-- Replace --");
-               break;
-       case 'X':                       // X- delete char before dot
-       case 'x':                       // x- delete the current char
-       case 's':                       // s- substitute the current char
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = 0;
-               if (c == 'X')
-                       dir = -1;
-               if (dot[dir] != '\n') {
-                       if (c == 'X')
-                               dot--;  // delete prev char
-                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
-               }
-               if (c == 's')
-                       goto dc_i;      // start insrting
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'Z':                       // Z- if modified, {write}; exit
-               // ZZ means to save file (if necessary), then exit
-               c1 = get_one_char();
-               if (c1 != 'Z') {
-                       indicate_error(c);
-                       break;
-               }
-               if (file_modified == TRUE
-#ifdef BB_FEATURE_VI_READONLY
-                       && vi_readonly == FALSE
-                       && readonly == FALSE
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       ) {
-                       cnt = file_write(cfn, text, end - 1);
-                       if (cnt == (end - 1 - text + 1)) {
-                               editing = 0;
-                       }
-               } else {
-                       editing = 0;
-               }
-               break;
-       case '^':                       // ^- move to first non-blank on line
-               dot_begin();
-               dot_skip_over_ws();
-               break;
-       case 'b':                       // b- back a word
-       case 'e':                       // e- end of word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = FORWARD;
-               if (c == 'b')
-                       dir = BACK;
-               if ((dot + dir) < text || (dot + dir) > end - 1)
-                       break;
-               dot += dir;
-               if (isspace(*dot)) {
-                       dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
-               }
-               if (isalnum(*dot) || *dot == '_') {
-                       dot = skip_thing(dot, 1, dir, S_END_ALNUM);
-               } else if (ispunct(*dot)) {
-                       dot = skip_thing(dot, 1, dir, S_END_PUNCT);
-               }
-               break;
-       case 'c':                       // c- change something
-       case 'd':                       // d- delete something
-#ifdef BB_FEATURE_VI_YANKMARK
-       case 'y':                       // y- yank   something
-       case 'Y':                       // Y- Yank a line
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               yf = YANKDEL;   // assume either "c" or "d"
-#ifdef BB_FEATURE_VI_YANKMARK
-               if (c == 'y' || c == 'Y')
-                       yf = YANKONLY;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               c1 = 'y';
-               if (c != 'Y')
-                       c1 = get_one_char();    // get the type of thing to delete
-               find_range(&p, &q, c1);
-               if (c1 == 27) { // ESC- user changed mind and wants out
-                       c = c1 = 27;    // Escape- do nothing
-               } else if (strchr("wW", c1)) {
-                       if (c == 'c') {
-                               // don't include trailing WS as part of word
-                               while (isblnk(*q)) {
-                                       if (q <= text || q[-1] == '\n')
-                                               break;
-                                       q--;
-                               }
-                       }
-                       dot = yank_delete(p, q, 0, yf); // delete word
-               } else if (strchr("^0bBeEft$", c1)) {
-                       // single line copy text into a register and delete
-                       dot = yank_delete(p, q, 0, yf); // delete word
-               } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
-                       // multiple line copy text into a register and delete
-                       dot = yank_delete(p, q, 1, yf); // delete lines
-                       if (c == 'c') {
-                               dot = char_insert(dot, '\n');
-                               // on the last line of file don't move to prev line
-                               if (dot != (end-1)) {
-                                       dot_prev();
-                               }
-                       } else if (c == 'd') {
-                               dot_begin();
-                               dot_skip_over_ws();
-                       }
-               } else {
-                       // could not recognize object
-                       c = c1 = 27;    // error-
-                       indicate_error(c);
-               }
-               if (c1 != 27) {
-                       // if CHANGING, not deleting, start inserting after the delete
-                       if (c == 'c') {
-                               strcpy((char *) buf, "Change");
-                               goto dc_i;      // start inserting
-                       }
-                       if (c == 'd') {
-                               strcpy((char *) buf, "Delete");
-                       }
-#ifdef BB_FEATURE_VI_YANKMARK
-                       if (c == 'y' || c == 'Y') {
-                               strcpy((char *) buf, "Yank");
-                       }
-                       p = reg[YDreg];
-                       q = p + strlen((char *) p);
-                       for (cnt = 0; p <= q; p++) {
-                               if (*p == '\n')
-                                       cnt++;
-                       }
-                       psb("%s %d lines (%d chars) using [%c]",
-                               buf, cnt, strlen((char *) reg[YDreg]), what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-                       end_cmd_q();    // stop adding to q
-               }
-               break;
-       case 'k':                       // k- goto prev line, same col
-       case VI_K_UP:           // cursor key Up
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_prev();
-               dot = move_to_col(dot, ccol + offset);  // try stay in same col
-               break;
-       case 'r':                       // r- replace the current char with user input
-               c1 = get_one_char();    // get the replacement char
-               if (*dot != '\n') {
-                       *dot = c1;
-                       file_modified = TRUE;   // has the file been modified
-               }
-               end_cmd_q();    // stop adding to q
-               break;
-       case 't':                       // t- move to char prior to next x
-                last_forward_char = get_one_char();
-                do_cmd(';');
-                if (*dot == last_forward_char)
-                        dot_left();
-                last_forward_char= 0;
-               break;
-       case 'w':                       // w- forward a word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               if (isalnum(*dot) || *dot == '_') {     // we are on ALNUM
-                       dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
-               } else if (ispunct(*dot)) {     // we are on PUNCT
-                       dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
-               }
-               if (dot < end - 1)
-                       dot++;          // move over word
-               if (isspace(*dot)) {
-                       dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
-               }
-               break;
-       case 'z':                       // z-
-               c1 = get_one_char();    // get the replacement char
-               cnt = 0;
-               if (c1 == '.')
-                       cnt = (rows - 2) / 2;   // put dot at center
-               if (c1 == '-')
-                       cnt = rows - 2; // put dot at bottom
-               screenbegin = begin_line(dot);  // start dot at top
-               dot_scroll(cnt, -1);
-               break;
-       case '|':                       // |- move to column "cmdcnt"
-               dot = move_to_col(dot, cmdcnt - 1);     // try to move to column
-               break;
-       case '~':                       // ~- flip the case of letters   a-z -> A-Z
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               if (islower(*dot)) {
-                       *dot = toupper(*dot);
-                       file_modified = TRUE;   // has the file been modified
-               } else if (isupper(*dot)) {
-                       *dot = tolower(*dot);
-                       file_modified = TRUE;   // has the file been modified
-               }
-               dot_right();
-               end_cmd_q();    // stop adding to q
-               break;
-               //----- The Cursor and Function Keys -----------------------------
-       case VI_K_HOME: // Cursor Key Home
-               dot_begin();
-               break;
-               // The Fn keys could point to do_macro which could translate them
-       case VI_K_FUN1: // Function Key F1
-       case VI_K_FUN2: // Function Key F2
-       case VI_K_FUN3: // Function Key F3
-       case VI_K_FUN4: // Function Key F4
-       case VI_K_FUN5: // Function Key F5
-       case VI_K_FUN6: // Function Key F6
-       case VI_K_FUN7: // Function Key F7
-       case VI_K_FUN8: // Function Key F8
-       case VI_K_FUN9: // Function Key F9
-       case VI_K_FUN10:        // Function Key F10
-       case VI_K_FUN11:        // Function Key F11
-       case VI_K_FUN12:        // Function Key F12
-               break;
-       }
-
-  dc1:
-       // if text[] just became empty, add back an empty line
-       if (end == text) {
-               (void) char_insert(text, '\n'); // start empty buf with dummy line
-               dot = text;
-       }
-       // it is OK for dot to exactly equal to end, otherwise check dot validity
-       if (dot != end) {
-               dot = bound_dot(dot);   // make sure "dot" is valid
-       }
-#ifdef BB_FEATURE_VI_YANKMARK
-       check_context(c);       // update the current context
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       if (!isdigit(c))
-               cmdcnt = 0;             // cmd was not a number, reset cmdcnt
-       cnt = dot - begin_line(dot);
-       // Try to stay off of the Newline
-       if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
-               dot--;
-}
-
-//----- The Colon commands -------------------------------------
-#ifdef BB_FEATURE_VI_COLON
-static Byte *get_one_address(Byte * p, int *addr)      // get colon addr, if present
-{
-       int st;
-       Byte *q;
-
-#ifdef BB_FEATURE_VI_YANKMARK
-       Byte c;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-       Byte *pat, buf[BUFSIZ];
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-       *addr = -1;                     // assume no addr
-       if (*p == '.') {        // the current line
-               p++;
-               q = begin_line(dot);
-               *addr = count_lines(text, q);
-#ifdef BB_FEATURE_VI_YANKMARK
-       } else if (*p == '\'') {        // is this a mark addr
-               p++;
-               c = tolower(*p);
-               p++;
-               if (c >= 'a' && c <= 'z') {
-                       // we have a mark
-                       c = c - 'a';
-                       q = mark[(int) c];
-                       if (q != NULL) {        // is mark valid
-                               *addr = count_lines(text, q);   // count lines
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-       } else if (*p == '/') { // a search pattern
-               q = buf;
-               for (p++; *p; p++) {
-                       if (*p == '/')
-                               break;
-                       *q++ = *p;
-                       *q = '\0';
-               }
-               pat = (Byte *) strdup((char *) buf);    // save copy of pattern
-               if (*p == '/')
-                       p++;
-               q = char_search(dot, pat, FORWARD, FULL);
-               if (q != NULL) {
-                       *addr = count_lines(text, q);
-               }
-               free(pat);
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       } else if (*p == '$') { // the last line in file
-               p++;
-               q = begin_line(end - 1);
-               *addr = count_lines(text, q);
-       } else if (isdigit(*p)) {       // specific line number
-               sscanf((char *) p, "%d%n", addr, &st);
-               p += st;
-       } else {                        // I don't reconise this
-               // unrecognised address- assume -1
-               *addr = -1;
-       }
-       return (p);
-}
-
-static Byte *get_address(Byte *p, int *b, int *e)      // get two colon addrs, if present
-{
-       //----- get the address' i.e., 1,3   'a,'b  -----
-       // get FIRST addr, if present
-       while (isblnk(*p))
-               p++;                            // skip over leading spaces
-       if (*p == '%') {                        // alias for 1,$
-               p++;
-               *b = 1;
-               *e = count_lines(text, end-1);
-               goto ga0;
-       }
-       p = get_one_address(p, b);
-       while (isblnk(*p))
-               p++;
-       if (*p == ',') {                        // is there a address seperator
-               p++;
-               while (isblnk(*p))
-                       p++;
-               // get SECOND addr, if present
-               p = get_one_address(p, e);
-       }
-ga0:
-       while (isblnk(*p))
-               p++;                            // skip over trailing spaces
-       return (p);
-}
-
-static void colon(Byte * buf)
-{
-       Byte c, *orig_buf, *buf1, *q, *r;
-       Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
-       int i, l, li, ch, st, b, e;
-       int useforce, forced;
-       struct stat st_buf;
-
-       // :3154        // if (-e line 3154) goto it  else stay put
-       // :4,33w! foo  // write a portion of buffer to file "foo"
-       // :w           // write all of buffer to current file
-       // :q           // quit
-       // :q!          // quit- dont care about modified file
-       // :'a,'z!sort -u   // filter block through sort
-       // :'f          // goto mark "f"
-       // :'fl         // list literal the mark "f" line
-       // :.r bar      // read file "bar" into buffer before dot
-       // :/123/,/abc/d    // delete lines from "123" line to "abc" line
-       // :/xyz/       // goto the "xyz" line
-       // :s/find/replace/ // substitute pattern "find" with "replace"
-       // :!<cmd>      // run <cmd> then return
-       //
-       if (strlen((char *) buf) <= 0)
-               goto vc1;
-       if (*buf == ':')
-               buf++;                  // move past the ':'
-
-       forced = useforce = FALSE;
-       li = st = ch = i = 0;
-       b = e = -1;
-       q = text;                       // assume 1,$ for the range
-       r = end - 1;
-       li = count_lines(text, end - 1);
-       fn = cfn;                       // default to current file
-       memset(cmd, '\0', BUFSIZ);      // clear cmd[]
-       memset(args, '\0', BUFSIZ);     // clear args[]
-
-       // look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
-       buf = get_address(buf, &b, &e);
-
-       // remember orig command line
-       orig_buf = buf;
-
-       // get the COMMAND into cmd[]
-       buf1 = cmd;
-       while (*buf != '\0') {
-               if (isspace(*buf))
-                       break;
-               *buf1++ = *buf++;
-       }
-       // get any ARGuments
-       while (isblnk(*buf))
-               buf++;
-       strcpy((char *) args, (char *) buf);
-       buf1 = last_char_is((char *)cmd, '!');
-       if (buf1) {
-               useforce = TRUE;
-               *buf1 = '\0';   // get rid of !
-       }
-       if (b >= 0) {
-               // if there is only one addr, then the addr
-               // is the line number of the single line the
-               // user wants. So, reset the end
-               // pointer to point at end of the "b" line
-               q = find_line(b);       // what line is #b
-               r = end_line(q);
-               li = 1;
-       }
-       if (e >= 0) {
-               // we were given two addrs.  change the
-               // end pointer to the addr given by user.
-               r = find_line(e);       // what line is #e
-               r = end_line(r);
-               li = e - b + 1;
-       }
-       // ------------ now look for the command ------------
-       i = strlen((char *) cmd);
-       if (i == 0) {           // :123CR goto line #123
-               if (b >= 0) {
-                       dot = find_line(b);     // what line is #b
-                       dot_skip_over_ws();
-               }
-       } else if (strncmp((char *) cmd, "!", 1) == 0) {        // run a cmd
-               // :!ls   run the <cmd>
-               (void) alarm(0);                // wait for input- no alarms
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line
-               clear_to_eol();                 // clear the line
-               cookmode();
-               system(orig_buf+1);             // run the cmd
-               rawmode();
-               Hit_Return();                   // let user see results
-               (void) alarm(3);                // done waiting for input
-       } else if (strncmp((char *) cmd, "=", i) == 0) {        // where is the address
-               if (b < 0) {    // no addr given- use defaults
-                       b = e = count_lines(text, dot);
-               }
-               psb("%d", b);
-       } else if (strncasecmp((char *) cmd, "delete", i) == 0) {       // delete lines
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               dot = yank_delete(q, r, 1, YANKDEL);    // save, then delete lines
-               dot_skip_over_ws();
-       } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
-               int sr;
-               sr= 0;
-               // don't edit, if the current file has been modified
-               if (file_modified == TRUE && useforce != TRUE) {
-                       psbs("No write since last change (:edit! overrides)");
-                       goto vc1;
-               }
-               if (strlen(args) > 0) {
-                       // the user supplied a file name
-                       fn= args;
-               } else if (cfn != 0 && strlen(cfn) > 0) {
-                       // no user supplied name- use the current filename
-                       fn= cfn;
-                       goto vc5;
-               } else {
-                       // no user file name, no current name- punt
-                       psbs("No current filename");
-                       goto vc1;
-               }
-
-               // see if file exists- if not, its just a new file request
-               if ((sr=stat((char*)fn, &st_buf)) < 0) {
-                       // This is just a request for a new file creation.
-                       // The file_insert below will fail but we get
-                       // an empty buffer with a file name.  Then the "write"
-                       // command can do the create.
-               } else {
-                       if ((st_buf.st_mode & (S_IFREG)) == 0) {
-                               // This is not a regular file
-                               psbs("\"%s\" is not a regular file", fn);
-                               goto vc1;
-                       }
-                       if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
-                               // dont have any read permissions
-                               psbs("\"%s\" is not readable", fn);
-                               goto vc1;
-                       }
-               }
-
-               // There is a read-able regular file
-               // make this the current file
-               q = (Byte *) strdup((char *) fn);       // save the cfn
-               if (cfn != 0)
-                       free(cfn);              // free the old name
-               cfn = q;                        // remember new cfn
-
-         vc5:
-               // delete all the contents of text[]
-               new_text(2 * file_size(fn));
-               screenbegin = dot = end = text;
-
-               // insert new file
-               ch = file_insert(fn, text, file_size(fn));
-
-               if (ch < 1) {
-                       // start empty buf with dummy line
-                       (void) char_insert(text, '\n');
-                       ch= 1;
-               }
-               file_modified = FALSE;
-#ifdef BB_FEATURE_VI_YANKMARK
-               if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
-                       free(reg[Ureg]);        //   free orig line reg- for 'U'
-                       reg[Ureg]= 0;
-               }
-               if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
-                       free(reg[YDreg]);       //   free default yank/delete register
-                       reg[YDreg]= 0;
-               }
-               for (li = 0; li < 28; li++) {
-                       mark[li] = 0;
-               }                               // init the marks
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               // how many lines in text[]?
-               li = count_lines(text, end - 1);
-               psb("\"%s\"%s"
-#ifdef BB_FEATURE_VI_READONLY
-                       "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       " %dL, %dC", cfn,
-                       (sr < 0 ? " [New file]" : ""),
-#ifdef BB_FEATURE_VI_READONLY
-                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       li, ch);
-       } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
-               if (b != -1 || e != -1) {
-                       ni((Byte *) "No address allowed on this command");
-                       goto vc1;
-               }
-               if (strlen((char *) args) > 0) {
-                       // user wants a new filename
-                       if (cfn != NULL)
-                               free(cfn);
-                       cfn = (Byte *) strdup((char *) args);
-               } else {
-                       // user wants file status info
-                       edit_status();
-               }
-       } else if (strncasecmp((char *) cmd, "features", i) == 0) {     // what features are available
-               // print out values of all features
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
-               cookmode();
-               show_help();
-               rawmode();
-               Hit_Return();
-       } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
-               write(1, "\r\n", 2);
-               for (; q <= r; q++) {
-                       c = *q;
-                       if (c > '~')
-                               standout_start();
-                       if (c == '\n') {
-                               write(1, "$\r", 2);
-                       } else if (*q < ' ') {
-                               write(1, "^", 1);
-                               c += '@';
-                       }
-                       write(1, &c, 1);
-                       if (c > '~')
-                               standout_end();
-               }
-#ifdef BB_FEATURE_VI_SET
-         vc2:
-#endif                                                 /* BB_FEATURE_VI_SET */
-               Hit_Return();
-       } else if ((strncasecmp((char *) cmd, "quit", i) == 0) ||       // Quit
-                          (strncasecmp((char *) cmd, "next", i) == 0)) {       // edit next file
-               if (useforce == TRUE) {
-                       // force end of argv list
-                       if (*cmd == 'q') {
-                               optind = save_argc;
-                       }
-                       editing = 0;
-                       goto vc1;
-               }
-               // don't exit if the file been modified
-               if (file_modified == TRUE) {
-                       psbs("No write since last change (:%s! overrides)",
-                                (*cmd == 'q' ? "quit" : "next"));
-                       goto vc1;
-               }
-               // are there other file to edit
-               if (*cmd == 'q' && optind < save_argc - 1) {
-                       psbs("%d more file to edit", (save_argc - optind - 1));
-                       goto vc1;
-               }
-               if (*cmd == 'n' && optind >= save_argc - 1) {
-                       psbs("No more files to edit");
-                       goto vc1;
-               }
-               editing = 0;
-       } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[]
-               fn = args;
-               if (strlen((char *) fn) <= 0) {
-                       psbs("No filename given");
-                       goto vc1;
-               }
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume "dot"
-               }
-               // read after current line- unless user said ":0r foo"
-               if (b != 0)
-                       q = next_line(q);
-#ifdef BB_FEATURE_VI_READONLY
-               l= readonly;                    // remember current files' status
-#endif
-               ch = file_insert(fn, q, file_size(fn));
-#ifdef BB_FEATURE_VI_READONLY
-               readonly= l;
-#endif
-               if (ch < 0)
-                       goto vc1;       // nothing was inserted
-               // how many lines in text[]?
-               li = count_lines(q, q + ch - 1);
-               psb("\"%s\""
-#ifdef BB_FEATURE_VI_READONLY
-                       "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       " %dL, %dC", fn,
-#ifdef BB_FEATURE_VI_READONLY
-                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       li, ch);
-               if (ch > 0) {
-                       // if the insert is before "dot" then we need to update
-                       if (q <= dot)
-                               dot += ch;
-                       file_modified = TRUE;
-               }
-       } else if (strncasecmp((char *) cmd, "rewind", i) == 0) {       // rewind cmd line args
-               if (file_modified == TRUE && useforce != TRUE) {
-                       psbs("No write since last change (:rewind! overrides)");
-               } else {
-                       // reset the filenames to edit
-                       optind = fn_start - 1;
-                       editing = 0;
-               }
-#ifdef BB_FEATURE_VI_SET
-       } else if (strncasecmp((char *) cmd, "set", i) == 0) {  // set or clear features
-               i = 0;                  // offset into args
-               if (strlen((char *) args) == 0) {
-                       // print out values of all options
-                       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-                       clear_to_eol(); // clear the line
-                       printf("----------------------------------------\r\n");
-#ifdef BB_FEATURE_VI_SETOPTS
-                       if (!autoindent)
-                               printf("no");
-                       printf("autoindent ");
-                       if (!err_method)
-                               printf("no");
-                       printf("flash ");
-                       if (!ignorecase)
-                               printf("no");
-                       printf("ignorecase ");
-                       if (!showmatch)
-                               printf("no");
-                       printf("showmatch ");
-                       printf("tabstop=%d ", tabstop);
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-                       printf("\r\n");
-                       goto vc2;
-               }
-               if (strncasecmp((char *) args, "no", 2) == 0)
-                       i = 2;          // ":set noautoindent"
-#ifdef BB_FEATURE_VI_SETOPTS
-               if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ai", 2) == 0) {
-                       autoindent = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
-                       strncasecmp((char *) args + i, "fl", 2) == 0) {
-                       err_method = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ic", 2) == 0) {
-                       ignorecase = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "showmatch", 9) == 0 ||
-                       strncasecmp((char *) args + i, "sm", 2) == 0) {
-                       showmatch = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "tabstop", 7) == 0) {
-                       sscanf(strchr((char *) args + i, '='), "=%d", &ch);
-                       if (ch > 0 && ch < columns - 1)
-                               tabstop = ch;
-               }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#endif                                                 /* BB_FEATURE_VI_SET */
-#ifdef BB_FEATURE_VI_SEARCH
-       } else if (strncasecmp((char *) cmd, "s", 1) == 0) {    // substitute a pattern with a replacement pattern
-               Byte *ls, *F, *R;
-               int gflag;
-
-               // F points to the "find" pattern
-               // R points to the "replace" pattern
-               // replace the cmd line delimiters "/" with NULLs
-               gflag = 0;              // global replace flag
-               c = orig_buf[1];        // what is the delimiter
-               F = orig_buf + 2;       // start of "find"
-               R = (Byte *) strchr((char *) F, c);     // middle delimiter
-               if (!R) goto colon_s_fail;
-               *R++ = '\0';    // terminate "find"
-               buf1 = (Byte *) strchr((char *) R, c);
-               if (!buf1) goto colon_s_fail;
-               *buf1++ = '\0'; // terminate "replace"
-               if (*buf1 == 'g') {     // :s/foo/bar/g
-                       buf1++;
-                       gflag++;        // turn on gflag
-               }
-               q = begin_line(q);
-               if (b < 0) {    // maybe :s/foo/bar/
-                       q = begin_line(dot);    // start with cur line
-                       b = count_lines(text, q);       // cur line number
-               }
-               if (e < 0)
-                       e = b;          // maybe :.s/foo/bar/
-               for (i = b; i <= e; i++) {      // so, :20,23 s \0 find \0 replace \0
-                       ls = q;         // orig line start
-                 vc4:
-                       buf1 = char_search(q, F, FORWARD, LIMITED);     // search cur line only for "find"
-                       if (buf1 != NULL) {
-                               // we found the "find" pattern- delete it
-                               (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1);
-                               // inset the "replace" patern
-                               (void) string_insert(buf1, R);  // insert the string
-                               // check for "global"  :s/foo/bar/g
-                               if (gflag == 1) {
-                                       if ((buf1 + strlen((char *) R)) < end_line(ls)) {
-                                               q = buf1 + strlen((char *) R);
-                                               goto vc4;       // don't let q move past cur line
-                                       }
-                               }
-                       }
-                       q = next_line(ls);
-               }
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       } else if (strncasecmp((char *) cmd, "version", i) == 0) {      // show software version
-               psb("%s", vi_Version);
-       } else if ((strncasecmp((char *) cmd, "write", i) == 0) ||      // write text to file
-                          (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file
-               // is there a file name to write to?
-               if (strlen((char *) args) > 0) {
-                       fn = args;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-               if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
-                       psbs("\"%s\" File is read only", fn);
-                       goto vc3;
-               }
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               // how many lines in text[]?
-               li = count_lines(q, r);
-               ch = r - q + 1;
-               // see if file exists- if not, its just a new file request
-               if (useforce == TRUE) {
-                       // if "fn" is not write-able, chmod u+w
-                       // sprintf(syscmd, "chmod u+w %s", fn);
-                       // system(syscmd);
-                       forced = TRUE;
-               }
-               l = file_write(fn, q, r);
-               if (useforce == TRUE && forced == TRUE) {
-                       // chmod u-w
-                       // sprintf(syscmd, "chmod u-w %s", fn);
-                       // system(syscmd);
-                       forced = FALSE;
-               }
-               psb("\"%s\" %dL, %dC", fn, li, l);
-               if (q == text && r == end - 1 && l == ch)
-                       file_modified = FALSE;
-               if (cmd[1] == 'q' && l == ch) {
-                       editing = 0;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-         vc3:;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_YANKMARK
-       } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               text_yank(q, r, YDreg);
-               li = count_lines(q, r);
-               psb("Yank %d lines (%d chars) into [%c]",
-                       li, strlen((char *) reg[YDreg]), what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       } else {
-               // cmd unknown
-               ni((Byte *) cmd);
-       }
-  vc1:
-       dot = bound_dot(dot);   // make sure "dot" is valid
-       return;
-#ifdef BB_FEATURE_VI_SEARCH
-colon_s_fail:
-       psb(":s expression missing delimiters");
-       return;
-#endif
-
-}
-
-static void Hit_Return(void)
-{
-       char c;
-
-       standout_start();       // start reverse video
-       write(1, "[Hit return to continue]", 24);
-       standout_end();         // end reverse video
-       while ((c = get_one_char()) != '\n' && c != '\r')       /*do nothing */
-               ;
-       redraw(TRUE);           // force redraw all
-}
-#endif                                                 /* BB_FEATURE_VI_COLON */
-
-//----- Synchronize the cursor to Dot --------------------------
-static void sync_cursor(Byte * d, int *row, int *col)
-{
-       Byte *beg_cur, *end_cur;        // begin and end of "d" line
-       Byte *beg_scr, *end_scr;        // begin and end of screen
-       Byte *tp;
-       int cnt, ro, co;
-
-       beg_cur = begin_line(d);        // first char of cur line
-       end_cur = end_line(d);  // last char of cur line
-
-       beg_scr = end_scr = screenbegin;        // first char of screen
-       end_scr = end_screen(); // last char of screen
-
-       if (beg_cur < screenbegin) {
-               // "d" is before  top line on screen
-               // how many lines do we have to move
-               cnt = count_lines(beg_cur, screenbegin);
-         sc1:
-               screenbegin = beg_cur;
-               if (cnt > (rows - 1) / 2) {
-                       // we moved too many lines. put "dot" in middle of screen
-                       for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
-                               screenbegin = prev_line(screenbegin);
-                       }
-               }
-       } else if (beg_cur > end_scr) {
-               // "d" is after bottom line on screen
-               // how many lines do we have to move
-               cnt = count_lines(end_scr, beg_cur);
-               if (cnt > (rows - 1) / 2)
-                       goto sc1;       // too many lines
-               for (ro = 0; ro < cnt - 1; ro++) {
-                       // move screen begin the same amount
-                       screenbegin = next_line(screenbegin);
-                       // now, move the end of screen
-                       end_scr = next_line(end_scr);
-                       end_scr = end_line(end_scr);
-               }
-       }
-       // "d" is on screen- find out which row
-       tp = screenbegin;
-       for (ro = 0; ro < rows - 1; ro++) {     // drive "ro" to correct row
-               if (tp == beg_cur)
-                       break;
-               tp = next_line(tp);
-       }
-
-       // find out what col "d" is on
-       co = 0;
-       do {                            // drive "co" to correct column
-               if (*tp == '\n' || *tp == '\0')
-                       break;
-               if (*tp == '\t') {
-                       //         7       - (co %    8  )
-                       co += ((tabstop - 1) - (co % tabstop));
-               } else if (*tp < ' ') {
-                       co++;           // display as ^X, use 2 columns
-               }
-       } while (tp++ < d && ++co);
-
-       // "co" is the column where "dot" is.
-       // The screen has "columns" columns.
-       // The currently displayed columns are  0+offset -- columns+ofset
-       // |-------------------------------------------------------------|
-       //               ^ ^                                ^
-       //        offset | |------- columns ----------------|
-       //
-       // If "co" is already in this range then we do not have to adjust offset
-       //      but, we do have to subtract the "offset" bias from "co".
-       // If "co" is outside this range then we have to change "offset".
-       // If the first char of a line is a tab the cursor will try to stay
-       //  in column 7, but we have to set offset to 0.
-
-       if (co < 0 + offset) {
-               offset = co;
-       }
-       if (co >= columns + offset) {
-               offset = co - columns + 1;
-       }
-       // if the first char of the line is a tab, and "dot" is sitting on it
-       //  force offset to 0.
-       if (d == beg_cur && *d == '\t') {
-               offset = 0;
-       }
-       co -= offset;
-
-       *row = ro;
-       *col = co;
-}
-
-//----- Text Movement Routines ---------------------------------
-static Byte *begin_line(Byte * p) // return pointer to first char cur line
-{
-       while (p > text && p[-1] != '\n')
-               p--;                    // go to cur line B-o-l
-       return (p);
-}
-
-static Byte *end_line(Byte * p) // return pointer to NL of cur line line
-{
-       while (p < end - 1 && *p != '\n')
-               p++;                    // go to cur line E-o-l
-       return (p);
-}
-
-static Byte *dollar_line(Byte * p) // return pointer to just before NL line
-{
-       while (p < end - 1 && *p != '\n')
-               p++;                    // go to cur line E-o-l
-       // Try to stay off of the Newline
-       if (*p == '\n' && (p - begin_line(p)) > 0)
-               p--;
-       return (p);
-}
-
-static Byte *prev_line(Byte * p) // return pointer first char prev line
-{
-       p = begin_line(p);      // goto begining of cur line
-       if (p[-1] == '\n' && p > text)
-               p--;                    // step to prev line
-       p = begin_line(p);      // goto begining of prev line
-       return (p);
-}
-
-static Byte *next_line(Byte * p) // return pointer first char next line
-{
-       p = end_line(p);
-       if (*p == '\n' && p < end - 1)
-               p++;                    // step to next line
-       return (p);
-}
-
-//----- Text Information Routines ------------------------------
-static Byte *end_screen(void)
-{
-       Byte *q;
-       int cnt;
-
-       // find new bottom line
-       q = screenbegin;
-       for (cnt = 0; cnt < rows - 2; cnt++)
-               q = next_line(q);
-       q = end_line(q);
-       return (q);
-}
-
-static int count_lines(Byte * start, Byte * stop) // count line from start to stop
-{
-       Byte *q;
-       int cnt;
-
-       if (stop < start) {     // start and stop are backwards- reverse them
-               q = start;
-               start = stop;
-               stop = q;
-       }
-       cnt = 0;
-       stop = end_line(stop);  // get to end of this line
-       for (q = start; q <= stop && q <= end - 1; q++) {
-               if (*q == '\n')
-                       cnt++;
-       }
-       return (cnt);
-}
-
-static Byte *find_line(int li) // find begining of line #li
-{
-       Byte *q;
-
-       for (q = text; li > 1; li--) {
-               q = next_line(q);
-       }
-       return (q);
-}
-
-//----- Dot Movement Routines ----------------------------------
-static void dot_left(void)
-{
-       if (dot > text && dot[-1] != '\n')
-               dot--;
-}
-
-static void dot_right(void)
-{
-       if (dot < end - 1 && *dot != '\n')
-               dot++;
-}
-
-static void dot_begin(void)
-{
-       dot = begin_line(dot);  // return pointer to first char cur line
-}
-
-static void dot_end(void)
-{
-       dot = end_line(dot);    // return pointer to last char cur line
-}
-
-static Byte *move_to_col(Byte * p, int l)
-{
-       int co;
-
-       p = begin_line(p);
-       co = 0;
-       do {
-               if (*p == '\n' || *p == '\0')
-                       break;
-               if (*p == '\t') {
-                       //         7       - (co %    8  )
-                       co += ((tabstop - 1) - (co % tabstop));
-               } else if (*p < ' ') {
-                       co++;           // display as ^X, use 2 columns
-               }
-       } while (++co <= l && p++ < end);
-       return (p);
-}
-
-static void dot_next(void)
-{
-       dot = next_line(dot);
-}
-
-static void dot_prev(void)
-{
-       dot = prev_line(dot);
-}
-
-static void dot_scroll(int cnt, int dir)
-{
-       Byte *q;
-
-       for (; cnt > 0; cnt--) {
-               if (dir < 0) {
-                       // scroll Backwards
-                       // ctrl-Y  scroll up one line
-                       screenbegin = prev_line(screenbegin);
-               } else {
-                       // scroll Forwards
-                       // ctrl-E  scroll down one line
-                       screenbegin = next_line(screenbegin);
-               }
-       }
-       // make sure "dot" stays on the screen so we dont scroll off
-       if (dot < screenbegin)
-               dot = screenbegin;
-       q = end_screen();       // find new bottom line
-       if (dot > q)
-               dot = begin_line(q);    // is dot is below bottom line?
-       dot_skip_over_ws();
-}
-
-static void dot_skip_over_ws(void)
-{
-       // skip WS
-       while (isspace(*dot) && *dot != '\n' && dot < end - 1)
-               dot++;
-}
-
-static void dot_delete(void)   // delete the char at 'dot'
-{
-       (void) text_hole_delete(dot, dot);
-}
-
-static Byte *bound_dot(Byte * p) // make sure  text[0] <= P < "end"
-{
-       if (p >= end && end > text) {
-               p = end - 1;
-               indicate_error('1');
-       }
-       if (p < text) {
-               p = text;
-               indicate_error('2');
-       }
-       return (p);
-}
-
-//----- Helper Utility Routines --------------------------------
-
-//----------------------------------------------------------------
-//----- Char Routines --------------------------------------------
-/* Chars that are part of a word-
- *    0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
- * Chars that are Not part of a word (stoppers)
- *    !"#$%&'()*+,-./:;<=>?@[\]^`{|}~
- * Chars that are WhiteSpace
- *    TAB NEWLINE VT FF RETURN SPACE
- * DO NOT COUNT NEWLINE AS WHITESPACE
- */
-
-static Byte *new_screen(int ro, int co)
-{
-       int li;
-
-       if (screen != 0)
-               free(screen);
-       screensize = ro * co + 8;
-       screen = (Byte *) malloc(screensize);
-       // initialize the new screen. assume this will be a empty file.
-       screen_erase();
-       //   non-existant text[] lines start with a tilde (~).
-       for (li = 1; li < ro - 1; li++) {
-               screen[(li * co) + 0] = '~';
-       }
-       return (screen);
-}
-
-static Byte *new_text(int size)
-{
-       if (size < 10240)
-               size = 10240;   // have a minimum size for new files
-       if (text != 0) {
-               //text -= 4;
-               free(text);
-       }
-       text = (Byte *) malloc(size + 8);
-       memset(text, '\0', size);       // clear new text[]
-       //text += 4;            // leave some room for "oops"
-       textend = text + size - 1;
-       //textend -= 4;         // leave some root for "oops"
-       return (text);
-}
-
-#ifdef BB_FEATURE_VI_SEARCH
-static int mycmp(Byte * s1, Byte * s2, int len)
-{
-       int i;
-
-       i = strncmp((char *) s1, (char *) s2, len);
-#ifdef BB_FEATURE_VI_SETOPTS
-       if (ignorecase) {
-               i = strncasecmp((char *) s1, (char *) s2, len);
-       }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-       return (i);
-}
-
-static Byte *char_search(Byte * p, Byte * pat, int dir, int range)     // search for pattern starting at p
-{
-#ifndef REGEX_SEARCH
-       Byte *start, *stop;
-       int len;
-
-       len = strlen((char *) pat);
-       if (dir == FORWARD) {
-               stop = end - 1; // assume range is p - end-1
-               if (range == LIMITED)
-                       stop = next_line(p);    // range is to next line
-               for (start = p; start < stop; start++) {
-                       if (mycmp(start, pat, len) == 0) {
-                               return (start);
-                       }
-               }
-       } else if (dir == BACK) {
-               stop = text;    // assume range is text - p
-               if (range == LIMITED)
-                       stop = prev_line(p);    // range is to prev line
-               for (start = p - len; start >= stop; start--) {
-                       if (mycmp(start, pat, len) == 0) {
-                               return (start);
-                       }
-               }
-       }
-       // pattern not found
-       return (NULL);
-#else                                                  /*REGEX_SEARCH */
-       char *q;
-       struct re_pattern_buffer preg;
-       int i;
-       int size, range;
-
-       re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
-       preg.translate = 0;
-       preg.fastmap = 0;
-       preg.buffer = 0;
-       preg.allocated = 0;
-
-       // assume a LIMITED forward search
-       q = next_line(p);
-       q = end_line(q);
-       q = end - 1;
-       if (dir == BACK) {
-               q = prev_line(p);
-               q = text;
-       }
-       // count the number of chars to search over, forward or backward
-       size = q - p;
-       if (size < 0)
-               size = p - q;
-       // RANGE could be negative if we are searching backwards
-       range = q - p;
-
-       q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg);
-       if (q != 0) {
-               // The pattern was not compiled
-               psbs("bad search pattern: \"%s\": %s", pat, q);
-               i = 0;                  // return p if pattern not compiled
-               goto cs1;
-       }
-
-       q = p;
-       if (range < 0) {
-               q = p - size;
-               if (q < text)
-                       q = text;
-       }
-       // search for the compiled pattern, preg, in p[]
-       // range < 0-  search backward
-       // range > 0-  search forward
-       // 0 < start < size
-       // re_search() < 0  not found or error
-       // re_search() > 0  index of found pattern
-       //            struct pattern    char     int    int    int     struct reg
-       // re_search (*pattern_buffer,  *string, size,  start, range,  *regs)
-       i = re_search(&preg, q, size, 0, range, 0);
-       if (i == -1) {
-               p = 0;
-               i = 0;                  // return NULL if pattern not found
-       }
-  cs1:
-       if (dir == FORWARD) {
-               p = p + i;
-       } else {
-               p = p - i;
-       }
-       return (p);
-#endif                                                 /*REGEX_SEARCH */
-}
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
-{
-       if (c == 22) {          // Is this an ctrl-V?
-               p = stupid_insert(p, '^');      // use ^ to indicate literal next
-               p--;                    // backup onto ^
-               refresh(FALSE); // show the ^
-               c = get_one_char();
-               *p = c;
-               p++;
-               file_modified = TRUE;   // has the file been modified
-       } else if (c == 27) {   // Is this an ESC?
-               cmd_mode = 0;
-               cmdcnt = 0;
-               end_cmd_q();    // stop adding to q
-               strcpy((char *) status_buffer, " ");    // clear the status buffer
-               if ((p[-1] != '\n') && (dot>text)) {
-                       p--;
-               }
-       } else if (c == erase_char) {   // Is this a BS
-               //     123456789
-               if ((p[-1] != '\n') && (dot>text)) {
-                       p--;
-                       p = text_hole_delete(p, p);     // shrink buffer 1 char
-#ifdef BB_FEATURE_VI_DOT_CMD
-                       // also rmove char from last_modifying_cmd
-                       if (strlen((char *) last_modifying_cmd) > 0) {
-                               Byte *q;
-
-                               q = last_modifying_cmd;
-                               q[strlen((char *) q) - 1] = '\0';       // erase BS
-                               q[strlen((char *) q) - 1] = '\0';       // erase prev char
-                       }
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               }
-       } else {
-               // insert a char into text[]
-               Byte *sp;               // "save p"
-
-               if (c == 13)
-                       c = '\n';       // translate \r to \n
-               sp = p;                 // remember addr of insert
-               p = stupid_insert(p, c);        // insert the char
-#ifdef BB_FEATURE_VI_SETOPTS
-               if (showmatch && strchr(")]}", *sp) != NULL) {
-                       showmatching(sp);
-               }
-               if (autoindent && c == '\n') {  // auto indent the new line
-                       Byte *q;
-
-                       q = prev_line(p);       // use prev line as templet
-                       for (; isblnk(*q); q++) {
-                               p = stupid_insert(p, *q);       // insert the char
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-       }
-       return (p);
-}
-
-static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p'
-{
-       p = text_hole_make(p, 1);
-       if (p != 0) {
-               *p = c;
-               file_modified = TRUE;   // has the file been modified
-               p++;
-       }
-       return (p);
-}
-
-static Byte find_range(Byte ** start, Byte ** stop, Byte c)
-{
-       Byte *save_dot, *p, *q;
-       int cnt;
-
-       save_dot = dot;
-       p = q = dot;
-
-       if (strchr("cdy><", c)) {
-               // these cmds operate on whole lines
-               p = q = begin_line(p);
-               for (cnt = 1; cnt < cmdcnt; cnt++) {
-                       q = next_line(q);
-               }
-               q = end_line(q);
-       } else if (strchr("^%$0bBeEft", c)) {
-               // These cmds operate on char positions
-               do_cmd(c);              // execute movement cmd
-               q = dot;
-       } else if (strchr("wW", c)) {
-               do_cmd(c);              // execute movement cmd
-               if (dot > text)
-                       dot--;          // move back off of next word
-               if (dot > text && *dot == '\n')
-                       dot--;          // stay off NL
-               q = dot;
-       } else if (strchr("H-k{", c)) {
-               // these operate on multi-lines backwards
-               q = end_line(dot);      // find NL
-               do_cmd(c);              // execute movement cmd
-               dot_begin();
-               p = dot;
-       } else if (strchr("L+j}\r\n", c)) {
-               // these operate on multi-lines forwards
-               p = begin_line(dot);
-               do_cmd(c);              // execute movement cmd
-               dot_end();              // find NL
-               q = dot;
-       } else {
-               c = 27;                 // error- return an ESC char
-               //break;
-       }
-       *start = p;
-       *stop = q;
-       if (q < p) {
-               *start = q;
-               *stop = p;
-       }
-       dot = save_dot;
-       return (c);
-}
-
-static int st_test(Byte * p, int type, int dir, Byte * tested)
-{
-       Byte c, c0, ci;
-       int test, inc;
-
-       inc = dir;
-       c = c0 = p[0];
-       ci = p[inc];
-       test = 0;
-
-       if (type == S_BEFORE_WS) {
-               c = ci;
-               test = ((!isspace(c)) || c == '\n');
-       }
-       if (type == S_TO_WS) {
-               c = c0;
-               test = ((!isspace(c)) || c == '\n');
-       }
-       if (type == S_OVER_WS) {
-               c = c0;
-               test = ((isspace(c)));
-       }
-       if (type == S_END_PUNCT) {
-               c = ci;
-               test = ((ispunct(c)));
-       }
-       if (type == S_END_ALNUM) {
-               c = ci;
-               test = ((isalnum(c)) || c == '_');
-       }
-       *tested = c;
-       return (test);
-}
-
-static Byte *skip_thing(Byte * p, int linecnt, int dir, int type)
-{
-       Byte c;
-
-       while (st_test(p, type, dir, &c)) {
-               // make sure we limit search to correct number of lines
-               if (c == '\n' && --linecnt < 1)
-                       break;
-               if (dir >= 0 && p >= end - 1)
-                       break;
-               if (dir < 0 && p <= text)
-                       break;
-               p += dir;               // move to next char
-       }
-       return (p);
-}
-
-// find matching char of pair  ()  []  {}
-static Byte *find_pair(Byte * p, Byte c)
-{
-       Byte match, *q;
-       int dir, level;
-
-       match = ')';
-       level = 1;
-       dir = 1;                        // assume forward
-       switch (c) {
-       case '(':
-               match = ')';
-               break;
-       case '[':
-               match = ']';
-               break;
-       case '{':
-               match = '}';
-               break;
-       case ')':
-               match = '(';
-               dir = -1;
-               break;
-       case ']':
-               match = '[';
-               dir = -1;
-               break;
-       case '}':
-               match = '{';
-               dir = -1;
-               break;
-       }
-       for (q = p + dir; text <= q && q < end; q += dir) {
-               // look for match, count levels of pairs  (( ))
-               if (*q == c)
-                       level++;        // increase pair levels
-               if (*q == match)
-                       level--;        // reduce pair level
-               if (level == 0)
-                       break;          // found matching pair
-       }
-       if (level != 0)
-               q = NULL;               // indicate no match
-       return (q);
-}
-
-#ifdef BB_FEATURE_VI_SETOPTS
-// show the matching char of a pair,  ()  []  {}
-static void showmatching(Byte * p)
-{
-       Byte *q, *save_dot;
-
-       // we found half of a pair
-       q = find_pair(p, *p);   // get loc of matching char
-       if (q == NULL) {
-               indicate_error('3');    // no matching char
-       } else {
-               // "q" now points to matching pair
-               save_dot = dot; // remember where we are
-               dot = q;                // go to new loc
-               refresh(FALSE); // let the user see it
-               (void) mysleep(40);     // give user some time
-               dot = save_dot; // go back to old loc
-               refresh(FALSE);
-       }
-}
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-
-//  open a hole in text[]
-static Byte *text_hole_make(Byte * p, int size)        // at "p", make a 'size' byte hole
-{
-       Byte *src, *dest;
-       int cnt;
-
-       if (size <= 0)
-               goto thm0;
-       src = p;
-       dest = p + size;
-       cnt = end - src;        // the rest of buffer
-       if (memmove(dest, src, cnt) != dest) {
-               psbs("can't create room for new characters");
-       }
-       memset(p, ' ', size);   // clear new hole
-       end = end + size;       // adjust the new END
-       file_modified = TRUE;   // has the file been modified
-  thm0:
-       return (p);
-}
-
-//  close a hole in text[]
-static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive
-{
-       Byte *src, *dest;
-       int cnt, hole_size;
-
-       // move forwards, from beginning
-       // assume p <= q
-       src = q + 1;
-       dest = p;
-       if (q < p) {            // they are backward- swap them
-               src = p + 1;
-               dest = q;
-       }
-       hole_size = q - p + 1;
-       cnt = end - src;
-       if (src < text || src > end)
-               goto thd0;
-       if (dest < text || dest >= end)
-               goto thd0;
-       if (src >= end)
-               goto thd_atend; // just delete the end of the buffer
-       if (memmove(dest, src, cnt) != dest) {
-               psbs("can't delete the character");
-       }
-  thd_atend:
-       end = end - hole_size;  // adjust the new END
-       if (dest >= end)
-               dest = end - 1; // make sure dest in below end-1
-       if (end <= text)
-               dest = end = text;      // keep pointers valid
-       file_modified = TRUE;   // has the file been modified
-  thd0:
-       return (dest);
-}
-
-// copy text into register, then delete text.
-// if dist <= 0, do not include, or go past, a NewLine
-//
-static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
-{
-       Byte *p;
-
-       // make sure start <= stop
-       if (start > stop) {
-               // they are backwards, reverse them
-               p = start;
-               start = stop;
-               stop = p;
-       }
-       if (dist <= 0) {
-               // we can not cross NL boundaries
-               p = start;
-               if (*p == '\n')
-                       return (p);
-               // dont go past a NewLine
-               for (; p + 1 <= stop; p++) {
-                       if (p[1] == '\n') {
-                               stop = p;       // "stop" just before NewLine
-                               break;
-                       }
-               }
-       }
-       p = start;
-#ifdef BB_FEATURE_VI_YANKMARK
-       text_yank(start, stop, YDreg);
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       if (yf == YANKDEL) {
-               p = text_hole_delete(start, stop);
-       }                                       // delete lines
-       return (p);
-}
-
-static void show_help(void)
-{
-       puts("These features are available:"
-#ifdef BB_FEATURE_VI_SEARCH
-       "\n\tPattern searches with / and ?"
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-#ifdef BB_FEATURE_VI_DOT_CMD
-       "\n\tLast command repeat with \'.\'"
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_YANKMARK
-       "\n\tLine marking with  'x"
-       "\n\tNamed buffers with  \"x"
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_READONLY
-       "\n\tReadonly if vi is called as \"view\""
-       "\n\tReadonly with -R command line arg"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SET
-       "\n\tSome colon mode commands with \':\'"
-#endif                                                 /* BB_FEATURE_VI_SET */
-#ifdef BB_FEATURE_VI_SETOPTS
-       "\n\tSettable options with \":set\""
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       "\n\tSignal catching- ^C"
-       "\n\tJob suspend and resume with ^Z"
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       "\n\tAdapt to window re-sizes"
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       );
-}
-
-static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
-{
-       Byte c, b[2];
-
-       b[1] = '\0';
-       strcpy((char *) buf, "");       // init buf
-       if (strlen((char *) s) <= 0)
-               s = (Byte *) "(NULL)";
-       for (; *s > '\0'; s++) {
-               c = *s;
-               if (*s > '~') {
-                       strcat((char *) buf, SOs);
-                       c = *s - 128;
-               }
-               if (*s < ' ') {
-                       strcat((char *) buf, "^");
-                       c += '@';
-               }
-               b[0] = c;
-               strcat((char *) buf, (char *) b);
-               if (*s > '~')
-                       strcat((char *) buf, SOn);
-               if (*s == '\n') {
-                       strcat((char *) buf, "$");
-               }
-       }
-}
-
-#ifdef BB_FEATURE_VI_DOT_CMD
-static void start_new_cmd_q(Byte c)
-{
-       // release old cmd
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
-       // get buffer for new cmd
-       last_modifying_cmd = (Byte *) malloc(BUFSIZ);
-       memset(last_modifying_cmd, '\0', BUFSIZ);       // clear new cmd queue
-       // if there is a current cmd count put it in the buffer first
-       if (cmdcnt > 0)
-               sprintf((char *) last_modifying_cmd, "%d", cmdcnt);
-       // save char c onto queue
-       last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
-       adding2q = 1;
-       return;
-}
-
-static void end_cmd_q()
-{
-#ifdef BB_FEATURE_VI_YANKMARK
-       YDreg = 26;                     // go back to default Yank/Delete reg
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       adding2q = 0;
-       return;
-}
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-
-#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
-static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
-{
-       int cnt, i;
-
-       i = strlen((char *) s);
-       p = text_hole_make(p, i);
-       strncpy((char *) p, (char *) s, i);
-       for (cnt = 0; *s != '\0'; s++) {
-               if (*s == '\n')
-                       cnt++;
-       }
-#ifdef BB_FEATURE_VI_YANKMARK
-       psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       return (p);
-}
-#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
-
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *text_yank(Byte * p, Byte * q, int dest)   // copy text into a register
-{
-       Byte *t;
-       int cnt;
-
-       if (q < p) {            // they are backwards- reverse them
-               t = q;
-               q = p;
-               p = t;
-       }
-       cnt = q - p + 1;
-       t = reg[dest];
-       if (t != 0) {           // if already a yank register
-               free(t);                //   free it
-       }
-       t = (Byte *) malloc(cnt + 1);   // get a new register
-       memset(t, '\0', cnt + 1);       // clear new text[]
-       strncpy((char *) t, (char *) p, cnt);   // copy text[] into bufer
-       reg[dest] = t;
-       return (p);
-}
-
-static Byte what_reg(void)
-{
-       Byte c;
-       int i;
-
-       i = 0;
-       c = 'D';                        // default to D-reg
-       if (0 <= YDreg && YDreg <= 25)
-               c = 'a' + (Byte) YDreg;
-       if (YDreg == 26)
-               c = 'D';
-       if (YDreg == 27)
-               c = 'U';
-       return (c);
-}
-
-static void check_context(Byte cmd)
-{
-       // A context is defined to be "modifying text"
-       // Any modifying command establishes a new context.
-
-       if (dot < context_start || dot > context_end) {
-               if (strchr((char *) modifying_cmds, cmd) != NULL) {
-                       // we are trying to modify text[]- make this the current context
-                       mark[27] = mark[26];    // move cur to prev
-                       mark[26] = dot; // move local to cur
-                       context_start = prev_line(prev_line(dot));
-                       context_end = next_line(next_line(dot));
-                       //loiter= start_loiter= now;
-               }
-       }
-       return;
-}
-
-static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
-{
-       Byte *tmp;
-
-       // the current context is in mark[26]
-       // the previous context is in mark[27]
-       // only swap context if other context is valid
-       if (text <= mark[27] && mark[27] <= end - 1) {
-               tmp = mark[27];
-               mark[27] = mark[26];
-               mark[26] = tmp;
-               p = mark[26];   // where we are going- previous context
-               context_start = prev_line(prev_line(prev_line(p)));
-               context_end = next_line(next_line(next_line(p)));
-       }
-       return (p);
-}
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-static int isblnk(Byte c) // is the char a blank or tab
-{
-       return (c == ' ' || c == '\t');
-}
-
-//----- Set terminal attributes --------------------------------
-static void rawmode(void)
-{
-       tcgetattr(0, &term_orig);
-       term_vi = term_orig;
-       term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG ON- allow intr's
-       term_vi.c_iflag &= (~IXON & ~ICRNL);
-       term_vi.c_oflag &= (~ONLCR);
-#ifndef linux
-       term_vi.c_cc[VMIN] = 1;
-       term_vi.c_cc[VTIME] = 0;
-#endif
-       erase_char = term_vi.c_cc[VERASE];
-       tcsetattr(0, TCSANOW, &term_vi);
-}
-
-static void cookmode(void)
-{
-       tcsetattr(0, TCSANOW, &term_orig);
-}
-
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-//----- See what the window size currently is --------------------
-static void window_size_get(int sig)
-{
-       int i;
-
-       i = ioctl(0, TIOCGWINSZ, &winsize);
-       if (i != 0) {
-               // force 24x80
-               winsize.ws_row = 24;
-               winsize.ws_col = 80;
-       }
-       if (winsize.ws_row <= 1) {
-               winsize.ws_row = 24;
-       }
-       if (winsize.ws_col <= 1) {
-               winsize.ws_col = 80;
-       }
-       rows = (int) winsize.ws_row;
-       columns = (int) winsize.ws_col;
-}
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-
-//----- Come here when we get a window resize signal ---------
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static void winch_sig(int sig)
-{
-       signal(SIGWINCH, winch_sig);
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       new_screen(rows, columns);      // get memory for virtual screen
-       redraw(TRUE);           // re-draw the screen
-}
-
-//----- Come here when we get a continue signal -------------------
-static void cont_sig(int sig)
-{
-       rawmode();                      // terminal to "raw"
-       *status_buffer = '\0';  // clear the status buffer
-       redraw(TRUE);           // re-draw the screen
-
-       signal(SIGTSTP, suspend_sig);
-       signal(SIGCONT, SIG_DFL);
-       kill(getpid(), SIGCONT);
-}
-
-//----- Come here when we get a Suspend signal -------------------
-static void suspend_sig(int sig)
-{
-       place_cursor(rows - 1, 0, FALSE);       // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
-       cookmode();                     // terminal to "cooked"
-
-       signal(SIGCONT, cont_sig);
-       signal(SIGTSTP, SIG_DFL);
-       kill(getpid(), SIGTSTP);
-}
-
-//----- Come here when we get a signal ---------------------------
-static void catch_sig(int sig)
-{
-       signal(SIGHUP, catch_sig);
-       signal(SIGINT, catch_sig);
-       signal(SIGTERM, catch_sig);
-       longjmp(restart, sig);
-}
-
-static void alarm_sig(int sig)
-{
-       signal(SIGALRM, catch_sig);
-       longjmp(restart, sig);
-}
-
-//----- Come here when we get a core dump signal -----------------
-static void core_sig(int sig)
-{
-       signal(SIGQUIT, core_sig);
-       signal(SIGILL, core_sig);
-       signal(SIGTRAP, core_sig);
-       signal(SIGIOT, core_sig);
-       signal(SIGABRT, core_sig);
-       signal(SIGFPE, core_sig);
-       signal(SIGBUS, core_sig);
-       signal(SIGSEGV, core_sig);
-#ifdef SIGSYS
-       signal(SIGSYS, core_sig);
-#endif
-
-       dot = bound_dot(dot);   // make sure "dot" is valid
-
-       longjmp(restart, sig);
-}
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-
-static int mysleep(int hund)   // sleep for 'h' 1/100 seconds
-{
-       // Don't hang- Wait 5/100 seconds-  1 Sec= 1000000
-       FD_ZERO(&rfds);
-       FD_SET(0, &rfds);
-       tv.tv_sec = 0;
-       tv.tv_usec = hund * 10000;
-       select(1, &rfds, NULL, NULL, &tv);
-       return (FD_ISSET(0, &rfds));
-}
-
-//----- IO Routines --------------------------------------------
-static Byte readit(void)       // read (maybe cursor) key from stdin
-{
-       Byte c;
-       int i, bufsiz, cnt, cmdindex;
-       struct esc_cmds {
-               Byte *seq;
-               Byte val;
-       };
-
-       static struct esc_cmds esccmds[] = {
-               {(Byte *) "\eOA", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\eOB", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\eOC", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\eOD", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\eOH", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\eOF", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[A", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\e[B", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\e[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\e[D", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\e[H", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\e[F", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
-               {(Byte *) "\e[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
-               {(Byte *) "\e[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
-               {(Byte *) "\eOP", (Byte) VI_K_FUN1},     // Function Key F1
-               {(Byte *) "\eOQ", (Byte) VI_K_FUN2},     // Function Key F2
-               {(Byte *) "\eOR", (Byte) VI_K_FUN3},     // Function Key F3
-               {(Byte *) "\eOS", (Byte) VI_K_FUN4},     // Function Key F4
-               {(Byte *) "\e[15~", (Byte) VI_K_FUN5},   // Function Key F5
-               {(Byte *) "\e[17~", (Byte) VI_K_FUN6},   // Function Key F6
-               {(Byte *) "\e[18~", (Byte) VI_K_FUN7},   // Function Key F7
-               {(Byte *) "\e[19~", (Byte) VI_K_FUN8},   // Function Key F8
-               {(Byte *) "\e[20~", (Byte) VI_K_FUN9},   // Function Key F9
-               {(Byte *) "\e[21~", (Byte) VI_K_FUN10},  // Function Key F10
-               {(Byte *) "\e[23~", (Byte) VI_K_FUN11},  // Function Key F11
-               {(Byte *) "\e[24~", (Byte) VI_K_FUN12},  // Function Key F12
-               {(Byte *) "\e[11~", (Byte) VI_K_FUN1},   // Function Key F1
-               {(Byte *) "\e[12~", (Byte) VI_K_FUN2},   // Function Key F2
-               {(Byte *) "\e[13~", (Byte) VI_K_FUN3},   // Function Key F3
-               {(Byte *) "\e[14~", (Byte) VI_K_FUN4},   // Function Key F4
-       };
-
-#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
-
-       (void) alarm(0);        // turn alarm OFF while we wait for input
-       // get input from User- are there already input chars in Q?
-       bufsiz = strlen((char *) readbuffer);
-       if (bufsiz <= 0) {
-         ri0:
-               // the Q is empty, wait for a typed char
-               bufsiz = read(0, readbuffer, BUFSIZ - 1);
-               if (bufsiz < 0) {
-                       if (errno == EINTR)
-                               goto ri0;       // interrupted sys call
-                       if (errno == EBADF)
-                               editing = 0;
-                       if (errno == EFAULT)
-                               editing = 0;
-                       if (errno == EINVAL)
-                               editing = 0;
-                       if (errno == EIO)
-                               editing = 0;
-                       errno = 0;
-                       bufsiz = 0;
-               }
-               readbuffer[bufsiz] = '\0';
-       }
-       // return char if it is not part of ESC sequence
-       if (readbuffer[0] != 27)
-               goto ri1;
-
-       // This is an ESC char. Is this Esc sequence?
-       // Could be bare Esc key. See if there are any
-       // more chars to read after the ESC. This would
-       // be a Function or Cursor Key sequence.
-       FD_ZERO(&rfds);
-       FD_SET(0, &rfds);
-       tv.tv_sec = 0;
-       tv.tv_usec = 50000;     // Wait 5/100 seconds- 1 Sec=1000000
-
-       // keep reading while there are input chars and room in buffer
-       while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
-               // read the rest of the ESC string
-               i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz);
-               if (i > 0) {
-                       bufsiz += i;
-                       readbuffer[bufsiz] = '\0';      // Terminate the string
-               }
-       }
-       // Maybe cursor or function key?
-       for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) {
-               cnt = strlen((char *) esccmds[cmdindex].seq);
-               i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt);
-               if (i == 0) {
-                       // is a Cursor key- put derived value back into Q
-                       readbuffer[0] = esccmds[cmdindex].val;
-                       // squeeze out the ESC sequence
-                       for (i = 1; i < cnt; i++) {
-                               memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2);
-                               readbuffer[BUFSIZ - 1] = '\0';
-                       }
-                       break;
-               }
-       }
-  ri1:
-       c = readbuffer[0];
-       // remove one char from Q
-       memmove(readbuffer, readbuffer + 1, BUFSIZ - 1);
-       readbuffer[BUFSIZ - 1] = '\0';
-       (void) alarm(3);        // we are done waiting for input, turn alarm ON
-       return (c);
-}
-
-//----- IO Routines --------------------------------------------
-static Byte get_one_char()
-{
-       static Byte c;
-
-#ifdef BB_FEATURE_VI_DOT_CMD
-       // ! adding2q  && ioq == 0  read()
-       // ! adding2q  && ioq != 0  *ioq
-       // adding2q         *last_modifying_cmd= read()
-       if (!adding2q) {
-               // we are not adding to the q.
-               // but, we may be reading from a q
-               if (ioq == 0) {
-                       // there is no current q, read from STDIN
-                       c = readit();   // get the users input
-               } else {
-                       // there is a queue to get chars from first
-                       c = *ioq++;
-                       if (c == '\0') {
-                               // the end of the q, read from STDIN
-                               free(ioq_start);
-                               ioq_start = ioq = 0;
-                               c = readit();   // get the users input
-                       }
-               }
-       } else {
-               // adding STDIN chars to q
-               c = readit();   // get the users input
-               if (last_modifying_cmd != 0) {
-                       // add new char to q
-                       last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
-               }
-       }
-#else                                                  /* BB_FEATURE_VI_DOT_CMD */
-       c = readit();           // get the users input
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-       return (c);                     // return the char, where ever it came from
-}
-
-static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
-{
-       Byte buf[BUFSIZ];
-       Byte c;
-       int i;
-       static Byte *obufp = NULL;
-
-       strcpy((char *) buf, (char *) prompt);
-       *status_buffer = '\0';  // clear the status buffer
-       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-       clear_to_eol();         // clear the line
-       write(1, prompt, strlen((char *) prompt));      // write out the :, /, or ? prompt
-
-       for (i = strlen((char *) buf); i < BUFSIZ;) {
-               c = get_one_char();     // read user input
-               if (c == '\n' || c == '\r' || c == 27)
-                       break;          // is this end of input
-               if (c == erase_char) {  // user wants to erase prev char
-                       i--;            // backup to prev char
-                       buf[i] = '\0';  // erase the char
-                       buf[i + 1] = '\0';      // null terminate buffer
-                       write(1, "\b \b", 3);     // erase char on screen
-                       if (i <= 0) {   // user backs up before b-o-l, exit
-                               break;
-                       }
-               } else {
-                       buf[i] = c;     // save char in buffer
-                       buf[i + 1] = '\0';      // make sure buffer is null terminated
-                       write(1, buf + i, 1);   // echo the char back to user
-                       i++;
-               }
-       }
-       refresh(FALSE);
-       if (obufp != NULL)
-               free(obufp);
-       obufp = (Byte *) strdup((char *) buf);
-       return (obufp);
-}
-
-static int file_size(Byte * fn) // what is the byte size of "fn"
-{
-       struct stat st_buf;
-       int cnt, sr;
-
-       if (fn == 0 || strlen(fn) <= 0)
-               return (-1);
-       cnt = -1;
-       sr = stat((char *) fn, &st_buf);        // see if file exists
-       if (sr >= 0) {
-               cnt = (int) st_buf.st_size;
-       }
-       return (cnt);
-}
-
-static int file_insert(Byte * fn, Byte * p, int size)
-{
-       int fd, cnt;
-
-       cnt = -1;
-#ifdef BB_FEATURE_VI_READONLY
-       readonly = FALSE;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-       if (fn == 0 || strlen((char*) fn) <= 0) {
-               psbs("No filename given");
-               goto fi0;
-       }
-       if (size == 0) {
-               // OK- this is just a no-op
-               cnt = 0;
-               goto fi0;
-       }
-       if (size < 0) {
-               psbs("Trying to insert a negative number (%d) of characters", size);
-               goto fi0;
-       }
-       if (p < text || p > end) {
-               psbs("Trying to insert file outside of memory");
-               goto fi0;
-       }
-
-       // see if we can open the file
-#ifdef BB_FEATURE_VI_READONLY
-       if (vi_readonly == TRUE) goto fi1;              // do not try write-mode
-#endif
-       fd = open((char *) fn, O_RDWR);                 // assume read & write
-       if (fd < 0) {
-               // could not open for writing- maybe file is read only
-#ifdef BB_FEATURE_VI_READONLY
-  fi1:
-#endif
-               fd = open((char *) fn, O_RDONLY);       // try read-only
-               if (fd < 0) {
-                       psbs("\"%s\" %s", fn, "could not open file");
-                       goto fi0;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-               // got the file- read-only
-               readonly = TRUE;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-       }
-       p = text_hole_make(p, size);
-       cnt = read(fd, p, size);
-       close(fd);
-       if (cnt < 0) {
-               cnt = -1;
-               p = text_hole_delete(p, p + size - 1);  // un-do buffer insert
-               psbs("could not read file \"%s\"", fn);
-       } else if (cnt < size) {
-               // There was a partial read, shrink unused space text[]
-               p = text_hole_delete(p + cnt, p + (size - cnt) - 1);    // un-do buffer insert
-               psbs("could not read all of file \"%s\"", fn);
-       }
-       if (cnt >= size)
-               file_modified = TRUE;
-  fi0:
-       return (cnt);
-}
-
-static int file_write(Byte * fn, Byte * first, Byte * last)
-{
-       int fd, cnt, charcnt;
-
-       if (fn == 0) {
-               psbs("No current filename");
-               return (-1);
-       }
-       charcnt = 0;
-       // FIXIT- use the correct umask()
-       fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
-       if (fd < 0)
-               return (-1);
-       cnt = last - first + 1;
-       charcnt = write(fd, first, cnt);
-       if (charcnt == cnt) {
-               // good write
-               //file_modified= FALSE; // the file has not been modified
-       } else {
-               charcnt = 0;
-       }
-       close(fd);
-       return (charcnt);
-}
-
-//----- Terminal Drawing ---------------------------------------
-// The terminal is made up of 'rows' line of 'columns' columns.
-// classicly this would be 24 x 80.
-//  screen coordinates
-//  0,0     ...     0,79
-//  1,0     ...     1,79
-//  .       ...     .
-//  .       ...     .
-//  22,0    ...     22,79
-//  23,0    ...     23,79   status line
-//
-
-//----- Move the cursor to row x col (count from 0, not 1) -------
-static void place_cursor(int row, int col, int opti)
-{
-       char cm1[BUFSIZ];
-       char *cm;
-       int l;
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       char cm2[BUFSIZ];
-       Byte *screenp;
-       // char cm3[BUFSIZ];
-       int Rrow= last_row;
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-       
-       memset(cm1, '\0', BUFSIZ - 1);  // clear the buffer
-
-       if (row < 0) row = 0;
-       if (row >= rows) row = rows - 1;
-       if (col < 0) col = 0;
-       if (col >= columns) col = columns - 1;
-       
-       //----- 1.  Try the standard terminal ESC sequence
-       sprintf((char *) cm1, CMrc, row + 1, col + 1);
-       cm= cm1;
-       if (opti == FALSE) goto pc0;
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       //----- find the minimum # of chars to move cursor -------------
-       //----- 2.  Try moving with discreet chars (Newline, [back]space, ...)
-       memset(cm2, '\0', BUFSIZ - 1);  // clear the buffer
-       
-       // move to the correct row
-       while (row < Rrow) {
-               // the cursor has to move up
-               strcat(cm2, CMup);
-               Rrow--;
-       }
-       while (row > Rrow) {
-               // the cursor has to move down
-               strcat(cm2, CMdown);
-               Rrow++;
-       }
-       
-       // now move to the correct column
-       strcat(cm2, "\r");                      // start at col 0
-       // just send out orignal source char to get to correct place
-       screenp = &screen[row * columns];       // start of screen line
-       strncat(cm2, screenp, col);
-
-       //----- 3.  Try some other way of moving cursor
-       //---------------------------------------------
-
-       // pick the shortest cursor motion to send out
-       cm= cm1;
-       if (strlen(cm2) < strlen(cm)) {
-               cm= cm2;
-       }  /* else if (strlen(cm3) < strlen(cm)) {
-               cm= cm3;
-       } */
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-  pc0:
-       l= strlen(cm);
-       if (l) write(1, cm, l);                 // move the cursor
-}
-
-//----- Erase from cursor to end of line -----------------------
-static void clear_to_eol()
-{
-       write(1, Ceol, strlen(Ceol));   // Erase from cursor to end of line
-}
-
-//----- Erase from cursor to end of screen -----------------------
-static void clear_to_eos()
-{
-       write(1, Ceos, strlen(Ceos));   // Erase from cursor to end of screen
-}
-
-//----- Start standout mode ------------------------------------
-static void standout_start() // send "start reverse video" sequence
-{
-       write(1, SOs, strlen(SOs));     // Start reverse video mode
-}
-
-//----- End standout mode --------------------------------------
-static void standout_end() // send "end reverse video" sequence
-{
-       write(1, SOn, strlen(SOn));     // End reverse video mode
-}
-
-//----- Flash the screen  --------------------------------------
-static void flash(int h)
-{
-       standout_start();       // send "start reverse video" sequence
-       redraw(TRUE);
-       (void) mysleep(h);
-       standout_end();         // send "end reverse video" sequence
-       redraw(TRUE);
-}
-
-static void beep()
-{
-       write(1, bell, strlen(bell));   // send out a bell character
-}
-
-static void indicate_error(char c)
-{
-#ifdef BB_FEATURE_VI_CRASHME
-       if (crashme > 0)
-               return;                 // generate a random command
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       if (err_method == 0) {
-               beep();
-       } else {
-               flash(10);
-       }
-}
-
-//----- Screen[] Routines --------------------------------------
-//----- Erase the Screen[] memory ------------------------------
-static void screen_erase()
-{
-       memset(screen, ' ', screensize);        // clear new screen
-}
-
-//----- Draw the status line at bottom of the screen -------------
-static void show_status_line(void)
-{
-       static int last_cksum;
-       int l, cnt, cksum;
-
-       cnt = strlen((char *) status_buffer);
-       for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
-       // don't write the status line unless it changes
-       if (cnt > 0 && last_cksum != cksum) {
-               last_cksum= cksum;              // remember if we have seen this line
-               place_cursor(rows - 1, 0, FALSE);       // put cursor on status line
-               write(1, status_buffer, cnt);
-               clear_to_eol();
-               place_cursor(crow, ccol, FALSE);        // put cursor back in correct place
-       }
-}
-
-//----- format the status buffer, the bottom line of screen ------
-// print status buffer, with STANDOUT mode
-static void psbs(char *format, ...)
-{
-       va_list args;
-
-       va_start(args, format);
-       strcpy((char *) status_buffer, SOs);    // Terminal standout mode on
-       vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
-                        args);
-       strcat((char *) status_buffer, SOn);    // Terminal standout mode off
-       va_end(args);
-
-       return;
-}
-
-// print status buffer
-static void psb(char *format, ...)
-{
-       va_list args;
-
-       va_start(args, format);
-       vsprintf((char *) status_buffer, format, args);
-       va_end(args);
-       return;
-}
-
-static void ni(Byte * s) // display messages
-{
-       Byte buf[BUFSIZ];
-
-       print_literal(buf, s);
-       psbs("\'%s\' is not implemented", buf);
-}
-
-static void edit_status(void)  // show file status on status line
-{
-       int cur, tot, percent;
-
-       cur = count_lines(text, dot);
-       tot = count_lines(text, end - 1);
-       //    current line         percent
-       //   -------------    ~~ ----------
-       //    total lines            100
-       if (tot > 0) {
-               percent = (100 * cur) / tot;
-       } else {
-               cur = tot = 0;
-               percent = 100;
-       }
-       psb("\"%s\""
-#ifdef BB_FEATURE_VI_READONLY
-               "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               "%s line %d of %d --%d%%--",
-               (cfn != 0 ? (char *) cfn : "No file"),
-#ifdef BB_FEATURE_VI_READONLY
-               ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               (file_modified == TRUE ? " [modified]" : ""),
-               cur, tot, percent);
-}
-
-//----- Force refresh of all Lines -----------------------------
-static void redraw(int full_screen)
-{
-       place_cursor(0, 0, FALSE);      // put cursor in correct place
-       clear_to_eos();         // tel terminal to erase display
-       screen_erase();         // erase the internal screen buffer
-       refresh(full_screen);   // this will redraw the entire display
-}
-
-//----- Format a text[] line into a buffer ---------------------
-static void format_line(Byte *dest, Byte *src, int li)
-{
-       int co;
-       Byte c;
-       
-       for (co= 0; co < MAX_SCR_COLS; co++) {
-               c= ' ';         // assume blank
-               if (li > 0 && co == 0) {
-                       c = '~';        // not first line, assume Tilde
-               }
-               // are there chars in text[] and have we gone past the end
-               if (text < end && src < end) {
-                       c = *src++;
-               }
-               if (c == '\n')
-                       break;
-               if (c < ' ' || c > '~') {
-                       if (c == '\t') {
-                               c = ' ';
-                               //       co %    8     !=     7
-                               for (; (co % tabstop) != (tabstop - 1); co++) {
-                                       dest[co] = c;
-                               }
-                       } else {
-                               dest[co++] = '^';
-                               c |= '@';       // make it visible
-                               c &= 0x7f;      // get rid of hi bit
-                       }
-               }
-               // the co++ is done here so that the column will
-               // not be overwritten when we blank-out the rest of line
-               dest[co] = c;
-               if (src >= end)
-                       break;
-       }
-}
-
-//----- Refresh the changed screen lines -----------------------
-// Copy the source line from text[] into the buffer and note
-// if the current screenline is different from the new buffer.
-// If they differ then that line needs redrawing on the terminal.
-//
-static void refresh(int full_screen)
-{
-       static int old_offset;
-       int li, changed;
-       Byte buf[MAX_SCR_COLS];
-       Byte *tp, *sp;          // pointer into text[] and screen[]
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       int last_li= -2;                                // last line that changed- for optimizing cursor movement
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
-       tp = screenbegin;       // index into text[] of top line
-
-       // compare text[] to screen[] and mark screen[] lines that need updating
-       for (li = 0; li < rows - 1; li++) {
-               int cs, ce;                             // column start & end
-               memset(buf, ' ', MAX_SCR_COLS);         // blank-out the buffer
-               buf[MAX_SCR_COLS-1] = 0;                // NULL terminate the buffer
-               // format current text line into buf
-               format_line(buf, tp, li);
-
-               // skip to the end of the current text[] line
-               while (tp < end && *tp++ != '\n') /*no-op*/ ;
-
-               // see if there are any changes between vitual screen and buf
-               changed = FALSE;        // assume no change
-               cs= 0;
-               ce= columns-1;
-               sp = &screen[li * columns];     // start of screen line
-               if (full_screen == TRUE) {
-                       // force re-draw of every single column from 0 - columns-1
-                       goto re0;
-               }
-               // compare newly formatted buffer with virtual screen
-               // look forward for first difference between buf and screen
-               for ( ; cs <= ce; cs++) {
-                       if (buf[cs + offset] != sp[cs]) {
-                               changed = TRUE; // mark for redraw
-                               break;
-                       }
-               }
-
-               // look backward for last difference between buf and screen
-               for ( ; ce >= cs; ce--) {
-                       if (buf[ce + offset] != sp[ce]) {
-                               changed = TRUE; // mark for redraw
-                               break;
-                       }
-               }
-               // now, cs is index of first diff, and ce is index of last diff
-
-               // if horz offset has changed, force a redraw
-               if (offset != old_offset) {
-  re0:
-                       changed = TRUE;
-               }
-
-               // make a sanity check of columns indexes
-               if (cs < 0) cs= 0;
-               if (ce > columns-1) ce= columns-1;
-               if (cs > ce) {  cs= 0;  ce= columns-1;  }
-               // is there a change between vitual screen and buf
-               if (changed == TRUE) {
-                       //  copy changed part of buffer to virtual screen
-                       memmove(sp+cs, buf+(cs+offset), ce-cs+1);
-
-                       // move cursor to column of first change
-                       if (offset != old_offset) {
-                               // opti_cur_move is still too stupid
-                               // to handle offsets correctly
-                               place_cursor(li, cs, FALSE);
-                       } else {
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-                               // if this just the next line
-                               //  try to optimize cursor movement
-                               //  otherwise, use standard ESC sequence
-                               place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
-                               last_li= li;
-#else                                                  /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-                               place_cursor(li, cs, FALSE);    // use standard ESC sequence
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-                       }
-
-                       // write line out to terminal
-                       write(1, sp+cs, ce-cs+1);
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-                       last_row = li;
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-               }
-       }
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
-       last_row = crow;
-#else
-       place_cursor(crow, ccol, FALSE);
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-       
-       if (offset != old_offset)
-               old_offset = offset;
-}
diff --git a/busybox/env.c b/busybox/env.c
deleted file mode 100644 (file)
index 8bb690b..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * env implementation for busybox
- *
- * Copyright (c) 1988, 1993, 1994
- *     The Regents of the University of California.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
- *
- * Modified for BusyBox by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int env_main(int argc, char** argv)
-{
-       char **ep, *p;
-       char *cleanenv[1];
-       int ignore_environment = 0;
-       int ch;
-
-       while ((ch = getopt(argc, argv, "+iu:")) != -1) {
-               switch(ch) {
-               case 'i':
-                       ignore_environment = 1;
-                       break;
-               case 'u':
-                       unsetenv(optarg);
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-       if (optind != argc && !strcmp(argv[optind], "-")) {
-               ignore_environment = 1;
-               argv++;
-       }
-       if (ignore_environment) {
-               environ = cleanenv;
-               cleanenv[0] = NULL;
-       }
-       for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
-               if (putenv(*argv) < 0)
-                       perror_msg_and_die("%s", *argv);
-       if (*argv) {
-               execvp(*argv, argv);
-               perror_msg_and_die("%s", *argv);
-       }
-       for (ep = environ; *ep; ep++)
-               puts(*ep);
-       return 0;
-}
-
-/*
- * Copyright (c) 1988, 1993, 1994
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
diff --git a/busybox/examples/bootfloppy/bootfloppy.txt b/busybox/examples/bootfloppy/bootfloppy.txt
deleted file mode 100644 (file)
index 575c93f..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-Building a Busybox Boot Floppy
-==============================
-
-This document describes how to buid a boot floppy using the following
-components:
-
- - Linux Kernel (http://www.kernel.org)
- - uClibc: C library (http://cvs.uclinux.org/uClibc.html)
- - Busybox: Unix utilities (http://busybox.lineo.com)
- - Syslinux: bootloader (http://syslinux.zytor.com)
-
-It is based heavily on a paper presented by Erik Andersen at the 2001 Embedded
-Systems Conference.
-
-
-
-Building The Software Components
---------------------------------
-
-Detailed instructions on how to build Busybox, uClibc, or a working Linux
-kernel are beyond the scope of this document. The following guidelines will
-help though:
-
-       - Stock Busybox from CVS or a tarball will work with no modifications to
-         any files. Just extract and go.
-       - Ditto uClibc.
-       - Your Linux kernel must include support for initrd or else the floppy
-         won't be able to mount it's root file system.
-
-If you require further information on building Busybox uClibc or Linux, please
-refer to the web pages and documentation for those individual programs.
-
-
-
-Making a Root File System
--------------------------
-
-The following steps will create a root file system.
-
- - Create an empty file that you can format as a filesystem:
-       dd if=/dev/zero of=rootfs bs=1k count=4000
-
- - Set up the rootfs file we just created to be used as a loop device (may not
-   be necessary) 
-
-       losetup /dev/loop0 rootfs 
-
- - Format the rootfs file with a filesystem:
-
-       mkfs.ext2 -F -i 2000 rootfs
-
- - Mount the file on a mountpoint so we can place files in it:
-
-       mkdir loop
-       mount -o loop rootfs loop/
-
-       (you will probably need to be root to do this)
-
- - Copy on the C library, the dynamic linking library, and other necessary
-   libraries. For this example, we copy the following files from the uClibc
-   tree:
-
-       mkdir loop/lib
-       (chdir to uClibc directory)
-       cp -a libc.so* uClibc*.so \
-               ld.so-1/d-link/ld-linux-uclibc.so* \
-               ld.so-1/libdl/libdl.so* \
-               crypt/libcrypt.so* \
-               (path to)loop/lib
-
- - Install the Busybox binary and accompanying symlinks:
-
-       (chdir to busybox directory)
-       make PREFIX=(path to)loop/ install
-
- - Make device files in /dev:
-
-       This can be done by running the 'mkdevs.sh' script. If you want the gory
-       details, you can read the script.
-
- - Make necessary files in /etc:
-
-       For this, just cp -a the etc/ directory onto rootfs. Again, if you want
-       all the details, you can just look at the files in the dir.
-
- - Run ldconfig so busybox and other binaries can have access to the libraries
-   that they need:
-
-   (path to)uClibc/ld.so-1/util/ldconfig -r loop/
-
- - Unmount the rootfs from the mountpoint:
-
-       umount loop
-
- - Compress it:
-
-       gzip -9 rootfs
-
-
-Making a SYSLINUX boot floppy
------------------------------
-
-The following steps will create the boot floppy.
-
-Note: You will need to have the mtools package installed beforehand.
-
- - Insert a floppy in the drive and format it with an MSDOS filesystem:
-       mformat a:
-
-       (if the system doesn't know what device 'a:' is, look at /etc/mtools.conf)
-
- - Run syslinux on the floppy:
-       syslinux -s /dev/fd0
-       
-       (the -s stands for "safe, slow, and stupid" and should work better with
-       buggy BIOSes; it can be omitted)
-
- - Put on a syslinux.cfg file:
-
-       mcopy syslinux.cfg a:
-
-       (more on syslinux.cfg below)
-
- - Copy the root file system you made onto the MSDOS formatted floppy
-
-       mcopy rootfs.gz a:
-
- - Build a linux kernel and copy it onto the disk with the filename 'linux'
-
-       mcopy bzImage a:linux
-
-
-Sample syslinux.cfg
-~~~~~~~~~~~~~~~~~~~
-
-The following simple syslinux.cfg file should work. You can tweak it if you
-like.
-
-----begin-syslinux.cfg---------------
-DEFAULT linux
-APPEND initrd=rootfs.gz root=/dev/ram0
-TIMEOUT 10
-PROMPT 1
-----end-syslinux.cfg---------------
-
-Some changes you could make to syslinux.cfg:
-
- - This value is the number seconds it will wait before booting. You can set
-   the timeout to 0 (or omit) to boot instantly, or you can set it as high as
-   10 to wait awhile.
-
- - PROMPT can be set to 0 to disable the 'boot:' prompt.
-
- - you can add this line to display the contents of a file as a welcome
-   message:
-
-       DISPLAY display.txt
-
-
-
-Additional Resources
---------------------
-
-Other useful information on making a Linux bootfloppy is available at the
-following URLs:
-
-http://www.linuxdoc.org/HOWTO/Bootdisk-HOWTO/index.html
-http://www.linux-embedded.com/howto/Embedded-Linux-Howto.html
-http://linux-embedded.org/howto/LFS-HOWTO.html
-http://linux-embedded.org/pmhowto.html
-http://recycle.lbl.gov/~ldoolitt/embedded/ (Larry Doolittle's stuff)
-
-
-
-Possible TODOs
---------------
-
-The following features that we might want to add later:
-
- - support for additional filesystems besides ext2, i.e. minix
- - different libc, static vs dynamic loading
- - maybe using an alternate bootloader
diff --git a/busybox/examples/bootfloppy/display.txt b/busybox/examples/bootfloppy/display.txt
deleted file mode 100644 (file)
index 399d326..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-
-This boot floppy is made with Busybox, uClibc, and the Linux kernel.
-Hit RETURN to boot or enter boot parameters at the prompt below.
-
diff --git a/busybox/examples/bootfloppy/etc/fstab b/busybox/examples/bootfloppy/etc/fstab
deleted file mode 100644 (file)
index ef14ca2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-proc           /proc   proc    defaults    0   0
-
diff --git a/busybox/examples/bootfloppy/etc/init.d/rcS b/busybox/examples/bootfloppy/etc/init.d/rcS
deleted file mode 100755 (executable)
index 4f29b92..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#! /bin/sh
-
-/bin/mount -a
diff --git a/busybox/examples/bootfloppy/etc/inittab b/busybox/examples/bootfloppy/etc/inittab
deleted file mode 100644 (file)
index eb3e979..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-::sysinit:/etc/init.d/rcS
-::respawn:-/bin/sh
-tty2::askfirst:-/bin/sh
-::ctrlaltdel:/bin/umount -a -r
-
diff --git a/busybox/examples/bootfloppy/etc/profile b/busybox/examples/bootfloppy/etc/profile
deleted file mode 100644 (file)
index e9b11e9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# /etc/profile: system-wide .profile file for the Bourne shells
-
-echo
-echo -n "Processing /etc/profile... "
-# no-op
-echo "Done"
-echo 
-
diff --git a/busybox/examples/bootfloppy/mkdevs.sh b/busybox/examples/bootfloppy/mkdevs.sh
deleted file mode 100755 (executable)
index 03a1a85..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-#
-# makedev.sh - creates device files for a busybox boot floppy image
-
-
-# we do our work in the dev/ directory
-if [ -z "$1" ]; then
-       echo "usage: `basename $0` path/to/dev/dir"
-       exit 1
-fi
-
-cd $1
-
-
-# miscellaneous one-of-a-kind stuff
-mknod console c 5 1
-mknod full c 1 7
-mknod kmem c 1 2
-mknod mem c 1 1
-mknod null c 1 3
-mknod port c 1 4
-mknod random c 1 8
-mknod urandom c 1 9
-mknod zero c 1 5
-ln -s /proc/kcore core
-
-# IDE HD devs
-# note: not going to bother creating all concievable partitions; you can do
-# that yourself as you need 'em.
-mknod hda b 3 0
-mknod hdb b 3 64
-mknod hdc b 22 0
-mknod hdd b 22 64
-
-# loop devs
-for i in `seq 0 7`; do
-       mknod loop$i b 7 $i
-done
-
-# ram devs
-for i in `seq 0 9`; do
-       mknod ram$i b 1 $i
-done
-ln -s ram1 ram
-
-# ttys
-mknod tty c 5 0
-for i in `seq 0 9`; do
-       mknod tty$i c 4 $i
-done
-
-# virtual console screen devs
-for i in `seq 0 9`; do
-       mknod vcs$i b 7 $i
-done
-ln -s vcs0 vcs
-
-# virtual console screen w/ attributes devs
-for i in `seq 0 9`; do
-       mknod vcsa$i b 7 $i
-done
-ln -s vcsa0 vcsa
diff --git a/busybox/examples/bootfloppy/mkrootfs.sh b/busybox/examples/bootfloppy/mkrootfs.sh
deleted file mode 100755 (executable)
index b59b57a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/bash
-#
-# mkrootfs.sh - creates a root file system
-#
-
-# TODO: need to add checks here to verify that busybox, uClibc and bzImage
-# exist
-
-
-# command-line settable variables
-BUSYBOX_DIR=..
-UCLIBC_DIR=../../uClibc
-TARGET_DIR=./loop
-FSSIZE=4000
-CLEANUP=1
-MKFS='mkfs.ext2 -F'
-
-# don't-touch variables
-BASE_DIR=`pwd`
-
-
-while getopts 'b:u:s:t:Cm' opt
-do
-       case $opt in
-               b) BUSYBOX_DIR=$OPTARG ;;
-               u) UCLIBC_DIR=$OPTARG ;;
-               t) TARGET_DIR=$OPTARG ;;
-               s) FSSIZE=$OPTARG ;;
-               C) CLEANUP=0 ;;
-               m) MKFS='mkfs.minix' ;;
-               *)
-                       echo "usage: `basename $0` [-bu]"
-                       echo "  -b DIR  path to busybox direcory (default ..)"
-                       echo "  -u DIR  path to uClibc direcory (default ../../uClibc)"
-                       echo "  -t DIR  path to target direcory (default ./loop)"
-                       echo "  -s SIZE size of root filesystem in Kbytes (default 4000)"
-                       echo "  -C      don't perform cleanup (umount target dir, gzip rootfs, etc.)"
-                       echo "          (this allows you to 'chroot loop/ /bin/sh' to test it)"
-                       echo "  -m      use minix filesystem (default is ext2)"
-                       exit 1
-                       ;;
-       esac
-done
-
-
-
-
-# clean up from any previous work
-mount | grep -q loop
-[ $? -eq 0 ] && umount $TARGET_DIR
-[ -d $TARGET_DIR ] && rm -rf $TARGET_DIR/
-[ -f rootfs ] && rm -f rootfs
-[ -f rootfs.gz ] && rm -f rootfs.gz
-
-
-# prepare root file system and mount as loopback
-dd if=/dev/zero of=rootfs bs=1k count=$FSSIZE
-$MKFS -i 2000 rootfs
-mkdir $TARGET_DIR
-mount -o loop,exec rootfs $TARGET_DIR # must be root
-
-
-# install uClibc
-mkdir -p $TARGET_DIR/lib
-cd $UCLIBC_DIR
-make INSTALL_DIR= 
-cp -a libc.so* $BASE_DIR/$TARGET_DIR/lib
-cp -a uClibc*.so $BASE_DIR/$TARGET_DIR/lib
-cp -a ld.so-1/d-link/ld-linux-uclibc.so* $BASE_DIR/$TARGET_DIR/lib 
-cp -a ld.so-1/libdl/libdl.so* $BASE_DIR/$TARGET_DIR/lib
-cp -a crypt/libcrypt.so* $BASE_DIR/$TARGET_DIR/lib
-cd $BASE_DIR
-
-
-# install busybox and components
-cd $BUSYBOX_DIR
-make distclean
-make CC=$BASE_DIR/$UCLIBC_DIR/extra/gcc-uClibc/i386-uclibc-gcc
-make PREFIX=$BASE_DIR/$TARGET_DIR install
-cd $BASE_DIR
-
-
-# make files in /dev
-mkdir $TARGET_DIR/dev
-./mkdevs.sh $TARGET_DIR/dev
-
-
-# make files in /etc
-cp -a etc $TARGET_DIR
-ln -s /proc/mounts $TARGET_DIR/etc/mtab
-
-
-# other miscellaneous setup
-mkdir $TARGET_DIR/initrd
-mkdir $TARGET_DIR/proc
-$UCLIBC_DIR/ld.so-1/util/ldconfig -r $TARGET_DIR
-
-
-# Done. Maybe do cleanup.
-if [ $CLEANUP -eq 1 ]
-then
-       umount $TARGET_DIR
-       rmdir $TARGET_DIR
-       gzip -9 rootfs
-fi
-
diff --git a/busybox/examples/bootfloppy/mksyslinux.sh b/busybox/examples/bootfloppy/mksyslinux.sh
deleted file mode 100755 (executable)
index e254173..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-#
-# Formats a floppy to use Syslinux
-
-dummy=""
-
-
-# need to have mtools installed
-if [ -z `which mformat` -o -z `which mcopy` ]; then
-       echo "You must have the mtools package installed to run this script"
-       exit 1
-fi
-
-
-# need an arg for the location of the kernel
-if [ -z "$1" ]; then
-       echo "usage: `basename $0` path/to/linux/kernel"
-       exit 1
-fi
-
-
-# need to have a root file system built
-if [ ! -f rootfs.gz ]; then
-       echo "You need to have a rootfs built first."
-       echo "Hit RETURN to make one now or Control-C to quit."
-       read dummy
-       ./mkrootfs.sh
-fi
-
-
-# prepare the floppy
-echo "Please insert a blank floppy in the drive and press RETURN to format"
-echo "(WARNING: All data will be erased! Hit Control-C to abort)"
-read dummy
-
-echo "Formatting the floppy..."
-mformat a:
-echo "Making it bootable with Syslinux..."
-syslinux -s /dev/fd0
-echo "Copying Syslinux configuration files..."
-mcopy syslinux.cfg display.txt a:
-echo "Copying root filesystem file..."
-mcopy rootfs.gz a:
-# XXX: maybe check for "no space on device" errors here
-echo "Copying linux kernel..."
-mcopy $1 a:linux
-# XXX: maybe check for "no space on device" errors here too
-echo "Finished: boot floppy created"
diff --git a/busybox/examples/bootfloppy/quickstart.txt b/busybox/examples/bootfloppy/quickstart.txt
deleted file mode 100644 (file)
index 0d80908..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Quickstart on making the Busybox boot-floppy:
-
-  1) Download Busybox and uClibc from CVS or tarballs. Make sure they share a
-     common parent directory. (i.e. busybox/ and uclibc/ are both right off of
-        /tmp, or wherever.)
-
-  2) Build a Linux kernel. Make sure you include support for initrd.
-
-  3) Put a floppy in the drive. Make sure it is a floppy you don't care about
-     because the contents will be overwritten.
-
-  4) As root, type ./mksyslinux.sh path/to/linux/kernel from this directory.
-     Wait patiently while the magic happens.
-
-  5) Boot up on the floppy.
diff --git a/busybox/examples/bootfloppy/syslinux.cfg b/busybox/examples/bootfloppy/syslinux.cfg
deleted file mode 100644 (file)
index 8d407ca..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-display display.txt
-default linux
-timeout 10
-prompt 1
-label linux
-       kernel linux
-       append initrd=rootfs.gz root=/dev/ram0 
diff --git a/busybox/examples/busybox.spec b/busybox/examples/busybox.spec
deleted file mode 100644 (file)
index 5cf13ca..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-%define name   busybox
-%define epoch   0
-%define version        0.60.2.pre
-%define release        %(date -I | sed -e 's/-/_/g')
-%define serial  1
-
-Name:   %{name}
-#Epoch:   %{epoch}
-Version: %{version}
-Release: %{release}
-Serial:         %{serial}
-Copyright: GPL
-Group: System/Utilities
-Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary.
-URL:    http://busybox.lineo.com/
-Source:         ftp://oss.lineo.com/busybox/%{name}-%{version}.tar.gz
-Buildroot: /var/tmp/%{name}-%{version}
-Packager : Erik Andersen <andersen@lineo.com>
-
-%Description
-BusyBox combines tiny versions of many common UNIX utilities into a single
-small executable. It provides minimalist replacements for most of the utilities
-you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
-tar, etc.  BusyBox provides a fairly complete POSIX environment for any small
-or emdedded system.  The utilities in BusyBox generally have fewer options then
-their full featured GNU cousins; however, the options that are provided behave
-very much like their GNU counterparts.
-
-%Prep
-%setup -q -n %{name}-%{version}
-
-%Build
-make
-
-%Install
-rm -rf $RPM_BUILD_ROOT
-make PREFIX=$RPM_BUILD_ROOT install
-
-%Clean
-rm -rf $RPM_BUILD_ROOT
-
-%Files 
-%defattr(-,root,root)
-/
diff --git a/busybox/examples/depmod.pl b/busybox/examples/depmod.pl
deleted file mode 100755 (executable)
index e65f07b..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/perl -w
-# vi: set ts=4:
-# Copyright (c) 2001 David Schleef <ds@schleef.org>
-# Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
-# Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
-# This program is free software; you can redistribute it and/or modify it 
-# under the same terms as Perl itself.
-
-# TODO -- use strict mode...
-#use strict;
-
-use Getopt::Long;
-use File::Find;
-
-
-# Set up some default values
-
-my $basedir="";
-my $kernel;
-my $kernelsyms;
-my $stdout=1;
-my $verbose=0;
-
-
-# get command-line options
-
-my %opt;
-
-GetOptions(
-       \%opt,
-       "help|h",
-       "basedir|b=s" => \$basedir,
-       "kernel|k=s" => \$kernel,
-       "kernelsyms|F=s" => \$kernelsyms,
-       "stdout|n" => \$stdout,
-       "verbose|v" => \$verbose,
-);
-
-if (defined $opt{help}) {
-       print
-               "$0 [OPTION]... [basedir]\n",
-               "\t-h --help\t\tShow this help screen\n",
-               "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n",
-               "\t-k --kernel\t\tKernel binary for the target\n",
-               "\t-F --kernelsyms\t\tKernel symbol file\n",
-               "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n",
-               "\t-v --verbose\t\tPrint out lots of debugging stuff\n",
-       ;
-       exit 1;
-}
-
-if($basedir !~ m-/lib/modules-) {
-    warn "WARNING: base directory does not match ..../lib/modules\n";
-}
-
-# Find the list of .o files living under $basedir 
-#if ($verbose) { printf "Locating all modules\n"; }
-my($file) = "";
-my(@liblist) = ();
-find sub { 
-       if ( -f $_  && ! -d $_ ) { 
-               $file = $File::Find::name;
-               if ( $file =~ /.o$/ ) {
-                       push(@liblist, $file);
-                       if ($verbose) { printf "$file\n"; }
-               }
-       }
-}, $basedir;
-if ($verbose) { printf "Finished locating modules\n"; }
-
-foreach $obj ( @liblist, $kernel ){
-    # turn the input file name into a target tag name
-    # vmlinux is a special that is only used to resolve symbols
-    if($obj =~ /vmlinux/) {
-        $tgtname = "vmlinux";
-    } else {
-        ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
-    }
-
-    warn "MODULE = $tgtname\n" if $verbose;
-
-    # get a list of symbols
-       @output=`nm $obj`;
-       $ksymtab=grep m/ __ksymtab/, @output;
-
-    # gather the exported symbols
-       if($ksymtab){
-        # explicitly exported
-        foreach ( @output ) {
-            / __ksymtab_(.*)$/ and do {
-                warn "sym = $1\n" if $verbose;
-                $exp->{$1} = $tgtname;
-            };
-        }
-       } else {
-        # exporting all symbols
-        foreach ( @output) {
-            / [ABCDGRST] (.*)$/ and do {
-                warn "syma = $1\n" if $verbose;
-                $exp->{$1} = $tgtname;
-            };
-        }
-       }
-    # gather the unresolved symbols
-    foreach ( @output ) {
-        !/ __this_module/ && / U (.*)$/ and do {
-            warn "und = $1\n" if $verbose;
-            push @{$dep->{$tgtname}}, $1;
-        };
-    }
-}
-
-
-# reduce dependancies: remove unresolvable and resolved from vmlinux
-# remove duplicates
-foreach $module (keys %$dep) {
-    $mod->{$module} = {};
-    foreach (@{$dep->{$module}}) {
-        if( $exp->{$_} ) { 
-            warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
-            next if $exp->{$_} =~ /vmlinux/;
-            $mod->{$module}{$exp->{$_}} = 1;
-        } else {
-            warn "unresolved symbol $_ in file $module\n";
-        }
-    } 
-}
-
-# resolve the dependancies for each module
-foreach $module ( keys %$mod )  {
-    print "$module:\t";
-    @sorted = sort bydep keys %{$mod->{$module}};
-    print join(" \\\n\t",@sorted);
-#    foreach $m (@sorted ) {
-#        print "\t$m\n";
-#    }
-    print "\n\n";
-}
-
-sub bydep
-{
-    foreach my $f ( keys %{$mod->{$b}} ) {
-        if($f eq $a) {
-            return 1;
-        }
-    }
-    return -1;
-}
-
-
-
-__END__
-
-=head1 NAME
-
-depmod.pl - a cross platform script to generate kernel module dependency
-               lists which can then be used by modprobe.
-
-=head1 SYNOPSIS
-
-depmod.pl [OPTION]... [FILE]...
-
-Example:
-
-       depmod.pl -F linux/System.map target/lib/modules
-
-=head1 DESCRIPTION
-
-The purpose of this script is to automagically generate a list of of kernel
-module dependancies.  This script produces dependancy lists that should be
-identical to the depmod program from the modutils package.  Unlike the depmod
-binary, however, depmod.pl is designed to be run on your host system, not
-on your target system.
-
-This script was written by David Schleef <ds@schleef.org> to be used in
-conjunction with the BusyBox modprobe applet.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-h --help>
-
-This displays the help message.
-
-=item B<-b --basedir>
-
-The base directory uner which the target's modules will be found.  This
-defaults to the /lib/modules directory.
-
-=item B<-k --kernel>
-
-Kernel binary for the target.  You must either supply a kernel binary
-or a kernel symbol file (using the -F option).
-
-=item B<-F --kernelsyms>
-
-Kernel symbol file for the target.  You must supply either a kernel symbol file
-kernel binary for the target (using the -k option).
-
-=item B<-n --stdout>
-
-Write to stdout instead of modules.dep.  This is currently hard coded...
-kernel binary for the target (using the -k option).
-
-=item B<--verbose>
-
-Be verbose (not implemented)
-
-=back
-
-=head1 COPYRIGHT
-
-Copyright (c) 2001 David Schleef <ds@schleef.org>
-Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
-Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
-This program is free software; you can redistribute it and/or modify it 
-under the same terms as Perl itself.
-
-=head1 AUTHOR
-
-David Schleef <ds@schleef.org>
-
-=cut
-
-# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $
-
diff --git a/busybox/examples/inittab b/busybox/examples/inittab
deleted file mode 100644 (file)
index 8e7e945..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# /etc/inittab init(8) configuration for BusyBox
-#
-# Copyright (C) 1999 by Lineo, inc.  Written by Erik Andersen
-# <andersen@lineo.com>, <andersee@debian.org>
-#
-#
-# Note, BusyBox init doesn't support runlevels.  The runlevels field is
-# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
-#
-#
-# Format for each entry: <id>:<runlevels>:<action>:<process>
-#
-# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
-#
-#      The id field is used by BusyBox init to specify the controlling tty for
-#      the specified process to run on.  The contents of this field are
-#      appended to "/dev/" and used as-is.  There is no need for this field to
-#      be unique, although if it isn't you may have strange results.  If this
-#      field is left blank, it is completely ignored.  Also note that if
-#      BusyBox detects that a serial console is in use, then all entries
-#      containing non-empty id fields will _not_ be run.  BusyBox init does
-#      nothing with utmp.  We don't need no stinkin' utmp.
-#
-# <runlevels>: The runlevels field is completely ignored.
-#
-# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once, 
-#                                  ctrlaltdel, and shutdown.
-#
-#       Note: askfirst acts just like respawn, but before running the specified
-#       process it displays the line "Please press Enter to activate this
-#       console." and then waits for the user to press enter before starting
-#       the specified process.
-#
-#       Note: unrecognised actions (like initdefault) will cause init to emit
-#       an error message, and then go along with its business.
-#
-# <process>: Specifies the process to be executed and it's command line.
-#
-# Note: BusyBox init works just fine without an inittab. If no inittab is
-# found, it has the following default behavior:
-#         ::sysinit:/etc/init.d/rcS
-#         ::askfirst:/bin/sh
-#         ::ctrlaltdel:/sbin/reboot
-#         ::shutdown:/sbin/swapoff -a
-#         ::shutdown:/bin/umount -a -r
-# if it detects that /dev/console is _not_ a serial console, it will
-# also run:
-#         tty2::askfirst:/bin/sh
-#         tty3::askfirst:/bin/sh
-#         tty4::askfirst:/bin/sh
-#
-# Boot-time system configuration/initialization script.
-# This is run first except when booting in single-user mode.
-#
-::sysinit:/etc/init.d/rcS
-
-# /bin/sh invocations on selected ttys
-#
-# Note below that we prefix the shell commands with a "-" to indicate to the
-# shell that it is supposed to be a login shell.  Normally this is handled by
-# login, but since we are bypassing login in this case, BusyBox lets you do
-# this yourself...
-#
-# Start an "askfirst" shell on the console (whatever that may be)
-::askfirst:-/bin/sh
-# Start an "askfirst" shell on /dev/tty2-4
-tty2::askfirst:-/bin/sh
-tty3::askfirst:-/bin/sh
-tty4::askfirst:-/bin/sh
-
-# /sbin/getty invocations for selected ttys
-tty4::respawn:/sbin/getty 38400 tty5
-tty5::respawn:/sbin/getty 38400 tty6
-
-# Example of how to put a getty on a serial line (for a terminal)
-#::respawn:/sbin/getty -L ttyS0 9600 vt100
-#::respawn:/sbin/getty -L ttyS1 9600 vt100
-#
-# Example how to put a getty on a modem line.
-#::respawn:/sbin/getty 57600 ttyS2
-
-# Stuff to do before rebooting
-::ctrlaltdel:/sbin/reboot
-::shutdown:/bin/umount -a -r
-::shutdown:/sbin/swapoff -a
-
diff --git a/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel b/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel
deleted file mode 100644 (file)
index 33ee8b4..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-I have been asked several times whether the devps patch will go into the
-mainline Linux kernel.  The following emails from Alan Cox and Linux Torvalds
-make it clear that it is not going to happen.  This does not mean this patch
-had no value -- it does.  It just means that those that like it get to apply it
-themselves...
-
- -Erik
-
-
--------------------------------
-
-From alan@lxorguk.ukuu.org.uk  Thu Apr 13 08:07:22 2000
-Return-Path: <alan@lxorguk.ukuu.org.uk>
-Delivered-To: andersen@dillweed.dsl.xmission.com
-Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1])
-       by dillweed.dsl.xmission.com (Postfix) with ESMTP id 1D57A11A4F5
-       for <andersen@dillweed.dsl.xmission.com>; Thu, 13 Apr 2000 08:07:22 -0600 (MDT)
-Envelope-to: andersen@xmission.com
-Received: from mail.xmission.com
-       by localhost with IMAP (fetchmail-5.3.3)
-       for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 08:07:22 -0600 (MDT)
-Received: from [194.168.151.1] (helo=the-village.bc.nu)
-       by mail.xmission.com with esmtp (Exim 3.03 #3)
-       id 12fhQk-0002OZ-00
-       for andersen@xmission.com; Thu, 13 Apr 2000 05:05:03 -0600
-Received: from alan by the-village.bc.nu with local (Exim 2.12 #1)
-       id 12fhQ9-0002nD-00
-       for andersen@xmission.com; Thu, 13 Apr 2000 12:04:25 +0100
-Subject: Re: kernel ps drivers [Was: vm locking question]
-To: andersen@xmission.com
-Date: Thu, 13 Apr 2000 12:04:23 +0100 (BST)
-In-Reply-To: <20000412224130.A2748@xmission.com> from "Erik Andersen" at Apr 12, 2000 10:41:30 PM
-X-Mailer: ELM [version 2.5 PL1]
-MIME-Version: 1.0
-Content-Type: text/plain; charset=us-ascii
-Content-Transfer-Encoding: 7bit
-Message-Id: <E12fhQ9-0002nD-00@the-village.bc.nu>
-From: Alan Cox <alan@lxorguk.ukuu.org.uk>
-Status: RO
-X-Status: A
-Content-Length: 242
-Lines: 6
-
-> On the subject of ps, would you be willing to accept my /dev/ps 
-> patch into the kernel?  If no, any suggestions on what should
-> be done differently (if anything) to make it worthy of inclusion?
-
-For 2.2.x no, for 2.3.x ask Linus not me
-
-
-From torvalds@transmeta.com  Thu Apr 13 09:18:16 2000
-Return-Path: <torvalds@transmeta.com>
-Delivered-To: andersen@dillweed.dsl.xmission.com
-Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1])
-       by dillweed.dsl.xmission.com (Postfix) with ESMTP id 3776411A3DF
-       for <andersen@dillweed.dsl.xmission.com>; Thu, 13 Apr 2000 09:18:16 -0600 (MDT)
-Envelope-to: andersen@xmission.com
-Received: from mail.xmission.com
-       by localhost with IMAP (fetchmail-5.3.3)
-       for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 09:18:16 -0600 (MDT)
-Received: from [209.10.217.66] (helo=neon-gw.transmeta.com)
-       by mail.xmission.com with esmtp (Exim 3.03 #3)
-       id 12flK2-0004dd-00
-       for andersen@xmission.com; Thu, 13 Apr 2000 09:14:22 -0600
-Received: (from root@localhost)
-       by neon-gw.transmeta.com (8.9.3/8.9.3) id IAA18635;
-       Thu, 13 Apr 2000 08:10:51 -0700
-Received: from mailhost.transmeta.com(10.1.1.15) by neon-gw.transmeta.com via smap (V2.1)
-       id xma018629; Thu, 13 Apr 00 08:10:25 -0700
-Received: from penguin.transmeta.com (root@penguin.transmeta.com [10.1.2.202])
-       by deepthought.transmeta.com (8.9.3/8.9.3) with ESMTP id IAA12264;
-       Thu, 13 Apr 2000 08:13:53 -0700 (PDT)
-Received: from localhost (torvalds@localhost) by penguin.transmeta.com (8.9.3/8.7.3) with ESMTP id IAA02051; Thu, 13 Apr 2000 08:13:53 -0700
-X-Authentication-Warning: penguin.transmeta.com: torvalds owned process doing -bs
-Date: Thu, 13 Apr 2000 08:13:53 -0700 (PDT)
-From: Linus Torvalds <torvalds@transmeta.com>
-To: Erik Andersen <andersen@xmission.com>
-Cc: Alan Cox <alan@redhat.com>
-Subject: Re: kernel ps drivers [Was: vm locking question]
-In-Reply-To: <20000413083127.A976@xmission.com>
-Message-ID: <Pine.LNX.4.10.10004130812170.2000-100000@penguin.transmeta.com>
-MIME-Version: 1.0
-Content-Type: TEXT/PLAIN; charset=US-ASCII
-Status: RO
-Content-Length: 659
-Lines: 16
-
-
-
-On Thu, 13 Apr 2000, Erik Andersen wrote:
-> 
-> For 2.3.x would you be willing to accept my /dev/ps driver into the kernel?
-> (Assuming I remove the /dev/modules driver (since it was pointed out that there
-> is a perfectly good syscall providing that interface).  If no, is there anything
-> that could be done differently (if anything) to make it worthy of inclusion?
-
-I do dislike /dev/ps mightily. If the problem is that /proc is too large,
-then the right solution is to just clean up /proc. Which is getting done.
-And yes, /proc will be larger than /dev/ps, but I still find that
-preferable to having two incompatible ways to do the same thing.
-
-               Linus
-
-
diff --git a/busybox/examples/kernel-patches/devps.patch.9_25_2000 b/busybox/examples/kernel-patches/devps.patch.9_25_2000
deleted file mode 100644 (file)
index d74a26a..0000000
+++ /dev/null
@@ -1,1478 +0,0 @@
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Config.in linux/drivers/char/Config.in
---- linux-2.2.18-9.virgin/drivers/char/Config.in       Mon Sep 18 15:02:30 2000
-+++ linux/drivers/char/Config.in       Mon Sep 25 16:33:16 2000
-@@ -56,6 +56,8 @@
-    dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m
-    dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m
- fi
-+tristate 'Devps support' CONFIG_DEVPS
-+tristate 'Devmounts support' CONFIG_DEVMTAB
- bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
- if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
-       int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Makefile linux/drivers/char/Makefile
---- linux-2.2.18-9.virgin/drivers/char/Makefile        Mon Sep 18 15:02:30 2000
-+++ linux/drivers/char/Makefile        Mon Sep 25 18:01:12 2000
-@@ -697,6 +697,22 @@
- M_OBJS          += $(sort $(filter     $(module-list), $(obj-m)))
-+ifeq ($(CONFIG_DEVPS),y)
-+O_OBJS += devps.o
-+else
-+  ifeq ($(CONFIG_DEVPS),m)
-+  M_OBJS += devps.o
-+  endif
-+endif
-+
-+ifeq ($(CONFIG_DEVMTAB),y)
-+O_OBJS += devmtab.o
-+else
-+  ifeq ($(CONFIG_DEVMTAB),m)
-+  M_OBJS += devmtab.o
-+  endif
-+endif
-+
- include $(TOPDIR)/Rules.make
- fastdep:
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devmtab.c linux/drivers/char/devmtab.c
---- linux-2.2.18-9.virgin/drivers/char/devmtab.c       Wed Dec 31 17:00:00 1969
-+++ linux/drivers/char/devmtab.c       Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,295 @@
-+/* vi: set sw=8 ts=8: */
-+/*
-+ * linux/drivers/char/devmtab.c
-+ * 
-+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
-+ *
-+ * May be copied or modified under the terms of the GNU General Public License.
-+ * See linux/COPYING for more information.
-+ *
-+ * This driver implements an interface whereby programs such as mount(8),
-+ * umount(8), and df(1) may obtain all the process information they need to do
-+ * their jobs without needing to use /proc.  This driver another step in my
-+ * evil plan to completely dismantle /proc.  Muhahahaha!
-+ *
-+ * Suggestions are welcome. Patches that work are more welcome though. ;-)
-+ *
-+ *
-+ * When using this driver, running:
-+ *    mknod /dev/mtab c 10 22
-+ * could be considered helpful.
-+ *
-+ * ----------------------------------
-+ * 1.00  Mar 07, 2000 -- Initial version.
-+ *
-+ *************************************************************************/
-+
-+#define DEVMTAB_VERSION "1.00"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/mm.h>
-+#include <linux/pagemap.h>
-+#include <linux/malloc.h>
-+#include <linux/miscdevice.h>
-+#include <linux/devmtab.h>
-+#include <linux/wrapper.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+
-+
-+/* Some variables used by this device */
-+static struct wait_queue *devmtab_waitq = NULL;
-+static int devmtab_already_opened = 0;
-+static char *mtabfile = NULL;
-+static int mtab_ptr;
-+static int mtab_size;
-+
-+
-+
-+/****************************************************************************
-+ * Handle opening and closing of the device
-+ */
-+
-+static long long
-+devmtab_lseek (struct file *file, long long offset, int orig)
-+{
-+      return -ESPIPE;
-+}
-+
-+static ssize_t
-+devmtab_read (struct file *file, char *buf, size_t count, loff_t * ppos)
-+{
-+      int n = mtab_size - mtab_ptr;
-+
-+      if (mtab_size == 0) {
-+              /* Make some space */
-+              if (!(mtabfile = (char *) get_free_page (GFP_KERNEL)))
-+                      return -ENOMEM;
-+              /* Grab the mtab */
-+              get_filesystem_info (mtabfile);
-+              mtab_ptr = 0;
-+              mtab_size = strlen (mtabfile);
-+              n = mtab_size - mtab_ptr;
-+      }
-+
-+      if (n > count)
-+              n = count;
-+      if (n <= 0)
-+              return 0;
-+
-+      if (copy_to_user (buf, mtabfile, n))
-+              return -EFAULT;
-+      mtab_ptr += n;
-+      return n;
-+}
-+
-+static int devmtab_open (struct inode *ip, struct file *fp)
-+{
-+      /* Only let one process use us at any time -- putting other
-+       * processes to sleep.  Those opening us O_NONBLOCK will
-+       * get an EAGAIN error */
-+      if ((fp->f_flags & O_NONBLOCK) && devmtab_already_opened) 
-+              return -EAGAIN;
-+
-+      MOD_INC_USE_COUNT;
-+
-+      while (devmtab_already_opened) {
-+              int i, got_signal=0;
-+
-+              /* Go to sleep until we get woken up 
-+               * by devmtab_close or we receive a signal */
-+              module_interruptible_sleep_on(&devmtab_waitq);
-+
-+              for(i=0; i<_NSIG_WORDS && !got_signal; i++)
-+                      got_signal = current->signal.sig[i] & ~current->blocked.sig[i];
-+
-+              /* If we got a signal, decrement the use count
-+               * and return to user space */
-+              if (got_signal) {
-+                      MOD_DEC_USE_COUNT;
-+                      return -EINTR;
-+              }
-+      }
-+
-+      /* Since we got here, then devmtab_already_opened must equal 0 */
-+      devmtab_already_opened=1;
-+      mtab_ptr = 0;
-+      mtab_size = 0;
-+
-+      return 0;
-+}
-+
-+static int devmtab_release (struct inode *ip, struct file *fp)
-+{
-+      /* Clean up */
-+      if (mtabfile != NULL) {
-+              free_page ((unsigned long) mtabfile);
-+              mtabfile = NULL;
-+      }
-+
-+      /* Zero out the reference counter */
-+      devmtab_already_opened=0;
-+
-+      /* Wake up anybody that is waiting to access this device */
-+      module_wake_up(&devmtab_waitq);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      return 0;
-+}
-+
-+static int
-+devmtab_ioctl (struct inode *ip, struct file *fp,
-+             unsigned int cmd, unsigned long arg)
-+{
-+      switch (cmd) {
-+      case DEVMTAB_COUNT_FILESYSTEMS:{
-+                      return(count_kfstypes());
-+              }
-+
-+      case DEVMTAB_GET_FILESYSTEMS:{
-+                      int stat, count;
-+                      struct k_fstype* fstypelist;
-+
-+                      /* How many are there? */
-+                      count = count_kfstypes();
-+
-+                      /* Make some space */
-+                      fstypelist = (struct k_fstype *)kmalloc(sizeof(struct k_fstype) * count, GFP_KERNEL);
-+                      if (!fstypelist)
-+                              return -ENOMEM;
-+                      memset(fstypelist, 0, sizeof(struct k_fstype) * count);
-+
-+                      /* Grab the mtab entries */
-+                      get_kfstype_list(count, fstypelist);
-+
-+                      /* Make sure there is enough room */
-+                      stat = verify_area (VERIFY_WRITE, (struct k_fstype *) arg,
-+                                          sizeof(struct k_fstype) * count);
-+                      if (stat) {
-+                              printk (KERN_INFO
-+                                      "devmtab: Insufficient space was provided.\n");
-+                              return stat;
-+                      }
-+
-+                      /* Send it to user space */
-+                      copy_to_user_ret ((struct k_fstype *) arg, fstypelist,
-+                                        sizeof(struct k_fstype) * count, 
-+                                        -EFAULT);
-+
-+                      /* Clean up */
-+                      kfree( fstypelist);
-+                      return 0;
-+              }
-+
-+      case DEVMTAB_COUNT_MOUNTS:{
-+                      return(count_mounted_filesystems());
-+              }
-+
-+      case DEVMTAB_GET_MOUNTS:{
-+                      int stat, count;
-+                      struct k_mntent* mntentlist;
-+
-+                      /* How many are there? */
-+                      count = count_mounted_filesystems();
-+
-+                      /* Make some space */
-+                      mntentlist = (struct k_mntent *)kmalloc(sizeof(struct k_mntent) * count, GFP_KERNEL);
-+                      if (!mntentlist)
-+                              return -ENOMEM;
-+                      memset(mntentlist, 0, sizeof(struct k_mntent) * count);
-+
-+                      /* Grab the mtab entries */
-+                      get_mtab_entries (count, mntentlist);
-+
-+                      /* Make sure there is enough room */
-+                      stat = verify_area (VERIFY_WRITE, (void*) arg,
-+                                          sizeof(struct k_mntent) * count);
-+                      if (stat) {
-+                              printk (KERN_INFO
-+                                      "devmtab: Insufficient space was provided.\n");
-+                              return stat;
-+                      }
-+
-+                      /* Send it to user space */
-+                      copy_to_user_ret ((struct k_mntent *) arg, mntentlist,
-+                                        sizeof(struct k_mntent) * count, 
-+                                        -EFAULT);
-+
-+                      /* Clean up */
-+                      kfree( mntentlist);
-+                      return 0;
-+              }
-+
-+      default:
-+              return -EINVAL;
-+
-+      }
-+      return 0;
-+}
-+
-+
-+
-+/****************************************************************************
-+ * Set up the file operations devmtab will support
-+ */
-+static struct file_operations devmtab_fops = {
-+      devmtab_lseek,
-+      devmtab_read,
-+      NULL,                   /* No write */
-+      NULL,                   /* No readdir */
-+      NULL,                   /* No poll */
-+      devmtab_ioctl,
-+      NULL,                   /* No mmap */
-+      devmtab_open,
-+      NULL,                   /* flush */
-+      devmtab_release,
-+      NULL,                   /* fsync */
-+      NULL,                   /* fasync */
-+      NULL,                   /* check_media_change */
-+      NULL                    /* revalidate */
-+};
-+
-+static struct miscdevice devmtab_misc_dev = {
-+      DEVMTAB_MINOR,
-+      "devmtab",
-+      &devmtab_fops
-+};
-+
-+/* The real driver initialization function */
-+extern int devmtab_init (void)
-+{
-+      printk (KERN_INFO "devmtab: driver %s loaded\n", DEVMTAB_VERSION);
-+
-+      if (misc_register (&devmtab_misc_dev)) {
-+              printk ("devmtab: can't register misc device %d\n",
-+                      DEVMTAB_MINOR);
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+#ifdef MODULE
-+
-+MODULE_AUTHOR ("Erik Andersen <andersee@debian.org>");
-+MODULE_DESCRIPTION
-+      ("devmtab driver -- exports filesystem and mount information to user space");
-+
-+/* Stub driver initialization function */
-+int init_module (void)
-+{
-+      return (devmtab_init ());
-+}
-+
-+void cleanup_module (void)
-+{
-+      printk (KERN_INFO "devmtab: driver unloaded\n");
-+      misc_deregister (&devmtab_misc_dev);
-+}
-+
-+#endif        /* MODULE */
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devps.c linux/drivers/char/devps.c
---- linux-2.2.18-9.virgin/drivers/char/devps.c Wed Dec 31 17:00:00 1969
-+++ linux/drivers/char/devps.c Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,518 @@
-+/* vi: set sw=8 ts=8: */
-+/*
-+ * linux/drivers/char/devps.c
-+ * 
-+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
-+ *
-+ * May be copied or modified under the terms of the GNU General Public License.
-+ * See linux/COPYING for more information.
-+ *
-+ * This driver implements an interface whereby programs such as ps(1), top(1),
-+ * killall(1) and the like may obtain all the process information they need to
-+ * do their jobs.  Now you may ask, "Why not use /proc?  BSD uses /proc.".
-+ * Thanks for asking.  /proc is designed as a virtual filesystem.  As such it
-+ * presents all of its information in a nice, human readable format.  But not
-+ * human readable enough that mere mortals can actually look at the /proc
-+ * information and know what is happening on their computer (which is why we
-+ * have nice programs like ps(1) to help us out.  Additionally, for ps (using
-+ * /proc) to do its job, it has to do something like:
-+ *
-+ *    dir = opendir("/proc");
-+ *    while ((entry = readdir(dir)) != NULL) { 
-+ *            if (!isdigit(*entry->d_name))
-+ *                    continue;
-+ *            open_lots_of files();
-+ *            parse_lots_of_strings();
-+ *            close_lots_of_files();
-+ *            print_stuff();
-+ *    }
-+ *
-+ *
-+ * This is bad, because:
-+ *
-+ * 1) opening and closing lots of files is slow,
-+ *
-+ * 2) parsing lots of strings is slow,
-+ *
-+ * 3) every one of those strings had to be carefully printed out and formatted
-+ * by the kernel, which is slow,
-+ *
-+ * 4) using a virtual filesystem is not the traditional UN*X solution to
-+ * getting information from the kernel out to userspace (ioctls and syscalls
-+ * are the established way to do this), and worst of all
-+ *
-+ * 5) having a virtual filesystem around has been so inviting that everyone has
-+ * put their own weird little files into it, causing /proc to become a
-+ * cluttered rubbish heap of 64 flavors of strange that takes a ridiculous
-+ * amount of memory.  
-+ *
-+ * This driver is the first step in my evil plan to completely 
-+ * dismantle /proc.  Muhahahaha!
-+ *
-+ * Suggestions are welcome. Patches that work are more welcome though. ;-)
-+ *
-+ * When using this driver, running:
-+ *    mknod /dev/ps c 10 21
-+ * could be considered helpful.
-+ *
-+ * ----------------------------------
-+ * 1.00  Mar 07, 2000 -- Initial version.
-+ *
-+ *
-+ * TODO
-+ * ----------------------------------
-+ *
-+ *  * Right now none of the vm or fd info is being returned to user space. 
-+ *  * There is probably other stuff that should be exported to user space.
-+ *
-+ *
-+ *************************************************************************/
-+
-+#define DEVPS_VERSION "1.00"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/mm.h>
-+#include <linux/pagemap.h>
-+#include <linux/malloc.h>
-+#include <linux/miscdevice.h>
-+#include <linux/devps.h>
-+#include <linux/wrapper.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+
-+/* Some variables used by this device */
-+static struct wait_queue *devps_waitq = NULL;
-+static int devps_already_opened = 0;
-+
-+/****************************************************************************
-+ * Handle opening and closing of the device
-+ */
-+
-+static int devps_open (struct inode *ip, struct file *fp)
-+{
-+      /* Only let one process use us at any time -- putting other
-+       * processes to sleep.  Those opening us O_NONBLOCK will
-+       * get an EAGAIN error */
-+      if ((fp->f_flags & O_NONBLOCK) && devps_already_opened) 
-+              return -EAGAIN;
-+
-+      MOD_INC_USE_COUNT;
-+
-+      while (devps_already_opened) {
-+              int i, got_signal=0;
-+
-+              /* Go to sleep until we get woken up 
-+               * by devps_close or we receive a signal */
-+              module_interruptible_sleep_on(&devps_waitq);
-+
-+              for(i=0; i<_NSIG_WORDS && !got_signal; i++)
-+                      got_signal = current->signal.sig[i] & ~current->blocked.sig[i];
-+
-+              /* If we got a signal, decrement the use count
-+               * and return to user space */
-+              if (got_signal) {
-+                      MOD_DEC_USE_COUNT;
-+                      return -EINTR;
-+              }
-+      }
-+
-+      /* Since we got here, then device_already_opened must equal 0 */
-+      devps_already_opened=1;
-+      return 0;
-+}
-+
-+static int devps_release (struct inode *ip, struct file *fp)
-+{
-+      /* Zero out the reference counter */
-+      devps_already_opened=0;
-+
-+      /* Wake up anybody that is waiting to access this device */
-+      module_wake_up(&devps_waitq);
-+
-+      MOD_DEC_USE_COUNT;
-+      return 0;
-+}
-+
-+
-+/*
-+ * This pretty-prints the pathname of a dentry,
-+ * clarifying sockets etc.
-+ */
-+static int
-+get_name_from_dentry (struct dentry *dentry, char *buffer, int buflen)
-+{
-+      struct inode *inode;
-+      char *tmp = (char *) __get_free_page (GFP_KERNEL), *path, *pattern;
-+      int len;
-+
-+      if (tmp == NULL)
-+              return -ENOMEM;
-+
-+      /* Check for special dentries.. */
-+      pattern = NULL;
-+      inode = dentry->d_inode;
-+      if (inode && dentry->d_parent == dentry) {
-+              if (S_ISSOCK (inode->i_mode))
-+                      pattern = "socket:[%lu]";
-+              if (S_ISFIFO (inode->i_mode))
-+                      pattern = "pipe:[%lu]";
-+      }
-+
-+      if (pattern) {
-+              len = sprintf (tmp, pattern, inode->i_ino);
-+              path = tmp;
-+      } else {
-+              path = d_path (dentry, tmp, PAGE_SIZE);
-+              len = tmp + PAGE_SIZE - 1 - path;
-+      }
-+
-+      if (len < buflen)
-+              buflen = len;
-+      dput (dentry);
-+      strncpy (buffer, path, buflen);
-+      free_page ((unsigned long) tmp);
-+      return buflen;
-+}
-+
-+static unsigned long get_phys_addr (struct task_struct *p,
-+                                  unsigned long ptr)
-+{
-+      pgd_t *page_dir;
-+      pmd_t *page_middle;
-+      pte_t pte;
-+
-+      if (!p || !p->mm || ptr >= TASK_SIZE)
-+              return 0;
-+      /* Check for NULL pgd .. shouldn't happen! */
-+      if (!p->mm->pgd) {
-+              printk ("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
-+              return 0;
-+      }
-+
-+      page_dir = pgd_offset (p->mm, ptr);
-+      if (pgd_none (*page_dir))
-+              return 0;
-+      if (pgd_bad (*page_dir)) {
-+              printk ("bad page directory entry %08lx\n",
-+                      pgd_val (*page_dir));
-+              pgd_clear (page_dir);
-+              return 0;
-+      }
-+      page_middle = pmd_offset (page_dir, ptr);
-+      if (pmd_none (*page_middle))
-+              return 0;
-+      if (pmd_bad (*page_middle)) {
-+              printk ("bad page middle entry %08lx\n",
-+                      pmd_val (*page_middle));
-+              pmd_clear (page_middle);
-+              return 0;
-+      }
-+      pte = *pte_offset (page_middle, ptr);
-+      if (!pte_present (pte))
-+              return 0;
-+      return pte_page (pte) + (ptr & ~PAGE_MASK);
-+}
-+
-+static int get_array (struct task_struct *p, unsigned long start,
-+                    unsigned long end, char *buffer)
-+{
-+      unsigned long addr;
-+      int size = 0, result = 0;
-+      char c;
-+
-+      if (start >= end)
-+              return result;
-+      for (;;) {
-+              addr = get_phys_addr (p, start);
-+              if (!addr)
-+                      return result;
-+              do {
-+                      c = *(char *) addr;
-+                      if (!c)
-+                              result = size;
-+                      if (size < PAGE_SIZE)
-+                              buffer[size++] = c;
-+                      else
-+                              return result;
-+                      addr++;
-+                      start++;
-+                      if (!c && start >= end)
-+                              return result;
-+              } while (addr & ~PAGE_MASK);
-+      }
-+      return result;
-+}
-+
-+static int
-+devps_ioctl (struct inode *ip, struct file *fp,
-+           unsigned int cmd, unsigned long arg)
-+{
-+      switch (cmd) {
-+
-+      /* Count up the total number of processes, 
-+       * and then return that total */
-+      case DEVPS_GET_NUM_PIDS:{
-+                      struct task_struct *p;
-+                      pid_t num_pids = 0;
-+
-+                      read_lock (&tasklist_lock);
-+                      for_each_task (p) {
-+                              if (!p->pid)
-+                                      continue;
-+                              num_pids++;
-+                      }
-+                      read_unlock (&tasklist_lock);
-+
-+                      copy_to_user_ret ((pid_t *) arg, &num_pids,
-+                                        sizeof (num_pids), -EFAULT);
-+                      return 0;
-+              }
-+
-+      /* Returns an array containing all current pids, where
-+         pidlist[0]=number of PIDs in the array. pidlist[0] also
-+         specifies the size of the array for the kernel to
-+         fill... */
-+      case DEVPS_GET_PID_LIST:{
-+                      struct task_struct *p;
-+                      pid_t *pid_array = NULL;
-+                      pid_t num_pids;
-+                      int stat;
-+
-+                      /* Grab the first element to see how many * entries
-+                         they want us to fill */
-+                      stat = verify_area (VERIFY_READ, (char *) arg,
-+                                           sizeof (pid_t));
-+                      if (stat) {
-+                              printk (KERN_INFO
-+                                      "devps: can't tell how many "
-+                                      "to pid's to write.\n");
-+                              return stat;
-+                      }
-+
-+                      copy_from_user (&num_pids, (void *) arg,
-+                                      sizeof (num_pids));
-+
-+                      /* Now make sure we can write the specified amount
-+                         of stuff into the array.  If we can't we might 
-+                         as well quit now and save ourselves the bother. */
-+                      stat = verify_area (VERIFY_WRITE, (char *) arg,
-+                                           sizeof (pid_t) * num_pids);
-+                      if (stat) {
-+                              printk (KERN_INFO
-+                                      "devps: Insufficient space was "
-+                                      "provided to write %d pid's.\n",
-+                                      num_pids);
-+                              return stat;
-+                      }
-+
-+                      /* Allocate some memory to hold this stuff in before
-+                         * we copy it out to user-space */
-+                      pid_array = (pid_t *) kmalloc (num_pids *
-+                                                 sizeof (pid_t),
-+                                                 GFP_KERNEL);
-+                      if (pid_array == NULL)
-+                              return -ENOMEM;
-+
-+                      /* Now march through the PID list */
-+                      pid_array[0] = 0;
-+                      read_lock (&tasklist_lock);
-+                      for_each_task (p) {
-+                              if (!p->pid)
-+                                      continue;
-+                              (pid_array[0])++;
-+                              if (pid_array[0] >= (num_pids - 1))
-+                                      continue;
-+                              pid_array[pid_array[0]] = p->pid;
-+                      }
-+                      read_unlock (&tasklist_lock);
-+
-+                      /* Copy out to the user the number we actually filled 
-+                       */
-+                      copy_to_user_ret ((void *) arg, pid_array,
-+                                        sizeof (pid_t) * pid_array[0],
-+                                        -EFAULT);
-+                      kfree (pid_array);
-+
-+                      return 0;
-+              }
-+
-+      /* Find the details on a particular pid, and fill out a
-+         struct with all the gory details. */
-+      case DEVPS_GET_PID_INFO:{
-+                      struct task_struct *p;
-+                      struct pid_info mypidinfo;
-+                      unsigned int state;
-+                      /* 'R' running    */
-+                      /* 'S' sleeping   */
-+                      /* 'D' disk sleep */
-+                      /* 'Z' zombie     */
-+                      /* 'T' stopped    */
-+                      /* 'W' paging     */
-+                      const char *state_string = "RSDZTW";
-+
-+                      copy_from_user_ret (&mypidinfo,
-+                                          (struct pid_info *) arg,
-+                                          sizeof (mypidinfo), -EFAULT);
-+
-+                      read_lock (&tasklist_lock);
-+                      p = find_task_by_pid (mypidinfo.pid);
-+                      read_unlock (&tasklist_lock);
-+
-+                      /* Now copy all this crap so we can tell user space 
-+                         all about it.  ick.  */
-+                      memset (mypidinfo.name, 0,
-+                              sizeof (mypidinfo.name));
-+                      strcpy (mypidinfo.name, p->comm);
-+                      mypidinfo.flags = p->flags;
-+                      mypidinfo.pgrp = p->pgrp;
-+                      mypidinfo.tms_cutime = p->times.tms_cutime;
-+                      mypidinfo.tms_cstime = p->times.tms_cstime;
-+                      mypidinfo.tms_utime = p->times.tms_utime;
-+                      mypidinfo.tms_stime = p->times.tms_stime;
-+                      mypidinfo.min_flt = p->min_flt;
-+                      mypidinfo.cmin_flt = p->cmin_flt;
-+                      mypidinfo.maj_flt = p->maj_flt;
-+                      mypidinfo.cmaj_flt = p->cmaj_flt;
-+                      mypidinfo.session = p->session;
-+                      mypidinfo.pid = p->pid;
-+                      mypidinfo.ppid = p->p_pptr->pid;
-+                      mypidinfo.tty =
-+                              p->tty ? kdev_t_to_nr (p->tty->device) : 0;
-+                      mypidinfo.start_time = p->start_time;
-+                      mypidinfo.uid = p->uid;
-+                      mypidinfo.euid = p->euid;
-+                      mypidinfo.suid = p->suid;
-+                      mypidinfo.fsuid = p->fsuid;
-+                      mypidinfo.gid = p->gid;
-+                      mypidinfo.egid = p->egid;
-+                      mypidinfo.sgid = p->sgid;
-+                      mypidinfo.fsgid = p->fsgid;
-+                      mypidinfo.priority = 20 - (p->counter * 10 + 
-+                                      DEF_PRIORITY / 2) / DEF_PRIORITY;
-+                      mypidinfo.nice = 20 - (mypidinfo.priority * 20 +
-+                                    DEF_PRIORITY / 2) / DEF_PRIORITY;
-+                      state = p-> state & (TASK_RUNNING | TASK_INTERRUPTIBLE
-+                                       | TASK_UNINTERRUPTIBLE |
-+                                       TASK_ZOMBIE | TASK_STOPPED |
-+                                       TASK_SWAPPING);
-+                      while (state) {
-+                              state_string++;
-+                              state >>= 1;
-+                      }
-+                      mypidinfo.state = *state_string;
-+                      mypidinfo.processor = p->processor;
-+                      mypidinfo.nswap = p->nswap;
-+                      mypidinfo.cnswap = p->cnswap;
-+                      if (p && p->mm) {
-+                              char *page = NULL;
-+
-+                              /* Look for some elbow room */
-+                              if (!(page = (char*)get_free_page (GFP_KERNEL)))
-+                                      return -ENOMEM;
-+                              /* Grab the command line */
-+                              get_array (p, p->mm->arg_start,
-+                                         p->mm->arg_end, page);
-+                              memcpy( mypidinfo.command_line, page, sizeof( mypidinfo.command_line));
-+                              mypidinfo.command_line[sizeof( mypidinfo.command_line)-1]='\0';
-+
-+                              /* Grab the environment */
-+                              memset (page, 0, PAGE_SIZE);
-+                              get_array (p, p->mm->env_start,
-+                                         p->mm->env_end, page);
-+                              memcpy( mypidinfo.environment, page, sizeof( mypidinfo.environment));
-+                              mypidinfo.command_line[sizeof( mypidinfo.environment)-1]='\0';
-+                              free_page ((unsigned long) page);
-+                      }
-+                      memset (mypidinfo.cwd, 0, sizeof (mypidinfo.cwd));
-+                      get_name_from_dentry (dget (p->fs->pwd), mypidinfo.cwd,
-+                                            sizeof (mypidinfo.cwd));
-+                      memset (mypidinfo.root, 0, sizeof (mypidinfo.root));
-+                      get_name_from_dentry (dget (p->fs->root),
-+                                            mypidinfo.root,
-+                                            sizeof (mypidinfo.root));
-+
-+                      copy_to_user_ret ((struct pid_info *) arg,
-+                                        &mypidinfo, sizeof (mypidinfo),
-+                                        -EFAULT);
-+
-+                      return 0;
-+              }
-+
-+      /* Return the PID of the current process */
-+      case DEVPS_GET_CURRENT_PID:{
-+                      return current->pid;
-+              }
-+
-+      default:
-+              return -EINVAL;
-+
-+      }
-+      return 0;
-+}
-+
-+
-+
-+/****************************************************************************
-+ * Set up the file operations devps will support
-+ */
-+static struct file_operations devps_fops = {
-+      NULL,                   /* No lseek */
-+      NULL,                   /* No read */
-+      NULL,                   /* No write */
-+      NULL,                   /* No readdir */
-+      NULL,                   /* No poll */
-+      devps_ioctl,
-+      NULL,                   /* No mmap */
-+      devps_open,
-+      NULL,                   /* flush */
-+      devps_release,
-+      NULL,                   /* fsync */
-+      NULL,                   /* fasync */
-+      NULL,                   /* check_media_change */
-+      NULL                    /* revalidate */
-+};
-+
-+static struct miscdevice devps_misc_dev = {
-+      DEVPS_MINOR,
-+      "devps",
-+      &devps_fops
-+};
-+
-+/* The real driver initialization function */
-+extern int devps_init (void)
-+{
-+      printk (KERN_INFO "devps driver %s loaded\n", DEVPS_VERSION);
-+
-+      if (misc_register (&devps_misc_dev)) {
-+              printk ("devps: unable to get misc device %d\n",
-+                      DEVPS_MINOR);
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+#ifdef MODULE
-+
-+MODULE_AUTHOR ("Erik Andersen <andersee@debian.org>");
-+MODULE_DESCRIPTION
-+      ("devps driver -- exports kernel process information to user space");
-+
-+
-+/* Stub driver initialization function */
-+int init_module (void)
-+{
-+      return (devps_init ());
-+}
-+
-+void cleanup_module (void)
-+{
-+      printk (KERN_INFO "devps driver unloaded\n");
-+      misc_deregister (&devps_misc_dev);
-+}
-+
-+#endif                                /* endif MODULE */
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/makedevps.sh linux/drivers/char/makedevps.sh
---- linux-2.2.18-9.virgin/drivers/char/makedevps.sh    Wed Dec 31 17:00:00 1969
-+++ linux/drivers/char/makedevps.sh    Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,5 @@
-+#!/bin/sh -x
-+
-+gcc -Wall -g -I /usr/src/linux/include ps-devps.c -o ps-devps
-+gcc -Wall -g -I /usr/src/linux/include mounts.c -o mounts
-+
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/misc.c linux/drivers/char/misc.c
---- linux-2.2.18-9.virgin/drivers/char/misc.c  Mon Sep 18 15:02:31 2000
-+++ linux/drivers/char/misc.c  Mon Sep 25 17:00:57 2000
-@@ -85,6 +85,8 @@
- extern int pmu_device_init(void);
- extern int tosh_init(void);
- extern int rng_init(void);
-+extern int devps_init(void);
-+extern int devmtab_init(void);
- static int misc_read_proc(char *buf, char **start, off_t offset,
-                         int len, int *eof, void *private)
-@@ -268,6 +270,12 @@
- #endif
- #ifdef CONFIG_PMAC_PBOOK
-       pmu_device_init();
-+#endif
-+#ifdef CONFIG_DEVPS
-+      devps_init();
-+#endif
-+#ifdef CONFIG_DEVMTAB
-+      devmtab_init();
- #endif
- #ifdef CONFIG_SGI_NEWPORT_GFX
-       gfx_register ();
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/mounts.c linux/drivers/char/mounts.c
---- linux-2.2.18-9.virgin/drivers/char/mounts.c        Wed Dec 31 17:00:00 1969
-+++ linux/drivers/char/mounts.c        Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,116 @@
-+/* vi: set sw=4 ts=4: */
-+/*
-+ * devmtab tester
-+ *
-+ *
-+ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <time.h>
-+#include <fcntl.h>
-+#include <sys/ioctl.h>
-+#include <sys/types.h>
-+#include <linux/devmtab.h>
-+
-+
-+int main (int argc, char **argv)
-+{
-+      char device[80] = "/dev/mtab";
-+      int fd;           /* file descriptor for devmtab device */
-+      int i, numfilesystems;
-+      struct k_fstype *fslist;
-+      struct k_mntent *mntentlist;
-+
-+      if (argc > 1 && **(argv + 1) == '-') {
-+              fprintf(stderr, "Usage: mounts\n\nReport mounted stuff\n\nThis version of mounts accepts no options.\n\n");
-+              exit(1);
-+      }
-+
-+      /* open device */ 
-+      if ((fd = open(device, O_RDONLY)) < 0) {
-+              fprintf (stderr, "open failed for `%s': %s\n",
-+                       device, strerror (errno));
-+              exit (1);
-+      }
-+
-+      /* How many filesystems?  We need to know to allocate 
-+       * enough space for later... */
-+      numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS);
-+      if (numfilesystems<0) {
-+              fprintf (stderr, "\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", 
-+                      strerror (errno));
-+              exit (1);
-+      } 
-+      fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype));
-+
-+      /* Grab the list of available filesystems */
-+      if (ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist)<0) {
-+              fprintf (stderr, "\nDEVMTAB_GET_FILESYSTEMS: %s\n", 
-+                      strerror (errno));
-+              exit (1);
-+      } 
-+      fprintf( stdout, "\nEquivalent of /proc/filesystems:\n");
-+      for( i = 0 ; i < numfilesystems ; i++) {
-+              fprintf( stdout, "%s%s\n", fslist[i].mnt_type, 
-+                              (fslist[i].mnt_nodev)? " nodev" : "");
-+      }
-+
-+
-+      /* How many mounted filesystems?  We need to know to 
-+       * allocate enough space for later... */
-+      numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
-+      if (numfilesystems<0) {
-+              fprintf (stderr, "\nDEVMTAB_COUNT_MOUNTS: %s\n", 
-+                      strerror (errno));
-+              exit (1);
-+      } 
-+      mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent));
-+      
-+      /* Grab the list of mounted filesystems */
-+      if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) {
-+              fprintf (stderr, "\nDEVMTAB_GET_MOUNTS: %s\n", 
-+                      strerror (errno));
-+              exit (1);
-+      } 
-+
-+      fprintf( stdout, "\nEquivalent of /proc/mounts:\n");
-+      for( i = 0 ; i < numfilesystems ; i++) {
-+              fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
-+                              mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
-+                              mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
-+                              mntentlist[i].mnt_passno);
-+      }
-+
-+
-+      /* clean up */
-+      free( fslist);
-+      free( mntentlist);
-+      if (close (fd) != 0) {
-+              fprintf (stderr, "close failed for `%s': %s\n",
-+                       device, strerror (errno));
-+              exit (1);
-+      }
-+ 
-+      exit (0);
-+}
-+
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/ps-devps.c linux/drivers/char/ps-devps.c
---- linux-2.2.18-9.virgin/drivers/char/ps-devps.c      Wed Dec 31 17:00:00 1969
-+++ linux/drivers/char/ps-devps.c      Mon Sep 25 17:32:19 2000
-@@ -0,0 +1,148 @@
-+/* vi: set sw=4 ts=4: */
-+/*
-+ * Mini ps implementation for use with the Linux devps driver
-+ *
-+ *
-+ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <time.h>
-+#include <fcntl.h>
-+#include <sys/ioctl.h>
-+#include <linux/devps.h>
-+#include <pwd.h>
-+#include <grp.h>
-+#include <sys/types.h>
-+
-+
-+#define MAX_COLUMN    79
-+
-+int
-+main (int argc, char **argv)
-+{
-+      char device[80] = "/dev/ps";
-+      int i, j, len;
-+      int fd;           /* file descriptor for devps device */
-+      int status;       /* return status for system calls */
-+      pid_t num_pids;
-+      pid_t* pid_array = NULL;
-+      struct pid_info info;
-+      struct passwd *pwd;
-+      struct group *grp;
-+      char uidName[10] = "";
-+      char groupName[10] = "";
-+
-+      if (argc > 1 && **(argv + 1) == '-') {
-+              fprintf(stderr, "Usage: ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n");
-+              exit(1);
-+      }
-+
-+      /* open device */ 
-+      //fd = open(device, O_RDWR);
-+      fd = open(device, O_RDONLY);
-+      if (fd < 0) {
-+              fprintf (stderr, "open failed for `%s': %s\n",
-+                       device, strerror (errno));
-+              goto error;
-+      }
-+
-+      /* Find out how many processes there are */
-+      status = ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids);
-+      if (status<0) {
-+              fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", 
-+                      strerror (errno));
-+              goto error;
-+      } 
-+      
-+      /* Allocate some memory -- grab a few extras just in case 
-+       * some new processes start up while we wait. The kernel will
-+       * just ignore any extras if we give it too many, and will trunc.
-+       * the list if we give it too few.  */
-+      pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
-+      pid_array[0] = num_pids+10;
-+
-+      /* Now grab the pid list */
-+      status = ioctl (fd, DEVPS_GET_PID_LIST, pid_array);
-+      if (status<0) {
-+              fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", 
-+                      strerror (errno));
-+              goto error;
-+      } 
-+
-+      /* Print up a ps listing */
-+      fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
-+                      "State", "Command");
-+
-+      for (i=1; i<pid_array[0] ; i++) {
-+          info.pid = pid_array[i];
-+          status = ioctl (fd, DEVPS_GET_PID_INFO, &info);
-+          if (status<0) {
-+                  fprintf (stderr, "\nDEVPS_GET_PID_INFO: %s\n", 
-+                          strerror (errno));
-+                  goto error;
-+          } 
-+              /* Make some adjustments as needed */
-+              pwd = getpwuid(info.euid);
-+              if (pwd == NULL)
-+                      sprintf(uidName, "%lu", info.euid);
-+              else
-+                      sprintf(uidName, "%s", pwd->pw_name);
-+              grp = getgrgid(info.egid);
-+              if (grp == NULL)
-+                      sprintf(groupName, "%lu", info.egid);
-+              else
-+                      sprintf(groupName, "%s", grp->gr_name);
-+
-+              len = fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state);
-+
-+              if (strlen(info.command_line) > 1) {
-+                      for( j=0; j<(sizeof(info.command_line)-1) && j < (MAX_COLUMN-len); j++) {
-+                              if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
-+                                      *(info.command_line+j) = ' ';
-+                              }
-+                      }
-+                      *(info.command_line+j) = '\0';
-+                      fprintf(stdout, "%s\n", info.command_line);
-+              } else {
-+                      fprintf(stdout, "[%s]\n", info.name);
-+              }
-+      }
-+
-+      /* Free memory */
-+      free( pid_array);
-+
-+      /* close device */
-+      status = close (fd);
-+      if (status != 0) {
-+              fprintf (stderr, "close failed for `%s': %s\n",
-+                       device, strerror (errno));
-+              goto error;
-+      }
-+ 
-+      exit (0);
-+error:
-+      fflush(stdout);
-+      fflush(stderr);
-+      exit (1);
-+}
-+
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/Makefile linux/fs/Makefile
---- linux-2.2.18-9.virgin/fs/Makefile  Wed Aug 25 18:29:49 1999
-+++ linux/fs/Makefile  Mon Sep 25 16:33:16 2000
-@@ -11,9 +11,10 @@
- L_OBJS    = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
- O_TARGET := fs.o
- O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
--              super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
-+              block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
-               ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-               dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) 
-+OX_OBJS = super.o
- MOD_LIST_NAME := FS_MODULES
- ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/super.c linux/fs/super.c
---- linux-2.2.18-9.virgin/fs/super.c   Mon Sep 18 15:02:34 2000
-+++ linux/fs/super.c   Mon Sep 25 17:00:57 2000
-@@ -18,6 +18,7 @@
-  */
- #include <linux/config.h>
-+#include <linux/module.h>
- #include <linux/malloc.h>
- #include <linux/locks.h>
- #include <linux/smp_lock.h>
-@@ -25,6 +26,7 @@
- #include <linux/init.h>
- #include <linux/quotaops.h>
- #include <linux/acct.h>
-+#include <linux/devmtab.h>
- #include <asm/uaccess.h>
-@@ -311,7 +313,57 @@
-       { 0, NULL }
- };
--int get_filesystem_info( char *buf )
-+
-+extern int count_mounted_filesystems()
-+{
-+      struct vfsmount *tmp = vfsmntlist;
-+      int count = 0;
-+
-+      while (tmp)
-+      {
-+              tmp = tmp->mnt_next;
-+              count++;
-+      }
-+
-+      return count;
-+}
-+EXPORT_SYMBOL(count_mounted_filesystems);
-+
-+
-+extern void get_mtab_entries( int count, struct k_mntent* mntentlist)
-+{
-+      struct vfsmount *tmp = vfsmntlist;
-+      struct proc_fs_info *fs_infop;
-+      int i = 0, len;
-+
-+      while (tmp && i < count)
-+      {
-+              strncpy(mntentlist[i].mnt_fsname, tmp->mnt_devname, 
-+                              sizeof(mntentlist[i].mnt_fsname));
-+              strncpy(mntentlist[i].mnt_dir, tmp->mnt_dirname, 
-+                              sizeof(mntentlist[i].mnt_dir));
-+              strncpy(mntentlist[i].mnt_type, tmp->mnt_sb->s_type->name,
-+                              sizeof(mntentlist[i].mnt_type));
-+              len = 0;
-+              len+=sprintf(mntentlist[i].mnt_opts, "%s", 
-+                              tmp->mnt_flags & MS_RDONLY ? "ro" : "rw");
-+              for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
-+                if (tmp->mnt_flags & fs_infop->flag) {
-+                  strncpy(mntentlist[i].mnt_opts+len, fs_infop->str, 
-+                                  sizeof(mntentlist[i].mnt_opts)-len);
-+                  len += strlen(fs_infop->str);
-+                }
-+              }
-+
-+              /* TODO -- add in NFS stuff */ 
-+
-+              tmp = tmp->mnt_next;
-+              i++;
-+      }
-+}
-+EXPORT_SYMBOL(get_mtab_entries);
-+
-+extern int get_filesystem_info( char *buf )
- {
-       struct vfsmount *tmp = vfsmntlist;
-       struct proc_fs_info *fs_infop;
-@@ -383,8 +435,37 @@
-       return len;
- }
-+EXPORT_SYMBOL(get_filesystem_info);
-+
-+extern int count_kfstypes()
-+{
-+      struct file_system_type * tmp = file_systems;
-+      int count = 0;
-+
-+      while (tmp) {
-+              count++;
-+              tmp = tmp->next;
-+      }
-+
-+      return count;
-+}
-+EXPORT_SYMBOL(count_kfstypes);
-+
-+extern void get_kfstype_list(int count, struct k_fstype* fstypelist)
-+{
-+      int i = 0;
-+      struct file_system_type * tmp = file_systems;
-+
-+      while (tmp && i < count) {
-+              strncpy(fstypelist[i].mnt_type, tmp->name, sizeof(fstypelist[i].mnt_type));
-+              fstypelist[i].mnt_nodev = (tmp->fs_flags & FS_REQUIRES_DEV)? 0 : 1;
-+              tmp = tmp->next;
-+              i++;
-+      }
-+}
-+EXPORT_SYMBOL(get_kfstype_list);
--int get_filesystem_list(char * buf)
-+extern int get_filesystem_list(char * buf)
- {
-       int len = 0;
-       struct file_system_type * tmp;
-@@ -398,6 +479,7 @@
-       }
-       return len;
- }
-+EXPORT_SYMBOL(get_filesystem_list);
- struct file_system_type *get_fs_type(const char *name)
- {
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devmtab.h linux/include/linux/devmtab.h
---- linux-2.2.18-9.virgin/include/linux/devmtab.h      Wed Dec 31 17:00:00 1969
-+++ linux/include/linux/devmtab.h      Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,55 @@
-+/* vi: set sw=8 ts=8: */
-+/*
-+ * -- <linux/devmtab.h>
-+ *  
-+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
-+ * 
-+ * May be copied or modified under the terms of the GNU General Public License.
-+ * See linux/COPYING for more information.
-+ *
-+ * This driver implements an interface whereby programs such as mount(8),
-+ * umount(8), and df(1) may obtain all the process information they need to do
-+ * their jobs without needing to use /proc.
-+ *
-+ */
-+ 
-+#ifndef       _LINUX_DEVMTAB_H
-+#define       _LINUX_DEVMTAB_H
-+
-+
-+/*******************************************************
-+ * The list of all ioctl(2) commands suported by devmtab.
-+ * For the devmtab ioctls, I have commandeered some of the
-+ * higher bits of byte 0xeb.
-+ *******************************************************/
-+#define DEVMTAB_COUNT_FILESYSTEMS  0xebaa /* Get a list of all fs */ 
-+#define DEVMTAB_GET_FILESYSTEMS    0xebab /* Get a list of all fs */ 
-+#define DEVMTAB_COUNT_MOUNTS       0xebac /* Returns number of mounted filesystems */
-+#define DEVMTAB_GET_MOUNTS         0xebad /* Get a list of a mounted fs */
-+#define DEVMTAB_SET_ROOTFS_DEVNAME 0xebae /* Replace /dev/root with real name */
-+
-+/*******************************************************
-+ * devmtab ioctl(2) structures
-+ *******************************************************/
-+
-+/* An array of these is returned by the DEVMTAB_GET_FILESYSTEMS ioctl.
-+ */
-+struct k_fstype {
-+      char    mnt_type[255];   /* filesystem type: ext2, nfs, etc. */
-+      int     mnt_nodev;       /* Is this a device-less filesystem? */
-+};
-+
-+/* An array of these is returned by the DEVMTAB_GET_MOUNTS ioctl.
-+ * This struct should be the same as what libc returns via the
-+ * getmntent(3) function (excat this comes from the kernel, not
-+ * from whatever noise is in /etc/mtab at the moment... */
-+struct k_mntent {
-+      char    mnt_fsname[255];    /* name of mounted file system */
-+      char    mnt_dir[255];       /* path of file system mount point */
-+      char    mnt_type[255];      /* filesystem type: ext2, nfs, etc. */
-+      char    mnt_opts[255];      /* Comma-separated list of mount options */
-+      int     mnt_freq;       /* dump frequency in days */
-+      int     mnt_passno;     /* pass number for parallel fsck */
-+};
-+
-+#endif  /* _LINUX_DEVMTAB_H */
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devps.h linux/include/linux/devps.h
---- linux-2.2.18-9.virgin/include/linux/devps.h        Wed Dec 31 17:00:00 1969
-+++ linux/include/linux/devps.h        Mon Sep 25 17:00:57 2000
-@@ -0,0 +1,78 @@
-+/*
-+ * -- <linux/devps.h>
-+ *  
-+ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
-+ * 
-+ * May be copied or modified under the terms of the GNU General Public License.
-+ * See linux/COPYING for more information.
-+ *
-+ * This driver implements an interface whereby programs such as ps(1), top(1),
-+ * killall(1) and the like may obtain all the process information they need to
-+ * do their jobs.
-+ *
-+ */
-+ 
-+#ifndef       _LINUX_DEVPS_H
-+#define       _LINUX_DEVPS_H
-+
-+
-+/*******************************************************
-+ * The list of all ioctl(2) commands suported by devps.
-+ * For the devps ioctls, I have commandeered some of the
-+ * higher bits of byte 0xeb.
-+ *******************************************************/
-+#define DEVPS_GET_NUM_PIDS    0xeba1 /* Get a list of all PIDs */ 
-+#define DEVPS_GET_PID_LIST    0xeba2 /* Get a list of all PIDs */ 
-+#define DEVPS_GET_PID_INFO    0xeba3 /* Get info about a specific PID */
-+#define DEVPS_GET_CURRENT_PID 0xeba4 /* Get the current PID */
-+
-+/*******************************************************
-+ * devps ioctl(2) structures
-+ *******************************************************/
-+
-+
-+struct pid_info
-+{
-+      char  name[16];
-+      long flags;
-+      pid_t pgrp;
-+      clock_t tms_cutime;
-+      clock_t tms_cstime;
-+      clock_t tms_utime;
-+      clock_t tms_stime;
-+      unsigned long min_flt;
-+      unsigned long cmin_flt;
-+      unsigned long maj_flt;
-+      unsigned long cmaj_flt;
-+      pid_t session;
-+      pid_t pid;
-+      pid_t ppid;
-+      int tty;
-+      unsigned long start_time;
-+      unsigned long uid,euid,suid,fsuid;
-+      unsigned long gid,egid,sgid,fsgid;
-+      long priority, nice;
-+      char state;
-+      int processor;
-+      unsigned long nswap, cnswap;
-+      char command_line[256];
-+      char environment[256];
-+      char root[256];
-+      char cwd[256];
-+#if 0
-+      /* TODO: Add in this (and probably more) stuff */
-+
-+      int resident;
-+      int size;
-+      int share;
-+      unsigned long vsize;
-+      char exe[MAX_PATH];
-+      unsigned long vm_total, vm_locked, vm_rss, vm_data, vm_stack, vm_exec, vm_lib;
-+      unsigned long start_code, end_code, start_data, eip, esp;
-+      unsigned long signal, blocked;
-+#endif
-+
-+
-+};
-+
-+#endif  /* _LINUX_DEVPS_H */
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/fs.h linux/include/linux/fs.h
---- linux-2.2.18-9.virgin/include/linux/fs.h   Mon Sep 18 15:08:47 2000
-+++ linux/include/linux/fs.h   Mon Sep 25 17:37:50 2000
-@@ -573,6 +573,16 @@
-       struct semaphore s_vfs_rename_sem;      /* Kludge */
- };
-+/* fs/super.c */
-+#include <linux/devmtab.h>
-+
-+extern int count_kfstypes( void);
-+extern void get_kfstype_list( int count, struct k_fstype* fstypelist); 
-+extern int count_mounted_filesystems( void);
-+extern int get_filesystem_info(char *buf);
-+extern int get_filesystem_list(char *buf);
-+extern void get_mtab_entries( int count, struct k_mntent* mntentlist);
-+
- /*
-  * VFS helper functions..
-  */
-diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/miscdevice.h linux/include/linux/miscdevice.h
---- linux-2.2.18-9.virgin/include/linux/miscdevice.h   Mon Aug  9 13:04:41 1999
-+++ linux/include/linux/miscdevice.h   Mon Sep 25 16:33:17 2000
-@@ -11,6 +11,8 @@
- #define APOLLO_MOUSE_MINOR 7
- #define PC110PAD_MINOR 9
- #define MAC_MOUSE_MINOR 10
-+#define DEVPS_MINOR           21
-+#define DEVMTAB_MINOR         22
- #define WATCHDOG_MINOR                130     /* Watchdog timer     */
- #define TEMP_MINOR            131     /* Temperature Sensor */
- #define RTC_MINOR 135
diff --git a/busybox/examples/mk2knr.pl b/busybox/examples/mk2knr.pl
deleted file mode 100755 (executable)
index aaf4963..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/perl -w
-#
-# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
-#
-# How to use this script:
-#  - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert'
-#  - Review the 'convertme.pl' script generated and remove / edit any of the
-#    substitutions in there (please especially check for false positives)
-#  - Type './convertme.pl same-files-as-before'
-#  - Compile and see if it works
-#
-# BUGS: This script does not ignore strings inside comments or strings inside
-# quotes (it probably should).
-
-# set this to something else if you want
-$convertme = 'convertme.pl';
-
-# internal-use variables (don't touch)
-$convert = 0;
-%converted = ();
-
-# if no files were specified, print usage
-die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0;
-
-# prepare the "convert me" file
-open(CM, ">$convertme") or die "convertme.pl $!";
-print CM "#!/usr/bin/perl -p -i\n\n";
-
-# process each file passed on the cmd line
-while (<>) {
-
-       # if the line says "getopt" in it anywhere, we don't want to muck with it
-       # because option lists tend to include strings like "cxtzvOf:" which get
-       # matched by the "check for mixed case" regexps below
-       next if /getopt/;
-
-       # tokenize the string into just the variables
-       while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) {
-               $var = $1;
-
-               # ignore the word "BusyBox"
-               next if ($var =~ /BusyBox/);
-
-               # this checks for javaStyle or szHungarianNotation
-               $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/);
-
-               # this checks for PascalStyle
-               $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/);
-
-               # if we want to add more checks, we can add 'em here, but the above
-               # checks catch "just enough" and not too much, so prolly not.
-
-               if ($convert) {
-                       $convert = 0;
-
-                       # skip ahead if we've already dealt with this one
-                       next if ($converted{$var});
-
-                       # record that we've dealt with this var
-                       $converted{$var} = 1;
-
-                       print CM "s/\\b$var\\b/"; # more to come in just a minute
-
-                       # change the first letter to lower-case
-                       $var = lcfirst($var);
-
-                       # put underscores before all remaining upper-case letters
-                       $var =~ s/([A-Z])/_$1/g;
-
-                       # now change the remaining characters to lower-case
-                       $var = lc($var);
-
-                       print CM "$var/g;\n";
-               }
-       }
-}
-
-# tidy up and make the $convertme script executable
-close(CM);
-chmod 0755, $convertme;
-
-# print a helpful help message
-print "Done. Scheduled name changes are in $convertme.\n";
-print "Please review/modify it and then type ./$convertme to do the search & replace.\n";
diff --git a/busybox/examples/undeb b/busybox/examples/undeb
deleted file mode 100644 (file)
index a72e1e2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-#
-# This should work with the GNU version of tar and gzip!
-# This should work with the bash or ash shell!
-# Requires the programs (ar, tar, gzip, and the pager more or less).
-#
-usage() {
-echo "Usage: undeb -c package.deb            <Print control file info>"
-echo "       undeb -l package.deb            <List contents of deb package>"
-echo "       undeb -x package.deb /foo/boo   <Extract deb package to this directory,"
-echo "                                        put . for current directory>"  
-exit
-}
-
-deb=$2
-exist() {
-if [ "$deb" = "" ]; then
-usage
-elif [ ! -s "$deb" ]; then
-echo "Can't find $deb!"
-exit
-fi
-}
-
-if [ "$1" = "" ]; then
-usage
-elif [ "$1" = "-l" ]; then
-exist
-type more >/dev/null 2>&1 && pager=more
-type less >/dev/null 2>&1 && pager=less
-[ "$pager" = "" ] && echo "No pager found!" && exit
-(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager 
-exit
-elif [ "$1" = "-c" ]; then
-exist
-ar -p $deb control.tar.gz | tar -xzO *control  
-exit
-elif [ "$1" = "-x" ]; then
-exist
-if [ "$3" = "" ]; then
-usage
-elif [ ! -d "$3" ]; then
-echo "No such directory $3!"
-exit
-fi
-ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit 
-echo
-echo "Extracted $deb to $3!"
-exit
-else
-usage
-fi
diff --git a/busybox/examples/unrpm b/busybox/examples/unrpm
deleted file mode 100644 (file)
index 376286a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/sh
-#
-# This should work with the GNU version of cpio and gzip!
-# This should work with the bash or ash shell!
-# Requires the programs (cpio, gzip, and the pager more or less).
-#
-usage() {
-echo "Usage: unrpm -l package.rpm            <List contents of rpm package>"
-echo "       unrpm -x package.rpm /foo/boo   <Extract rpm package to this directory,"
-echo "                                        put . for current directory>"  
-exit
-}
-
-rpm=$2
-exist() {
-if [ "$rpm" = "" ]; then
-usage
-elif [ ! -s "$rpm" ]; then
-echo "Can't find $rpm!"
-exit
-fi
-}
-
-if [ "$1" = "" ]; then
-usage
-elif [ "$1" = "-l" ]; then
-exist
-type more >/dev/null 2>&1 && pager=more
-type less >/dev/null 2>&1 && pager=less
-[ "$pager" = "" ] && echo "No pager found!" && exit
-(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager
-exit
-elif [ "$1" = "-x" ]; then
-exist
-if [ "$3" = "" ]; then
-usage
-elif [ ! -d "$3" ]; then
-echo "No such directory $3!"
-exit
-fi
-rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit
-echo
-echo "Extracted $rpm to $3!"
-exit
-else
-usage
-fi
diff --git a/busybox/expr.c b/busybox/expr.c
deleted file mode 100644 (file)
index d6cc82e..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini expr implementation for busybox
- *
- * based on GNU expr Mike Parker.
- * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
- *
- * Busybox modifications 
- * Copyright (c) 2000  Edward Betts <edward@debian.org>.
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2 of the license, or
- * (at your option) any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the gnu
- * general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; if not, write to the free software
- * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
- *
- */
-
-/* This program evaluates expressions.  Each token (operator, operand,
- * parenthesis) of the expression must be a seperate argument.  The
- * parser used is a reasonably general one, though any incarnation of
- * it is language-specific.  It is especially nice for expressions.
- *
- * No parse tree is needed; a new node is evaluated immediately.
- * One function can handle multiple operators all of equal precedence,
- * provided they all associate ((x op x) op x). */
-
-/* no getopt needed */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <regex.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-
-/* The kinds of value we can have.  */
-enum valtype {
-       integer,
-       string
-};
-typedef enum valtype TYPE;
-
-/* A value is.... */
-struct valinfo {
-       TYPE type;                      /* Which kind. */
-       union {                         /* The value itself. */
-               int i;
-               char *s;
-       } u;
-};
-typedef struct valinfo VALUE;
-
-/* The arguments given to the program, minus the program name.  */
-static char **args;
-
-static VALUE *docolon (VALUE *sv, VALUE *pv);
-static VALUE *eval (void);
-static VALUE *int_value (int i);
-static VALUE *str_value (char *s);
-static int nextarg (char *str);
-static int null (VALUE *v);
-static int toarith (VALUE *v);
-static void freev (VALUE *v);
-static void tostring (VALUE *v);
-
-int expr_main (int argc, char **argv)
-{
-       VALUE *v;
-
-       if (argc == 1) {
-               error_msg_and_die("too few arguments");
-       }
-
-       args = argv + 1;
-
-       v = eval ();
-       if (*args)
-               error_msg_and_die ("syntax error");
-
-       if (v->type == integer)
-               printf ("%d\n", v->u.i);
-       else
-               puts (v->u.s);
-
-       exit (null (v));
-}
-
-/* Return a VALUE for I.  */
-
-static VALUE *int_value (int i)
-{
-       VALUE *v;
-
-       v = xmalloc (sizeof(VALUE));
-       v->type = integer;
-       v->u.i = i;
-       return v;
-}
-
-/* Return a VALUE for S.  */
-
-static VALUE *str_value (char *s)
-{
-       VALUE *v;
-
-       v = xmalloc (sizeof(VALUE));
-       v->type = string;
-       v->u.s = strdup (s);
-       return v;
-}
-
-/* Free VALUE V, including structure components.  */
-
-static void freev (VALUE *v)
-{
-       if (v->type == string)
-               free (v->u.s);
-       free (v);
-}
-
-/* Return nonzero if V is a null-string or zero-number.  */
-
-static int null (VALUE *v)
-{
-       switch (v->type) {
-               case integer:
-                       return v->u.i == 0;
-               case string:
-                       return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
-               default:
-                       abort ();
-       }
-}
-
-/* Coerce V to a string value (can't fail).  */
-
-static void tostring (VALUE *v)
-{
-       char *temp;
-
-       if (v->type == integer) {
-               temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
-               sprintf (temp, "%d", v->u.i);
-               v->u.s = temp;
-               v->type = string;
-       }
-}
-
-/* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
-
-static int toarith (VALUE *v)
-{
-       int i;
-
-       switch (v->type) {
-               case integer:
-                       return 1;
-               case string:
-                       i = 0;
-                       /* Don't interpret the empty string as an integer.  */
-                       if (v->u.s == 0)
-                               return 0;
-                       i = atoi(v->u.s);
-                       free (v->u.s);
-                       v->u.i = i;
-                       v->type = integer;
-                       return 1;
-               default:
-                       abort ();
-       }
-}
-
-/* Return nonzero if the next token matches STR exactly.
-   STR must not be NULL.  */
-
-static int
-nextarg (char *str)
-{
-       if (*args == NULL)
-               return 0;
-       return strcmp (*args, str) == 0;
-}
-
-/* The comparison operator handling functions.  */
-
-#define cmpf(name, rel)                                        \
-static int name (l, r) VALUE *l; VALUE *r;             \
-{                                                      \
-       if (l->type == string || r->type == string) {           \
-               tostring (l);                           \
-               tostring (r);                           \
-               return strcmp (l->u.s, r->u.s) rel 0;   \
-       }                                               \
-       else                                            \
-               return l->u.i rel r->u.i;               \
-}
- cmpf (less_than, <)
- cmpf (less_equal, <=)
- cmpf (equal, ==)
- cmpf (not_equal, !=)
- cmpf (greater_equal, >=)
- cmpf (greater_than, >)
-
-#undef cmpf
-
-/* The arithmetic operator handling functions.  */
-
-#define arithf(name, op)                       \
-static                                         \
-int name (l, r) VALUE *l; VALUE *r;            \
-{                                              \
-  if (!toarith (l) || !toarith (r))            \
-    error_msg_and_die ("non-numeric argument");        \
-  return l->u.i op r->u.i;                     \
-}
-
-#define arithdivf(name, op)                    \
-static int name (l, r) VALUE *l; VALUE *r;             \
-{                                              \
-  if (!toarith (l) || !toarith (r))            \
-    error_msg_and_die ( "non-numeric argument");       \
-  if (r->u.i == 0)                             \
-    error_msg_and_die ( "division by zero");           \
-  return l->u.i op r->u.i;                     \
-}
-
- arithf (plus, +)
- arithf (minus, -)
- arithf (multiply, *)
- arithdivf (divide, /)
- arithdivf (mod, %)
-
-#undef arithf
-#undef arithdivf
-
-/* Do the : operator.
-   SV is the VALUE for the lhs (the string),
-   PV is the VALUE for the rhs (the pattern).  */
-
-static VALUE *docolon (VALUE *sv, VALUE *pv)
-{
-       VALUE *v;
-       const char *errmsg;
-       struct re_pattern_buffer re_buffer;
-       struct re_registers re_regs;
-       int len;
-
-       tostring (sv);
-       tostring (pv);
-
-       if (pv->u.s[0] == '^') {
-               fprintf (stderr, "\
-warning: unportable BRE: `%s': using `^' as the first character\n\
-of a basic regular expression is not portable; it is being ignored",
-               pv->u.s);
-       }
-
-       len = strlen (pv->u.s);
-       memset (&re_buffer, 0, sizeof (re_buffer));
-       memset (&re_regs, 0, sizeof (re_regs));
-       re_buffer.allocated = 2 * len;
-       re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
-       re_buffer.translate = 0;
-       re_syntax_options = RE_SYNTAX_POSIX_BASIC;
-       errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
-       if (errmsg) {
-               error_msg_and_die("%s", errmsg);
-       }
-
-       len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
-       if (len >= 0) {
-               /* Were \(...\) used? */
-               if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
-                       sv->u.s[re_regs.end[1]] = '\0';
-                       v = str_value (sv->u.s + re_regs.start[1]);
-               }
-               else
-                       v = int_value (len);
-       }
-       else {
-               /* Match failed -- return the right kind of null.  */
-               if (re_buffer.re_nsub > 0)
-                       v = str_value ("");
-               else
-                       v = int_value (0);
-       }
-       free (re_buffer.buffer);
-       return v;
-}
-
-/* Handle bare operands and ( expr ) syntax.  */
-
-static VALUE *eval7 (void)
-{
-       VALUE *v;
-
-       if (!*args)
-               error_msg_and_die ( "syntax error");
-
-       if (nextarg ("(")) {
-               args++;
-               v = eval ();
-               if (!nextarg (")"))
-                       error_msg_and_die ( "syntax error");
-                       args++;
-                       return v;
-               }
-
-       if (nextarg (")"))
-               error_msg_and_die ( "syntax error");
-
-       return str_value (*args++);
-}
-
-/* Handle match, substr, index, length, and quote keywords.  */
-
-static VALUE *eval6 (void)
-{
-       VALUE *l, *r, *v, *i1, *i2;
-
-       if (nextarg ("quote")) {
-               args++;
-               if (!*args)
-                       error_msg_and_die ( "syntax error");
-               return str_value (*args++);
-       }
-       else if (nextarg ("length")) {
-               args++;
-               r = eval6 ();
-               tostring (r);
-               v = int_value (strlen (r->u.s));
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("match")) {
-               args++;
-               l = eval6 ();
-               r = eval6 ();
-               v = docolon (l, r);
-               freev (l);
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("index")) {
-               args++;
-               l = eval6 ();
-               r = eval6 ();
-               tostring (l);
-               tostring (r);
-               v = int_value (strcspn (l->u.s, r->u.s) + 1);
-               if (v->u.i == (int) strlen (l->u.s) + 1)
-                       v->u.i = 0;
-               freev (l);
-               freev (r);
-               return v;
-       }
-       else if (nextarg ("substr")) {
-               args++;
-               l = eval6 ();
-               i1 = eval6 ();
-               i2 = eval6 ();
-               tostring (l);
-               if (!toarith (i1) || !toarith (i2)
-                       || i1->u.i > (int) strlen (l->u.s)
-                       || i1->u.i <= 0 || i2->u.i <= 0)
-               v = str_value ("");
-               else {
-                       v = xmalloc (sizeof(VALUE));
-                       v->type = string;
-                       v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
-                               l->u.s + i1->u.i - 1, i2->u.i);
-                               v->u.s[i2->u.i] = 0;
-               }
-               freev (l);
-               freev (i1);
-               freev (i2);
-               return v;
-       }
-       else
-               return eval7 ();
-}
-
-/* Handle : operator (pattern matching).
-   Calls docolon to do the real work.  */
-
-static VALUE *eval5 (void)
-{
-       VALUE *l, *r, *v;
-
-       l = eval6 ();
-       while (nextarg (":")) {
-               args++;
-               r = eval6 ();
-               v = docolon (l, r);
-               freev (l);
-               freev (r);
-               l = v;
-       }
-       return l;
-}
-
-/* Handle *, /, % operators.  */
-
-static VALUE *eval4 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval5 ();
-       while (1) {
-               if (nextarg ("*"))
-                       fxn = multiply;
-               else if (nextarg ("/"))
-                       fxn = divide;
-               else if (nextarg ("%"))
-                       fxn = mod;
-               else
-                       return l;
-               args++;
-               r = eval5 ();
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle +, - operators.  */
-
-static VALUE *eval3 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval4 ();
-       while (1) {
-               if (nextarg ("+"))
-                       fxn = plus;
-               else if (nextarg ("-"))
-                       fxn = minus;
-               else
-                       return l;
-               args++;
-               r = eval4 ();
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle comparisons.  */
-
-static VALUE *eval2 (void)
-{
-       VALUE *l, *r;
-       int (*fxn) (), val;
-
-       l = eval3 ();
-       while (1) {
-               if (nextarg ("<"))
-                       fxn = less_than;
-               else if (nextarg ("<="))
-                       fxn = less_equal;
-               else if (nextarg ("=") || nextarg ("=="))
-                       fxn = equal;
-               else if (nextarg ("!="))
-                       fxn = not_equal;
-               else if (nextarg (">="))
-                       fxn = greater_equal;
-               else if (nextarg (">"))
-                       fxn = greater_than;
-               else
-                       return l;
-               args++;
-               r = eval3 ();
-               toarith (l);
-               toarith (r);
-               val = (*fxn) (l, r);
-               freev (l);
-               freev (r);
-               l = int_value (val);
-       }
-}
-
-/* Handle &.  */
-
-static VALUE *eval1 (void)
-{
-       VALUE *l, *r;
-
-       l = eval2 ();
-       while (nextarg ("&")) {
-               args++;
-               r = eval2 ();
-               if (null (l) || null (r)) {
-                       freev (l);
-                       freev (r);
-                       l = int_value (0);
-               }
-               else
-                       freev (r);
-       }
-       return l;
-}
-
-/* Handle |.  */
-
-static VALUE *eval (void)
-{
-       VALUE *l, *r;
-
-       l = eval1 ();
-       while (nextarg ("|")) {
-               args++;
-               r = eval1 ();
-               if (null (l)) {
-                       freev (l);
-                       l = r;
-               }
-               else
-                       freev (r);
-       }
-       return l;
-}
diff --git a/busybox/fbset.c b/busybox/fbset.c
deleted file mode 100644 (file)
index 5ccd80e..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini fbset implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This is a from-scratch implementation of fbset; but the de facto fbset
- * implementation was a good reference. fbset (original) is released under
- * the GPL, and is (c) 1995-1999 by: 
- *     Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#define DEFAULTFBDEV  "/dev/fb0"
-#define DEFAULTFBMODE "/etc/fb.modes"
-
-static const int OPT_CHANGE   = (1 << 0);
-static const int OPT_INFO     = (1 << 1);
-static const int OPT_READMODE = (1 << 2);
-
-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_CHANGE = 13,
-
-#ifdef BB_FEATURE_FBSET_FANCY
-       CMD_XRES = 100,
-       CMD_YRES = 101,
-       CMD_VXRES = 102,
-       CMD_VYRES = 103,
-       CMD_DEPTH = 104,
-       CMD_MATCH = 105,
-       CMD_PIXCLOCK = 106,
-       CMD_LEFT = 107,
-       CMD_RIGHT = 108,
-       CMD_UPPER = 109,
-       CMD_LOWER = 110,
-       CMD_HSLEN = 111,
-       CMD_VSLEN = 112,
-       CMD_CSYNC = 113,
-       CMD_GSYNC = 114,
-       CMD_EXTSYNC = 115,
-       CMD_BCAST = 116,
-       CMD_RGBA = 117,
-       CMD_STEP = 118,
-       CMD_MOVE = 119,
-#endif
-};
-
-static unsigned int g_options = 0;
-
-/* Stuff stolen from the kernel's fb.h */
-static const int FBIOGET_VSCREENINFO = 0x4600;
-static const int FBIOPUT_VSCREENINFO = 0x4601;
-#define __u32                  u_int32_t
-struct fb_bitfield {
-       __u32 offset;                   /* beginning of bitfield        */
-       __u32 length;                   /* length of bitfield           */
-       __u32 msb_right;                /* != 0 : Most significant bit is */ 
-                                       /* right */ 
-};
-struct fb_var_screeninfo {
-       __u32 xres;                     /* visible resolution           */
-       __u32 yres;
-       __u32 xres_virtual;             /* virtual resolution           */
-       __u32 yres_virtual;
-       __u32 xoffset;                  /* offset from virtual to visible */
-       __u32 yoffset;                  /* resolution                   */
-
-       __u32 bits_per_pixel;           /* guess what                   */
-       __u32 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                 */      
-
-       __u32 nonstd;                   /* != 0 Non standard pixel format */
-
-       __u32 activate;                 /* see FB_ACTIVATE_*            */
-
-       __u32 height;                   /* height of picture in mm    */
-       __u32 width;                    /* width of picture in mm     */
-
-       __u32 accel_flags;              /* acceleration flags (hints)   */
-
-       /* Timing: All values in pixclocks, except pixclock (of course) */
-       __u32 pixclock;                 /* pixel clock in ps (pico seconds) */
-       __u32 left_margin;              /* time from sync to picture    */
-       __u32 right_margin;             /* time from picture to sync    */
-       __u32 upper_margin;             /* time from sync to picture    */
-       __u32 lower_margin;
-       __u32 hsync_len;                /* length of horizontal sync    */
-       __u32 vsync_len;                /* length of vertical sync      */
-       __u32 sync;                     /* see FB_SYNC_*                */
-       __u32 vmode;                    /* see FB_VMODE_*               */
-       __u32 reserved[6];              /* Reserved for future compatibility */
-};
-
-
-static struct cmdoptions_t {
-       char *name;
-       unsigned char param_count;
-       unsigned char code;
-} g_cmdoptions[] = {
-       {
-       "-fb", 1, CMD_FB}, {
-       "-db", 1, CMD_DB}, {
-       "-a", 0, CMD_ALL}, {
-       "-i", 0, CMD_INFO}, {
-       "-g", 5, CMD_GEOMETRY}, {
-       "-t", 7, CMD_TIMING}, {
-       "-accel", 1, CMD_ACCEL}, {
-       "-hsync", 1, CMD_HSYNC}, {
-       "-vsync", 1, CMD_VSYNC}, {
-       "-laced", 1, CMD_LACED}, {
-       "-double", 1, CMD_DOUBLE}, {
-       "-n", 0, CMD_CHANGE}, {
-#ifdef BB_FEATURE_FBSET_FANCY
-       "-all", 0, CMD_ALL}, {
-       "-xres", 1, CMD_XRES}, {
-       "-yres", 1, CMD_YRES}, {
-       "-vxres", 1, CMD_VXRES}, {
-       "-vyres", 1, CMD_VYRES}, {
-       "-depth", 1, CMD_DEPTH}, {
-       "-match", 0, CMD_MATCH}, {
-       "-geometry", 5, CMD_GEOMETRY}, {
-       "-pixclock", 1, CMD_PIXCLOCK}, {
-       "-left", 1, CMD_LEFT}, {
-       "-right", 1, CMD_RIGHT}, {
-       "-upper", 1, CMD_UPPER}, {
-       "-lower", 1, CMD_LOWER}, {
-       "-hslen", 1, CMD_HSLEN}, {
-       "-vslen", 1, CMD_VSLEN}, {
-       "-timings", 7, CMD_TIMING}, {
-       "-csync", 1, CMD_CSYNC}, {
-       "-gsync", 1, CMD_GSYNC}, {
-       "-extsync", 1, CMD_EXTSYNC}, {
-       "-bcast", 1, CMD_BCAST}, {
-       "-rgba", 1, CMD_RGBA}, {
-       "-step", 1, CMD_STEP}, {
-       "-move", 1, CMD_MOVE}, {
-#endif
-       0, 0, 0}
-};
-
-#ifdef BB_FEATURE_FBSET_READMODE
-/* taken from linux/fb.h */
-static const int FB_VMODE_INTERLACED = 1;      /* interlaced   */
-static const int FB_VMODE_DOUBLE = 2;  /* double scan */
-static const int FB_SYNC_HOR_HIGH_ACT = 1;     /* horizontal sync high active  */
-static const int FB_SYNC_VERT_HIGH_ACT = 2;    /* vertical sync high active    */
-static const int FB_SYNC_EXT = 4;      /* external sync                */
-static const int FB_SYNC_COMP_HIGH_ACT = 8;    /* composite sync high active   */
-#endif
-static int readmode(struct fb_var_screeninfo *base, const char *fn,
-                                       const char *mode)
-{
-#ifdef BB_FEATURE_FBSET_READMODE
-       FILE *f;
-       char buf[256];
-       char *p = buf;
-
-       f = xfopen(fn, "r");
-       while (!feof(f)) {
-               fgets(buf, sizeof(buf), f);
-               if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) {
-                       p += 5;
-                       if ((p = strstr(buf, mode))) {
-                               p += strlen(mode);
-                               if (!isspace(*p) && (*p != 0) && (*p != '"')
-                                       && (*p != '\r') && (*p != '\n'))
-                                       continue;       /* almost, but not quite */
-                               while (!feof(f)) {
-                                       fgets(buf, sizeof(buf), f);
-
-                    if ((p = strstr(buf, "geometry "))) {
-                        p += 9;
-
-                        sscanf(p, "%d %d %d %d %d", 
-                                &(base->xres), &(base->yres), 
-                                &(base->xres_virtual), &(base->yres_virtual), 
-                                &(base->bits_per_pixel));
-                    } else if ((p = strstr(buf, "timings "))) {
-                        p += 8;
-                        
-                        sscanf(p, "%d %d %d %d %d %d %d",
-                                &(base->pixclock),
-                                &(base->left_margin), &(base->right_margin),
-                                &(base->upper_margin), &(base->lower_margin),
-                                &(base->hsync_len), &(base->vsync_len));
-                    } else if ((p = strstr(buf, "laced "))) {
-                        p += 6;
-
-                        if (strstr(buf, "false")) {
-                            base->vmode &= ~FB_VMODE_INTERLACED;
-                        } else {
-                            base->vmode |= FB_VMODE_INTERLACED;
-                        }
-                    } else if ((p = strstr(buf, "double "))) {
-                        p += 7;
-
-                        if (strstr(buf, "false")) {
-                            base->vmode &= ~FB_VMODE_DOUBLE;
-                        } else {
-                            base->vmode |= FB_VMODE_DOUBLE;
-                        }
-                    } else if ((p = strstr(buf, "vsync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_VERT_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "hsync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_HOR_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "csync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_COMP_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "extsync "))) {
-                        p += 8;
-
-                        if (strstr(buf, "false")) {
-                            base->sync &= ~FB_SYNC_EXT;
-                        } else {
-                            base->sync |= FB_SYNC_EXT;
-                        }
-                    }
-                    
-                                       if (strstr(buf, "endmode"))
-                                               return 1;
-                               }
-                       }
-               }
-       }
-#else
-       error_msg( "mode reading not compiled in");
-#endif
-       return 0;
-}
-
-static void setmode(struct fb_var_screeninfo *base,
-                                       struct fb_var_screeninfo *set)
-{
-       if ((int) set->xres > 0)
-               base->xres = set->xres;
-       if ((int) set->yres > 0)
-               base->yres = set->yres;
-       if ((int) set->xres_virtual > 0)
-               base->xres_virtual = set->xres_virtual;
-       if ((int) set->yres_virtual > 0)
-               base->yres_virtual = set->yres_virtual;
-       if ((int) set->bits_per_pixel > 0)
-               base->bits_per_pixel = set->bits_per_pixel;
-}
-
-static 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", v->xres, v->yres, (int) (vrate + 0.5));
-#ifdef BB_FEATURE_FBSET_FANCY
-       printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6,
-                  hrate / 1e3, vrate);
-#endif
-       printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres,
-                  v->xres_virtual, v->yres_virtual, v->bits_per_pixel);
-       printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin,
-                  v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len,
-                  v->vsync_len);
-       printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false"));
-       printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length,
-                  v->red.offset, v->green.length, v->green.offset, v->blue.length,
-                  v->blue.offset, v->transp.length, v->transp.offset);
-       printf("endmode\n\n");
-}
-
-#ifdef STANDALONE
-int main(int argc, char **argv)
-#else
-extern int fbset_main(int argc, char **argv)
-#endif
-{
-       struct fb_var_screeninfo var, varset;
-       int fh, i;
-       char *fbdev = DEFAULTFBDEV;
-       char *modefile = DEFAULTFBMODE;
-       char *thisarg, *mode = NULL;
-
-       memset(&varset, 0xFF, sizeof(varset));
-
-       /* parse cmd args.... why do they have to make things so difficult? */
-       argv++;
-       argc--;
-       for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
-               for (i = 0; g_cmdoptions[i].name; i++) {
-                       if (!strcmp(thisarg, g_cmdoptions[i].name)) {
-                               if (argc - 1 < g_cmdoptions[i].param_count)
-                                       show_usage();
-                               switch (g_cmdoptions[i].code) {
-                               case CMD_FB:
-                                       fbdev = argv[1];
-                                       break;
-                               case CMD_DB:
-                                       modefile = argv[1];
-                                       break;
-                               case CMD_GEOMETRY:
-                                       varset.xres = strtoul(argv[1], 0, 0);
-                                       varset.yres = strtoul(argv[2], 0, 0);
-                                       varset.xres_virtual = strtoul(argv[3], 0, 0);
-                                       varset.yres_virtual = strtoul(argv[4], 0, 0);
-                                       varset.bits_per_pixel = strtoul(argv[5], 0, 0);
-                                       break;
-                               case CMD_TIMING:
-                                       varset.pixclock = strtoul(argv[1], 0, 0);
-                                       varset.left_margin = strtoul(argv[2], 0, 0);
-                                       varset.right_margin = strtoul(argv[3], 0, 0);
-                                       varset.upper_margin = strtoul(argv[4], 0, 0);
-                                       varset.lower_margin = strtoul(argv[5], 0, 0);
-                                       varset.hsync_len = strtoul(argv[6], 0, 0);
-                                       varset.vsync_len = strtoul(argv[7], 0, 0);
-                                       break;
-                case CMD_CHANGE:
-                    g_options |= OPT_CHANGE;
-                    break;
-#ifdef BB_FEATURE_FBSET_FANCY
-                               case CMD_XRES:
-                                       varset.xres = strtoul(argv[1], 0, 0);
-                                       break;
-                               case CMD_YRES:
-                                       varset.yres = strtoul(argv[1], 0, 0);
-                                       break;
-#endif
-                               }
-                               argc -= g_cmdoptions[i].param_count;
-                               argv += g_cmdoptions[i].param_count;
-                               break;
-                       }
-               }
-               if (!g_cmdoptions[i].name) {
-                       if (argc == 1) {
-                               mode = *argv;
-                               g_options |= OPT_READMODE;
-                       } else {
-                               show_usage();
-                       }
-               }
-       }
-
-       if ((fh = open(fbdev, O_RDONLY)) < 0)
-               perror_msg_and_die("fbset(open)");
-       if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
-               perror_msg_and_die("fbset(ioctl)");
-       if (g_options & OPT_READMODE) {
-               if (!readmode(&var, modefile, mode)) {
-                       error_msg("Unknown video mode `%s'", mode);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       setmode(&var, &varset);
-       if (g_options & OPT_CHANGE)
-               if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
-                       perror_msg_and_die("fbset(ioctl)");
-       showmode(&var);
-       /* Don't close the file, as exiting will take care of that */
-       /* close(fh); */
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/fdflush.c b/busybox/fdflush.c
deleted file mode 100644 (file)
index 28f5cb6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini fdflush implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-/* From <linux/fd.h> */
-#define FDFLUSH  _IO(2,0x4b)
-
-extern int fdflush_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc <= 1 || **(++argv) == '-')
-               show_usage();
-
-       if ((fd = open(*argv, 0)) < 0)
-               perror_msg_and_die("%s", *argv);
-
-       if (ioctl(fd, FDFLUSH, 0))
-               perror_msg_and_die("%s", *argv);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/find.c b/busybox/find.c
deleted file mode 100644 (file)
index e814c97..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini find implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * Reworked by David Douthitt <n9ubh@callsign.net> and
- *  Matt Kraai <kraai@alumni.carnegiemellon.edu>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fnmatch.h>
-#include <time.h>
-#include <ctype.h>
-#include "busybox.h"
-
-
-static char *pattern;
-
-#ifdef BB_FEATURE_FIND_TYPE
-static int type_mask = 0;
-#endif
-
-#ifdef BB_FEATURE_FIND_PERM
-static char perm_char = 0;
-static int perm_mask = 0;
-#endif
-
-#ifdef BB_FEATURE_FIND_MTIME
-static char mtime_char;
-static int mtime_days;
-#endif
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (pattern != NULL) {
-               const char *tmp = strrchr(fileName, '/');
-
-               if (tmp == NULL)
-                       tmp = fileName;
-               else
-                       tmp++;
-               if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
-                       goto no_match;
-       }
-#ifdef BB_FEATURE_FIND_TYPE
-       if (type_mask != 0) {
-               if (!((statbuf->st_mode & S_IFMT) == type_mask))
-                       goto no_match;
-       }
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-       if (perm_mask != 0) {
-               if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
-                        (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
-                        (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
-                       goto no_match;
-       }
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-       if (mtime_days != 0) {
-               time_t file_age = time(NULL) - statbuf->st_mtime;
-               time_t mtime_secs = mtime_days * 24 * 60 * 60;
-               if (!((isdigit(mtime_char) && mtime_secs >= file_age &&
-                                               mtime_secs < file_age + 24 * 60 * 60) ||
-                               (mtime_char == '+' && mtime_secs >= file_age) || 
-                               (mtime_char == '-' && mtime_secs < file_age)))
-                       goto no_match;
-       }
-#endif
-       puts(fileName);
-no_match:
-       return (TRUE);
-}
-
-#ifdef BB_FEATURE_FIND_TYPE
-static int find_type(char *type)
-{
-       int mask = 0;
-
-       switch (type[0]) {
-               case 'b':
-                       mask = S_IFBLK;
-                       break;
-               case 'c':
-                       mask = S_IFCHR;
-                       break;
-               case 'd':
-                       mask = S_IFDIR;
-                       break;
-               case 'p':
-                       mask = S_IFIFO;
-                       break;
-               case 'f':
-                       mask = S_IFREG;
-                       break;
-               case 'l':
-                       mask = S_IFLNK;
-                       break;
-               case 's':
-                       mask = S_IFSOCK;
-                       break;
-       }
-
-       if (mask == 0 || type[1] != '\0')
-               error_msg_and_die("invalid argument `%s' to `-type'", type);
-
-       return mask;
-}
-#endif
-
-int find_main(int argc, char **argv)
-{
-       int dereference = FALSE;
-       int i, firstopt, status = EXIT_SUCCESS;
-
-       for (firstopt = 1; firstopt < argc; firstopt++) {
-               if (argv[firstopt][0] == '-')
-                       break;
-       }
-
-       /* Parse any options */
-       for (i = firstopt; i < argc; i++) {
-               if (strcmp(argv[i], "-follow") == 0)
-                       dereference = TRUE;
-               else if (strcmp(argv[i], "-print") == 0) {
-                       ;
-                       }
-               else if (strcmp(argv[i], "-name") == 0) {
-                       if (++i == argc)
-                               error_msg_and_die("option `-name' requires an argument");
-                       pattern = argv[i];
-#ifdef BB_FEATURE_FIND_TYPE
-               } else if (strcmp(argv[i], "-type") == 0) {
-                       if (++i == argc)
-                               error_msg_and_die("option `-type' requires an argument");
-                       type_mask = find_type(argv[i]);
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-               } else if (strcmp(argv[i], "-perm") == 0) {
-                       char *end;
-                       if (++i == argc)
-                               error_msg_and_die("option `-perm' requires an argument");
-                       perm_mask = strtol(argv[i], &end, 8);
-                       if (end[0] != '\0')
-                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
-                       if (perm_mask > 07777)
-                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
-                       if ((perm_char = argv[i][0]) == '-')
-                               perm_mask = -perm_mask;
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-               } else if (strcmp(argv[i], "-mtime") == 0) {
-                       char *end;
-                       if (++i == argc)
-                               error_msg_and_die("option `-mtime' requires an argument");
-                       mtime_days = strtol(argv[i], &end, 10);
-                       if (end[0] != '\0')
-                               error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]);
-                       if ((mtime_char = argv[i][0]) == '-')
-                               mtime_days = -mtime_days;
-#endif
-               } else
-                       show_usage();
-       }
-
-       if (firstopt == 1) {
-               if (recursive_action(".", TRUE, dereference, FALSE, fileAction,
-                                       fileAction, NULL) == FALSE)
-                       status = EXIT_FAILURE;
-       } else {
-               for (i = 1; i < firstopt; i++) {
-                       if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
-                                               fileAction, NULL) == FALSE)
-                               status = EXIT_FAILURE;
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/findutils/find.c b/busybox/findutils/find.c
deleted file mode 100644 (file)
index e814c97..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini find implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * Reworked by David Douthitt <n9ubh@callsign.net> and
- *  Matt Kraai <kraai@alumni.carnegiemellon.edu>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fnmatch.h>
-#include <time.h>
-#include <ctype.h>
-#include "busybox.h"
-
-
-static char *pattern;
-
-#ifdef BB_FEATURE_FIND_TYPE
-static int type_mask = 0;
-#endif
-
-#ifdef BB_FEATURE_FIND_PERM
-static char perm_char = 0;
-static int perm_mask = 0;
-#endif
-
-#ifdef BB_FEATURE_FIND_MTIME
-static char mtime_char;
-static int mtime_days;
-#endif
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
-       if (pattern != NULL) {
-               const char *tmp = strrchr(fileName, '/');
-
-               if (tmp == NULL)
-                       tmp = fileName;
-               else
-                       tmp++;
-               if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
-                       goto no_match;
-       }
-#ifdef BB_FEATURE_FIND_TYPE
-       if (type_mask != 0) {
-               if (!((statbuf->st_mode & S_IFMT) == type_mask))
-                       goto no_match;
-       }
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-       if (perm_mask != 0) {
-               if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
-                        (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
-                        (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
-                       goto no_match;
-       }
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-       if (mtime_days != 0) {
-               time_t file_age = time(NULL) - statbuf->st_mtime;
-               time_t mtime_secs = mtime_days * 24 * 60 * 60;
-               if (!((isdigit(mtime_char) && mtime_secs >= file_age &&
-                                               mtime_secs < file_age + 24 * 60 * 60) ||
-                               (mtime_char == '+' && mtime_secs >= file_age) || 
-                               (mtime_char == '-' && mtime_secs < file_age)))
-                       goto no_match;
-       }
-#endif
-       puts(fileName);
-no_match:
-       return (TRUE);
-}
-
-#ifdef BB_FEATURE_FIND_TYPE
-static int find_type(char *type)
-{
-       int mask = 0;
-
-       switch (type[0]) {
-               case 'b':
-                       mask = S_IFBLK;
-                       break;
-               case 'c':
-                       mask = S_IFCHR;
-                       break;
-               case 'd':
-                       mask = S_IFDIR;
-                       break;
-               case 'p':
-                       mask = S_IFIFO;
-                       break;
-               case 'f':
-                       mask = S_IFREG;
-                       break;
-               case 'l':
-                       mask = S_IFLNK;
-                       break;
-               case 's':
-                       mask = S_IFSOCK;
-                       break;
-       }
-
-       if (mask == 0 || type[1] != '\0')
-               error_msg_and_die("invalid argument `%s' to `-type'", type);
-
-       return mask;
-}
-#endif
-
-int find_main(int argc, char **argv)
-{
-       int dereference = FALSE;
-       int i, firstopt, status = EXIT_SUCCESS;
-
-       for (firstopt = 1; firstopt < argc; firstopt++) {
-               if (argv[firstopt][0] == '-')
-                       break;
-       }
-
-       /* Parse any options */
-       for (i = firstopt; i < argc; i++) {
-               if (strcmp(argv[i], "-follow") == 0)
-                       dereference = TRUE;
-               else if (strcmp(argv[i], "-print") == 0) {
-                       ;
-                       }
-               else if (strcmp(argv[i], "-name") == 0) {
-                       if (++i == argc)
-                               error_msg_and_die("option `-name' requires an argument");
-                       pattern = argv[i];
-#ifdef BB_FEATURE_FIND_TYPE
-               } else if (strcmp(argv[i], "-type") == 0) {
-                       if (++i == argc)
-                               error_msg_and_die("option `-type' requires an argument");
-                       type_mask = find_type(argv[i]);
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-               } else if (strcmp(argv[i], "-perm") == 0) {
-                       char *end;
-                       if (++i == argc)
-                               error_msg_and_die("option `-perm' requires an argument");
-                       perm_mask = strtol(argv[i], &end, 8);
-                       if (end[0] != '\0')
-                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
-                       if (perm_mask > 07777)
-                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
-                       if ((perm_char = argv[i][0]) == '-')
-                               perm_mask = -perm_mask;
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-               } else if (strcmp(argv[i], "-mtime") == 0) {
-                       char *end;
-                       if (++i == argc)
-                               error_msg_and_die("option `-mtime' requires an argument");
-                       mtime_days = strtol(argv[i], &end, 10);
-                       if (end[0] != '\0')
-                               error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]);
-                       if ((mtime_char = argv[i][0]) == '-')
-                               mtime_days = -mtime_days;
-#endif
-               } else
-                       show_usage();
-       }
-
-       if (firstopt == 1) {
-               if (recursive_action(".", TRUE, dereference, FALSE, fileAction,
-                                       fileAction, NULL) == FALSE)
-                       status = EXIT_FAILURE;
-       } else {
-               for (i = 1; i < firstopt; i++) {
-                       if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
-                                               fileAction, NULL) == FALSE)
-                               status = EXIT_FAILURE;
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/findutils/grep.c b/busybox/findutils/grep.c
deleted file mode 100644 (file)
index 3254868..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Mini grep implementation for busybox using libc regex.
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <regex.h>
-#include <string.h> /* for strerror() */
-#include <errno.h>
-#include "busybox.h"
-
-
-extern int optind; /* in unistd.h */
-extern int errno;  /* for use with strerror() */
-extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */
-
-/* options */
-static int reflags            = REG_NOSUB; 
-static int print_filename     = 0;
-static int print_line_num     = 0;
-static int print_match_counts = 0;
-static int be_quiet           = 0;
-static int invert_search      = 0;
-static int suppress_err_msgs  = 0;
-static int print_files_with_matches  = 0;
-
-#ifdef BB_FEATURE_GREP_CONTEXT
-extern char *optarg; /* in getopt.h */
-static int lines_before      = 0;
-static int lines_after       = 0;
-static char **before_buf     = NULL;
-static int last_line_printed = 0;
-#endif /* BB_FEATURE_GREP_CONTEXT */
-
-/* globals used internally */
-static regex_t *regexes = NULL; /* growable array of compiled regular expressions */
-static int nregexes = 0; /* number of elements in above arrary */
-static int matched; /* keeps track of whether we ever matched */
-static char *cur_file = NULL; /* the current file we are reading */
-
-
-static void print_line(const char *line, int linenum, char decoration)
-{
-#ifdef BB_FEATURE_GREP_CONTEXT
-       /* possibly print the little '--' seperator */
-       if ((lines_before || lines_after) && last_line_printed &&
-                       last_line_printed < linenum - 1) {
-               puts("--");
-       }
-       last_line_printed = linenum;
-#endif
-       if (print_filename)
-               printf("%s%c", cur_file, decoration);
-       if (print_line_num)
-               printf("%i%c", linenum, decoration);
-       puts(line);
-}
-
-
-static void grep_file(FILE *file)
-{
-       char *line = NULL;
-       int ret;
-       int linenum = 0;
-       int nmatches = 0;
-       int i;
-#ifdef BB_FEATURE_GREP_CONTEXT
-       int print_n_lines_after = 0;
-       int curpos = 0; /* track where we are in the circular 'before' buffer */
-       int idx = 0; /* used for iteration through the circular buffer */
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-
-       while ((line = get_line_from_file(file)) != NULL) {
-               chomp(line);
-               linenum++;
-
-               for (i = 0; i < nregexes; i++) {
-                       /*
-                        * test for a postitive-assertion match (regexec returns success (0)
-                        * and the user did not specify invert search), or a negative-assertion
-                        * match (regexec returns failure (REG_NOMATCH) and the user specified
-                        * invert search)
-                        */
-                       ret = regexec(&regexes[i], line, 0, NULL, 0);
-                       if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) {
-
-                               /* if we found a match but were told to be quiet, stop here and
-                                * return success */
-                               if (be_quiet)
-                                       exit(0);
-
-                               /* keep track of matches */
-                               nmatches++;
-
-                               /* if we're just printing filenames, we stop after the first match */
-                               if (print_files_with_matches)
-                                       break;
-
-                               /* print the matched line */
-                               if (print_match_counts == 0) {
-#ifdef BB_FEATURE_GREP_CONTEXT
-                                       int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
-
-                                       /* if we were told to print 'before' lines and there is at least
-                                        * one line in the circular buffer, print them */
-                                       if (lines_before && before_buf[prevpos] != NULL) {
-                                               int first_buf_entry_line_num = linenum - lines_before;
-
-                                               /* advance to the first entry in the circular buffer, and
-                                                * figure out the line number is of the first line in the
-                                                * buffer */
-                                               idx = curpos;
-                                               while (before_buf[idx] == NULL) {
-                                                       idx = (idx + 1) % lines_before;
-                                                       first_buf_entry_line_num++;
-                                               }
-
-                                               /* now print each line in the buffer, clearing them as we go */
-                                               while (before_buf[idx] != NULL) {
-                                                       print_line(before_buf[idx], first_buf_entry_line_num, '-');
-                                                       free(before_buf[idx]);
-                                                       before_buf[idx] = NULL;
-                                                       idx = (idx + 1) % lines_before;
-                                                       first_buf_entry_line_num++;
-                                               }
-                                       }
-
-                                       /* make a note that we need to print 'after' lines */
-                                       print_n_lines_after = lines_after;
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-                                       print_line(line, linenum, ':');
-                               }
-                       }
-#ifdef BB_FEATURE_GREP_CONTEXT
-                       else { /* no match */
-                               /* Add the line to the circular 'before' buffer */
-                               if(lines_before) {
-                                       if(before_buf[curpos])
-                                               free(before_buf[curpos]);
-                                       before_buf[curpos] = strdup(line);
-                                       curpos = (curpos + 1) % lines_before;
-                               }
-                       }
-
-                       /* if we need to print some context lines after the last match, do so */
-                       if (print_n_lines_after && (last_line_printed != linenum)) {
-                               print_line(line, linenum, '-');
-                               print_n_lines_after--;
-                       }
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-               } /* for */
-               free(line);
-       }
-
-
-       /* special-case file post-processing for options where we don't print line
-        * matches, just filenames and possibly match counts */
-
-       /* grep -c: print [filename:]count, even if count is zero */
-       if (print_match_counts) {
-               if (print_filename)
-                       printf("%s:", cur_file);
-               if (print_files_with_matches && nmatches > 0)
-                       printf("1\n");
-               else
-                   printf("%d\n", nmatches);
-       }
-
-       /* grep -l: print just the filename, but only if we grepped the line in the file  */
-       if (print_files_with_matches && nmatches > 0) {
-               puts(cur_file);
-       }
-
-
-       /* remember if we matched */
-       if (nmatches != 0)
-               matched = 1;
-}
-
-
-static void add_regex(const char *restr)
-{
-       regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes));
-       xregcomp(&regexes[nregexes-1], restr, reflags);
-}
-
-
-static void    load_regexes_from_file(const char *filename)
-{
-       char *line;
-       FILE *f = xfopen(filename, "r");
-       while ((line = get_line_from_file(f)) != NULL) {
-               chomp(line);
-               add_regex(line);
-               free(line);
-       }
-}
-
-
-#ifdef BB_FEATURE_CLEAN_UP
-static void destroy_regexes()
-{
-       if (regexes == NULL)
-               return;
-
-       /* destroy all the elments in the array */
-       while (--nregexes >= 0) {
-               regfree(&regexes[nregexes]);
-               free(&regexes[nregexes]);
-       }
-}
-#endif
-
-
-extern int grep_main(int argc, char **argv)
-{
-       int opt;
-#ifdef BB_FEATURE_GREP_CONTEXT
-       char *junk;
-#endif
-
-#ifdef BB_FEATURE_CLEAN_UP
-       /* destroy command strings on exit */
-       if (atexit(destroy_regexes) == -1)
-               perror_msg_and_die("atexit");
-#endif
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "iHhlnqvsce:f:"
-#ifdef BB_FEATURE_GREP_CONTEXT
-"A:B:C:"
-#endif
-)) > 0) {
-               switch (opt) {
-                       case 'i':
-                               reflags |= REG_ICASE;
-                               break;
-                       case 'l':
-                               print_files_with_matches++;
-                               break;
-                       case 'H':
-                               print_filename++;
-                               break;
-                       case 'h':
-                               print_filename--;
-                               break;
-                       case 'n':
-                               print_line_num++;
-                               break;
-                       case 'q':
-                               be_quiet++;
-                               break;
-                       case 'v':
-                               invert_search++;
-                               break;
-                       case 's':
-                               suppress_err_msgs++;
-                               break;
-                       case 'c':
-                               print_match_counts++;
-                               break;
-                       case 'e':
-                               add_regex(optarg);
-                               break;
-                       case 'f':
-                               load_regexes_from_file(optarg);
-                               break;
-#ifdef BB_FEATURE_GREP_CONTEXT
-                       case 'A':
-                               lines_after = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               break;
-                       case 'B':
-                               lines_before = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               before_buf = (char **)calloc(lines_before, sizeof(char *));
-                               break;
-                       case 'C':
-                               lines_after = lines_before = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               before_buf = (char **)calloc(lines_before, sizeof(char *));
-                               break;
-#endif /* BB_FEATURE_GREP_CONTEXT */
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a pattern from a -e and no command file was specified,
-        * argv[optind] should be the pattern. no pattern, no worky */
-       if (nregexes == 0) {
-               if (argv[optind] == NULL)
-                       show_usage();
-               else {
-                       add_regex(argv[optind]);
-                       optind++;
-               }
-       }
-
-       /* sanity checks */
-       if (print_match_counts || be_quiet || print_files_with_matches) {
-               print_line_num = 0;
-#ifdef BB_FEATURE_GREP_CONTEXT
-               lines_before = 0;
-               lines_after = 0;
-#endif
-       }
-
-       /* argv[(optind)..(argc-1)] should be names of file to grep through. If
-        * there is more than one file to grep, we will print the filenames */
-       if ((argc-1) - (optind) > 0)
-               print_filename++;
-
-       /* If no files were specified, or '-' was specified, take input from
-        * stdin. Otherwise, we grep through all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               grep_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       cur_file = argv[i];
-                       file = fopen(cur_file, "r");
-                       if (file == NULL) {
-                               if (!suppress_err_msgs)
-                                       perror_msg("%s", cur_file);
-                       }
-                       else {
-                               grep_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-
-       return !matched; /* invert return value 0 = success, 1 = failed */
-}
diff --git a/busybox/findutils/which.c b/busybox/findutils/which.c
deleted file mode 100644 (file)
index c460ffd..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Which implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int which_main(int argc, char **argv)
-{
-       char *path_list, *path_n;
-       struct stat filestat;
-       int i, count=1, found, status = EXIT_SUCCESS;
-
-       if (argc <= 1 || **(argv + 1) == '-')
-               show_usage();
-       argc--;
-
-       path_list = getenv("PATH");
-       if (!path_list)
-               path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
-
-       /* Replace colons with zeros in path_parsed and count them */
-       for(i=strlen(path_list); i > 0; i--) 
-               if (path_list[i]==':') {
-                       path_list[i]=0;
-                       count++;
-               }
-
-       while(argc-- > 0) { 
-               path_n = path_list;
-               argv++;
-               found = 0;
-               for (i = 0; i < count; i++) {
-                       char *buf;
-                       buf = concat_path_file(path_n, *argv);
-                       if (stat (buf, &filestat) == 0
-                           && filestat.st_mode & S_IXUSR)
-                       {
-                               puts(buf);
-                               found = 1;
-                               break;
-                       }
-                       free(buf);
-                       path_n += (strlen(path_n) + 1);
-               }
-               if (!found)
-                       status = EXIT_FAILURE;
-       }
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/findutils/xargs.c b/busybox/findutils/xargs.c
deleted file mode 100644 (file)
index 48adae9..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Mini xargs implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * Remixed by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-int xargs_main(int argc, char **argv)
-{
-       char *cmd_to_be_executed = NULL;
-       char *file_to_act_on = NULL;
-
-       /*
-        * No options are supported in this version of xargs; no getopt.
-        *
-        * Re: The missing -t flag: Most programs that produce output also print
-        * the filename, so xargs doesn't really need to do it again. Supporting
-        * the -t flag =greatly= bloats up the size of this app and the memory it
-        * uses because you have to buffer all the input file strings in memory. If
-        * you really want to see the filenames that xargs will act on, just run it
-        * once with no args and xargs will echo the filename. Simple.
-        */
-
-       /* Store the command to be executed (taken from the command line) */
-       if (argc == 1) {
-               /* default behavior is to echo all the filenames */
-               cmd_to_be_executed = xstrdup("/bin/echo ");
-       } else {
-               /* concatenate all the arguments passed to xargs together */
-               int i;
-               int len = 1; /* for the '\0' */
-               for (i = 1; i < argc; i++) {
-                       len += strlen(argv[i]);
-                       len += 1;  /* for the space between the args */
-                       cmd_to_be_executed = xrealloc(cmd_to_be_executed, len);
-                       strcat(cmd_to_be_executed, argv[i]);
-                       strcat(cmd_to_be_executed, " ");
-               }
-       }
-
-       /* Now, read in one line at a time from stdin, and store this 
-        * line to be used later as an argument to the command */
-       while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) {
-
-               FILE *cmd_output = NULL;
-               char *output_line = NULL;
-               char *execstr = NULL;
-
-               /* eat the newline off the filename. */
-               chomp(file_to_act_on);
-
-               /* eat blank lines */
-               if (strlen(file_to_act_on) == 0)
-                       continue;
-
-               /* assemble the command and execute it */
-               execstr = xcalloc(strlen(cmd_to_be_executed) +
-                               strlen(file_to_act_on) + 1, sizeof(char));
-               strcat(execstr, cmd_to_be_executed);
-               strcat(execstr, file_to_act_on);
-               cmd_output = popen(execstr, "r");
-               if (cmd_output == NULL)
-                       perror_msg_and_die("popen");
-
-               /* harvest the output */
-               while ((output_line = get_line_from_file(cmd_output)) != NULL) {
-                       fputs(output_line, stdout);
-                       free(output_line);
-               }
-
-               /* clean up */
-               pclose(cmd_output);
-               free(execstr);
-               free(file_to_act_on);
-       }
-
-#ifdef BB_FEATURE_CLEAN_UP
-       free(cmd_to_be_executed);
-#endif
-
-       return 0;
-}
-
-/* vi: set sw=4 ts=4: */
diff --git a/busybox/free.c b/busybox/free.c
deleted file mode 100644 (file)
index 2e34a97..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini free implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int free_main(int argc, char **argv)
-{
-       struct sysinfo info;
-       sysinfo(&info);
-
-       /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
-       if (info.mem_unit==0) {
-               info.mem_unit=1;
-       }
-       info.mem_unit*=1024;
-       
-       /* TODO:  Make all this stuff not overflow when mem >= 4 Gib */
-       info.totalram/=info.mem_unit;
-       info.freeram/=info.mem_unit;
-       info.totalswap/=info.mem_unit;
-       info.freeswap/=info.mem_unit;
-       info.sharedram/=info.mem_unit;
-       info.bufferram/=info.mem_unit;
-
-       if (argc > 1 && **(argv + 1) == '-')
-               show_usage();
-
-       printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", 
-                       "shared", "buffers");
-
-       printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, 
-                       info.totalram-info.freeram, info.freeram, 
-                       info.sharedram, info.bufferram);
-
-       printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap,
-                       info.totalswap-info.freeswap, info.freeswap);
-
-       printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap,
-                       (info.totalram-info.freeram)+(info.totalswap-info.freeswap),
-                       info.freeram+info.freeswap);
-       return EXIT_SUCCESS;
-}
-
-
diff --git a/busybox/freeramdisk.c b/busybox/freeramdisk.c
deleted file mode 100644 (file)
index cf25fae..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * freeramdisk implementation for busybox
- *
- * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
- * Adjusted a bit by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-/* From linux/fs.h */
-#define BLKFLSBUF  _IO(0x12,97)        /* flush buffer cache */
-
-extern int
-freeramdisk_main(int argc, char **argv)
-{
-       int   f;
-
-       if (argc != 2 || *argv[1] == '-') {
-               show_usage();
-       }
-
-       if ((f = open(argv[1], O_RDWR)) == -1) {
-               perror_msg_and_die("cannot open %s", argv[1]);
-       }
-       if (ioctl(f, BLKFLSBUF) < 0) {
-               perror_msg_and_die("failed ioctl on %s", argv[1]);
-       }
-       /* Don't bother closing.  Exit does
-        * that, so we can save a few bytes */
-       /* close(f); */
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/busybox/fsck_minix.c b/busybox/fsck_minix.c
deleted file mode 100644 (file)
index 952968d..0000000
+++ /dev/null
@@ -1,1478 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * fsck.c - a file system consistency checker for Linux.
- *
- * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
- * as per the GNU copyleft.
- */
-
-/*
- * 09.11.91  -  made the first rudimetary functions
- *
- * 10.11.91  -  updated, does checking, no repairs yet.
- *             Sent out to the mailing-list for testing.
- *
- * 14.11.91  - Testing seems to have gone well. Added some
- *             correction-code, and changed some functions.
- *
- * 15.11.91  -  More correction code. Hopefully it notices most
- *             cases now, and tries to do something about them.
- *
- * 16.11.91  -  More corrections (thanks to Mika Jalava). Most
- *             things seem to work now. Yeah, sure.
- *
- *
- * 19.04.92  - Had to start over again from this old version, as a
- *             kernel bug ate my enhanced fsck in february.
- *
- * 28.02.93  - added support for different directory entry sizes..
- *
- * Sat Mar  6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
- *                           super-block information
- *
- * Sat Oct  9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
- *                           to that required by fsutil
- *
- * Mon Jan  3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
- *                           Added support for file system valid flag.  Also
- *                           added program_version variable and output of
- *                           program name and version number when program
- *                           is executed.
- *
- * 30.10.94 - added support for v2 filesystem
- *            (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
- *
- * 10.12.94  -  added test to prevent checking of mounted fs adapted
- *              from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
- *              program.  (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 01.07.96  - Fixed the v2 fs stuff to use the right #defines and such
- *            for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
- *
- * 02.07.96  - Added C bit fiddling routines from rmk@ecs.soton.ac.uk 
- *             (Russell King).  He made them for ARM.  It would seem
- *            that the ARM is powerful enough to do this in C whereas
- *             i386 and m64k must use assembly to get it fast >:-)
- *            This should make minix fsck systemindependent.
- *            (janl@math.uio.no, Nicolai Langfeldt)
- *
- * 04.11.96  - Added minor fixes from Andreas Schwab to avoid compiler
- *             warnings.  Added mc68k bitops from 
- *            Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
- *
- * 06.11.96  - Added v2 code submitted by Joerg Dorchain, but written by
- *             Andreas Schwab.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- *
- * I've had no time to add comments - hopefully the function names
- * are comments enough. As with all file system checkers, this assumes
- * the file system is quiescent - don't use it on a mounted device
- * unless you can be sure nobody is writing to it (and remember that the
- * kernel can write to it when it searches for files).
- *
- * Usuage: fsck [-larvsm] device
- *     -l for a listing of all the filenames
- *     -a for automatic repairs (not implemented)
- *     -r for repairs (interactive) (not implemented)
- *     -v for verbose (tells how many files)
- *     -s for super-block info
- *     -m for minix-like "mode not cleared" warnings
- *     -f force filesystem check even if filesystem marked as valid
- *
- * The device may be a block device or a image of one, but this isn't
- * enforced (but it's not much fun on a character device :-). 
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <mntent.h>
-#include <sys/param.h>
-#include "busybox.h"
-
-static const int MINIX_ROOT_INO = 1;
-static const int MINIX_LINK_MAX = 250;
-static const int MINIX2_LINK_MAX = 65530;
-
-static const int MINIX_I_MAP_SLOTS = 8;
-static const int MINIX_Z_MAP_SLOTS = 64;
-static const int MINIX_SUPER_MAGIC = 0x137F;           /* original minix fs */
-static const int MINIX_SUPER_MAGIC2 = 0x138F;          /* minix fs, 30 char names */
-static const int MINIX2_SUPER_MAGIC = 0x2468;          /* minix V2 fs */
-static const int MINIX2_SUPER_MAGIC2 = 0x2478;         /* minix V2 fs, 30 char names */
-static const int MINIX_VALID_FS = 0x0001;              /* Clean fs. */
-static const int MINIX_ERROR_FS = 0x0002;              /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-
-static const int MINIX_V1 = 0x0001;            /* original minix fs */
-static const int MINIX_V2 = 0x0002;            /* minix V2 fs */
-
-#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
-       u_int16_t i_mode;
-       u_int16_t i_uid;
-       u_int32_t i_size;
-       u_int32_t i_time;
-       u_int8_t  i_gid;
-       u_int8_t  i_nlinks;
-       u_int16_t i_zone[9];
-};
-
-/*
- * The new minix inode has all the time entries, as well as
- * long block numbers and a third indirect block (7+1+1+1
- * instead of 7+1+1). Also, some previously 8-bit values are
- * now 16-bit. The inode is now 64 bytes instead of 32.
- */
-struct minix2_inode {
-       u_int16_t i_mode;
-       u_int16_t i_nlinks;
-       u_int16_t i_uid;
-       u_int16_t i_gid;
-       u_int32_t i_size;
-       u_int32_t i_atime;
-       u_int32_t i_mtime;
-       u_int32_t i_ctime;
-       u_int32_t i_zone[10];
-};
-
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
-       u_int16_t s_ninodes;
-       u_int16_t s_nzones;
-       u_int16_t s_imap_blocks;
-       u_int16_t s_zmap_blocks;
-       u_int16_t s_firstdatazone;
-       u_int16_t s_log_zone_size;
-       u_int32_t s_max_size;
-       u_int16_t s_magic;
-       u_int16_t s_state;
-       u_int32_t s_zones;
-};
-
-struct minix_dir_entry {
-       u_int16_t inode;
-       char name[0];
-};
-
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-#define NAME_MAX         255   /* # chars in a file name */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96)    /* return device size */
-#endif
-
-#ifndef __linux__
-#define volatile
-#endif
-
-static const int ROOT_INO = 1;
-
-#define UPPER(size,n) ((size+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef BB_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
-                                   : MINIX_INODES_PER_BLOCK))
-#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
-#endif
-#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
-
-#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *program_version = "1.2 - 11/11/96";
-static char *device_name = NULL;
-static int IN;
-static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
-       0, warn_mode = 0, force = 0;
-static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
-       0, symlinks = 0, total = 0;
-
-static int changed = 0;                        /* flags if the filesystem has been changed */
-static int errors_uncorrected = 0;     /* flag if some error was not corrected */
-static int dirsize = 16;
-static int namelen = 14;
-static int version2 = 0;
-static struct termios termios;
-static int termios_set = 0;
-
-/* File-name data */
-static const int MAX_DEPTH = 32;
-static int name_depth = 0;
-// static char name_list[MAX_DEPTH][BUFSIZ + 1];
-static char **name_list = NULL;
-
-static char *inode_buffer = NULL;
-
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-static char super_block_buffer[BLOCK_SIZE];
-
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef BB_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
-#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned char *inode_count = NULL;
-static unsigned char *zone_count = NULL;
-
-static void recursive_check(unsigned int ino);
-#ifdef BB_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino);
-#endif
-
-static inline int bit(char * a,unsigned int i)
-{
-         return (a[i >> 3] & (1<<(i & 7))) != 0;
-}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-
-#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
-#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
-
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-
-static void leave(int) __attribute__ ((noreturn));
-static void leave(int status)
-{
-       if (termios_set)
-               tcsetattr(0, TCSANOW, &termios);
-       exit(status);
-}
-
-static void die(const char *str)
-{
-       error_msg("%s", str);
-       leave(8);
-}
-
-/*
- * This simply goes through the file-name data and prints out the
- * current file.
- */
-static void print_current_name(void)
-{
-       int i = 0;
-
-       while (i < name_depth)
-               printf("/%.*s", namelen, name_list[i++]);
-       if (i == 0)
-               printf("/");
-}
-
-static int ask(const char *string, int def)
-{
-       int c;
-
-       if (!repair) {
-               printf("\n");
-               errors_uncorrected = 1;
-               return 0;
-       }
-       if (automatic) {
-               printf("\n");
-               if (!def)
-                       errors_uncorrected = 1;
-               return def;
-       }
-       printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
-       for (;;) {
-               fflush(stdout);
-               if ((c = getchar()) == EOF) {
-                       if (!def)
-                               errors_uncorrected = 1;
-                       return def;
-               }
-               c = toupper(c);
-               if (c == 'Y') {
-                       def = 1;
-                       break;
-               } else if (c == 'N') {
-                       def = 0;
-                       break;
-               } else if (c == ' ' || c == '\n')
-                       break;
-       }
-       if (def)
-               printf("y\n");
-       else {
-               printf("n\n");
-               errors_uncorrected = 1;
-       }
-       return def;
-}
-
-/*
- * Make certain that we aren't checking a filesystem that is on a
- * mounted partition.  Code adapted from e2fsck, Copyright (C) 1993,
- * 1994 Theodore Ts'o.  Also licensed under GPL.
- */
-static void check_mount(void)
-{
-       FILE *f;
-       struct mntent *mnt;
-       int cont;
-       int fd;
-
-       if ((f = setmntent(MOUNTED, "r")) == NULL)
-               return;
-       while ((mnt = getmntent(f)) != NULL)
-               if (strcmp(device_name, mnt->mnt_fsname) == 0)
-                       break;
-       endmntent(f);
-       if (!mnt)
-               return;
-
-       /*
-        * If the root is mounted read-only, then /etc/mtab is
-        * probably not correct; so we won't issue a warning based on
-        * it.
-        */
-       fd = open(MOUNTED, O_RDWR);
-       if (fd < 0 && errno == EROFS)
-               return;
-       else
-               close(fd);
-
-       printf("%s is mounted.   ", device_name);
-       if (isatty(0) && isatty(1))
-               cont = ask("Do you really want to continue", 0);
-       else
-               cont = 0;
-       if (!cont) {
-               printf("check aborted.\n");
-               exit(0);
-       }
-       return;
-}
-
-/*
- * 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_nr(unsigned short *nr, int *corrected)
-{
-       if (!*nr)
-               return 0;
-       if (*nr < FIRSTZONE)
-               printf("Zone nr < FIRSTZONE in file `");
-       else if (*nr >= ZONES)
-               printf("Zone nr >= ZONES in file `");
-       else
-               return *nr;
-       print_current_name();
-       printf("'.");
-       if (ask("Remove block", 1)) {
-               *nr = 0;
-               *corrected = 1;
-       }
-       return 0;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int check_zone_nr2(unsigned int *nr, int *corrected)
-{
-       if (!*nr)
-               return 0;
-       if (*nr < FIRSTZONE)
-               printf("Zone nr < FIRSTZONE in file `");
-       else if (*nr >= ZONES)
-               printf("Zone nr >= ZONES in file `");
-       else
-               return *nr;
-       print_current_name();
-       printf("'.");
-       if (ask("Remove block", 1)) {
-               *nr = 0;
-               *corrected = 1;
-       }
-       return 0;
-}
-#endif
-
-/*
- * read-block reads block nr into the buffer at addr.
- */
-static void read_block(unsigned int nr, char *addr)
-{
-       if (!nr) {
-               memset(addr, 0, BLOCK_SIZE);
-               return;
-       }
-       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
-               printf("Read error: unable to seek to block in file '");
-               print_current_name();
-               printf("'\n");
-               memset(addr, 0, BLOCK_SIZE);
-               errors_uncorrected = 1;
-       } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
-               printf("Read error: bad block in file '");
-               print_current_name();
-               printf("'\n");
-               memset(addr, 0, BLOCK_SIZE);
-               errors_uncorrected = 1;
-       }
-}
-
-/*
- * write_block writes block nr to disk.
- */
-static void write_block(unsigned int nr, char *addr)
-{
-       if (!nr)
-               return;
-       if (nr < FIRSTZONE || nr >= ZONES) {
-               printf("Internal error: trying to write bad block\n"
-                          "Write request ignored\n");
-               errors_uncorrected = 1;
-               return;
-       }
-       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
-               die("seek failed in write_block");
-       if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
-               printf("Write error: bad block in file '");
-               print_current_name();
-               printf("'\n");
-               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 minix_inode *inode, unsigned int blknr)
-{
-       unsigned short ind[BLOCK_SIZE >> 1];
-       unsigned short dind[BLOCK_SIZE >> 1];
-       int blk_chg, block, result;
-
-       if (blknr < 7)
-               return check_zone_nr(inode->i_zone + blknr, &changed);
-       blknr -= 7;
-       if (blknr < 512) {
-               block = check_zone_nr(inode->i_zone + 7, &changed);
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr(blknr + ind, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 512;
-       block = check_zone_nr(inode->i_zone + 8, &changed);
-       read_block(block, (char *) dind);
-       blk_chg = 0;
-       result = check_zone_nr(dind + (blknr / 512), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) dind);
-       block = result;
-       read_block(block, (char *) ind);
-       blk_chg = 0;
-       result = check_zone_nr(ind + (blknr % 512), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) ind);
-       return result;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int map_block2(struct minix2_inode *inode, unsigned int blknr)
-{
-       unsigned int ind[BLOCK_SIZE >> 2];
-       unsigned int dind[BLOCK_SIZE >> 2];
-       unsigned int tind[BLOCK_SIZE >> 2];
-       int blk_chg, block, result;
-
-       if (blknr < 7)
-               return check_zone_nr2(inode->i_zone + blknr, &changed);
-       blknr -= 7;
-       if (blknr < 256) {
-               block = check_zone_nr2(inode->i_zone + 7, &changed);
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr2(blknr + ind, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 256;
-       if (blknr >= 256 * 256) {
-               block = check_zone_nr2(inode->i_zone + 8, &changed);
-               read_block(block, (char *) dind);
-               blk_chg = 0;
-               result = check_zone_nr2(dind + blknr / 256, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) dind);
-               block = result;
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr2(ind + blknr % 256, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 256 * 256;
-       block = check_zone_nr2(inode->i_zone + 9, &changed);
-       read_block(block, (char *) tind);
-       blk_chg = 0;
-       result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) tind);
-       block = result;
-       read_block(block, (char *) dind);
-       blk_chg = 0;
-       result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) dind);
-       block = result;
-       read_block(block, (char *) ind);
-       blk_chg = 0;
-       result = check_zone_nr2(ind + blknr % 256, &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) ind);
-       return result;
-}
-#endif
-
-static void write_super_block(void)
-{
-       /*
-        * Set the state of the filesystem based on whether or not there
-        * are uncorrected errors.  The filesystem valid flag is
-        * unconditionally set if we get this far.
-        */
-       Super.s_state |= MINIX_VALID_FS;
-       if (errors_uncorrected)
-               Super.s_state |= MINIX_ERROR_FS;
-       else
-               Super.s_state &= ~MINIX_ERROR_FS;
-
-       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
-               die("seek failed in write_super_block");
-       if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
-               die("unable to write super-block");
-
-       return;
-}
-
-static void write_tables(void)
-{
-       write_super_block();
-
-       if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
-               die("Unable to write inode map");
-       if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
-               die("Unable to write zone map");
-       if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
-               die("Unable to write inodes");
-}
-
-static void get_dirsize(void)
-{
-       int block;
-       char blk[BLOCK_SIZE];
-       int size;
-
-#ifdef BB_FEATURE_MINIX2
-       if (version2)
-               block = Inode2[ROOT_INO].i_zone[0];
-       else
-#endif
-               block = Inode[ROOT_INO].i_zone[0];
-       read_block(block, blk);
-       for (size = 16; size < BLOCK_SIZE; size <<= 1) {
-               if (strcmp(blk + size + 2, "..") == 0) {
-                       dirsize = size;
-                       namelen = size - 2;
-                       return;
-               }
-       }
-       /* use defaults */
-}
-
-static void read_superblock(void)
-{
-       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
-               die("seek failed");
-       if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
-               die("unable to read super block");
-       if (MAGIC == MINIX_SUPER_MAGIC) {
-               namelen = 14;
-               dirsize = 16;
-               version2 = 0;
-       } else if (MAGIC == MINIX_SUPER_MAGIC2) {
-               namelen = 30;
-               dirsize = 32;
-               version2 = 0;
-#ifdef BB_FEATURE_MINIX2
-       } else if (MAGIC == MINIX2_SUPER_MAGIC) {
-               namelen = 14;
-               dirsize = 16;
-               version2 = 1;
-       } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
-               namelen = 30;
-               dirsize = 32;
-               version2 = 1;
-#endif
-       } else
-               die("bad magic number in super-block");
-       if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
-               die("Only 1k blocks/zones supported");
-       if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
-               die("bad s_imap_blocks field in super-block");
-       if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
-               die("bad s_zmap_blocks field in super-block");
-}
-
-static void read_tables(void)
-{
-       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
-       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
-       memset(inode_map, 0, sizeof(inode_map));
-       memset(zone_map, 0, sizeof(zone_map));
-       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
-       inode_count = xmalloc(INODES + 1);
-       zone_count = xmalloc(ZONES);
-       if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
-               die("Unable to read inode map");
-       if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
-               die("Unable to read zone map");
-       if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
-               die("Unable to read inodes");
-       if (NORM_FIRSTZONE != FIRSTZONE) {
-               printf("Warning: Firstzone != Norm_firstzone\n");
-               errors_uncorrected = 1;
-       }
-       get_dirsize();
-       if (show) {
-               printf("%ld inodes\n", INODES);
-               printf("%ld blocks\n", ZONES);
-               printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
-               printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
-               printf("Maxsize=%ld\n", MAXSIZE);
-               printf("Filesystem state=%d\n", Super.s_state);
-               printf("namelen=%d\n\n", namelen);
-       }
-}
-
-static struct minix_inode *get_inode(unsigned int nr)
-{
-       struct minix_inode *inode;
-
-       if (!nr || nr > INODES)
-               return NULL;
-       total++;
-       inode = Inode + nr;
-       if (!inode_count[nr]) {
-               if (!inode_in_use(nr)) {
-                       printf("Inode %d marked not used, but used for file '", nr);
-                       print_current_name();
-                       printf("'\n");
-                       if (repair) {
-                               if (ask("Mark in use", 1))
-                                       mark_inode(nr);
-                       } else {
-                               errors_uncorrected = 1;
-                       }
-               }
-               if (S_ISDIR(inode->i_mode))
-                       directory++;
-               else if (S_ISREG(inode->i_mode))
-                       regular++;
-               else if (S_ISCHR(inode->i_mode))
-                       chardev++;
-               else if (S_ISBLK(inode->i_mode))
-                       blockdev++;
-               else if (S_ISLNK(inode->i_mode))
-                       symlinks++;
-               else if (S_ISSOCK(inode->i_mode));
-               else if (S_ISFIFO(inode->i_mode));
-               else {
-                       print_current_name();
-                       printf(" has mode %05o\n", inode->i_mode);
-               }
-
-       } else
-               links++;
-       if (!++inode_count[nr]) {
-               printf("Warning: inode count too big.\n");
-               inode_count[nr]--;
-               errors_uncorrected = 1;
-       }
-       return inode;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static struct minix2_inode *get_inode2(unsigned int nr)
-{
-       struct minix2_inode *inode;
-
-       if (!nr || nr > INODES)
-               return NULL;
-       total++;
-       inode = Inode2 + nr;
-       if (!inode_count[nr]) {
-               if (!inode_in_use(nr)) {
-                       printf("Inode %d marked not used, but used for file '", nr);
-                       print_current_name();
-                       printf("'\n");
-                       if (repair) {
-                               if (ask("Mark in use", 1))
-                                       mark_inode(nr);
-                               else
-                                       errors_uncorrected = 1;
-                       }
-               }
-               if (S_ISDIR(inode->i_mode))
-                       directory++;
-               else if (S_ISREG(inode->i_mode))
-                       regular++;
-               else if (S_ISCHR(inode->i_mode))
-                       chardev++;
-               else if (S_ISBLK(inode->i_mode))
-                       blockdev++;
-               else if (S_ISLNK(inode->i_mode))
-                       symlinks++;
-               else if (S_ISSOCK(inode->i_mode));
-               else if (S_ISFIFO(inode->i_mode));
-               else {
-                       print_current_name();
-                       printf(" has mode %05o\n", inode->i_mode);
-               }
-       } else
-               links++;
-       if (!++inode_count[nr]) {
-               printf("Warning: inode count too big.\n");
-               inode_count[nr]--;
-               errors_uncorrected = 1;
-       }
-       return inode;
-}
-#endif
-
-static void check_root(void)
-{
-       struct minix_inode *inode = Inode + ROOT_INO;
-
-       if (!inode || !S_ISDIR(inode->i_mode))
-               die("root inode isn't a directory");
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_root2(void)
-{
-       struct minix2_inode *inode = Inode2 + ROOT_INO;
-
-       if (!inode || !S_ISDIR(inode->i_mode))
-               die("root inode isn't a directory");
-}
-#endif
-
-static int add_zone(unsigned short *znr, int *corrected)
-{
-       int result;
-       int block;
-
-       result = 0;
-       block = check_zone_nr(znr, corrected);
-       if (!block)
-               return 0;
-       if (zone_count[block]) {
-               printf("Block has been used before. Now in file `");
-               print_current_name();
-               printf("'.");
-               if (ask("Clear", 1)) {
-                       *znr = 0;
-                       block = 0;
-                       *corrected = 1;
-               }
-       }
-       if (!block)
-               return 0;
-       if (!zone_in_use(block)) {
-               printf("Block %d in file `", block);
-               print_current_name();
-               printf("' is marked not in use.");
-               if (ask("Correct", 1))
-                       mark_zone(block);
-       }
-       if (!++zone_count[block])
-               zone_count[block]--;
-       return block;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int add_zone2(unsigned int *znr, int *corrected)
-{
-       int result;
-       int block;
-
-       result = 0;
-       block = check_zone_nr2(znr, corrected);
-       if (!block)
-               return 0;
-       if (zone_count[block]) {
-               printf("Block has been used before. Now in file `");
-               print_current_name();
-               printf("'.");
-               if (ask("Clear", 1)) {
-                       *znr = 0;
-                       block = 0;
-                       *corrected = 1;
-               }
-       }
-       if (!block)
-               return 0;
-       if (!zone_in_use(block)) {
-               printf("Block %d in file `", block);
-               print_current_name();
-               printf("' is marked not in use.");
-               if (ask("Correct", 1))
-                       mark_zone(block);
-       }
-       if (!++zone_count[block])
-               zone_count[block]--;
-       return block;
-}
-#endif
-
-static void add_zone_ind(unsigned short *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, chg_blk = 0;
-       int block;
-
-       block = add_zone(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
-               add_zone(i + (unsigned short *) blk, &chg_blk);
-       if (chg_blk)
-               write_block(block, blk);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void add_zone_ind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, chg_blk = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone2(i + (unsigned int *) blk, &chg_blk);
-       if (chg_blk)
-               write_block(block, blk);
-}
-#endif
-
-static void add_zone_dind(unsigned short *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
-               add_zone_ind(i + (unsigned short *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void add_zone_dind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-
-static void add_zone_tind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-#endif
-
-static void check_zones(unsigned int i)
-{
-       struct minix_inode *inode;
-
-       if (!i || i > INODES)
-               return;
-       if (inode_count[i] > 1)         /* have we counted this file already? */
-               return;
-       inode = Inode + 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);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_zones2(unsigned int 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 minix_inode *dir, unsigned int offset)
-{
-       static char blk[BLOCK_SIZE];
-       struct minix_inode *inode;
-       int ino;
-       char *name;
-       int block;
-
-       block = map_block(dir, offset / BLOCK_SIZE);
-       read_block(block, blk);
-       name = blk + (offset % BLOCK_SIZE) + 2;
-       ino = *(unsigned short *) (name - 2);
-       if (ino > INODES) {
-               print_current_name();
-               printf(" contains a bad inode number for file '");
-               printf("%.*s'.", namelen, name);
-               if (ask(" Remove", 1)) {
-                       *(unsigned short *) (name - 2) = 0;
-                       write_block(block, blk);
-               }
-               ino = 0;
-       }
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       inode = get_inode(ino);
-       name_depth--;
-       if (!offset) {
-               if (!inode || strcmp(".", name)) {
-                       print_current_name();
-                       printf(": bad directory: '.' isn't first\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (offset == dirsize) {
-               if (!inode || strcmp("..", name)) {
-                       print_current_name();
-                       printf(": bad directory: '..' isn't second\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (!inode)
-               return;
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       if (list) {
-               if (verbose)
-                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
-               print_current_name();
-               if (S_ISDIR(inode->i_mode))
-                       printf(":\n");
-               else
-                       printf("\n");
-       }
-       check_zones(ino);
-       if (inode && S_ISDIR(inode->i_mode))
-               recursive_check(ino);
-       name_depth--;
-       return;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_file2(struct minix2_inode *dir, unsigned int offset)
-{
-       static char blk[BLOCK_SIZE];
-       struct minix2_inode *inode;
-       int ino;
-       char *name;
-       int block;
-
-       block = map_block2(dir, offset / BLOCK_SIZE);
-       read_block(block, blk);
-       name = blk + (offset % BLOCK_SIZE) + 2;
-       ino = *(unsigned short *) (name - 2);
-       if (ino > INODES) {
-               print_current_name();
-               printf(" contains a bad inode number for file '");
-               printf("%.*s'.", namelen, name);
-               if (ask(" Remove", 1)) {
-                       *(unsigned short *) (name - 2) = 0;
-                       write_block(block, blk);
-               }
-               ino = 0;
-       }
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       inode = get_inode2(ino);
-       name_depth--;
-       if (!offset) {
-               if (!inode || strcmp(".", name)) {
-                       print_current_name();
-                       printf(": bad directory: '.' isn't first\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (offset == dirsize) {
-               if (!inode || strcmp("..", name)) {
-                       print_current_name();
-                       printf(": bad directory: '..' isn't second\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (!inode)
-               return;
-       name_depth++;
-       if (list) {
-               if (verbose)
-                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
-               print_current_name();
-               if (S_ISDIR(inode->i_mode))
-                       printf(":\n");
-               else
-                       printf("\n");
-       }
-       check_zones2(ino);
-       if (inode && S_ISDIR(inode->i_mode))
-               recursive_check2(ino);
-       name_depth--;
-       return;
-}
-#endif
-
-static void recursive_check(unsigned int ino)
-{
-       struct minix_inode *dir;
-       unsigned int offset;
-
-       dir = Inode + ino;
-       if (!S_ISDIR(dir->i_mode))
-               die("internal error");
-       if (dir->i_size < 2 * dirsize) {
-               print_current_name();
-               printf(": bad directory: size<32");
-               errors_uncorrected = 1;
-       }
-       for (offset = 0; offset < dir->i_size; offset += dirsize)
-               check_file(dir, offset);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino)
-{
-       struct minix2_inode *dir;
-       unsigned int offset;
-
-       dir = Inode2 + ino;
-       if (!S_ISDIR(dir->i_mode))
-               die("internal error");
-       if (dir->i_size < 2 * dirsize) {
-               print_current_name();
-               printf(": bad directory: size < 32");
-               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[1024];
-
-       if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
-               die("seek failed in bad_zone");
-       return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
-}
-
-static void check_counts(void)
-{
-       int i;
-
-       for (i = 1; i <= INODES; i++) {
-               if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
-                       printf("Inode %d mode not cleared.", i);
-                       if (ask("Clear", 1)) {
-                               Inode[i].i_mode = 0;
-                               changed = 1;
-                       }
-               }
-               if (!inode_count[i]) {
-                       if (!inode_in_use(i))
-                               continue;
-                       printf("Inode %d not used, marked used in the bitmap.", i);
-                       if (ask("Clear", 1))
-                               unmark_inode(i);
-                       continue;
-               }
-               if (!inode_in_use(i)) {
-                       printf("Inode %d used, marked unused in the bitmap.", i);
-                       if (ask("Set", 1))
-                               mark_inode(i);
-               }
-               if (Inode[i].i_nlinks != inode_count[i]) {
-                       printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
-                                  i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]);
-                       if (ask("Set i_nlinks to count", 1)) {
-                               Inode[i].i_nlinks = inode_count[i];
-                               changed = 1;
-                       }
-               }
-       }
-       for (i = FIRSTZONE; i < ZONES; i++) {
-               if (zone_in_use(i) == zone_count[i])
-                       continue;
-               if (!zone_count[i]) {
-                       if (bad_zone(i))
-                               continue;
-                       printf("Zone %d: marked in use, 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]);
-       }
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_counts2(void)
-{
-       int i;
-
-       for (i = 1; i <= INODES; i++) {
-               if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
-                       printf("Inode %d mode not cleared.", i);
-                       if (ask("Clear", 1)) {
-                               Inode2[i].i_mode = 0;
-                               changed = 1;
-                       }
-               }
-               if (!inode_count[i]) {
-                       if (!inode_in_use(i))
-                               continue;
-                       printf("Inode %d not used, marked used in the bitmap.", i);
-                       if (ask("Clear", 1))
-                               unmark_inode(i);
-                       continue;
-               }
-               if (!inode_in_use(i)) {
-                       printf("Inode %d used, marked 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) == zone_count[i])
-                       continue;
-               if (!zone_count[i]) {
-                       if (bad_zone(i))
-                               continue;
-                       printf("Zone %d: marked in use, 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(ROOT_INO);
-       recursive_check(ROOT_INO);
-       check_counts();
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check2(void)
-{
-       memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
-       memset(zone_count, 0, ZONES * sizeof(*zone_count));
-       check_zones2(ROOT_INO);
-       recursive_check2(ROOT_INO);
-       check_counts2();
-}
-#endif
-
-/* Wed Feb  9 15:17:06 MST 2000 */
-/* dynamically allocate name_list (instead of making it static) */
-static void alloc_name_list(void)
-{
-       int i;
-
-       name_list = xmalloc(sizeof(char *) * MAX_DEPTH);
-       for (i = 0; i < MAX_DEPTH; i++)
-               name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
-}
-
-#ifdef BB_FEATURE_CLEAN_UP
-/* execute this atexit() to deallocate name_list[] */
-/* piptigger was here */
-static void free_name_list(void)
-{
-       int i;
-
-       if (name_list) { 
-               for (i = 0; i < MAX_DEPTH; i++) {
-                       if (name_list[i]) {
-                               free(name_list[i]);
-                       }
-               }
-               free(name_list);
-       }
-}
-#endif
-
-extern int fsck_minix_main(int argc, char **argv)
-{
-       struct termios tmp;
-       int count;
-       int retcode = 0;
-
-       alloc_name_list();
-#ifdef BB_FEATURE_CLEAN_UP
-       /* Don't bother to free memory.  Exit does
-        * that automagically, so we can save a few bytes */
-       atexit(free_name_list);
-#endif
-
-       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
-               die("bad inode size");
-#ifdef BB_FEATURE_MINIX2
-       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
-               die("bad v2 inode size");
-#endif
-       while (argc-- > 1) {
-               argv++;
-               if (argv[0][0] != '-') {
-                       if (device_name)
-                               show_usage();
-                       else
-                               device_name = argv[0];
-               } else
-                       while (*++argv[0])
-                               switch (argv[0][0]) {
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 'a':
-                                       automatic = 1;
-                                       repair = 1;
-                                       break;
-                               case 'r':
-                                       automatic = 0;
-                                       repair = 1;
-                                       break;
-                               case 'v':
-                                       verbose = 1;
-                                       break;
-                               case 's':
-                                       show = 1;
-                                       break;
-                               case 'm':
-                                       warn_mode = 1;
-                                       break;
-                               case 'f':
-                                       force = 1;
-                                       break;
-                               default:
-                                       show_usage();
-                               }
-       }
-       if (!device_name)
-               show_usage();
-       check_mount();                          /* trying to check a mounted filesystem? */
-       if (repair && !automatic) {
-               if (!isatty(0) || !isatty(1))
-                       die("need terminal for interactive repairs");
-       }
-       IN = open(device_name, repair ? O_RDWR : O_RDONLY);
-       if (IN < 0){
-               fprintf(stderr,"unable to open device '%s'.\n",device_name);
-               leave(8);
-       }
-       for (count = 0; count < 3; count++)
-               sync();
-       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, program_version);
-       if (!(Super.s_state & MINIX_ERROR_FS) &&
-               (Super.s_state & MINIX_VALID_FS) && !force) {
-               if (repair)
-                       printf("%s is clean, no check.\n", device_name);
-               return retcode;
-       } else if (force)
-               printf("Forcing filesystem check on %s.\n", device_name);
-       else if (repair)
-               printf("Filesystem on %s is dirty, needs checking.\n",
-                          device_name);
-
-       read_tables();
-
-       if (repair && !automatic) {
-               tcgetattr(0, &termios);
-               tmp = termios;
-               tmp.c_lflag &= ~(ICANON | ECHO);
-               tcsetattr(0, TCSANOW, &tmp);
-               termios_set = 1;
-       }
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               check_root2();
-               check2();
-       } else
-#endif
-       {
-               check_root();
-               check();
-       }
-       if (verbose) {
-               int i, free_cnt;
-
-               for (i = 1, free_cnt = 0; i <= INODES; i++)
-                       if (!inode_in_use(i))
-                               free_cnt++;
-               printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt),
-                          100 * (INODES - free_cnt) / INODES);
-               for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
-                       if (!zone_in_use(i))
-                               free_cnt++;
-               printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt),
-                          100 * (ZONES - free_cnt) / ZONES);
-               printf("\n%6d regular files\n"
-                          "%6d directories\n"
-                          "%6d character device files\n"
-                          "%6d block device files\n"
-                          "%6d links\n"
-                          "%6d symbolic links\n"
-                          "------\n"
-                          "%6d files\n",
-                          regular, directory, chardev, blockdev,
-                          links - 2 * directory + 1, symlinks,
-                          total - 2 * directory + 1);
-       }
-       if (changed) {
-               write_tables();
-               printf("----------------------------\n"
-                          "FILE SYSTEM HAS BEEN CHANGED\n"
-                          "----------------------------\n");
-               for (count = 0; count < 3; count++)
-                       sync();
-       } else if (repair)
-               write_super_block();
-
-       if (repair && !automatic)
-               tcsetattr(0, TCSANOW, &termios);
-
-       if (changed)
-               retcode += 3;
-       if (errors_uncorrected)
-               retcode += 4;
-       return retcode;
-}
diff --git a/busybox/getopt.c b/busybox/getopt.c
deleted file mode 100644 (file)
index 95ecba6..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * getopt.c - Enhanced implementation of BSD getopt(1)
- *   Copyright (c) 1997, 1998, 1999, 2000  Frodo Looijaard <frodol@dds.nl>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * Version 1.0-b4: Tue Sep 23 1997. First public release.
- * Version 1.0: Wed Nov 19 1997.
- *   Bumped up the version number to 1.0
- *   Fixed minor typo (CSH instead of TCSH)
- * Version 1.0.1: Tue Jun 3 1998
- *   Fixed sizeof instead of strlen bug
- *   Bumped up the version number to 1.0.1
- * Version 1.0.2: Thu Jun 11 1998 (not present)
- *   Fixed gcc-2.8.1 warnings
- *   Fixed --version/-V option (not present)
- * Version 1.0.5: Tue Jun 22 1999
- *   Make -u option work (not present)
- * Version 1.0.6: Tue Jun 27 2000
- *   No important changes
- * Version 1.1.0: Tue Jun 30 2000
- *   Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
- *     <misiek@misiek.eu.org>)
- * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
- *  Removed --version/-V and --help/-h in
- *  Removed prase_error(), using error_msg() from Busybox instead
- *  Replaced our_malloc with xmalloc and our_realloc with xrealloc
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <getopt.h>
-
-#include "busybox.h"
-
-/* NON_OPT is the code that is returned when a non-option is found in '+'
-   mode */
-static const int NON_OPT = 1;
-/* LONG_OPT is the code that is returned when a long option is found. */
-static const int LONG_OPT = 2;
-
-/* The shells recognized. */
-typedef enum {BASH,TCSH} shell_t;
-
-
-/* Some global variables that tells us how to parse. */
-static shell_t shell=BASH; /* The shell we generate output for. */
-static int quiet_errors=0; /* 0 is not quiet. */
-static int quiet_output=0; /* 0 is not quiet. */
-static int quote=1; /* 1 is do quote. */
-static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
-
-/* Function prototypes */
-static const char *normalize(const char *arg);
-static int generate_output(char * argv[],int argc,const char *optstr,
-                    const struct option *longopts);
-static void add_long_options(char *options);
-static void add_longopt(const char *name,int has_arg);
-static void set_shell(const char *new_shell);
-
-
-/*
- * This function 'normalizes' a single argument: it puts single quotes around
- * it and escapes other special characters. If quote is false, it just
- * returns its argument.
- * Bash only needs special treatment for single quotes; tcsh also recognizes
- * exclamation marks within single quotes, and nukes whitespace.
- * This function returns a pointer to a buffer that is overwritten by
- * each call.
- */
-const char *normalize(const char *arg)
-{
-        static char *BUFFER=NULL;
-        const char *argptr=arg;
-        char *bufptr;
-
-        if (BUFFER != NULL)
-                free(BUFFER);
-
-        if (!quote) { /* Just copy arg */
-                BUFFER=xmalloc(strlen(arg)+1);
-
-                strcpy(BUFFER,arg);
-                return BUFFER;
-        }
-
-        /* Each character in arg may take upto four characters in the result:
-           For a quote we need a closing quote, a backslash, a quote and an
-           opening quote! We need also the global opening and closing quote,
-           and one extra character for '\0'. */
-        BUFFER=xmalloc(strlen(arg)*4+3);
-
-        bufptr=BUFFER;
-        *bufptr++='\'';
-
-        while (*argptr) {
-                if (*argptr == '\'') {
-                        /* Quote: replace it with: '\'' */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++='\'';
-                        *bufptr++='\'';
-                } else if (shell==TCSH && *argptr=='!') {
-                        /* Exclamation mark: replace it with: \! */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++='!';
-                        *bufptr++='\'';
-                } else if (shell==TCSH && *argptr=='\n') {
-                        /* Newline: replace it with: \n */
-                        *bufptr++='\\';
-                        *bufptr++='n';
-                } else if (shell==TCSH && isspace(*argptr)) {
-                        /* Non-newline whitespace: replace it with \<ws> */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++=*argptr;
-                        *bufptr++='\'';
-                } else
-                        /* Just copy */
-                        *bufptr++=*argptr;
-                argptr++;
-        }
-        *bufptr++='\'';
-        *bufptr++='\0';
-        return BUFFER;
-}
-
-/*
- * Generate the output. argv[0] is the program name (used for reporting errors).
- * argv[1..] contains the options to be parsed. argc must be the number of
- * elements in argv (ie. 1 if there are no options, only the program name),
- * optstr must contain the short options, and longopts the long options.
- * Other settings are found in global variables.
- */
-int generate_output(char * argv[],int argc,const char *optstr,
-                    const struct option *longopts)
-{
-        int exit_code = 0; /* We assume everything will be OK */
-        int opt;
-        int longindex;
-        const char *charptr;
-
-        if (quiet_errors) /* No error reporting from getopt(3) */
-                opterr=0;
-        optind=0; /* Reset getopt(3) */
-
-        while ((opt = (alternative?
-                       getopt_long_only(argc,argv,optstr,longopts,&longindex):
-                       getopt_long(argc,argv,optstr,longopts,&longindex)))
-               != EOF)
-                if (opt == '?' || opt == ':' )
-                        exit_code = 1;
-                else if (!quiet_output) {
-                        if (opt == LONG_OPT) {
-                                printf(" --%s",longopts[longindex].name);
-                                if (longopts[longindex].has_arg)
-                                        printf(" %s",
-                                               normalize(optarg?optarg:""));
-                        } else if (opt == NON_OPT)
-                                printf(" %s",normalize(optarg));
-                        else {
-                                printf(" -%c",opt);
-                                charptr = strchr(optstr,opt);
-                                if (charptr != NULL && *++charptr == ':')
-                                        printf(" %s",
-                                               normalize(optarg?optarg:""));
-                        }
-                }
-
-        if (! quiet_output) {
-                printf(" --");
-                while (optind < argc)
-                        printf(" %s",normalize(argv[optind++]));
-                printf("\n");
-        }
-        return exit_code;
-}
-
-static struct option *long_options=NULL;
-static int long_options_length=0; /* Length of array */
-static int long_options_nr=0; /* Nr of used elements in array */
-static const int LONG_OPTIONS_INCR = 10;
-#define init_longopt() add_longopt(NULL,0)
-
-/* Register a long option. The contents of name is copied. */
-void add_longopt(const char *name,int has_arg)
-{
-        char *tmp;
-        if (!name) { /* init */
-                free(long_options);
-                long_options=NULL;
-                long_options_length=0;
-                long_options_nr=0;
-        }
-
-        if (long_options_nr == long_options_length) {
-                long_options_length += LONG_OPTIONS_INCR;
-                long_options=xrealloc(long_options,
-                                         sizeof(struct option) *
-                                         long_options_length);
-        }
-
-        long_options[long_options_nr].name=NULL;
-        long_options[long_options_nr].has_arg=0;
-        long_options[long_options_nr].flag=NULL;
-        long_options[long_options_nr].val=0;
-
-        if (long_options_nr) { /* Not for init! */
-                long_options[long_options_nr-1].has_arg=has_arg;
-                long_options[long_options_nr-1].flag=NULL;
-                long_options[long_options_nr-1].val=LONG_OPT;
-                tmp = xmalloc(strlen(name)+1);
-                strcpy(tmp,name);
-                long_options[long_options_nr-1].name=tmp;
-        }
-        long_options_nr++;
-}
-
-
-/*
- * Register several long options. options is a string of long options,
- * separated by commas or whitespace.
- * This nukes options!
- */
-void add_long_options(char *options)
-{
-        int arg_opt, tlen;
-        char *tokptr=strtok(options,", \t\n");
-        while (tokptr) {
-                arg_opt=no_argument;
-               tlen=strlen(tokptr);
-                if (tlen > 0) {
-                        if (tokptr[tlen-1] == ':') {
-                                if (tlen > 1 && tokptr[tlen-2] == ':') {
-                                        tokptr[tlen-2]='\0';
-                                       tlen -= 2;
-                                        arg_opt=optional_argument;
-                                } else {
-                                        tokptr[tlen-1]='\0';
-                                       tlen -= 1;
-                                        arg_opt=required_argument;
-                                }
-                                if (tlen == 0)
-                                        error_msg("empty long option after -l or --long argument");
-                        }
-                        add_longopt(tokptr,arg_opt);
-                }
-                tokptr=strtok(NULL,", \t\n");
-        }
-}
-
-void set_shell(const char *new_shell)
-{
-        if (!strcmp(new_shell,"bash"))
-                shell=BASH;
-        else if (!strcmp(new_shell,"tcsh"))
-                shell=TCSH;
-        else if (!strcmp(new_shell,"sh"))
-                shell=BASH;
-        else if (!strcmp(new_shell,"csh"))
-                shell=TCSH;
-        else
-                error_msg("unknown shell after -s or --shell argument");
-}
-
-
-/* Exit codes:
- *   0) No errors, succesful operation.
- *   1) getopt(3) returned an error.
- *   2) A problem with parameter parsing for getopt(1).
- *   3) Internal error, out of memory
- *   4) Returned for -T
- */
-
-static struct option longopts[]=
-{
-        {"options",required_argument,NULL,'o'},
-        {"longoptions",required_argument,NULL,'l'},
-        {"quiet",no_argument,NULL,'q'},
-        {"quiet-output",no_argument,NULL,'Q'},
-        {"shell",required_argument,NULL,'s'},
-        {"test",no_argument,NULL,'T'},
-        {"unquoted",no_argument,NULL,'u'},
-        {"alternative",no_argument,NULL,'a'},
-        {"name",required_argument,NULL,'n'},
-        {NULL,0,NULL,0}
-};
-
-/* Stop scanning as soon as a non-option argument is found! */
-static const char *shortopts="+ao:l:n:qQs:Tu";
-
-
-int getopt_main(int argc, char *argv[])
-{
-        char *optstr=NULL;
-        char *name=NULL;
-        int opt;
-        int compatible=0;
-
-        init_longopt();
-
-        if (getenv("GETOPT_COMPATIBLE"))
-                compatible=1;
-
-        if (argc == 1) {
-                if (compatible) {
-                        /* For some reason, the original getopt gave no error
-                           when there were no arguments. */
-                        printf(" --\n");
-                        exit(0);
-                } else
-                        error_msg_and_die("missing optstring argument");
-        }
-
-        if (argv[1][0] != '-' || compatible) {
-                quote=0;
-                optstr=xmalloc(strlen(argv[1])+1);
-                strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
-                argv[1]=argv[0];
-                exit(generate_output(argv+1,argc-1,optstr,long_options));
-        }
-
-        while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
-                switch (opt) {
-                case 'a':
-                        alternative=1;
-                        break;
-                case 'o':
-                        if (optstr)
-                                free(optstr);
-                        optstr=xmalloc(strlen(optarg)+1);
-                        strcpy(optstr,optarg);
-                        break;
-                case 'l':
-                        add_long_options(optarg);
-                        break;
-                case 'n':
-                        if (name)
-                                free(name);
-                        name=xmalloc(strlen(optarg)+1);
-                        strcpy(name,optarg);
-                        break;
-                case 'q':
-                        quiet_errors=1;
-                        break;
-                case 'Q':
-                        quiet_output=1;
-                        break;
-                case 's':
-                        set_shell(optarg);
-                        break;
-                case 'T':
-                        exit(4);
-                case 'u':
-                        quote=0;
-                        break;
-                default:
-                        show_usage();
-                }
-
-        if (!optstr) {
-                if (optind >= argc)
-                        error_msg_and_die("missing optstring argument");
-                else {
-                        optstr=xmalloc(strlen(argv[optind])+1);
-                        strcpy(optstr,argv[optind]);
-                        optind++;
-                }
-        }
-        if (name)
-                argv[optind-1]=name;
-        else
-                argv[optind-1]=argv[0];
-        exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
-}
-
-/*
-  Local Variables:
-  c-file-style: "linux"
-  c-basic-offset: 4
-  tab-width: 4
-  End:
-*/
diff --git a/busybox/grep.c b/busybox/grep.c
deleted file mode 100644 (file)
index 3254868..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Mini grep implementation for busybox using libc regex.
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <regex.h>
-#include <string.h> /* for strerror() */
-#include <errno.h>
-#include "busybox.h"
-
-
-extern int optind; /* in unistd.h */
-extern int errno;  /* for use with strerror() */
-extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */
-
-/* options */
-static int reflags            = REG_NOSUB; 
-static int print_filename     = 0;
-static int print_line_num     = 0;
-static int print_match_counts = 0;
-static int be_quiet           = 0;
-static int invert_search      = 0;
-static int suppress_err_msgs  = 0;
-static int print_files_with_matches  = 0;
-
-#ifdef BB_FEATURE_GREP_CONTEXT
-extern char *optarg; /* in getopt.h */
-static int lines_before      = 0;
-static int lines_after       = 0;
-static char **before_buf     = NULL;
-static int last_line_printed = 0;
-#endif /* BB_FEATURE_GREP_CONTEXT */
-
-/* globals used internally */
-static regex_t *regexes = NULL; /* growable array of compiled regular expressions */
-static int nregexes = 0; /* number of elements in above arrary */
-static int matched; /* keeps track of whether we ever matched */
-static char *cur_file = NULL; /* the current file we are reading */
-
-
-static void print_line(const char *line, int linenum, char decoration)
-{
-#ifdef BB_FEATURE_GREP_CONTEXT
-       /* possibly print the little '--' seperator */
-       if ((lines_before || lines_after) && last_line_printed &&
-                       last_line_printed < linenum - 1) {
-               puts("--");
-       }
-       last_line_printed = linenum;
-#endif
-       if (print_filename)
-               printf("%s%c", cur_file, decoration);
-       if (print_line_num)
-               printf("%i%c", linenum, decoration);
-       puts(line);
-}
-
-
-static void grep_file(FILE *file)
-{
-       char *line = NULL;
-       int ret;
-       int linenum = 0;
-       int nmatches = 0;
-       int i;
-#ifdef BB_FEATURE_GREP_CONTEXT
-       int print_n_lines_after = 0;
-       int curpos = 0; /* track where we are in the circular 'before' buffer */
-       int idx = 0; /* used for iteration through the circular buffer */
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-
-       while ((line = get_line_from_file(file)) != NULL) {
-               chomp(line);
-               linenum++;
-
-               for (i = 0; i < nregexes; i++) {
-                       /*
-                        * test for a postitive-assertion match (regexec returns success (0)
-                        * and the user did not specify invert search), or a negative-assertion
-                        * match (regexec returns failure (REG_NOMATCH) and the user specified
-                        * invert search)
-                        */
-                       ret = regexec(&regexes[i], line, 0, NULL, 0);
-                       if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) {
-
-                               /* if we found a match but were told to be quiet, stop here and
-                                * return success */
-                               if (be_quiet)
-                                       exit(0);
-
-                               /* keep track of matches */
-                               nmatches++;
-
-                               /* if we're just printing filenames, we stop after the first match */
-                               if (print_files_with_matches)
-                                       break;
-
-                               /* print the matched line */
-                               if (print_match_counts == 0) {
-#ifdef BB_FEATURE_GREP_CONTEXT
-                                       int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
-
-                                       /* if we were told to print 'before' lines and there is at least
-                                        * one line in the circular buffer, print them */
-                                       if (lines_before && before_buf[prevpos] != NULL) {
-                                               int first_buf_entry_line_num = linenum - lines_before;
-
-                                               /* advance to the first entry in the circular buffer, and
-                                                * figure out the line number is of the first line in the
-                                                * buffer */
-                                               idx = curpos;
-                                               while (before_buf[idx] == NULL) {
-                                                       idx = (idx + 1) % lines_before;
-                                                       first_buf_entry_line_num++;
-                                               }
-
-                                               /* now print each line in the buffer, clearing them as we go */
-                                               while (before_buf[idx] != NULL) {
-                                                       print_line(before_buf[idx], first_buf_entry_line_num, '-');
-                                                       free(before_buf[idx]);
-                                                       before_buf[idx] = NULL;
-                                                       idx = (idx + 1) % lines_before;
-                                                       first_buf_entry_line_num++;
-                                               }
-                                       }
-
-                                       /* make a note that we need to print 'after' lines */
-                                       print_n_lines_after = lines_after;
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-                                       print_line(line, linenum, ':');
-                               }
-                       }
-#ifdef BB_FEATURE_GREP_CONTEXT
-                       else { /* no match */
-                               /* Add the line to the circular 'before' buffer */
-                               if(lines_before) {
-                                       if(before_buf[curpos])
-                                               free(before_buf[curpos]);
-                                       before_buf[curpos] = strdup(line);
-                                       curpos = (curpos + 1) % lines_before;
-                               }
-                       }
-
-                       /* if we need to print some context lines after the last match, do so */
-                       if (print_n_lines_after && (last_line_printed != linenum)) {
-                               print_line(line, linenum, '-');
-                               print_n_lines_after--;
-                       }
-#endif /* BB_FEATURE_GREP_CONTEXT */ 
-               } /* for */
-               free(line);
-       }
-
-
-       /* special-case file post-processing for options where we don't print line
-        * matches, just filenames and possibly match counts */
-
-       /* grep -c: print [filename:]count, even if count is zero */
-       if (print_match_counts) {
-               if (print_filename)
-                       printf("%s:", cur_file);
-               if (print_files_with_matches && nmatches > 0)
-                       printf("1\n");
-               else
-                   printf("%d\n", nmatches);
-       }
-
-       /* grep -l: print just the filename, but only if we grepped the line in the file  */
-       if (print_files_with_matches && nmatches > 0) {
-               puts(cur_file);
-       }
-
-
-       /* remember if we matched */
-       if (nmatches != 0)
-               matched = 1;
-}
-
-
-static void add_regex(const char *restr)
-{
-       regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes));
-       xregcomp(&regexes[nregexes-1], restr, reflags);
-}
-
-
-static void    load_regexes_from_file(const char *filename)
-{
-       char *line;
-       FILE *f = xfopen(filename, "r");
-       while ((line = get_line_from_file(f)) != NULL) {
-               chomp(line);
-               add_regex(line);
-               free(line);
-       }
-}
-
-
-#ifdef BB_FEATURE_CLEAN_UP
-static void destroy_regexes()
-{
-       if (regexes == NULL)
-               return;
-
-       /* destroy all the elments in the array */
-       while (--nregexes >= 0) {
-               regfree(&regexes[nregexes]);
-               free(&regexes[nregexes]);
-       }
-}
-#endif
-
-
-extern int grep_main(int argc, char **argv)
-{
-       int opt;
-#ifdef BB_FEATURE_GREP_CONTEXT
-       char *junk;
-#endif
-
-#ifdef BB_FEATURE_CLEAN_UP
-       /* destroy command strings on exit */
-       if (atexit(destroy_regexes) == -1)
-               perror_msg_and_die("atexit");
-#endif
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "iHhlnqvsce:f:"
-#ifdef BB_FEATURE_GREP_CONTEXT
-"A:B:C:"
-#endif
-)) > 0) {
-               switch (opt) {
-                       case 'i':
-                               reflags |= REG_ICASE;
-                               break;
-                       case 'l':
-                               print_files_with_matches++;
-                               break;
-                       case 'H':
-                               print_filename++;
-                               break;
-                       case 'h':
-                               print_filename--;
-                               break;
-                       case 'n':
-                               print_line_num++;
-                               break;
-                       case 'q':
-                               be_quiet++;
-                               break;
-                       case 'v':
-                               invert_search++;
-                               break;
-                       case 's':
-                               suppress_err_msgs++;
-                               break;
-                       case 'c':
-                               print_match_counts++;
-                               break;
-                       case 'e':
-                               add_regex(optarg);
-                               break;
-                       case 'f':
-                               load_regexes_from_file(optarg);
-                               break;
-#ifdef BB_FEATURE_GREP_CONTEXT
-                       case 'A':
-                               lines_after = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               break;
-                       case 'B':
-                               lines_before = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               before_buf = (char **)calloc(lines_before, sizeof(char *));
-                               break;
-                       case 'C':
-                               lines_after = lines_before = strtoul(optarg, &junk, 10);
-                               if(*junk != '\0')
-                                       error_msg_and_die("invalid context length argument");
-                               before_buf = (char **)calloc(lines_before, sizeof(char *));
-                               break;
-#endif /* BB_FEATURE_GREP_CONTEXT */
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a pattern from a -e and no command file was specified,
-        * argv[optind] should be the pattern. no pattern, no worky */
-       if (nregexes == 0) {
-               if (argv[optind] == NULL)
-                       show_usage();
-               else {
-                       add_regex(argv[optind]);
-                       optind++;
-               }
-       }
-
-       /* sanity checks */
-       if (print_match_counts || be_quiet || print_files_with_matches) {
-               print_line_num = 0;
-#ifdef BB_FEATURE_GREP_CONTEXT
-               lines_before = 0;
-               lines_after = 0;
-#endif
-       }
-
-       /* argv[(optind)..(argc-1)] should be names of file to grep through. If
-        * there is more than one file to grep, we will print the filenames */
-       if ((argc-1) - (optind) > 0)
-               print_filename++;
-
-       /* If no files were specified, or '-' was specified, take input from
-        * stdin. Otherwise, we grep through all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               grep_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       cur_file = argv[i];
-                       file = fopen(cur_file, "r");
-                       if (file == NULL) {
-                               if (!suppress_err_msgs)
-                                       perror_msg("%s", cur_file);
-                       }
-                       else {
-                               grep_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-
-       return !matched; /* invert return value 0 = success, 1 = failed */
-}
diff --git a/busybox/gunzip.c b/busybox/gunzip.c
deleted file mode 100644 (file)
index 430bc63..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Gzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
-       "   Copyright (C) 1992-1993 Jean-loup Gailly",
-       "   This program is free software; you can redistribute it and/or modify",
-       "   it under the terms of the GNU General Public License as published by",
-       "   the Free Software Foundation; either version 2, or (at your option)",
-       "   any later version.",
-       "",
-       "   This program is distributed in the hope that it will be useful,",
-       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
-       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
-       "   GNU General Public License for more details.",
-       "",
-       "   You should have received a copy of the GNU General Public License",
-       "   along with this program; if not, write to the Free Software",
-       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
-       0
-};
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int gunzip_main(int argc, char **argv)
-{
-       FILE *in_file = stdin;
-       FILE *out_file = NULL;
-       struct stat stat_buf;
-
-       char *if_name = NULL;
-       char *of_name = NULL;
-       char *delete_file_name = NULL;
-
-       const int gunzip_to_stdout = 1;
-       const int gunzip_force = 2;
-       const int gunzip_test = 4;
-
-       int flags = 0;
-       int opt = 0;
-       int delete_old_file = FALSE;
-
-       /* if called as zcat */
-       if (strcmp(applet_name, "zcat") == 0)
-               flags |= gunzip_to_stdout;
-
-       while ((opt = getopt(argc, argv, "ctfhdq")) != -1) {
-               switch (opt) {
-               case 'c':
-                       flags |= gunzip_to_stdout;
-                       break;
-               case 'f':
-                       flags |= gunzip_force;
-                       break;
-               case 't':
-                       flags |= gunzip_test;
-                       break;
-               case 'd': /* Used to convert gzip to gunzip. */
-                       break;
-               case 'q':
-                       error_msg("-q option not supported, ignored");
-                       break;
-               case 'h':
-               default:
-                       show_usage(); /* exit's inside usage */
-               }
-       }
-
-       /* Set input filename and number */
-       if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
-               flags |= gunzip_to_stdout;
-       } else {
-               if_name = strdup(argv[optind]);
-               /* Open input file */
-               in_file = xfopen(if_name, "r");
-
-               /* set the buffer size */
-               setvbuf(in_file, NULL, _IOFBF, 0x8000);
-
-               /* Get the time stamp on the input file. */
-               if (stat(if_name, &stat_buf) < 0) {
-                       error_msg_and_die("Couldn't stat file %s", if_name);
-               }
-       }
-
-       /* Check that the input is sane.  */
-       if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0)
-               error_msg_and_die("compressed data not read from terminal.  Use -f to force it.");
-
-       /* Set output filename and number */
-       if (flags & gunzip_test) {
-               out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
-       } else if (flags & gunzip_to_stdout) {
-               out_file = stdout;
-       } else {
-               char *extension;
-               int length = strlen(if_name);
-
-               delete_old_file = TRUE;
-               extension = strrchr(if_name, '.');
-               if (extension && strcmp(extension, ".gz") == 0) {
-                       length -= 3;
-               } else if (extension && strcmp(extension, ".tgz") == 0) {
-                       length -= 4;
-               } else {
-                       error_msg_and_die("Invalid extension");
-               }
-               of_name = (char *) xcalloc(sizeof(char), length + 1);
-               strncpy(of_name, if_name, length);
-
-               /* Open output file */
-               out_file = xfopen(of_name, "w");
-
-               /* Set permissions on the file */
-               chmod(of_name, stat_buf.st_mode);
-       }
-
-       /* do the decompression, and cleanup */
-       if (unzip(in_file, out_file) == 0) {
-               /* Success, remove .gz file */
-               delete_file_name = if_name;
-       } else {
-               /* remove failed attempt */
-               delete_file_name = of_name;
-       }
-
-       fclose(out_file);
-       fclose(in_file);
-
-       if (delete_old_file == TRUE) {
-               if (unlink(delete_file_name) < 0) {
-                       error_msg_and_die("Couldnt remove %s", delete_file_name);
-               }
-       }
-
-       free(of_name);
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/gzip.c b/busybox/gzip.c
deleted file mode 100644 (file)
index 54bb727..0000000
+++ /dev/null
@@ -1,2550 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Gzip implementation for busybox
- *
- * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
- *             "this is a stripped down version of gzip I put into busybox, it does
- *             only standard in to standard out with -9 compression.  It also requires
- *             the zcat module for some important functions."
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* These defines are very important for BusyBox.  Without these,
- * huge chunks of ram are pre-allocated making the BusyBox bss 
- * size Freaking Huge(tm), which is a bad thing.*/
-#define SMALL_MEM
-#define DYN_ALLOC
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <utime.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <time.h>
-#include "busybox.h"
-
-#define memzero(s, n)     memset ((void *)(s), 0, (n))
-
-#ifndef RETSIGTYPE
-#  define RETSIGTYPE void
-#endif
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-/* Return codes from gzip */
-#define OK      0
-#define ERROR   1
-#define WARNING 2
-
-/* Compression methods (see algorithm.doc) */
-/* Only STORED and DEFLATED are supported by this BusyBox module */
-#define STORED      0
-/* methods 4 to 7 reserved */
-#define DEFLATED    8
-static int method;                             /* compression method */
-
-/* To save memory for 16 bit systems, some arrays are overlaid between
- * the various modules:
- * deflate:  prev+head   window      d_buf  l_buf  outbuf
- * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
- * For compression, input is done in window[]. For decompression, output
- * is done in window except for unlzw.
- */
-
-#ifndef        INBUFSIZ
-#  ifdef SMALL_MEM
-#    define INBUFSIZ  0x2000   /* input buffer size */
-#  else
-#    define INBUFSIZ  0x8000   /* input buffer size */
-#  endif
-#endif
-#define INBUF_EXTRA  64                        /* required by unlzw() */
-
-#ifndef        OUTBUFSIZ
-#  ifdef SMALL_MEM
-#    define OUTBUFSIZ   8192   /* output buffer size */
-#  else
-#    define OUTBUFSIZ  16384   /* output buffer size */
-#  endif
-#endif
-#define OUTBUF_EXTRA 2048              /* required by unlzw() */
-
-#ifndef DIST_BUFSIZE
-#  ifdef SMALL_MEM
-#    define DIST_BUFSIZE 0x2000        /* buffer for distances, see trees.c */
-#  else
-#    define DIST_BUFSIZE 0x8000        /* buffer for distances, see trees.c */
-#  endif
-#endif
-
-#ifdef DYN_ALLOC
-#  define DECLARE(type, array, size)  static type * array
-#  define ALLOC(type, array, size) { \
-      array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
-      if (array == NULL) error_msg(memory_exhausted); \
-   }
-#  define FREE(array) {if (array != NULL) free(array), array=NULL;}
-#else
-#  define DECLARE(type, array, size)  static type array[size]
-#  define ALLOC(type, array, size)
-#  define FREE(array)
-#endif
-
-#define tab_suffix window
-#define tab_prefix prev                /* hash link (see deflate.c) */
-#define head (prev+WSIZE)              /* hash head (see deflate.c) */
-
-static long bytes_in;                  /* number of input bytes */
-
-#define isize bytes_in
-/* for compatibility with old zip sources (to be cleaned) */
-
-typedef int file_t;                            /* Do not use stdio */
-
-#define NO_FILE  (-1)                  /* in memory compression */
-
-
-#define        PACK_MAGIC     "\037\036"       /* Magic header for packed files */
-#define        GZIP_MAGIC     "\037\213"       /* Magic header for gzip files, 1F 8B */
-#define        OLD_GZIP_MAGIC "\037\236"       /* Magic header for gzip 0.5 = freeze 1.x */
-#define        LZH_MAGIC      "\037\240"       /* Magic header for SCO LZH Compress files */
-#define PKZIP_MAGIC    "\120\113\003\004"      /* Magic header for pkzip files */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01              /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02              /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04              /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08              /* bit 3 set: original file name present */
-#define COMMENT      0x10              /* bit 4 set: file comment present */
-#define RESERVED     0xC0              /* bit 6,7:   reserved */
-
-/* internal file attribute */
-#define UNKNOWN 0xffff
-#define BINARY  0
-#define ASCII   1
-
-#ifndef WSIZE
-#  define WSIZE 0x8000                 /* window size--must be a power of two, and */
-#endif                                                 /*  at least 32K for zip's deflate method */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-/* put_byte is used for the compressed output */
-#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
-   flush_outbuf();}
-
-/* Output a 16 bit value, lsb first */
-#define put_short(w) \
-{ if (outcnt < OUTBUFSIZ-2) { \
-    outbuf[outcnt++] = (uch) ((w) & 0xff); \
-    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
-  } else { \
-    put_byte((uch)((w) & 0xff)); \
-    put_byte((uch)((ush)(w) >> 8)); \
-  } \
-}
-
-/* Output a 32 bit value to the bit stream, lsb first */
-#define put_long(n) { \
-    put_short((n) & 0xffff); \
-    put_short(((ulg)(n)) >> 16); \
-}
-
-#define seekable()    0                        /* force sequential output */
-#define translate_eol 0                        /* no option -a yet */
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error_msg(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-#define WARN(msg) {if (!quiet) fprintf msg ; \
-                  if (exit_code == OK) exit_code = WARNING;}
-
-#ifndef MAX_PATH_LEN
-#  define MAX_PATH_LEN   1024  /* max pathname length */
-#endif
-
-
-
-       /* from zip.c: */
-static int zip (int in, int out);
-static int file_read (char *buf, unsigned size);
-
-       /* from gzip.c */
-static RETSIGTYPE abort_gzip (void);
-
-               /* from deflate.c */
-static void lm_init (ush * flags);
-static ulg deflate (void);
-
-               /* from trees.c */
-static void ct_init (ush * attr, int *methodp);
-static int ct_tally (int dist, int lc);
-static ulg flush_block (char *buf, ulg stored_len, int eof);
-
-               /* from bits.c */
-static void bi_init (file_t zipfile);
-static void send_bits (int value, int length);
-static unsigned bi_reverse (unsigned value, int length);
-static void bi_windup (void);
-static void copy_block (char *buf, unsigned len, int header);
-static int (*read_buf) (char *buf, unsigned size);
-
-       /* from util.c: */
-static void flush_outbuf (void);
-
-/* lzw.h -- define the lzw functions.
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if !defined(OF) && defined(lint)
-#  include "gzip.h"
-#endif
-
-#ifndef BITS
-#  define BITS 16
-#endif
-#define INIT_BITS 9                            /* Initial number of bits per code */
-
-#define BIT_MASK    0x1f               /* Mask for 'number of compression bits' */
-/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
- * It's a pity that old uncompress does not check bit 0x20. That makes
- * extension of the format actually undesirable because old compress
- * would just crash on the new format instead of giving a meaningful
- * error message. It does check the number of bits, but it's more
- * helpful to say "unsupported format, get a new version" than
- * "can only handle 16 bits".
- */
-
-/* tailor.h -- target dependent definitions
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/* The target dependent definitions should be defined here only.
- * The target dependent functions should be defined in tailor.c.
- */
-
-
-       /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03                        /* assume Unix */
-#endif
-
-#ifndef PATH_SEP
-#  define PATH_SEP '/'
-#endif
-
-#ifndef OPTIONS_VAR
-#  define OPTIONS_VAR "GZIP"
-#endif
-
-#ifndef Z_SUFFIX
-#  define Z_SUFFIX ".gz"
-#endif
-
-#ifdef MAX_EXT_CHARS
-#  define MAX_SUFFIX  MAX_EXT_CHARS
-#else
-#  define MAX_SUFFIX  30
-#endif
-
-               /* global buffers */
-
-DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
-DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
-DECLARE(ush, d_buf, DIST_BUFSIZE);
-DECLARE(uch, window, 2L * WSIZE);
-DECLARE(ush, tab_prefix, 1L << BITS);
-
-static int crc_table_empty = 1;
-
-static int foreground;                                 /* set if program run in foreground */
-static int method = DEFLATED;  /* compression method */
-static int exit_code = OK;             /* program exit code */
-static int part_nb;                                    /* number of parts in .gz file */
-static long time_stamp;                                /* original time stamp (modification time) */
-static long ifile_size;                                /* input file size, -1 for devices (debug only) */
-static char z_suffix[MAX_SUFFIX + 1];  /* default suffix (can be set with --suffix) */
-static int z_len;                                              /* strlen(z_suffix) */
-
-static char ifname[MAX_PATH_LEN];              /* input file name */
-static char ofname[MAX_PATH_LEN];              /* output file name */
-static int ifd;                                                /* input file descriptor */
-static int ofd;                                                /* output file descriptor */
-static unsigned insize;                                /* valid bytes in inbuf */
-static unsigned outcnt;                                /* bytes in output buffer */
-
-/* ========================================================================
- * Signal and error handler.
- */
-static void abort_gzip()
-{
-       exit(ERROR);
-}
-
-/* ===========================================================================
- * Clear input and output buffers
- */
-static void clear_bufs(void)
-{
-       outcnt = 0;
-       insize = 0;
-       bytes_in = 0L;
-}
-
-static void write_error_msg()
-{
-       fprintf(stderr, "\n");
-       perror("");
-       abort_gzip();
-}
-
-/* ===========================================================================
- * Does the same as write(), but also handles partial pipe writes and checks
- * for error return.
- */
-static void write_buf(int fd, void *buf, unsigned cnt)
-{
-       unsigned n;
-
-       while ((n = write(fd, buf, cnt)) != cnt) {
-               if (n == (unsigned) (-1)) {
-                       write_error_msg();
-               }
-               cnt -= n;
-               buf = (void *) ((char *) buf + n);
-       }
-}
-
-/* ===========================================================================
- * Run a set of bytes through the crc shift register.  If s is a NULL
- * pointer, then initialize the crc shift register contents instead.
- * Return the current crc in either case.
- */
-static ulg updcrc(uch *s, unsigned n)
-{
-       static ulg crc = (ulg) 0xffffffffL;     /* shift register contents */
-       register ulg c;                         /* temporary variable */
-       static unsigned long crc_32_tab[256];
-       if (crc_table_empty) {
-               unsigned long csr;      /* crc shift register */
-               unsigned long e=0;      /* polynomial exclusive-or pattern */
-               int i;                /* counter for all possible eight bit values */
-               int k;                /* byte being shifted into crc apparatus */
-
-               /* terms of polynomial defining this crc (except x^32): */
-               static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-               /* Make exclusive-or pattern from polynomial (0xedb88320) */
-               for (i = 0; i < sizeof(p)/sizeof(int); i++)
-                       e |= 1L << (31 - p[i]);
-
-               /* Compute and print table of CRC's, five per line */
-               crc_32_tab[0] = 0x00000000L;
-               for (i = 1; i < 256; i++) {
-                       csr = i;
-                  /* The idea to initialize the register with the byte instead of
-                    * zero was stolen from Haruhiko Okumura's ar002
-                    */
-                       for (k = 8; k; k--)
-                               csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1;
-                       crc_32_tab[i]=csr;
-               }
-       }
-
-       if (s == NULL) {
-               c = 0xffffffffL;
-       } else {
-               c = crc;
-               if (n)
-                       do {
-                               c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8);
-                       } while (--n);
-       }
-       crc = c;
-       return c ^ 0xffffffffL;         /* (instead of ~c for 64-bit machines) */
-}
-
-/* bits.c -- output variable-length bit strings
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-
-/*
- *  PURPOSE
- *
- *      Output variable-length bit strings. Compression can be done
- *      to a file or to memory. (The latter is not supported in this version.)
- *
- *  DISCUSSION
- *
- *      The PKZIP "deflate" file format interprets compressed file data
- *      as a sequence of bits.  Multi-bit strings in the file may cross
- *      byte boundaries without restriction.
- *
- *      The first bit of each byte is the low-order bit.
- *
- *      The routines in this file allow a variable-length bit value to
- *      be output right-to-left (useful for literal values). For
- *      left-to-right output (useful for code strings from the tree routines),
- *      the bits must have been reversed first with bi_reverse().
- *
- *      For in-memory compression, the compressed bit stream goes directly
- *      into the requested output buffer. The input data is read in blocks
- *      by the mem_read() function. The buffer is limited to 64K on 16 bit
- *      machines.
- *
- *  INTERFACE
- *
- *      void bi_init (FILE *zipfile)
- *          Initialize the bit string routines.
- *
- *      void send_bits (int value, int length)
- *          Write out a bit string, taking the source bits right to
- *          left.
- *
- *      int bi_reverse (int value, int length)
- *          Reverse the bits of a bit string, taking the source bits left to
- *          right and emitting them right to left.
- *
- *      void bi_windup (void)
- *          Write out any remaining bits in an incomplete byte.
- *
- *      void copy_block(char *buf, unsigned len, int header)
- *          Copy a stored block to the zip file, storing first the length and
- *          its one's complement if requested.
- *
- */
-
-/* ===========================================================================
- * Local data used by the "bit string" routines.
- */
-
-static file_t zfile;                           /* output gzip file */
-
-static unsigned short bi_buf;
-
-/* Output buffer. bits are inserted starting at the bottom (least significant
- * bits).
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-static int bi_valid;
-
-/* Current input function. Set to mem_read for in-memory compression */
-
-#ifdef DEBUG
-ulg bits_sent;                                 /* bit length of the compressed data */
-#endif
-
-/* ===========================================================================
- * Initialize the bit string routines.
- */
-static void bi_init(file_t zipfile)
-{
-       zfile = zipfile;
-       bi_buf = 0;
-       bi_valid = 0;
-#ifdef DEBUG
-       bits_sent = 0L;
-#endif
-
-       /* Set the defaults for file compression. They are set by memcompress
-        * for in-memory compression.
-        */
-       if (zfile != NO_FILE) {
-               read_buf = file_read;
-       }
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-static void send_bits(int value, int length)
-{
-#ifdef DEBUG
-       Tracev((stderr, " l %2d v %4x ", length, value));
-       Assert(length > 0 && length <= 15, "invalid length");
-       bits_sent += (ulg) length;
-#endif
-       /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-        * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-        * unused bits in value.
-        */
-       if (bi_valid > (int) Buf_size - length) {
-               bi_buf |= (value << bi_valid);
-               put_short(bi_buf);
-               bi_buf = (ush) value >> (Buf_size - bi_valid);
-               bi_valid += length - Buf_size;
-       } else {
-               bi_buf |= value << bi_valid;
-               bi_valid += length;
-       }
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-static unsigned bi_reverse(unsigned code, int len)
-{
-       register unsigned res = 0;
-
-       do {
-               res |= code & 1;
-               code >>= 1, res <<= 1;
-       } while (--len > 0);
-       return res >> 1;
-}
-
-/* ===========================================================================
- * Write out any remaining bits in an incomplete byte.
- */
-static void bi_windup()
-{
-       if (bi_valid > 8) {
-               put_short(bi_buf);
-       } else if (bi_valid > 0) {
-               put_byte(bi_buf);
-       }
-       bi_buf = 0;
-       bi_valid = 0;
-#ifdef DEBUG
-       bits_sent = (bits_sent + 7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block to the zip file, storing first the length and its
- * one's complement if requested.
- */
-static void copy_block(char *buf, unsigned len, int header)
-{
-       bi_windup();                            /* align on byte boundary */
-
-       if (header) {
-               put_short((ush) len);
-               put_short((ush) ~ len);
-#ifdef DEBUG
-               bits_sent += 2 * 16;
-#endif
-       }
-#ifdef DEBUG
-       bits_sent += (ulg) len << 3;
-#endif
-       while (len--) {
-               put_byte(*buf++);
-       }
-}
-
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/*
- *  PURPOSE
- *
- *      Identify new text as repetitions of old text within a fixed-
- *      length sliding window trailing behind the new text.
- *
- *  DISCUSSION
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many info-zippers for bug reports and testing.
- *
- *  REFERENCES
- *
- *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- *  INTERFACE
- *
- *      void lm_init (int pack_level, ush *flags)
- *          Initialize the "longest match" routines for a new file
- *
- *      ulg deflate (void)
- *          Processes a new input file and return its compressed length. Sets
- *          the compressed length, crc, deflate flags and internal file
- *          attributes.
- */
-
-
-/* ===========================================================================
- * Configuration parameters
- */
-
-/* Compile with MEDIUM_MEM to reduce the memory requirements or
- * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
- * entire input file can be held in memory (not possible on 16 bit systems).
- * Warning: defining these symbols affects HASH_BITS (see below) and thus
- * affects the compression ratio. The compressed output
- * is still correct, and might even be smaller in some cases.
- */
-
-#ifdef SMALL_MEM
-#   define HASH_BITS  13               /* Number of bits used to hash strings */
-#endif
-#ifdef MEDIUM_MEM
-#   define HASH_BITS  14
-#endif
-#ifndef HASH_BITS
-#   define HASH_BITS  15
-   /* For portability to 16 bit machines, do not use values above 15. */
-#endif
-
-/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
- * window with tab_suffix. Check that we can do this:
- */
-#if (WSIZE<<1) > (1<<BITS)
-#  error cannot overlay window with tab_suffix and prev with tab_prefix0
-#endif
-#if HASH_BITS > BITS-1
-#  error cannot overlay head with tab_prefix1
-#endif
-#define HASH_SIZE (unsigned)(1<<HASH_BITS)
-#define HASH_MASK (HASH_SIZE-1)
-#define WMASK     (WSIZE-1)
-/* HASH_SIZE and WSIZE must be powers of two */
-#define NIL 0
-/* Tail of hash chains */
-#define FAST 4
-#define SLOW 2
-/* speed options for the general purpose bit flag */
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-/* ===========================================================================
- * Local data used by the "longest match" routines.
- */
-typedef ush Pos;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-/* DECLARE(uch, window, 2L*WSIZE); */
-/* Sliding window. Input bytes are read into the second half of the window,
- * and move to the first half later to keep a dictionary of at least WSIZE
- * bytes. With this organization, matches are limited to a distance of
- * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
- * performed with a length multiple of the block size. Also, it limits
- * the window size to 64K, which is quite useful on MSDOS.
- * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
- * be less efficient).
- */
-
-/* DECLARE(Pos, prev, WSIZE); */
-/* Link to older string with same hash index. To limit the size of this
- * array to 64K, this link is maintained only for the last 32K strings.
- * An index in this array is thus a window index modulo 32K.
- */
-
-/* DECLARE(Pos, head, 1<<HASH_BITS); */
-/* Heads of the hash chains or NIL. */
-
-static const ulg window_size = (ulg) 2 * WSIZE;
-
-/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
- * input file length plus MIN_LOOKAHEAD.
- */
-
-static long block_start;
-
-/* window position at the beginning of the current output block. Gets
- * negative when the window is moved backwards.
- */
-
-static unsigned ins_h;                 /* hash index of string to be inserted */
-
-#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
-/* Number of bits by which ins_h and del_h must be shifted at each
- * input step. It must be such that after MIN_MATCH steps, the oldest
- * byte no longer takes part in the hash key, that is:
- *   H_SHIFT * MIN_MATCH >= HASH_BITS
- */
-
-static unsigned int prev_length;
-
-/* Length of the best match at previous step. Matches not greater than this
- * are discarded. This is used in the lazy match evaluation.
- */
-
-static unsigned strstart;                      /* start of string to insert */
-static unsigned match_start;           /* start of matching string */
-static int eofile;                             /* flag set at end of input file */
-static unsigned lookahead;             /* number of valid bytes ahead in window */
-
-static const unsigned max_chain_length=4096;
-
-/* To speed up deflation, hash chains are never searched beyond this length.
- * A higher limit improves compression ratio but degrades the speed.
- */
-
-static const unsigned int max_lazy_match=258;
-
-/* Attempt to find a better match only when the current match is strictly
- * smaller than this value. This mechanism is used only for compression
- * levels >= 4.
- */
-#define max_insert_length  max_lazy_match
-/* Insert new strings in the hash table only if the match length
- * is not greater than this length. This saves time but degrades compression.
- * max_insert_length is used only for compression levels <= 3.
- */
-
-static const unsigned good_match=32;
-
-/* Use a faster search when the previous match is longer than this */
-
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-
-static const int nice_match=258;                       /* Stop searching when current match exceeds this */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-/* ===========================================================================
- *  Prototypes for local functions.
- */
-static void fill_window (void);
-
-static int longest_match (IPos cur_match);
-
-#ifdef DEBUG
-static void check_match (IPos start, IPos match, int length);
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
-
-/* ===========================================================================
- * Insert string s in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of s are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, match_head) \
-   (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
-    prev[(s) & WMASK] = match_head = head[ins_h], \
-    head[ins_h] = (s))
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new file
- */
-static void lm_init(ush *flags)
-{
-       register unsigned j;
-
-       /* Initialize the hash table. */
-       memzero((char *) head, HASH_SIZE * sizeof(*head));
-       /* prev will be initialized on the fly */
-
-       *flags |= SLOW;
-       /* ??? reduce max_chain_length for binary files */
-
-       strstart = 0;
-       block_start = 0L;
-
-       lookahead = read_buf((char *) window,
-                                                sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
-
-       if (lookahead == 0 || lookahead == (unsigned) EOF) {
-               eofile = 1, lookahead = 0;
-               return;
-       }
-       eofile = 0;
-       /* Make sure that we always have enough lookahead. This is important
-        * if input comes from a device such as a tty.
-        */
-       while (lookahead < MIN_LOOKAHEAD && !eofile)
-               fill_window();
-
-       ins_h = 0;
-       for (j = 0; j < MIN_MATCH - 1; j++)
-               UPDATE_HASH(ins_h, window[j]);
-       /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
-        * not important since only literal bytes will be emitted.
-        */
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- */
-
-/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
- * match.s. The code is functionally equivalent, so you can use the C version
- * if desired.
- */
-static int longest_match(IPos cur_match)
-{
-       unsigned chain_length = max_chain_length;       /* max hash chain length */
-       register uch *scan = window + strstart; /* current string */
-       register uch *match;            /* matched string */
-       register int len;                       /* length of current match */
-       int best_len = prev_length;     /* best match length so far */
-       IPos limit =
-
-               strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL;
-       /* Stop when cur_match becomes <= limit. To simplify the code,
-        * we prevent matches with the string of window index 0.
-        */
-
-/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
- * It is easy to get rid of this optimization if necessary.
- */
-#if HASH_BITS < 8 || MAX_MATCH != 258
-#  error Code too clever
-#endif
-       register uch *strend = window + strstart + MAX_MATCH;
-       register uch scan_end1 = scan[best_len - 1];
-       register uch scan_end = scan[best_len];
-
-       /* Do not waste too much time if we already have a good match: */
-       if (prev_length >= good_match) {
-               chain_length >>= 2;
-       }
-       Assert(strstart <= window_size - MIN_LOOKAHEAD,
-                  "insufficient lookahead");
-
-       do {
-               Assert(cur_match < strstart, "no future");
-               match = window + cur_match;
-
-               /* Skip to next match if the match length cannot increase
-                * or if the match length is less than 2:
-                */
-               if (match[best_len] != scan_end ||
-                       match[best_len - 1] != scan_end1 ||
-                       *match != *scan || *++match != scan[1])
-                       continue;
-
-               /* The check at best_len-1 can be removed because it will be made
-                * again later. (This heuristic is not always a win.)
-                * It is not necessary to compare scan[2] and match[2] since they
-                * are always equal when the other bytes match, given that
-                * the hash keys are equal and that HASH_BITS >= 8.
-                */
-               scan += 2, match++;
-
-               /* We check for insufficient lookahead only every 8th comparison;
-                * the 256th check will be made at strstart+258.
-                */
-               do {
-               } while (*++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                *++scan == *++match && *++scan == *++match &&
-                                scan < strend);
-
-               len = MAX_MATCH - (int) (strend - scan);
-               scan = strend - MAX_MATCH;
-
-               if (len > best_len) {
-                       match_start = cur_match;
-                       best_len = len;
-                       if (len >= nice_match)
-                               break;
-                       scan_end1 = scan[best_len - 1];
-                       scan_end = scan[best_len];
-               }
-       } while ((cur_match = prev[cur_match & WMASK]) > limit
-                        && --chain_length != 0);
-
-       return best_len;
-}
-
-#ifdef DEBUG
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-static void check_match(IPos start, IPos match, int length)
-{
-       /* check that the match is indeed a match */
-       if (memcmp((char *) window + match,
-                          (char *) window + start, length) != EQUAL) {
-               fprintf(stderr,
-                               " start %d, match %d, length %d\n", start, match, length);
-               error_msg("invalid match");
-       }
-       if (verbose > 1) {
-               fprintf(stderr, "\\[%d,%d]", start - match, length);
-               do {
-                       putc(window[start++], stderr);
-               } while (--length != 0);
-       }
-}
-#else
-#  define check_match(start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead, and sets eofile if end of input file.
- * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
- * OUT assertions: at least one byte has been read, or eofile is set;
- *    file reads are performed for at least two bytes (required for the
- *    translate_eol option).
- */
-static void fill_window()
-{
-       register unsigned n, m;
-       unsigned more =
-
-               (unsigned) (window_size - (ulg) lookahead - (ulg) strstart);
-       /* Amount of free space at the end of the window. */
-
-       /* If the window is almost full and there is insufficient lookahead,
-        * move the upper half to the lower one to make room in the upper half.
-        */
-       if (more == (unsigned) EOF) {
-               /* Very unlikely, but possible on 16 bit machine if strstart == 0
-                * and lookahead == 1 (input done one byte at time)
-                */
-               more--;
-       } else if (strstart >= WSIZE + MAX_DIST) {
-               /* By the IN assertion, the window is not empty so we can't confuse
-                * more == 0 with more == 64K on a 16 bit machine.
-                */
-               Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM");
-
-               memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE);
-               match_start -= WSIZE;
-               strstart -= WSIZE;              /* we now have strstart >= MAX_DIST: */
-
-               block_start -= (long) WSIZE;
-
-               for (n = 0; n < HASH_SIZE; n++) {
-                       m = head[n];
-                       head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
-               }
-               for (n = 0; n < WSIZE; n++) {
-                       m = prev[n];
-                       prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
-                       /* If n is not on any hash chain, prev[n] is garbage but
-                        * its value will never be used.
-                        */
-               }
-               more += WSIZE;
-       }
-       /* At this point, more >= 2 */
-       if (!eofile) {
-               n = read_buf((char *) window + strstart + lookahead, more);
-               if (n == 0 || n == (unsigned) EOF) {
-                       eofile = 1;
-               } else {
-                       lookahead += n;
-               }
-       }
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK(eof) \
-   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
-                (char*)NULL, (long)strstart - block_start, (eof))
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-static ulg deflate()
-{
-       IPos hash_head;                         /* head of hash chain */
-       IPos prev_match;                        /* previous match */
-       int flush;                                      /* set if current block must be flushed */
-       int match_available = 0;        /* set if previous match exists */
-       register unsigned match_length = MIN_MATCH - 1; /* length of best match */
-
-       /* Process the input block. */
-       while (lookahead != 0) {
-               /* Insert the string window[strstart .. strstart+2] in the
-                * dictionary, and set hash_head to the head of the hash chain:
-                */
-               INSERT_STRING(strstart, hash_head);
-
-               /* Find the longest match, discarding those <= prev_length.
-                */
-               prev_length = match_length, prev_match = match_start;
-               match_length = MIN_MATCH - 1;
-
-               if (hash_head != NIL && prev_length < max_lazy_match &&
-                       strstart - hash_head <= MAX_DIST) {
-                       /* To simplify the code, we prevent matches with the string
-                        * of window index 0 (in particular we have to avoid a match
-                        * of the string with itself at the start of the input file).
-                        */
-                       match_length = longest_match(hash_head);
-                       /* longest_match() sets match_start */
-                       if (match_length > lookahead)
-                               match_length = lookahead;
-
-                       /* Ignore a length 3 match if it is too distant: */
-                       if (match_length == MIN_MATCH
-                               && strstart - match_start > TOO_FAR) {
-                               /* If prev_match is also MIN_MATCH, match_start is garbage
-                                * but we will ignore the current match anyway.
-                                */
-                               match_length--;
-                       }
-               }
-               /* If there was a match at the previous step and the current
-                * match is not better, output the previous match:
-                */
-               if (prev_length >= MIN_MATCH && match_length <= prev_length) {
-
-                       check_match(strstart - 1, prev_match, prev_length);
-
-                       flush =
-                               ct_tally(strstart - 1 - prev_match,
-                                                prev_length - MIN_MATCH);
-
-                       /* Insert in hash table all strings up to the end of the match.
-                        * strstart-1 and strstart are already inserted.
-                        */
-                       lookahead -= prev_length - 1;
-                       prev_length -= 2;
-                       do {
-                               strstart++;
-                               INSERT_STRING(strstart, hash_head);
-                               /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                                * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
-                                * these bytes are garbage, but it does not matter since the
-                                * next lookahead bytes will always be emitted as literals.
-                                */
-                       } while (--prev_length != 0);
-                       match_available = 0;
-                       match_length = MIN_MATCH - 1;
-                       strstart++;
-                       if (flush)
-                               FLUSH_BLOCK(0), block_start = strstart;
-
-               } else if (match_available) {
-                       /* If there was no match at the previous position, output a
-                        * single literal. If there was a match but the current match
-                        * is longer, truncate the previous match to a single literal.
-                        */
-                       Tracevv((stderr, "%c", window[strstart - 1]));
-                       if (ct_tally(0, window[strstart - 1])) {
-                               FLUSH_BLOCK(0), block_start = strstart;
-                       }
-                       strstart++;
-                       lookahead--;
-               } else {
-                       /* There is no previous match to compare with, wait for
-                        * the next step to decide.
-                        */
-                       match_available = 1;
-                       strstart++;
-                       lookahead--;
-               }
-               Assert(strstart <= isize && lookahead <= isize, "a bit too far");
-
-               /* Make sure that we always have enough lookahead, except
-                * at the end of the input file. We need MAX_MATCH bytes
-                * for the next match, plus MIN_MATCH bytes to insert the
-                * string following the next match.
-                */
-               while (lookahead < MIN_LOOKAHEAD && !eofile)
-                       fill_window();
-       }
-       if (match_available)
-               ct_tally(0, window[strstart - 1]);
-
-       return FLUSH_BLOCK(1);          /* eof */
-}
-
-/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-/* Compress files with zip algorithm and 'compress' interface.
- * See usage() and help() functions below for all options.
- * Outputs:
- *        file.gz:   compressed file with same mode, owner, and utimes
- *     or stdout with -c option or if stdin used as input.
- * If the output file name had to be truncated, the original name is kept
- * in the compressed file.
- */
-
-               /* configuration */
-
-typedef struct dirent dir_type;
-
-typedef RETSIGTYPE(*sig_type) (int);
-
-
-/* ======================================================================== */
-// int main (argc, argv)
-//    int argc;
-//    char **argv;
-int gzip_main(int argc, char **argv)
-{
-       int result;
-       int inFileNum;
-       int outFileNum;
-       struct stat statBuf;
-       char *delFileName;
-       int tostdout = 0;
-       int fromstdin = 0;
-       int force = 0;
-       int opt;
-
-       while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) {
-               switch (opt) {
-               case 'c':
-                       tostdout = 1;
-                       break;
-               case 'f':
-                       force = 1;
-                       break;
-               /* Ignore 1-9 (compression level) options */
-               case '1': case '2': case '3': case '4': case '5':
-               case '6': case '7': case '8': case '9':
-                       break;
-               case 'q':
-                       break;
-#ifdef BB_GUNZIP
-               case 'd':
-                       optind = 1;
-                       return gunzip_main(argc, argv);
-#endif
-               default:
-                       show_usage();
-               }
-       }
-       if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) {
-               fromstdin = 1;
-               tostdout = 1;
-       }
-
-       if (isatty(fileno(stdout)) && tostdout==1 && force==0)
-               error_msg_and_die( "compressed data not written to terminal. Use -f to force it.");
-
-       foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
-       if (foreground) {
-               (void) signal(SIGINT, (sig_type) abort_gzip);
-       }
-#ifdef SIGTERM
-       if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGTERM, (sig_type) abort_gzip);
-       }
-#endif
-#ifdef SIGHUP
-       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGHUP, (sig_type) abort_gzip);
-       }
-#endif
-
-       strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1);
-       z_len = strlen(z_suffix);
-
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
-       ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
-       ALLOC(ush, d_buf, DIST_BUFSIZE);
-       ALLOC(uch, window, 2L * WSIZE);
-       ALLOC(ush, tab_prefix, 1L << BITS);
-
-       if (fromstdin == 1) {
-               strcpy(ofname, "stdin");
-
-               inFileNum = fileno(stdin);
-               time_stamp = 0;                 /* time unknown by default */
-               ifile_size = -1L;               /* convention for unknown size */
-       } else {
-               /* Open up the input file */
-               strncpy(ifname, argv[optind], MAX_PATH_LEN);
-
-               /* Open input file */
-               inFileNum = open(ifname, O_RDONLY);
-               if (inFileNum < 0)
-                       perror_msg_and_die("%s", ifname);
-               /* Get the time stamp on the input file. */
-               if (stat(ifname, &statBuf) < 0)
-                       perror_msg_and_die("%s", ifname);
-               time_stamp = statBuf.st_ctime;
-               ifile_size = statBuf.st_size;
-       }
-
-
-       if (tostdout == 1) {
-               /* And get to work */
-               strcpy(ofname, "stdout");
-               outFileNum = fileno(stdout);
-
-               clear_bufs();                   /* clear input and output buffers */
-               part_nb = 0;
-
-               /* Actually do the compression/decompression. */
-               zip(inFileNum, outFileNum);
-
-       } else {
-
-               /* And get to work */
-               strncpy(ofname, ifname, MAX_PATH_LEN - 4);
-               strcat(ofname, ".gz");
-
-
-               /* Open output fille */
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW);
-#else
-               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL);
-#endif
-               if (outFileNum < 0)
-                       perror_msg_and_die("%s", ofname);
-               /* Set permissions on the file */
-               fchmod(outFileNum, statBuf.st_mode);
-
-               clear_bufs();                   /* clear input and output buffers */
-               part_nb = 0;
-
-               /* Actually do the compression/decompression. */
-               result = zip(inFileNum, outFileNum);
-               close(outFileNum);
-               close(inFileNum);
-               /* Delete the original file */
-               if (result == OK)
-                       delFileName = ifname;
-               else
-                       delFileName = ofname;
-
-               if (unlink(delFileName) < 0)
-                       perror_msg_and_die("%s", delFileName);
-       }
-
-       return(exit_code);
-}
-
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-/*
- *  PURPOSE
- *
- *      Encode various sets of source values using variable-length
- *      binary code trees.
- *
- *  DISCUSSION
- *
- *      The PKZIP "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in the ZIP file in a compressed form
- *      which is itself a Huffman encoding of the lengths of
- *      all the code strings (in ascending order by source values).
- *      The actual code strings are reconstructed from the lengths in
- *      the UNZIP process, as described in the "application note"
- *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
- *
- *  REFERENCES
- *
- *      Lynch, Thomas J.
- *          Data Compression:  Techniques and Applications, pp. 53-55.
- *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- *
- *  INTERFACE
- *
- *      void ct_init (ush *attr, int *methodp)
- *          Allocate the match buffer, initialize the various tables and save
- *          the location of the internal file attribute (ascii/binary) and
- *          method (DEFLATE/STORE)
- *
- *      void ct_tally (int dist, int lc);
- *          Save the match info and tally the frequency counts.
- *
- *      long flush_block (char *buf, ulg stored_len, int eof)
- *          Determine the best encoding for the current block: dynamic trees,
- *          static trees or store, and output the encoded block to the zip
- *          file. Returns the total compressed length for the file so far.
- *
- */
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-
-static const int extra_lbits[LENGTH_CODES]     /* extra bits for each length code */
-       = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
-               4, 4, 5, 5, 5, 5, 0 };
-
-static const int extra_dbits[D_CODES]  /* extra bits for each distance code */
-       = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
-               10, 10, 11, 11, 12, 12, 13, 13 };
-
-static const int extra_blbits[BL_CODES]        /* extra bits for each bit length code */
-= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
-
-#define STORED_BLOCK 0
-#define STATIC_TREES 1
-#define DYN_TREES    2
-/* The three kinds of block type */
-
-#ifndef LIT_BUFSIZE
-#  ifdef SMALL_MEM
-#    define LIT_BUFSIZE  0x2000
-#  else
-#  ifdef MEDIUM_MEM
-#    define LIT_BUFSIZE  0x4000
-#  else
-#    define LIT_BUFSIZE  0x8000
-#  endif
-#  endif
-#endif
-#ifndef DIST_BUFSIZE
-#  define DIST_BUFSIZE  LIT_BUFSIZE
-#endif
-/* Sizes of match buffers for literals/lengths and distances.  There are
- * 4 reasons for limiting LIT_BUFSIZE to 64K:
- *   - frequencies can be kept in 16 bit counters
- *   - if compression is not successful for the first block, all input data is
- *     still in the window so we can still emit a stored block even when input
- *     comes from standard input.  (This can also be done for all blocks if
- *     LIT_BUFSIZE is not greater than 32K.)
- *   - if compression is not successful for a file smaller than 64K, we can
- *     even emit a stored file instead of a stored block (saving 5 bytes).
- *   - creating new Huffman trees less frequently may not provide fast
- *     adaptation to changes in the input data statistics. (Take for
- *     example a binary file with poorly compressible code followed by
- *     a highly compressible string table.) Smaller buffer sizes give
- *     fast adaptation but have of course the overhead of transmitting trees
- *     more frequently.
- *   - I can't count above 4
- * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
- * memory at the expense of compression). Some optimizations would be possible
- * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
- */
-#if LIT_BUFSIZE > INBUFSIZ
-error cannot overlay l_buf and inbuf
-#endif
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) *//* ===========================================================================
- * Local data
- *//* Data structure describing a single value and its code string. */ typedef struct ct_data {
-       union {
-               ush freq;                               /* frequency count */
-               ush code;                               /* bit string */
-       } fc;
-       union {
-               ush dad;                                /* father node in Huffman tree */
-               ush len;                                /* length of bit string */
-       } dl;
-} ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-static ct_data dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-static ct_data dyn_dtree[2 * D_CODES + 1];     /* distance tree */
-
-static ct_data static_ltree[L_CODES + 2];
-
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see ct_init
- * below).
- */
-
-static ct_data static_dtree[D_CODES];
-
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-static ct_data bl_tree[2 * BL_CODES + 1];
-
-/* Huffman tree for the bit lengths */
-
-typedef struct tree_desc {
-       ct_data *dyn_tree;              /* the dynamic tree */
-       ct_data *static_tree;   /* corresponding static tree or NULL */
-       const int *extra_bits;          /* extra bits for each code or NULL */
-       int extra_base;                         /* base index for extra_bits */
-       int elems;                                      /* max number of elements in the tree */
-       int max_length;                         /* max bit length for the codes */
-       int max_code;                           /* largest code with non zero frequency */
-} tree_desc;
-
-static tree_desc l_desc =
-       { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES,
-               MAX_BITS, 0 };
-
-static tree_desc d_desc =
-       { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 };
-
-static tree_desc bl_desc =
-       { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS,
-               0 };
-
-
-static ush bl_count[MAX_BITS + 1];
-
-/* number of codes at each bit length for an optimal tree */
-
-static const uch bl_order[BL_CODES]
-= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-static int heap[2 * L_CODES + 1];      /* heap used to build the Huffman trees */
-static int heap_len;                           /* number of elements in the heap */
-static int heap_max;                           /* element of largest frequency */
-
-/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
- * The same heap array is used to build all trees.
- */
-
-static uch depth[2 * L_CODES + 1];
-
-/* Depth of each subtree used as tie breaker for trees of equal frequency */
-
-static uch length_code[MAX_MATCH - MIN_MATCH + 1];
-
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-static uch dist_code[512];
-
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-static int base_length[LENGTH_CODES];
-
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-static int base_dist[D_CODES];
-
-/* First normalized distance for each code (0 = distance of 1) */
-
-#define l_buf inbuf
-/* DECLARE(uch, l_buf, LIT_BUFSIZE);  buffer for literals or lengths */
-
-/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
-
-static uch flag_buf[(LIT_BUFSIZE / 8)];
-
-/* flag_buf is a bit array distinguishing literals from lengths in
- * l_buf, thus indicating the presence or absence of a distance.
- */
-
-static unsigned last_lit;              /* running index in l_buf */
-static unsigned last_dist;             /* running index in d_buf */
-static unsigned last_flags;            /* running index in flag_buf */
-static uch flags;                              /* current flags not yet saved in flag_buf */
-static uch flag_bit;                           /* current bit used in flags */
-
-/* bits are filled in flags starting at bit 0 (least significant).
- * Note: these flags are overkill in the current code since we don't
- * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
- */
-
-static ulg opt_len;                            /* bit length of current block with optimal trees */
-static ulg static_len;                 /* bit length of current block with static trees */
-
-static ulg compressed_len;             /* total bit length of compressed file */
-
-
-static ush *file_type;                                 /* pointer to UNKNOWN, BINARY or ASCII */
-static int *file_method;                               /* pointer to DEFLATE or STORE */
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-static void init_block (void);
-static void pqdownheap (ct_data * tree, int k);
-static void gen_bitlen (tree_desc * desc);
-static void gen_codes (ct_data * tree, int max_code);
-static void build_tree (tree_desc * desc);
-static void scan_tree (ct_data * tree, int max_code);
-static void send_tree (ct_data * tree, int max_code);
-static int build_bl_tree (void);
-static void send_all_trees (int lcodes, int dcodes, int blcodes);
-static void compress_block (ct_data * ltree, ct_data * dtree);
-static void set_file_type (void);
-
-
-#ifndef DEBUG
-#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else                                                  /* DEBUG */
-#  define send_code(c, tree) \
-     { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Allocate the match buffer, initialize the various tables and save the
- * location of the internal file attribute (ascii/binary) and method
- * (DEFLATE/STORE).
- */
-static void ct_init(ush *attr, int *methodp)
-{
-       int n;                                          /* iterates over tree elements */
-       int bits;                                       /* bit counter */
-       int length;                                     /* length value */
-       int code;                                       /* code value */
-       int dist;                                       /* distance index */
-
-       file_type = attr;
-       file_method = methodp;
-       compressed_len = 0L;
-
-       if (static_dtree[0].Len != 0)
-               return;                                 /* ct_init already called */
-
-       /* Initialize the mapping length (0..255) -> length code (0..28) */
-       length = 0;
-       for (code = 0; code < LENGTH_CODES - 1; code++) {
-               base_length[code] = length;
-               for (n = 0; n < (1 << extra_lbits[code]); n++) {
-                       length_code[length++] = (uch) code;
-               }
-       }
-       Assert(length == 256, "ct_init: length != 256");
-       /* Note that the length 255 (match length 258) can be represented
-        * in two different ways: code 284 + 5 bits or code 285, so we
-        * overwrite length_code[255] to use the best encoding:
-        */
-       length_code[length - 1] = (uch) code;
-
-       /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-       dist = 0;
-       for (code = 0; code < 16; code++) {
-               base_dist[code] = dist;
-               for (n = 0; n < (1 << extra_dbits[code]); n++) {
-                       dist_code[dist++] = (uch) code;
-               }
-       }
-       Assert(dist == 256, "ct_init: dist != 256");
-       dist >>= 7;                                     /* from now on, all distances are divided by 128 */
-       for (; code < D_CODES; code++) {
-               base_dist[code] = dist << 7;
-               for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
-                       dist_code[256 + dist++] = (uch) code;
-               }
-       }
-       Assert(dist == 256, "ct_init: 256+dist != 512");
-
-       /* Construct the codes of the static literal tree */
-       for (bits = 0; bits <= MAX_BITS; bits++)
-               bl_count[bits] = 0;
-       n = 0;
-       while (n <= 143)
-               static_ltree[n++].Len = 8, bl_count[8]++;
-       while (n <= 255)
-               static_ltree[n++].Len = 9, bl_count[9]++;
-       while (n <= 279)
-               static_ltree[n++].Len = 7, bl_count[7]++;
-       while (n <= 287)
-               static_ltree[n++].Len = 8, bl_count[8]++;
-       /* Codes 286 and 287 do not exist, but we must include them in the
-        * tree construction to get a canonical Huffman tree (longest code
-        * all ones)
-        */
-       gen_codes((ct_data *) static_ltree, L_CODES + 1);
-
-       /* The static distance tree is trivial: */
-       for (n = 0; n < D_CODES; n++) {
-               static_dtree[n].Len = 5;
-               static_dtree[n].Code = bi_reverse(n, 5);
-       }
-
-       /* Initialize the first block of the first file: */
-       init_block();
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-static void init_block()
-{
-       int n;                                          /* iterates over tree elements */
-
-       /* Initialize the trees. */
-       for (n = 0; n < L_CODES; n++)
-               dyn_ltree[n].Freq = 0;
-       for (n = 0; n < D_CODES; n++)
-               dyn_dtree[n].Freq = 0;
-       for (n = 0; n < BL_CODES; n++)
-               bl_tree[n].Freq = 0;
-
-       dyn_ltree[END_BLOCK].Freq = 1;
-       opt_len = static_len = 0L;
-       last_lit = last_dist = last_flags = 0;
-       flags = 0;
-       flag_bit = 1;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(tree, top) \
-{\
-    top = heap[SMALLEST]; \
-    heap[SMALLEST] = heap[heap_len--]; \
-    pqdownheap(tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-static void pqdownheap(ct_data *tree, int k)
-{
-       int v = heap[k];
-       int j = k << 1;                         /* left son of k */
-
-       while (j <= heap_len) {
-               /* Set j to the smallest of the two sons: */
-               if (j < heap_len && smaller(tree, heap[j + 1], heap[j]))
-                       j++;
-
-               /* Exit if v is smaller than both sons */
-               if (smaller(tree, v, heap[j]))
-                       break;
-
-               /* Exchange v with the smallest son */
-               heap[k] = heap[j];
-               k = j;
-
-               /* And continue down the tree, setting j to the left son of k */
-               j <<= 1;
-       }
-       heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-static void gen_bitlen(tree_desc *desc)
-{
-       ct_data *tree = desc->dyn_tree;
-       const int *extra = desc->extra_bits;
-       int base = desc->extra_base;
-       int max_code = desc->max_code;
-       int max_length = desc->max_length;
-       ct_data *stree = desc->static_tree;
-       int h;                                          /* heap index */
-       int n, m;                                       /* iterate over the tree elements */
-       int bits;                                       /* bit length */
-       int xbits;                                      /* extra bits */
-       ush f;                                          /* frequency */
-       int overflow = 0;                       /* number of elements with bit length too large */
-
-       for (bits = 0; bits <= MAX_BITS; bits++)
-               bl_count[bits] = 0;
-
-       /* In a first pass, compute the optimal bit lengths (which may
-        * overflow in the case of the bit length tree).
-        */
-       tree[heap[heap_max]].Len = 0;   /* root of the heap */
-
-       for (h = heap_max + 1; h < HEAP_SIZE; h++) {
-               n = heap[h];
-               bits = tree[tree[n].Dad].Len + 1;
-               if (bits > max_length)
-                       bits = max_length, overflow++;
-               tree[n].Len = (ush) bits;
-               /* We overwrite tree[n].Dad which is no longer needed */
-
-               if (n > max_code)
-                       continue;                       /* not a leaf node */
-
-               bl_count[bits]++;
-               xbits = 0;
-               if (n >= base)
-                       xbits = extra[n - base];
-               f = tree[n].Freq;
-               opt_len += (ulg) f *(bits + xbits);
-
-               if (stree)
-                       static_len += (ulg) f *(stree[n].Len + xbits);
-       }
-       if (overflow == 0)
-               return;
-
-       Trace((stderr, "\nbit length overflow\n"));
-       /* This happens for example on obj2 and pic of the Calgary corpus */
-
-       /* Find the first bit length which could increase: */
-       do {
-               bits = max_length - 1;
-               while (bl_count[bits] == 0)
-                       bits--;
-               bl_count[bits]--;               /* move one leaf down the tree */
-               bl_count[bits + 1] += 2;        /* move one overflow item as its brother */
-               bl_count[max_length]--;
-               /* The brother of the overflow item also moves one step up,
-                * but this does not affect bl_count[max_length]
-                */
-               overflow -= 2;
-       } while (overflow > 0);
-
-       /* Now recompute all bit lengths, scanning in increasing frequency.
-        * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-        * lengths instead of fixing only the wrong ones. This idea is taken
-        * from 'ar' written by Haruhiko Okumura.)
-        */
-       for (bits = max_length; bits != 0; bits--) {
-               n = bl_count[bits];
-               while (n != 0) {
-                       m = heap[--h];
-                       if (m > max_code)
-                               continue;
-                       if (tree[m].Len != (unsigned) bits) {
-                               Trace(
-                                         (stderr, "code %d bits %d->%d\n", m, tree[m].Len,
-                                          bits));
-                               opt_len +=
-                                       ((long) bits -
-                                        (long) tree[m].Len) * (long) tree[m].Freq;
-                               tree[m].Len = (ush) bits;
-                       }
-                       n--;
-               }
-       }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-static void gen_codes(ct_data *tree, int max_code)
-{
-       ush next_code[MAX_BITS + 1];    /* next code value for each bit length */
-       ush code = 0;                           /* running code value */
-       int bits;                                       /* bit index */
-       int n;                                          /* code index */
-
-       /* The distribution counts are first used to generate the code values
-        * without bit reversal.
-        */
-       for (bits = 1; bits <= MAX_BITS; bits++) {
-               next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
-       }
-       /* Check that the bit counts in bl_count are consistent. The last code
-        * must be all ones.
-        */
-       Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
-                  "inconsistent bit counts");
-       Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
-
-       for (n = 0; n <= max_code; n++) {
-               int len = tree[n].Len;
-
-               if (len == 0)
-                       continue;
-               /* Now reverse the bits */
-               tree[n].Code = bi_reverse(next_code[len]++, len);
-
-               Tracec(tree != static_ltree,
-                          (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
-                               (isgraph(n) ? n : ' '), len, tree[n].Code,
-                               next_code[len] - 1));
-       }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-static void build_tree(tree_desc *desc)
-{
-       ct_data *tree = desc->dyn_tree;
-       ct_data *stree = desc->static_tree;
-       int elems = desc->elems;
-       int n, m;                                       /* iterate over heap elements */
-       int max_code = -1;                      /* largest code with non zero frequency */
-       int node = elems;                       /* next internal node of the tree */
-
-       /* Construct the initial heap, with least frequent element in
-        * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-        * heap[0] is not used.
-        */
-       heap_len = 0, heap_max = HEAP_SIZE;
-
-       for (n = 0; n < elems; n++) {
-               if (tree[n].Freq != 0) {
-                       heap[++heap_len] = max_code = n;
-                       depth[n] = 0;
-               } else {
-                       tree[n].Len = 0;
-               }
-       }
-
-       /* The pkzip format requires that at least one distance code exists,
-        * and that at least one bit should be sent even if there is only one
-        * possible code. So to avoid special checks later on we force at least
-        * two codes of non zero frequency.
-        */
-       while (heap_len < 2) {
-               int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
-
-               tree[new].Freq = 1;
-               depth[new] = 0;
-               opt_len--;
-               if (stree)
-                       static_len -= stree[new].Len;
-               /* new is 0 or 1 so it does not have extra bits */
-       }
-       desc->max_code = max_code;
-
-       /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-        * establish sub-heaps of increasing lengths:
-        */
-       for (n = heap_len / 2; n >= 1; n--)
-               pqdownheap(tree, n);
-
-       /* Construct the Huffman tree by repeatedly combining the least two
-        * frequent nodes.
-        */
-       do {
-               pqremove(tree, n);              /* n = node of least frequency */
-               m = heap[SMALLEST];             /* m = node of next least frequency */
-
-               heap[--heap_max] = n;   /* keep the nodes sorted by frequency */
-               heap[--heap_max] = m;
-
-               /* Create a new node father of n and m */
-               tree[node].Freq = tree[n].Freq + tree[m].Freq;
-               depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
-               tree[n].Dad = tree[m].Dad = (ush) node;
-#ifdef DUMP_BL_TREE
-               if (tree == bl_tree) {
-                       fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
-                                       node, tree[node].Freq, n, tree[n].Freq, m,
-                                       tree[m].Freq);
-               }
-#endif
-               /* and insert the new node in the heap */
-               heap[SMALLEST] = node++;
-               pqdownheap(tree, SMALLEST);
-
-       } while (heap_len >= 2);
-
-       heap[--heap_max] = heap[SMALLEST];
-
-       /* At this point, the fields freq and dad are set. We can now
-        * generate the bit lengths.
-        */
-       gen_bitlen((tree_desc *) desc);
-
-       /* The field len is now set, we can generate the bit codes */
-       gen_codes((ct_data *) tree, max_code);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree. Updates opt_len to take into account the repeat
- * counts. (The contribution of the bit length codes will be added later
- * during the construction of bl_tree.)
- */
-static void scan_tree(ct_data *tree, int max_code)
-{
-       int n;                                          /* iterates over all tree elements */
-       int prevlen = -1;                       /* last emitted length */
-       int curlen;                                     /* length of current code */
-       int nextlen = tree[0].Len;      /* length of next code */
-       int count = 0;                          /* repeat count of the current code */
-       int max_count = 7;                      /* max repeat count */
-       int min_count = 4;                      /* min repeat count */
-
-       if (nextlen == 0)
-               max_count = 138, min_count = 3;
-       tree[max_code + 1].Len = (ush) 0xffff;  /* guard */
-
-       for (n = 0; n <= max_code; n++) {
-               curlen = nextlen;
-               nextlen = tree[n + 1].Len;
-               if (++count < max_count && curlen == nextlen) {
-                       continue;
-               } else if (count < min_count) {
-                       bl_tree[curlen].Freq += count;
-               } else if (curlen != 0) {
-                       if (curlen != prevlen)
-                               bl_tree[curlen].Freq++;
-                       bl_tree[REP_3_6].Freq++;
-               } else if (count <= 10) {
-                       bl_tree[REPZ_3_10].Freq++;
-               } else {
-                       bl_tree[REPZ_11_138].Freq++;
-               }
-               count = 0;
-               prevlen = curlen;
-               if (nextlen == 0) {
-                       max_count = 138, min_count = 3;
-               } else if (curlen == nextlen) {
-                       max_count = 6, min_count = 3;
-               } else {
-                       max_count = 7, min_count = 4;
-               }
-       }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-static void send_tree(ct_data *tree, int max_code)
-{
-       int n;                                          /* iterates over all tree elements */
-       int prevlen = -1;                       /* last emitted length */
-       int curlen;                                     /* length of current code */
-       int nextlen = tree[0].Len;      /* length of next code */
-       int count = 0;                          /* repeat count of the current code */
-       int max_count = 7;                      /* max repeat count */
-       int min_count = 4;                      /* min repeat count */
-
-/* tree[max_code+1].Len = -1; *//* guard already set */
-       if (nextlen == 0)
-               max_count = 138, min_count = 3;
-
-       for (n = 0; n <= max_code; n++) {
-               curlen = nextlen;
-               nextlen = tree[n + 1].Len;
-               if (++count < max_count && curlen == nextlen) {
-                       continue;
-               } else if (count < min_count) {
-                       do {
-                               send_code(curlen, bl_tree);
-                       } while (--count != 0);
-
-               } else if (curlen != 0) {
-                       if (curlen != prevlen) {
-                               send_code(curlen, bl_tree);
-                               count--;
-                       }
-                       Assert(count >= 3 && count <= 6, " 3_6?");
-                       send_code(REP_3_6, bl_tree);
-                       send_bits(count - 3, 2);
-
-               } else if (count <= 10) {
-                       send_code(REPZ_3_10, bl_tree);
-                       send_bits(count - 3, 3);
-
-               } else {
-                       send_code(REPZ_11_138, bl_tree);
-                       send_bits(count - 11, 7);
-               }
-               count = 0;
-               prevlen = curlen;
-               if (nextlen == 0) {
-                       max_count = 138, min_count = 3;
-               } else if (curlen == nextlen) {
-                       max_count = 6, min_count = 3;
-               } else {
-                       max_count = 7, min_count = 4;
-               }
-       }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-static const int build_bl_tree()
-{
-       int max_blindex;                        /* index of last bit length code of non zero freq */
-
-       /* Determine the bit length frequencies for literal and distance trees */
-       scan_tree((ct_data *) dyn_ltree, l_desc.max_code);
-       scan_tree((ct_data *) dyn_dtree, d_desc.max_code);
-
-       /* Build the bit length tree: */
-       build_tree((tree_desc *) (&bl_desc));
-       /* opt_len now includes the length of the tree representations, except
-        * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-        */
-
-       /* Determine the number of bit length codes to send. The pkzip format
-        * requires that at least 4 bit length codes be sent. (appnote.txt says
-        * 3 but the actual value used is 4.)
-        */
-       for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
-               if (bl_tree[bl_order[max_blindex]].Len != 0)
-                       break;
-       }
-       /* Update opt_len to include the bit length tree and counts */
-       opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
-       Tracev(
-                  (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len,
-                       static_len));
-
-       return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-static void send_all_trees(int lcodes, int dcodes, int blcodes)
-{
-       int rank;                                       /* index in bl_order */
-
-       Assert(lcodes >= 257 && dcodes >= 1
-                  && blcodes >= 4, "not enough codes");
-       Assert(lcodes <= L_CODES && dcodes <= D_CODES
-                  && blcodes <= BL_CODES, "too many codes");
-       Tracev((stderr, "\nbl counts: "));
-       send_bits(lcodes - 257, 5);     /* not +255 as stated in appnote.txt */
-       send_bits(dcodes - 1, 5);
-       send_bits(blcodes - 4, 4);      /* not -3 as stated in appnote.txt */
-       for (rank = 0; rank < blcodes; rank++) {
-               Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-               send_bits(bl_tree[bl_order[rank]].Len, 3);
-       }
-       Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
-
-       send_tree((ct_data *) dyn_ltree, lcodes - 1);   /* send the literal tree */
-       Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
-
-       send_tree((ct_data *) dyn_dtree, dcodes - 1);   /* send the distance tree */
-       Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-static ulg flush_block(char *buf, ulg stored_len, int eof)
-{
-       ulg opt_lenb, static_lenb;      /* opt_len and static_len in bytes */
-       int max_blindex;                        /* index of last bit length code of non zero freq */
-
-       flag_buf[last_flags] = flags;   /* Save the flags for the last 8 items */
-
-       /* Check if the file is ascii or binary */
-       if (*file_type == (ush) UNKNOWN)
-               set_file_type();
-
-       /* Construct the literal and distance trees */
-       build_tree((tree_desc *) (&l_desc));
-       Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
-
-       build_tree((tree_desc *) (&d_desc));
-       Tracev(
-                  (stderr, "\ndist data: dyn %ld, stat %ld", opt_len,
-                       static_len));
-       /* At this point, opt_len and static_len are the total bit lengths of
-        * the compressed block data, excluding the tree representations.
-        */
-
-       /* Build the bit length tree for the above two trees, and get the index
-        * in bl_order of the last bit length code to send.
-        */
-       max_blindex = build_bl_tree();
-
-       /* Determine the best encoding. Compute first the block length in bytes */
-       opt_lenb = (opt_len + 3 + 7) >> 3;
-       static_lenb = (static_len + 3 + 7) >> 3;
-
-       Trace(
-                 (stderr,
-                  "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
-                  opt_lenb, opt_len, static_lenb, static_len, stored_len,
-                  last_lit, last_dist));
-
-       if (static_lenb <= opt_lenb)
-               opt_lenb = static_lenb;
-
-       /* If compression failed and this is the first and last block,
-        * and if the zip file can be seeked (to rewrite the local header),
-        * the whole file is transformed into a stored file:
-        */
-       if (stored_len <= opt_lenb && eof && compressed_len == 0L
-               && seekable()) {
-               /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-               if (buf == (char *) 0)
-                       error_msg("block vanished");
-
-               copy_block(buf, (unsigned) stored_len, 0);      /* without header */
-               compressed_len = stored_len << 3;
-               *file_method = STORED;
-
-       } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) {
-               /* 4: two words for the lengths */
-               /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-                * Otherwise we can't have processed more than WSIZE input bytes since
-                * the last block flush, because compression would have been
-                * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-                * transform a block into a stored block.
-                */
-               send_bits((STORED_BLOCK << 1) + eof, 3);        /* send block type */
-               compressed_len = (compressed_len + 3 + 7) & ~7L;
-               compressed_len += (stored_len + 4) << 3;
-
-               copy_block(buf, (unsigned) stored_len, 1);      /* with header */
-
-       } else if (static_lenb == opt_lenb) {
-               send_bits((STATIC_TREES << 1) + eof, 3);
-               compress_block((ct_data *) static_ltree,
-                                          (ct_data *) static_dtree);
-               compressed_len += 3 + static_len;
-       } else {
-               send_bits((DYN_TREES << 1) + eof, 3);
-               send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1,
-                                          max_blindex + 1);
-               compress_block((ct_data *) dyn_ltree,
-                                          (ct_data *) dyn_dtree);
-               compressed_len += 3 + opt_len;
-       }
-       Assert(compressed_len == bits_sent, "bad compressed size");
-       init_block();
-
-       if (eof) {
-               bi_windup();
-               compressed_len += 7;    /* align on byte boundary */
-       }
-       Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3,
-                       compressed_len - 7 * eof));
-
-       return compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-static int ct_tally(int dist, int lc)
-{
-       l_buf[last_lit++] = (uch) lc;
-       if (dist == 0) {
-               /* lc is the unmatched char */
-               dyn_ltree[lc].Freq++;
-       } else {
-               /* Here, lc is the match length - MIN_MATCH */
-               dist--;                                 /* dist = match distance - 1 */
-               Assert((ush) dist < (ush) MAX_DIST &&
-                          (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) &&
-                          (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match");
-
-               dyn_ltree[length_code[lc] + LITERALS + 1].Freq++;
-               dyn_dtree[d_code(dist)].Freq++;
-
-               d_buf[last_dist++] = (ush) dist;
-               flags |= flag_bit;
-       }
-       flag_bit <<= 1;
-
-       /* Output the flags if they fill a byte: */
-       if ((last_lit & 7) == 0) {
-               flag_buf[last_flags++] = flags;
-               flags = 0, flag_bit = 1;
-       }
-       /* Try to guess if it is profitable to stop the current block here */
-       if ((last_lit & 0xfff) == 0) {
-               /* Compute an upper bound for the compressed length */
-               ulg out_length = (ulg) last_lit * 8L;
-               ulg in_length = (ulg) strstart - block_start;
-               int dcode;
-
-               for (dcode = 0; dcode < D_CODES; dcode++) {
-                       out_length +=
-                               (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
-               }
-               out_length >>= 3;
-               Trace(
-                         (stderr,
-                          "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
-                          last_lit, last_dist, in_length, out_length,
-                          100L - out_length * 100L / in_length));
-               if (last_dist < last_lit / 2 && out_length < in_length / 2)
-                       return 1;
-       }
-       return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE);
-       /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
-        * on 16 bit machines and because stored blocks are restricted to
-        * 64K-1 bytes.
-        */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-static void compress_block(ct_data *ltree, ct_data *dtree)
-{
-       unsigned dist;                          /* distance of matched string */
-       int lc;                                         /* match length or unmatched char (if dist == 0) */
-       unsigned lx = 0;                        /* running index in l_buf */
-       unsigned dx = 0;                        /* running index in d_buf */
-       unsigned fx = 0;                        /* running index in flag_buf */
-       uch flag = 0;                           /* current flags */
-       unsigned code;                          /* the code to send */
-       int extra;                                      /* number of extra bits to send */
-
-       if (last_lit != 0)
-               do {
-                       if ((lx & 7) == 0)
-                               flag = flag_buf[fx++];
-                       lc = l_buf[lx++];
-                       if ((flag & 1) == 0) {
-                               send_code(lc, ltree);   /* send a literal byte */
-                               Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
-                       } else {
-                               /* Here, lc is the match length - MIN_MATCH */
-                               code = length_code[lc];
-                               send_code(code + LITERALS + 1, ltree);  /* send the length code */
-                               extra = extra_lbits[code];
-                               if (extra != 0) {
-                                       lc -= base_length[code];
-                                       send_bits(lc, extra);   /* send the extra length bits */
-                               }
-                               dist = d_buf[dx++];
-                               /* Here, dist is the match distance - 1 */
-                               code = d_code(dist);
-                               Assert(code < D_CODES, "bad d_code");
-
-                               send_code(code, dtree); /* send the distance code */
-                               extra = extra_dbits[code];
-                               if (extra != 0) {
-                                       dist -= base_dist[code];
-                                       send_bits(dist, extra); /* send the extra distance bits */
-                               }
-                       }                                       /* literal or match pair ? */
-                       flag >>= 1;
-               } while (lx < last_lit);
-
-       send_code(END_BLOCK, ltree);
-}
-
-/* ===========================================================================
- * Set the file type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-static void set_file_type()
-{
-       int n = 0;
-       unsigned ascii_freq = 0;
-       unsigned bin_freq = 0;
-
-       while (n < 7)
-               bin_freq += dyn_ltree[n++].Freq;
-       while (n < 128)
-               ascii_freq += dyn_ltree[n++].Freq;
-       while (n < LITERALS)
-               bin_freq += dyn_ltree[n++].Freq;
-       *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
-       if (*file_type == BINARY && translate_eol) {
-               error_msg("-l used on binary file");
-       }
-}
-
-/* zip.c -- compress files to the gzip or pkzip format
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-
-static ulg crc;                                        /* crc on uncompressed file data */
-static long header_bytes;                              /* number of bytes in gzip header */
-
-/* ===========================================================================
- * Deflate in to out.
- * IN assertions: the input and output buffers are cleared.
- *   The variables time_stamp and save_orig_name are initialized.
- */
-static int zip(int in, int out)
-{
-       uch my_flags = 0;                               /* general purpose bit flags */
-       ush attr = 0;                           /* ascii/binary flag */
-       ush deflate_flags = 0;          /* pkzip -es, -en or -ex equivalent */
-
-       ifd = in;
-       ofd = out;
-       outcnt = 0;
-
-       /* Write the header to the gzip file. See algorithm.doc for the format */
-
-
-       method = DEFLATED;
-       put_byte(GZIP_MAGIC[0]);        /* magic header */
-       put_byte(GZIP_MAGIC[1]);
-       put_byte(DEFLATED);                     /* compression method */
-
-       put_byte(my_flags);                     /* general flags */
-       put_long(time_stamp);
-
-       /* Write deflated file to zip file */
-       crc = updcrc(0, 0);
-
-       bi_init(out);
-       ct_init(&attr, &method);
-       lm_init(&deflate_flags);
-
-       put_byte((uch) deflate_flags);  /* extra flags */
-       put_byte(OS_CODE);                      /* OS identifier */
-
-       header_bytes = (long) outcnt;
-
-       (void) deflate();
-
-       /* Write the crc and uncompressed size */
-       put_long(crc);
-       put_long(isize);
-       header_bytes += 2 * sizeof(long);
-
-       flush_outbuf();
-       return OK;
-}
-
-
-/* ===========================================================================
- * Read a new buffer from the current input file, perform end-of-line
- * translation, and update the crc and input file size.
- * IN assertion: size >= 2 (for end-of-line translation)
- */
-static int file_read(char *buf, unsigned size)
-{
-       unsigned len;
-
-       Assert(insize == 0, "inbuf not empty");
-
-       len = read(ifd, buf, size);
-       if (len == (unsigned) (-1) || len == 0)
-               return (int) len;
-
-       crc = updcrc((uch *) buf, len);
-       isize += (ulg) len;
-       return (int) len;
-}
-
-/* ===========================================================================
- * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
- * (used for the compressed data only)
- */
-static void flush_outbuf()
-{
-       if (outcnt == 0)
-               return;
-
-       write_buf(ofd, (char *) outbuf, outcnt);
-       outcnt = 0;
-}
diff --git a/busybox/halt.c b/busybox/halt.c
deleted file mode 100644 (file)
index d66e28d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini halt implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int halt_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGUSR1));
-#else
-       return(kill(1, SIGUSR1));
-#endif
-}
diff --git a/busybox/head.c b/busybox/head.c
deleted file mode 100644 (file)
index 688c250..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini head implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-static int head(int len, FILE *fp)
-{
-       int i;
-       char *input;
-
-       for (i = 0; i < len; i++) {
-               if ((input = get_line_from_file(fp)) == NULL)
-                       break;
-               fputs(input, stdout);
-               free(input);
-       }
-       return 0;
-}
-
-/* BusyBoxed head(1) */
-int head_main(int argc, char **argv)
-{
-       FILE *fp;
-       int need_headers, opt, len = 10, status = EXIT_SUCCESS;
-
-       /* parse argv[] */
-       while ((opt = getopt(argc, argv, "n:")) > 0) {
-               switch (opt) {
-               case 'n':
-                       len = atoi(optarg);
-                       if (len >= 1)
-                               break;
-                       /* fallthrough */
-               default:
-                       show_usage();
-               }
-       }
-
-       /* get rest of argv[] or stdin if nothing's left */
-       if (argv[optind] == NULL) {
-               head(len, stdin);
-               return status;
-       } 
-
-       need_headers = optind != (argc - 1);
-       while (argv[optind]) {
-               if (strcmp(argv[optind], "-") == 0) {
-                       fp = stdin;
-                       argv[optind] = "standard input";
-               } else {
-                       if ((fp = wfopen(argv[optind], "r")) == NULL)
-                               status = EXIT_FAILURE;
-               }
-               if (fp) {
-                       if (need_headers) {
-                               printf("==> %s <==\n", argv[optind]);
-                       }
-                       head(len, fp);
-                       if (ferror(fp)) {
-                               perror_msg("%s", argv[optind]);
-                               status = EXIT_FAILURE;
-                       }
-                       if (optind < argc - 1)
-                               putchar('\n');
-                       if (fp != stdin)
-                               fclose(fp);
-               }
-               optind++;
-       }
-
-       return status;
-}
diff --git a/busybox/hostid.c b/busybox/hostid.c
deleted file mode 100644 (file)
index 68a2cc6..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini hostid implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int hostid_main(int argc, char **argv)
-{
-       printf("%lx\n", gethostid());
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/hostname.c b/busybox/hostname.c
deleted file mode 100644 (file)
index d878515..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $
- * Mini hostname implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * adjusted by Erik Andersen <andersee@debian.org> to remove
- * use of long options and GNU getopt.  Improved the usage info.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <errno.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static void do_sethostname(char *s, int isfile)
-{
-       FILE *f;
-       char buf[255];
-
-       if (!s)
-               return;
-       if (!isfile) {
-               if (sethostname(s, strlen(s)) < 0) {
-                       if (errno == EPERM)
-                               error_msg_and_die("you must be root to change the hostname");
-                       else
-                               perror_msg_and_die("sethostname");
-               }
-       } else {
-               f = xfopen(s, "r");
-               fgets(buf, 255, f);
-#ifdef BB_FEATURE_CLEAN_UP
-               fclose(f);
-#endif
-               chomp(buf);
-               do_sethostname(buf, 0);
-       }
-}
-
-int hostname_main(int argc, char **argv)
-{
-       int opt_short = 0;
-       int opt_domain = 0;
-       int opt_ip = 0;
-       struct hostent *h;
-       char *filename = NULL;
-       char buf[255];
-       char *s = NULL;
-
-       if (argc < 1)
-               show_usage();
-
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 's':
-                               opt_short = 1;
-                               break;
-                       case 'i':
-                               opt_ip = 1;
-                               break;
-                       case 'd':
-                               opt_domain = 1;
-                               break;
-                       case 'F':
-                               if (--argc == 0) {
-                                       show_usage();
-                               }
-                               filename = *(++argv);
-                               break;
-                       case '-':
-                               if (strcmp(++(*argv), "file") || --argc ==0 ) {
-                                       show_usage();
-                               }
-                               filename = *(++argv);
-                               break;
-                       default:
-                               show_usage();
-                       }
-                       if (filename != NULL)
-                               break;
-               }
-       }
-
-       if (argc >= 1) {
-               do_sethostname(*argv, 0);
-       } else if (filename != NULL) {
-               do_sethostname(filename, 1);
-       } else {
-               gethostname(buf, 255);
-               if (opt_short) {
-                       s = strchr(buf, '.');
-                       if (!s)
-                               s = buf;
-                       *s = 0;
-                       puts(buf);
-               } else if (opt_domain) {
-                       s = strchr(buf, '.');
-                       puts(s ? s + 1 : "");
-               } else if (opt_ip) {
-                       h = xgethostbyname(buf);
-                       puts(inet_ntoa(*(struct in_addr *) (h->h_addr)));
-               } else {
-                       puts(buf);
-               }
-       }
-       return(0);
-}
diff --git a/busybox/hush.c b/busybox/hush.c
deleted file mode 100644 (file)
index 0e619f8..0000000
+++ /dev/null
@@ -1,2692 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * sh.c -- a prototype Bourne shell grammar parser
- *      Intended to follow the original Thompson and Ritchie
- *      "small and simple is beautiful" philosophy, which
- *      incidentally is a good match to today's BusyBox.
- *
- * Copyright (C) 2000,2001  Larry Doolittle  <larry@doolittle.boa.org>
- *
- * Credits:
- *      The parser routines proper are all original material, first
- *      written Dec 2000 and Jan 2001 by Larry Doolittle.
- *      The execution engine, the builtins, and much of the underlying
- *      support has been adapted from busybox-0.49pre's lash,
- *      which is Copyright (C) 2000 by Lineo, Inc., and
- *      written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
- *      That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
- *      Erik W. Troan, which they placed in the public domain.  I don't know
- *      how much of the Johnson/Troan code has survived the repeated rewrites.
- * Other credits:
- *      simple_itoa() was lifted from boa-0.93.15
- *      b_addchr() derived from similar w_addchar function in glibc-2.2
- *      setup_redirect(), redirect_opt_num(), and big chunks of main()
- *        and many builtins derived from contributions by Erik Andersen
- *      miscellaneous bugfixes from Matt Kraai
- *
- * There are two big (and related) architecture differences between
- * this parser and the lash parser.  One is that this version is
- * actually designed from the ground up to understand nearly all
- * of the Bourne grammar.  The second, consequential change is that
- * the parser and input reader have been turned inside out.  Now,
- * the parser is in control, and asks for input as needed.  The old
- * way had the input reader in control, and it asked for parsing to
- * take place as needed.  The new way makes it much easier to properly
- * handle the recursion implicit in the various substitutions, especially
- * across continuation lines.
- *
- * Bash grammar not implemented: (how many of these were in original sh?)
- *      $@ (those sure look like weird quoting rules)
- *      $_
- *      ! negation operator for pipes
- *      &> and >& redirection of stdout+stderr
- *      Brace Expansion
- *      Tilde Expansion
- *      fancy forms of Parameter Expansion
- *      aliases
- *      Arithmetic Expansion
- *      <(list) and >(list) Process Substitution
- *      reserved words: case, esac, select, function
- *      Here Documents ( << word )
- *      Functions
- * Major bugs:
- *      job handling woefully incomplete and buggy
- *      reserved word execution woefully incomplete and buggy
- * to-do:
- *      port selected bugfixes from post-0.49 busybox lash - done?
- *      finish implementing reserved words: for, while, until, do, done
- *      change { and } from special chars to reserved words
- *      builtins: break, continue, eval, return, set, trap, ulimit
- *      test magic exec
- *      handle children going into background
- *      clean up recognition of null pipes
- *      check setting of global_argc and global_argv
- *      control-C handling, probably with longjmp
- *      follow IFS rules more precisely, including update semantics
- *      figure out what to do with backslash-newline
- *      explain why we use signal instead of sigaction
- *      propagate syntax errors, die on resource errors?
- *      continuation lines, both explicit and implicit - done?
- *      memory leak finding and plugging - done?
- *      more testing, especially quoting rules and redirection
- *      document how quoting rules not precisely followed for variable assignments
- *      maybe change map[] to use 2-bit entries
- *      (eventually) remove all the printf's
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <ctype.h>     /* isalpha, isdigit */
-#include <unistd.h>    /* getpid */
-#include <stdlib.h>    /* getenv, atoi */
-#include <string.h>    /* strchr */
-#include <stdio.h>     /* popen etc. */
-#include <glob.h>      /* glob, of course */
-#include <stdarg.h>    /* va_list */
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>    /* should be pretty obvious */
-
-#include <sys/stat.h>  /* ulimit */
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-/* #include <dmalloc.h> */
-/* #define DEBUG_SHELL */
-
-#ifdef BB_VER
-#include "busybox.h"
-#include "cmdedit.h"
-#else
-#define applet_name "hush"
-#include "standalone.h"
-#define hush_main main
-#undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-
-typedef enum {
-       REDIRECT_INPUT     = 1,
-       REDIRECT_OVERWRITE = 2,
-       REDIRECT_APPEND    = 3,
-       REDIRECT_HEREIS    = 4,
-       REDIRECT_IO        = 5
-} redir_type;
-
-/* The descrip member of this structure is only used to make debugging
- * output pretty */
-struct {int mode; int default_fd; char *descrip;} redir_table[] = {
-       { 0,                         0, "()" },
-       { O_RDONLY,                  0, "<"  },
-       { O_CREAT|O_TRUNC|O_WRONLY,  1, ">"  },
-       { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
-       { O_RDONLY,                 -1, "<<" },
-       { O_RDWR,                    1, "<>" }
-};
-
-typedef enum {
-       PIPE_SEQ = 1,
-       PIPE_AND = 2,
-       PIPE_OR  = 3,
-       PIPE_BG  = 4,
-} pipe_style;
-
-/* might eventually control execution */
-typedef enum {
-       RES_NONE  = 0,
-       RES_IF    = 1,
-       RES_THEN  = 2,
-       RES_ELIF  = 3,
-       RES_ELSE  = 4,
-       RES_FI    = 5,
-       RES_FOR   = 6,
-       RES_WHILE = 7,
-       RES_UNTIL = 8,
-       RES_DO    = 9,
-       RES_DONE  = 10,
-       RES_XXXX  = 11,
-       RES_SNTX  = 12
-} reserved_style;
-#define FLAG_END   (1<<RES_NONE)
-#define FLAG_IF    (1<<RES_IF)
-#define FLAG_THEN  (1<<RES_THEN)
-#define FLAG_ELIF  (1<<RES_ELIF)
-#define FLAG_ELSE  (1<<RES_ELSE)
-#define FLAG_FI    (1<<RES_FI)
-#define FLAG_FOR   (1<<RES_FOR)
-#define FLAG_WHILE (1<<RES_WHILE)
-#define FLAG_UNTIL (1<<RES_UNTIL)
-#define FLAG_DO    (1<<RES_DO)
-#define FLAG_DONE  (1<<RES_DONE)
-#define FLAG_START (1<<RES_XXXX)
-
-/* This holds pointers to the various results of parsing */
-struct p_context {
-       struct child_prog *child;
-       struct pipe *list_head;
-       struct pipe *pipe;
-       struct redir_struct *pending_redirect;
-       reserved_style w;
-       int old_flag;                           /* for figuring out valid reserved words */
-       struct p_context *stack;
-       /* How about quoting status? */
-};
-
-struct redir_struct {
-       redir_type type;                        /* type of redirection */
-       int fd;                                         /* file descriptor being redirected */
-       int dup;                                        /* -1, or file descriptor being duplicated */
-       struct redir_struct *next;      /* pointer to the next redirect in the list */ 
-       glob_t word;                            /* *word.gl_pathv is the filename */
-};
-
-struct child_prog {
-       pid_t pid;                                      /* 0 if exited */
-       char **argv;                            /* program name and arguments */
-       struct pipe *group;                     /* if non-NULL, first in group or subshell */
-       int subshell;                           /* flag, non-zero if group must be forked */
-       struct redir_struct *redirects; /* I/O redirections */
-       glob_t glob_result;                     /* result of parameter globbing */
-       int is_stopped;                         /* is the program currently running? */
-       struct pipe *family;            /* pointer back to the child's parent pipe */
-};
-
-struct pipe {
-       int jobid;                                      /* job number */
-       int num_progs;                          /* total number of programs in job */
-       int running_progs;                      /* number of programs running */
-       char *text;                                     /* name of job */
-       char *cmdbuf;                           /* buffer various argv's point into */
-       pid_t pgrp;                                     /* process group ID for the job */
-       struct child_prog *progs;       /* array of commands in pipe */
-       struct pipe *next;                      /* to track background commands */
-       int stopped_progs;                      /* number of programs alive, but stopped */
-       int job_context;                        /* bitmask defining current context */
-       pipe_style followup;            /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
-       reserved_style r_mode;          /* supports if, for, while, until */
-};
-
-struct close_me {
-       int fd;
-       struct close_me *next;
-};
-
-struct variables {
-       char *name;
-       char *value;
-       int flg_export;
-       int flg_read_only;
-       struct variables *next;
-};
-
-/* globals, connect us to the outside world
- * the first three support $?, $#, and $1 */
-char **global_argv;
-unsigned int global_argc;
-unsigned int last_return_code;
-extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
-/* "globals" within this file */
-static char *ifs;
-static char map[256];
-static int fake_mode;
-static int interactive;
-static struct close_me *close_me_head;
-static const char *cwd;
-static struct pipe *job_list;
-static unsigned int last_bg_pid;
-static unsigned int last_jobid;
-static unsigned int shell_terminal;
-static char *PS1;
-static char *PS2;
-struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
-struct variables *top_vars = &shell_ver;
-
-
-#define B_CHUNK (100)
-#define B_NOSPAC 1
-
-typedef struct {
-       char *data;
-       int length;
-       int maxlen;
-       int quote;
-       int nonnull;
-} o_string;
-#define NULL_O_STRING {NULL,0,0,0,0}
-/* used for initialization:
-       o_string foo = NULL_O_STRING; */
-
-/* I can almost use ordinary FILE *.  Is open_memstream() universally
- * available?  Where is it documented? */
-struct in_str {
-       const char *p;
-       char peek_buf[2];
-       int __promptme;
-       int promptmode;
-       FILE *file;
-       int (*get) (struct in_str *);
-       int (*peek) (struct in_str *);
-};
-#define b_getch(input) ((input)->get(input))
-#define b_peek(input) ((input)->peek(input))
-
-#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
-
-struct built_in_command {
-       char *cmd;                                      /* name */
-       char *descr;                            /* description */
-       int (*function) (struct child_prog *);  /* function ptr */
-};
-
-/* belongs in busybox.h */
-static inline int max(int a, int b) {
-       return (a>b)?a:b;
-}
-
-/* This should be in utility.c */
-#ifdef DEBUG_SHELL
-static void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-}
-#else
-static inline void debug_printf(const char *format, ...) { }
-#endif
-#define final_printf debug_printf
-
-static void __syntax(char *file, int line) {
-       error_msg("syntax error %s:%d", file, line);
-}
-#define syntax() __syntax(__FILE__, __LINE__)
-
-/* Index of subroutines: */
-/*   function prototypes for builtins */
-static int builtin_cd(struct child_prog *child);
-static int builtin_env(struct child_prog *child);
-static int builtin_exec(struct child_prog *child);
-static int builtin_exit(struct child_prog *child);
-static int builtin_export(struct child_prog *child);
-static int builtin_fg_bg(struct child_prog *child);
-static int builtin_help(struct child_prog *child);
-static int builtin_jobs(struct child_prog *child);
-static int builtin_pwd(struct child_prog *child);
-static int builtin_read(struct child_prog *child);
-static int builtin_set(struct child_prog *child);
-static int builtin_shift(struct child_prog *child);
-static int builtin_source(struct child_prog *child);
-static int builtin_umask(struct child_prog *child);
-static int builtin_unset(struct child_prog *child);
-static int builtin_not_written(struct child_prog *child);
-/*   o_string manipulation: */
-static int b_check_space(o_string *o, int len);
-static int b_addchr(o_string *o, int ch);
-static void b_reset(o_string *o);
-static int b_addqchr(o_string *o, int ch, int quote);
-static int b_adduint(o_string *o, unsigned int i);
-/*  in_str manipulations: */
-static int static_get(struct in_str *i);
-static int static_peek(struct in_str *i);
-static int file_get(struct in_str *i);
-static int file_peek(struct in_str *i);
-static void setup_file_in_str(struct in_str *i, FILE *f);
-static void setup_string_in_str(struct in_str *i, const char *s);
-/*  close_me manipulations: */
-static void mark_open(int fd);
-static void mark_closed(int fd);
-static void close_all();
-/*  "run" the final data structures: */
-static char *indenter(int i);
-static int free_pipe_list(struct pipe *head, int indent);
-static int free_pipe(struct pipe *pi, int indent);
-/*  really run the final data structures: */
-static int setup_redirects(struct child_prog *prog, int squirrel[]);
-static int run_list_real(struct pipe *pi);
-static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
-static int run_pipe_real(struct pipe *pi);
-/*   extended glob support: */
-static int globhack(const char *src, int flags, glob_t *pglob);
-static int glob_needed(const char *s);
-static int xglob(o_string *dest, int flags, glob_t *pglob);
-/*   variable assignment: */
-static int is_assignment(const char *s);
-/*   data structure manipulation: */
-static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
-static void initialize_context(struct p_context *ctx);
-static int done_word(o_string *dest, struct p_context *ctx);
-static int done_command(struct p_context *ctx);
-static int done_pipe(struct p_context *ctx, pipe_style type);
-/*   primary string parsing: */
-static int redirect_dup_num(struct in_str *input);
-static int redirect_opt_num(o_string *o);
-static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
-static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
-static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src);
-static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
-static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
-static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
-/*   setup: */
-static int parse_stream_outer(struct in_str *inp);
-static int parse_string_outer(const char *s);
-static int parse_file_outer(FILE *f);
-/*   job management: */
-static int checkjobs(struct pipe* fg_pipe);
-static void insert_bg_job(struct pipe *pi);
-static void remove_bg_job(struct pipe *pi);
-/*     local variable support */
-static char *get_local_var(const char *var);
-static void  unset_local_var(const char *name);
-static int set_local_var(const char *s, int flg_export);
-
-/* Table of built-in functions.  They can be forked or not, depending on
- * context: within pipes, they fork.  As simple commands, they do not.
- * When used in non-forking context, they can change global variables
- * in the parent shell process.  If forked, of course they can not.
- * For example, 'unset foo | whatever' will parse and run, but foo will
- * still be set at the end. */
-static struct built_in_command bltins[] = {
-       {"bg", "Resume a job in the background", builtin_fg_bg},
-       {"break", "Exit for, while or until loop", builtin_not_written},
-       {"cd", "Change working directory", builtin_cd},
-       {"continue", "Continue for, while or until loop", builtin_not_written},
-       {"env", "Print all environment variables", builtin_env},
-       {"eval", "Construct and run shell command", builtin_not_written},
-       {"exec", "Exec command, replacing this shell with the exec'd process", 
-               builtin_exec},
-       {"exit", "Exit from shell()", builtin_exit},
-       {"export", "Set environment variable", builtin_export},
-       {"fg", "Bring job into the foreground", builtin_fg_bg},
-       {"jobs", "Lists the active jobs", builtin_jobs},
-       {"pwd", "Print current directory", builtin_pwd},
-       {"read", "Input environment variable", builtin_read},
-       {"return", "Return from a function", builtin_not_written},
-       {"set", "Set/unset shell local variables", builtin_set},
-       {"shift", "Shift positional parameters", builtin_shift},
-       {"trap", "Trap signals", builtin_not_written},
-       {"ulimit","Controls resource limits", builtin_not_written},
-       {"umask","Sets file creation mask", builtin_umask},
-       {"unset", "Unset environment variable", builtin_unset},
-       {".", "Source-in and run commands in a file", builtin_source},
-       {"help", "List shell built-in commands", builtin_help},
-       {NULL, NULL, NULL}
-};
-
-static const char *set_cwd(void)
-{
-       if(cwd==unknown)
-               cwd = NULL;     /* xgetcwd(arg) called free(arg) */
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       return cwd;
-}
-
-
-/* built-in 'cd <path>' handler */
-static int builtin_cd(struct child_prog *child)
-{
-       char *newdir;
-       if (child->argv[1] == NULL)
-               newdir = getenv("HOME");
-       else
-               newdir = child->argv[1];
-       if (chdir(newdir)) {
-               printf("cd: %s: %s\n", newdir, strerror(errno));
-               return EXIT_FAILURE;
-       }
-       set_cwd();
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'env' handler */
-static int builtin_env(struct child_prog *dummy)
-{
-       char **e = environ;
-       if (e == NULL) return EXIT_FAILURE;
-       for (; *e; e++) {
-               puts(*e);
-       }
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'exec' handler */
-static int builtin_exec(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               return EXIT_SUCCESS;   /* Really? */
-       child->argv++;
-       pseudo_exec(child);
-       /* never returns */
-}
-
-/* built-in 'exit' handler */
-static int builtin_exit(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               exit(last_return_code);
-       exit (atoi(child->argv[1]));
-}
-
-/* built-in 'export VAR=value' handler */
-static int builtin_export(struct child_prog *child)
-{
-       int res = 0;
-       char *name = child->argv[1];
-
-       if (name == NULL) {
-               return (builtin_env(child));
-       }
-
-       name = strdup(name);
-
-       if(name) {
-               char *value = strchr(name, '=');
-
-               if (!value) {
-                       char *tmp;
-                       /* They are exporting something without an =VALUE */
-
-                       value = get_local_var(name);
-                       if (value) {
-                               size_t ln = strlen(name);
-
-                               tmp = realloc(name, ln+strlen(value)+2);
-                               if(tmp==NULL)
-                                       res = -1;
-                               else {
-                                       sprintf(tmp+ln, "=%s", value);
-                                       name = tmp;
-                               }
-                       } else {
-                               /* bash does not return an error when trying to export
-                                * an undefined variable.  Do likewise. */
-                               res = 1;
-                       }
-               }
-       }
-       if (res<0)
-               perror_msg("export");
-       else if(res==0)
-               res = set_local_var(name, 1);
-       else
-               res = 0;
-       free(name);
-       return res;
-}
-
-/* built-in 'fg' and 'bg' handler */
-static int builtin_fg_bg(struct child_prog *child)
-{
-       int i, jobnum;
-       struct pipe *pi=NULL;
-
-       if (!interactive)
-               return EXIT_FAILURE;
-       /* If they gave us no args, assume they want the last backgrounded task */
-       if (!child->argv[1]) {
-               for (pi = job_list; pi; pi = pi->next) {
-                       if (pi->jobid == last_jobid) {
-                               break;
-                       }
-               }
-               if (!pi) {
-                       error_msg("%s: no current job", child->argv[0]);
-                       return EXIT_FAILURE;
-               }
-       } else {
-               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
-                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
-                       return EXIT_FAILURE;
-               }
-               for (pi = job_list; pi; pi = pi->next) {
-                       if (pi->jobid == jobnum) {
-                               break;
-                       }
-               }
-               if (!pi) {
-                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       if (*child->argv[0] == 'f') {
-               /* Put the job into the foreground.  */
-               tcsetpgrp(shell_terminal, pi->pgrp);
-       }
-
-       /* Restart the processes in the job */
-       for (i = 0; i < pi->num_progs; i++)
-               pi->progs[i].is_stopped = 0;
-
-       if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
-               if (i == ESRCH) {
-                       remove_bg_job(pi);
-               } else {
-                       perror_msg("kill (SIGCONT)");
-               }
-       }
-
-       pi->stopped_progs = 0;
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'help' handler */
-static int builtin_help(struct child_prog *dummy)
-{
-       struct built_in_command *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-       for (x = bltins; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'jobs' handler */
-static int builtin_jobs(struct child_prog *child)
-{
-       struct pipe *job;
-       char *status_string;
-
-       for (job = job_list; job; job = job->next) {
-               if (job->running_progs == job->stopped_progs)
-                       status_string = "Stopped";
-               else
-                       status_string = "Running";
-
-               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
-       }
-       return EXIT_SUCCESS;
-}
-
-
-/* built-in 'pwd' handler */
-static int builtin_pwd(struct child_prog *dummy)
-{
-       puts(set_cwd());
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'read VAR' handler */
-static int builtin_read(struct child_prog *child)
-{
-       int res;
-
-       if (child->argv[1]) {
-               char string[BUFSIZ];
-               char *var = 0;
-
-               string[0] = 0;  /* In case stdin has only EOF */
-               /* read string */
-               fgets(string, sizeof(string), stdin);
-               chomp(string);
-               var = malloc(strlen(child->argv[1])+strlen(string)+2);
-               if(var) {
-                       sprintf(var, "%s=%s", child->argv[1], string);
-                       res = set_local_var(var, 0);
-               } else
-                       res = -1;
-               if (res)
-                       fprintf(stderr, "read: %m\n");
-               free(var);      /* So not move up to avoid breaking errno */
-               return res;
-       } else {
-               do res=getchar(); while(res!='\n' && res!=EOF);
-               return 0;
-       }
-}
-
-/* built-in 'set VAR=value' handler */
-static int builtin_set(struct child_prog *child)
-{
-       char *temp = child->argv[1];
-       struct variables *e;
-
-       if (temp == NULL)
-               for(e = top_vars; e; e=e->next)
-                       printf("%s=%s\n", e->name, e->value);
-       else
-               set_local_var(temp, 0);
-
-               return EXIT_SUCCESS;
-}
-
-
-/* Built-in 'shift' handler */
-static int builtin_shift(struct child_prog *child)
-{
-       int n=1;
-       if (child->argv[1]) {
-               n=atoi(child->argv[1]);
-       }
-       if (n>=0 && n<global_argc) {
-               /* XXX This probably breaks $0 */
-               global_argc -= n;
-               global_argv += n;
-               return EXIT_SUCCESS;
-       } else {
-               return EXIT_FAILURE;
-       }
-}
-
-/* Built-in '.' handler (read-in and execute commands from file) */
-static int builtin_source(struct child_prog *child)
-{
-       FILE *input;
-       int status;
-
-       if (child->argv[1] == NULL)
-               return EXIT_FAILURE;
-
-       /* XXX search through $PATH is missing */
-       input = fopen(child->argv[1], "r");
-       if (!input) {
-               error_msg("Couldn't open file '%s'", child->argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       /* Now run the file */
-       /* XXX argv and argc are broken; need to save old global_argv
-        * (pointer only is OK!) on this stack frame,
-        * set global_argv=child->argv+1, recurse, and restore. */
-       mark_open(fileno(input));
-       status = parse_file_outer(input);
-       mark_closed(fileno(input));
-       fclose(input);
-       return (status);
-}
-
-static int builtin_umask(struct child_prog *child)
-{
-       mode_t new_umask;
-       const char *arg = child->argv[1];
-       char *end;
-       if (arg) {
-               new_umask=strtoul(arg, &end, 8);
-               if (*end!='\0' || end == arg) {
-                       return EXIT_FAILURE;
-               }
-       } else {
-               printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
-       }
-       umask(new_umask);
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'unset VAR' handler */
-static int builtin_unset(struct child_prog *child)
-{
-       /* bash returned already true */
-       unset_local_var(child->argv[1]);
-       return EXIT_SUCCESS;
-}
-
-static int builtin_not_written(struct child_prog *child)
-{
-       printf("builtin_%s not written\n",child->argv[0]);
-       return EXIT_FAILURE;
-}
-
-static int b_check_space(o_string *o, int len)
-{
-       /* It would be easy to drop a more restrictive policy
-        * in here, such as setting a maximum string length */
-       if (o->length + len > o->maxlen) {
-               char *old_data = o->data;
-               /* assert (data == NULL || o->maxlen != 0); */
-               o->maxlen += max(2*len, B_CHUNK);
-               o->data = realloc(o->data, 1 + o->maxlen);
-               if (o->data == NULL) {
-                       free(old_data);
-               }
-       }
-       return o->data == NULL;
-}
-
-static int b_addchr(o_string *o, int ch)
-{
-       debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
-       if (b_check_space(o, 1)) return B_NOSPAC;
-       o->data[o->length] = ch;
-       o->length++;
-       o->data[o->length] = '\0';
-       return 0;
-}
-
-static void b_reset(o_string *o)
-{
-       o->length = 0;
-       o->nonnull = 0;
-       if (o->data != NULL) *o->data = '\0';
-}
-
-static void b_free(o_string *o)
-{
-       b_reset(o);
-       if (o->data != NULL) free(o->data);
-       o->data = NULL;
-       o->maxlen = 0;
-}
-
-/* My analysis of quoting semantics tells me that state information
- * is associated with a destination, not a source.
- */
-static int b_addqchr(o_string *o, int ch, int quote)
-{
-       if (quote && strchr("*?[\\",ch)) {
-               int rc;
-               rc = b_addchr(o, '\\');
-               if (rc) return rc;
-       }
-       return b_addchr(o, ch);
-}
-
-/* belongs in utility.c */
-char *simple_itoa(unsigned int i)
-{
-       /* 21 digits plus null terminator, good for 64-bit or smaller ints */
-       static char local[22];
-       char *p = &local[21];
-       *p-- = '\0';
-       do {
-               *p-- = '0' + i % 10;
-               i /= 10;
-       } while (i > 0);
-       return p + 1;
-}
-
-static int b_adduint(o_string *o, unsigned int i)
-{
-       int r;
-       char *p = simple_itoa(i);
-       /* no escape checking necessary */
-       do r=b_addchr(o, *p++); while (r==0 && *p);
-       return r;
-}
-
-static int static_get(struct in_str *i)
-{
-       int ch=*i->p++;
-       if (ch=='\0') return EOF;
-       return ch;
-}
-
-static int static_peek(struct in_str *i)
-{
-       return *i->p;
-}
-
-static inline void cmdedit_set_initial_prompt(void)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       PS1 = NULL;
-#else
-       PS1 = getenv("PS1");
-       if(PS1==0)
-               PS1 = "\\w \\$ ";
-#endif 
-}
-
-static inline void setup_prompt_string(int promptmode, char **prompt_str)
-{
-       debug_printf("setup_prompt_string %d ",promptmode);
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       /* Set up the prompt */
-       if (promptmode == 1) {
-               if (PS1)
-                       free(PS1);
-               PS1=xmalloc(strlen(cwd)+4);
-               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
-               *prompt_str = PS1;
-       } else {
-               *prompt_str = PS2;
-       }
-#else
-       *prompt_str = (promptmode==1)? PS1 : PS2;
-#endif
-       debug_printf("result %s\n",*prompt_str);
-}
-
-static void get_user_input(struct in_str *i)
-{
-       char *prompt_str;
-       static char the_command[BUFSIZ];
-
-       setup_prompt_string(i->promptmode, &prompt_str);
-#ifdef BB_FEATURE_COMMAND_EDITING
-       /*
-        ** enable command line editing only while a command line
-        ** is actually being read; otherwise, we'll end up bequeathing
-        ** atexit() handlers and other unwanted stuff to our
-        ** child processes (rob@sysgo.de)
-        */
-       cmdedit_read_input(prompt_str, the_command);
-#else
-       fputs(prompt_str, stdout);
-       fflush(stdout);
-       the_command[0]=fgetc(i->file);
-       the_command[1]='\0';
-#endif
-       fflush(stdout);
-       i->p = the_command;
-}
-
-/* This is the magic location that prints prompts 
- * and gets data back from the user */
-static int file_get(struct in_str *i)
-{
-       int ch;
-
-       ch = 0;
-       /* If there is data waiting, eat it up */
-       if (i->p && *i->p) {
-               ch=*i->p++;
-       } else {
-               /* need to double check i->file because we might be doing something
-                * more complicated by now, like sourcing or substituting. */
-               if (i->__promptme && interactive && i->file == stdin) {
-                       while(! i->p || (interactive && strlen(i->p)==0) ) {
-                               get_user_input(i);
-                       }
-                       i->promptmode=2;
-                       i->__promptme = 0;
-                       if (i->p && *i->p) {
-                               ch=*i->p++;
-                       }
-               } else {
-                       ch = fgetc(i->file);
-               }
-
-               debug_printf("b_getch: got a %d\n", ch);
-       }
-       if (ch == '\n') i->__promptme=1;
-       return ch;
-}
-
-/* All the callers guarantee this routine will never be
- * used right after a newline, so prompting is not needed.
- */
-static int file_peek(struct in_str *i)
-{
-       if (i->p && *i->p) {
-               return *i->p;
-       } else {
-               i->peek_buf[0] = fgetc(i->file);
-               i->peek_buf[1] = '\0';
-               i->p = i->peek_buf;
-               debug_printf("b_peek: got a %d\n", *i->p);
-               return *i->p;
-       }
-}
-
-static void setup_file_in_str(struct in_str *i, FILE *f)
-{
-       i->peek = file_peek;
-       i->get = file_get;
-       i->__promptme=1;
-       i->promptmode=1;
-       i->file = f;
-       i->p = NULL;
-}
-
-static void setup_string_in_str(struct in_str *i, const char *s)
-{
-       i->peek = static_peek;
-       i->get = static_get;
-       i->__promptme=1;
-       i->promptmode=1;
-       i->p = s;
-}
-
-static void mark_open(int fd)
-{
-       struct close_me *new = xmalloc(sizeof(struct close_me));
-       new->fd = fd;
-       new->next = close_me_head;
-       close_me_head = new;
-}
-
-static void mark_closed(int fd)
-{
-       struct close_me *tmp;
-       if (close_me_head == NULL || close_me_head->fd != fd)
-               error_msg_and_die("corrupt close_me");
-       tmp = close_me_head;
-       close_me_head = close_me_head->next;
-       free(tmp);
-}
-
-static void close_all()
-{
-       struct close_me *c;
-       for (c=close_me_head; c; c=c->next) {
-               close(c->fd);
-       }
-       close_me_head = NULL;
-}
-
-/* squirrel != NULL means we squirrel away copies of stdin, stdout,
- * and stderr if they are redirected. */
-static int setup_redirects(struct child_prog *prog, int squirrel[])
-{
-       int openfd, mode;
-       struct redir_struct *redir;
-
-       for (redir=prog->redirects; redir; redir=redir->next) {
-               if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
-                       /* something went wrong in the parse.  Pretend it didn't happen */
-                       continue;
-               }
-               if (redir->dup == -1) {
-                       mode=redir_table[redir->type].mode;
-                       openfd = open(redir->word.gl_pathv[0], mode, 0666);
-                       if (openfd < 0) {
-                       /* this could get lost if stderr has been redirected, but
-                          bash and ash both lose it as well (though zsh doesn't!) */
-                               perror_msg("error opening %s", redir->word.gl_pathv[0]);
-                               return 1;
-                       }
-               } else {
-                       openfd = redir->dup;
-               }
-
-               if (openfd != redir->fd) {
-                       if (squirrel && redir->fd < 3) {
-                               squirrel[redir->fd] = dup(redir->fd);
-                       }
-                       if (openfd == -3) {
-                               close(openfd);
-                       } else {
-                               dup2(openfd, redir->fd);
-                               if (redir->dup == -1)
-                                       close (openfd);
-                       }
-               }
-       }
-       return 0;
-}
-
-static void restore_redirects(int squirrel[])
-{
-       int i, fd;
-       for (i=0; i<3; i++) {
-               fd = squirrel[i];
-               if (fd != -1) {
-                       /* No error checking.  I sure wouldn't know what
-                        * to do with an error if I found one! */
-                       dup2(fd, i);
-                       close(fd);
-               }
-       }
-}
-
-/* never returns */
-/* XXX no exit() here.  If you don't exec, use _exit instead.
- * The at_exit handlers apparently confuse the calling process,
- * in particular stdin handling.  Not sure why? */
-static void pseudo_exec(struct child_prog *child)
-{
-       int i, rcode;
-       struct built_in_command *x;
-       if (child->argv) {
-               for (i=0; is_assignment(child->argv[i]); i++) {
-                       debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
-                       putenv(strdup(child->argv[i]));
-               }
-               child->argv+=i;  /* XXX this hack isn't so horrible, since we are about
-                                       to exit, and therefore don't need to keep data
-                                       structures consistent for free() use. */
-               /* If a variable is assigned in a forest, and nobody listens,
-                * was it ever really set?
-                */
-               if (child->argv[0] == NULL) {
-                       _exit(EXIT_SUCCESS);
-               }
-
-               /*
-                * Check if the command matches any of the builtins.
-                * Depending on context, this might be redundant.  But it's
-                * easier to waste a few CPU cycles than it is to figure out
-                * if this is one of those cases.
-                */
-               for (x = bltins; x->cmd; x++) {
-                       if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                               debug_printf("builtin exec %s\n", child->argv[0]);
-                               rcode = x->function(child);
-                               fflush(stdout);
-                               _exit(rcode);
-                       }
-               }
-
-               /* Check if the command matches any busybox internal commands
-                * ("applets") here.  
-                * FIXME: This feature is not 100% safe, since
-                * BusyBox is not fully reentrant, so we have no guarantee the things
-                * from the .bss are still zeroed, or that things from .data are still
-                * at their defaults.  We could exec ourself from /proc/self/exe, but I
-                * really dislike relying on /proc for things.  We could exec ourself
-                * from global_argv[0], but if we are in a chroot, we may not be able
-                * to find ourself... */ 
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-               {
-                       int argc_l;
-                       char** argv_l=child->argv;
-                       char *name = child->argv[0];
-
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-                       /* Following discussions from November 2000 on the busybox mailing
-                        * list, the default configuration, (without
-                        * get_last_path_component()) lets the user force use of an
-                        * external command by specifying the full (with slashes) filename.
-                        * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets
-                        * _aways_ override external commands, so if you want to run
-                        * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
-                        * filesystem and is _not_ busybox.  Some systems may want this,
-                        * most do not.  */
-                       name = get_last_path_component(name);
-#endif
-                       /* Count argc for use in a second... */
-                       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
-                       optind = 1;
-                       debug_printf("running applet %s\n", name);
-                       run_applet_by_name(name, argc_l, child->argv);
-               }
-#endif
-               debug_printf("exec of %s\n",child->argv[0]);
-               execvp(child->argv[0],child->argv);
-               perror_msg("couldn't exec: %s",child->argv[0]);
-               _exit(1);
-       } else if (child->group) {
-               debug_printf("runtime nesting to group\n");
-               interactive=0;    /* crucial!!!! */
-               rcode = run_list_real(child->group);
-               /* OK to leak memory by not calling free_pipe_list,
-                * since this process is about to exit */
-               _exit(rcode);
-       } else {
-               /* Can happen.  See what bash does with ">foo" by itself. */
-               debug_printf("trying to pseudo_exec null command\n");
-               _exit(EXIT_SUCCESS);
-       }
-}
-
-static void insert_bg_job(struct pipe *pi)
-{
-       struct pipe *thejob;
-
-       /* Linear search for the ID of the job to use */
-       pi->jobid = 1;
-       for (thejob = job_list; thejob; thejob = thejob->next)
-               if (thejob->jobid >= pi->jobid)
-                       pi->jobid = thejob->jobid + 1;
-
-       /* add thejob to the list of running jobs */
-       if (!job_list) {
-               thejob = job_list = xmalloc(sizeof(*thejob));
-       } else {
-               for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
-               thejob->next = xmalloc(sizeof(*thejob));
-               thejob = thejob->next;
-       }
-
-       /* physically copy the struct job */
-       memcpy(thejob, pi, sizeof(struct pipe));
-       thejob->next = NULL;
-       thejob->running_progs = thejob->num_progs;
-       thejob->stopped_progs = 0;
-       thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
-
-       //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
-       {
-               char *bar=thejob->text;
-               char **foo=pi->progs[0].argv;
-               while(foo && *foo) {
-                       bar += sprintf(bar, "%s ", *foo++);
-               }
-       }
-
-       /* we don't wait for background thejobs to return -- append it 
-          to the list of backgrounded thejobs and leave it alone */
-       printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
-       last_bg_pid = thejob->progs[0].pid;
-       last_jobid = thejob->jobid;
-}
-
-/* remove a backgrounded job */
-static void remove_bg_job(struct pipe *pi)
-{
-       struct pipe *prev_pipe;
-
-       if (pi == job_list) {
-               job_list = pi->next;
-       } else {
-               prev_pipe = job_list;
-               while (prev_pipe->next != pi)
-                       prev_pipe = prev_pipe->next;
-               prev_pipe->next = pi->next;
-       }
-       if (job_list)
-               last_jobid = job_list->jobid;
-       else
-               last_jobid = 0;
-
-       pi->stopped_progs = 0;
-       free_pipe(pi, 0);
-       free(pi);
-}
-
-/* Checks to see if any processes have exited -- if they 
-   have, figure out why and see if a job has completed */
-static int checkjobs(struct pipe* fg_pipe)
-{
-       int attributes;
-       int status;
-       int prognum = 0;
-       struct pipe *pi;
-       pid_t childpid;
-
-       attributes = WUNTRACED;
-       if (fg_pipe==NULL) {
-               attributes |= WNOHANG;
-       }
-
-       while ((childpid = waitpid(-1, &status, attributes)) > 0) {
-               if (fg_pipe) {
-                       int i, rcode = 0;
-                       for (i=0; i < fg_pipe->num_progs; i++) {
-                               if (fg_pipe->progs[i].pid == childpid) {
-                                       if (i==fg_pipe->num_progs-1) 
-                                               rcode=WEXITSTATUS(status);
-                                       (fg_pipe->num_progs)--;
-                                       return(rcode);
-                               }
-                       }
-               }
-
-               for (pi = job_list; pi; pi = pi->next) {
-                       prognum = 0;
-                       while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
-                               prognum++;
-                       }
-                       if (prognum < pi->num_progs)
-                               break;
-               }
-
-               if(pi==NULL) {
-                       debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
-                       continue;
-               }
-
-               if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                       /* child exited */
-                       pi->running_progs--;
-                       pi->progs[prognum].pid = 0;
-
-                       if (!pi->running_progs) {
-                               printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
-                               remove_bg_job(pi);
-                       }
-               } else {
-                       /* child stopped */
-                       pi->stopped_progs++;
-                       pi->progs[prognum].is_stopped = 1;
-
-#if 0
-                       /* Printing this stuff is a pain, since it tends to
-                        * overwrite the prompt an inconveinient moments.  So
-                        * don't do that.  */
-                       if (pi->stopped_progs == pi->num_progs) {
-                               printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
-                       }
-#endif 
-               }
-       }
-
-       if (childpid == -1 && errno != ECHILD)
-               perror_msg("waitpid");
-
-       /* move the shell to the foreground */
-       //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
-       //      perror_msg("tcsetpgrp-2");
-       return -1;
-}
-
-/* Figure out our controlling tty, checking in order stderr,
- * stdin, and stdout.  If check_pgrp is set, also check that
- * we belong to the foreground process group associated with
- * that tty.  The value of shell_terminal is needed in order to call
- * tcsetpgrp(shell_terminal, ...); */
-void controlling_tty(int check_pgrp)
-{
-       pid_t curpgrp;
-
-       if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
-                       && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
-                       && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
-               goto shell_terminal_error;
-
-       if (check_pgrp && curpgrp != getpgid(0))
-               goto shell_terminal_error;
-
-       return;
-
-shell_terminal_error:
-               shell_terminal = -1;
-               return;
-}
-
-/* run_pipe_real() starts all the jobs, but doesn't wait for anything
- * to finish.  See checkjobs().
- *
- * return code is normally -1, when the caller has to wait for children
- * to finish to determine the exit status of the pipe.  If the pipe
- * is a simple builtin command, however, the action is done by the
- * time run_pipe_real returns, and the exit code is provided as the
- * return value.
- *
- * The input of the pipe is always stdin, the output is always
- * stdout.  The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
- * because it tries to avoid running the command substitution in
- * subshell, when that is in fact necessary.  The subshell process
- * now has its stdout directed to the input of the appropriate pipe,
- * so this routine is noticeably simpler.
- */
-static int run_pipe_real(struct pipe *pi)
-{
-       int i;
-       int nextin, nextout;
-       int pipefds[2];                         /* pipefds[0] is for reading */
-       struct child_prog *child;
-       struct built_in_command *x;
-
-       nextin = 0;
-       pi->pgrp = -1;
-
-       /* Check if this is a simple builtin (not part of a pipe).
-        * Builtins within pipes have to fork anyway, and are handled in
-        * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
-        */
-       if (pi->num_progs == 1) child = & (pi->progs[0]);
-       if (pi->num_progs == 1 && child->group && child->subshell == 0) {
-               int squirrel[] = {-1, -1, -1};
-               int rcode;
-               debug_printf("non-subshell grouping\n");
-               setup_redirects(child, squirrel);
-               /* XXX could we merge code with following builtin case,
-                * by creating a pseudo builtin that calls run_list_real? */
-               rcode = run_list_real(child->group);
-               restore_redirects(squirrel);
-               return rcode;
-       } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
-               for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
-               if (i!=0 && child->argv[i]==NULL) {
-                       /* assignments, but no command: set the local environment */
-                       for (i=0; child->argv[i]!=NULL; i++) {
-
-                               /* Ok, this case is tricky.  We have to decide if this is a
-                                * local variable, or an already exported variable.  If it is
-                                * already exported, we have to export the new value.  If it is
-                                * not exported, we need only set this as a local variable. 
-                                * This junk is all to decide whether or not to export this
-                                * variable. */
-                               int export_me=0;
-                               char *name, *value;
-                               name = xstrdup(child->argv[i]);
-                               debug_printf("Local environment set: %s\n", name);
-                               value = strchr(name, '=');
-                               if (value)
-                                       *value=0;
-                               if ( get_local_var(name)) {
-                                       export_me=1;
-                               }
-                               free(name);
-                               set_local_var(child->argv[i], export_me);
-                       }
-                       return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
-               }
-               for (x = bltins; x->cmd; x++) {
-                       if (strcmp(child->argv[i], x->cmd) == 0 ) {
-                               int squirrel[] = {-1, -1, -1};
-                               int rcode;
-                               if (x->function == builtin_exec && child->argv[i+1]==NULL) {
-                                       debug_printf("magic exec\n");
-                                       setup_redirects(child,NULL);
-                                       return EXIT_SUCCESS;
-                               }
-                               debug_printf("builtin inline %s\n", child->argv[0]);
-                               /* XXX setup_redirects acts on file descriptors, not FILEs.
-                                * This is perfect for work that comes after exec().
-                                * Is it really safe for inline use?  Experimentally,
-                                * things seem to work with glibc. */
-                               setup_redirects(child, squirrel);
-                               for (i=0; is_assignment(child->argv[i]); i++) {
-                                       putenv(strdup(child->argv[i]));
-                               }
-                               child->argv+=i;  /* XXX horrible hack */
-                               rcode = x->function(child);
-                               child->argv-=i;  /* XXX restore hack so free() can work right */
-                               restore_redirects(squirrel);
-                               return rcode;
-                       }
-               }
-       }
-
-       for (i = 0; i < pi->num_progs; i++) {
-               child = & (pi->progs[i]);
-
-               /* pipes are inserted between pairs of commands */
-               if ((i + 1) < pi->num_progs) {
-                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
-                       nextout = pipefds[1];
-               } else {
-                       nextout=1;
-                       pipefds[0] = -1;
-               }
-
-               /* XXX test for failed fork()? */
-               if (!(child->pid = fork())) {
-                       /* Set the handling for job control signals back to the default.  */
-                       signal(SIGINT, SIG_DFL);
-                       signal(SIGQUIT, SIG_DFL);
-                       signal(SIGTERM, SIG_DFL);
-                       signal(SIGTSTP, SIG_DFL);
-                       signal(SIGTTIN, SIG_DFL);
-                       signal(SIGTTOU, SIG_DFL);
-                       signal(SIGCHLD, SIG_DFL);
-                       
-                       close_all();
-
-                       if (nextin != 0) {
-                               dup2(nextin, 0);
-                               close(nextin);
-                       }
-                       if (nextout != 1) {
-                               dup2(nextout, 1);
-                               close(nextout);
-                       }
-                       if (pipefds[0]!=-1) {
-                               close(pipefds[0]);  /* opposite end of our output pipe */
-                       }
-
-                       /* Like bash, explicit redirects override pipes,
-                        * and the pipe fd is available for dup'ing. */
-                       setup_redirects(child,NULL);
-
-                       if (interactive && pi->followup!=PIPE_BG) {
-                               /* If we (the child) win the race, put ourselves in the process
-                                * group whose leader is the first process in this pipe. */
-                               if (pi->pgrp < 0) {
-                                       pi->pgrp = getpid();
-                               }
-                               if (setpgid(0, pi->pgrp) == 0) {
-                                       tcsetpgrp(2, pi->pgrp);
-                               }
-                       }
-
-                       pseudo_exec(child);
-               }
-               
-
-               /* put our child in the process group whose leader is the
-                  first process in this pipe */
-               if (pi->pgrp < 0) {
-                       pi->pgrp = child->pid;
-               }
-               /* Don't check for errors.  The child may be dead already,
-                * in which case setpgid returns error code EACCES. */
-               setpgid(child->pid, pi->pgrp);
-
-               if (nextin != 0)
-                       close(nextin);
-               if (nextout != 1)
-                       close(nextout);
-
-               /* If there isn't another process, nextin is garbage 
-                  but it doesn't matter */
-               nextin = pipefds[0];
-       }
-       return -1;
-}
-
-static int run_list_real(struct pipe *pi)
-{
-       int rcode=0;
-       int if_code=0, next_if_code=0;  /* need double-buffer to handle elif */
-       reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
-       for (;pi;pi=pi->next) {
-               rmode = pi->r_mode;
-               debug_printf("rmode=%d  if_code=%d  next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
-               if (rmode == skip_more_in_this_rmode) continue;
-               skip_more_in_this_rmode = RES_XXXX;
-               if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
-               if (rmode == RES_THEN &&  if_code) continue;
-               if (rmode == RES_ELSE && !if_code) continue;
-               if (rmode == RES_ELIF && !if_code) continue;
-               if (pi->num_progs == 0) continue;
-               rcode = run_pipe_real(pi);
-               debug_printf("run_pipe_real returned %d\n",rcode);
-               if (rcode!=-1) {
-                       /* We only ran a builtin: rcode was set by the return value
-                        * of run_pipe_real(), and we don't need to wait for anything. */
-               } else if (pi->followup==PIPE_BG) {
-                       /* XXX check bash's behavior with nontrivial pipes */
-                       /* XXX compute jobid */
-                       /* XXX what does bash do with attempts to background builtins? */
-                       insert_bg_job(pi);
-                       rcode = EXIT_SUCCESS;
-               } else {
-                       if (interactive) {
-                               /* move the new process group into the foreground */
-                               if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp-3");
-                               rcode = checkjobs(pi);
-                               /* move the shell to the foreground */
-                               if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp-4");
-                       } else {
-                               rcode = checkjobs(pi);
-                       }
-                       debug_printf("checkjobs returned %d\n",rcode);
-               }
-               last_return_code=rcode;
-               if ( rmode == RES_IF || rmode == RES_ELIF )
-                       next_if_code=rcode;  /* can be overwritten a number of times */
-               if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
-                    (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
-                       skip_more_in_this_rmode=rmode;
-               checkjobs(NULL);
-       }
-       return rcode;
-}
-
-/* broken, of course, but OK for testing */
-static char *indenter(int i)
-{
-       static char blanks[]="                                    ";
-       return &blanks[sizeof(blanks)-i-1];
-}
-
-/* return code is the exit status of the pipe */
-static int free_pipe(struct pipe *pi, int indent)
-{
-       char **p;
-       struct child_prog *child;
-       struct redir_struct *r, *rnext;
-       int a, i, ret_code=0;
-       char *ind = indenter(indent);
-
-       if (pi->stopped_progs > 0)
-               return ret_code;
-       final_printf("%s run pipe: (pid %d)\n",ind,getpid());
-       for (i=0; i<pi->num_progs; i++) {
-               child = &pi->progs[i];
-               final_printf("%s  command %d:\n",ind,i);
-               if (child->argv) {
-                       for (a=0,p=child->argv; *p; a++,p++) {
-                               final_printf("%s   argv[%d] = %s\n",ind,a,*p);
-                       }
-                       globfree(&child->glob_result);
-                       child->argv=NULL;
-               } else if (child->group) {
-                       final_printf("%s   begin group (subshell:%d)\n",ind, child->subshell);
-                       ret_code = free_pipe_list(child->group,indent+3);
-                       final_printf("%s   end group\n",ind);
-               } else {
-                       final_printf("%s   (nil)\n",ind);
-               }
-               for (r=child->redirects; r; r=rnext) {
-                       final_printf("%s   redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
-                       if (r->dup == -1) {
-                               /* guard against the case >$FOO, where foo is unset or blank */
-                               if (r->word.gl_pathv) {
-                                       final_printf(" %s\n", *r->word.gl_pathv);
-                                       globfree(&r->word);
-                               }
-                       } else {
-                               final_printf("&%d\n", r->dup);
-                       }
-                       rnext=r->next;
-                       free(r);
-               }
-               child->redirects=NULL;
-       }
-       free(pi->progs);   /* children are an array, they get freed all at once */
-       pi->progs=NULL;
-       return ret_code;
-}
-
-static int free_pipe_list(struct pipe *head, int indent)
-{
-       int rcode=0;   /* if list has no members */
-       struct pipe *pi, *next;
-       char *ind = indenter(indent);
-       for (pi=head; pi; pi=next) {
-               final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
-               rcode = free_pipe(pi, indent);
-               final_printf("%s pipe followup code %d\n", ind, pi->followup);
-               next=pi->next;
-               pi->next=NULL;
-               free(pi);
-       }
-       return rcode;   
-}
-
-/* Select which version we will use */
-static int run_list(struct pipe *pi)
-{
-       int rcode=0;
-       if (fake_mode==0) {
-               rcode = run_list_real(pi);
-       } 
-       /* free_pipe_list has the side effect of clearing memory
-        * In the long run that function can be merged with run_list_real,
-        * but doing that now would hobble the debugging effort. */
-       free_pipe_list(pi,0);
-       return rcode;
-}
-
-/* The API for glob is arguably broken.  This routine pushes a non-matching
- * string into the output structure, removing non-backslashed backslashes.
- * If someone can prove me wrong, by performing this function within the
- * original glob(3) api, feel free to rewrite this routine into oblivion.
- * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
- * XXX broken if the last character is '\\', check that before calling.
- */
-static int globhack(const char *src, int flags, glob_t *pglob)
-{
-       int cnt=0, pathc;
-       const char *s;
-       char *dest;
-       for (cnt=1, s=src; s && *s; s++) {
-               if (*s == '\\') s++;
-               cnt++;
-       }
-       dest = malloc(cnt);
-       if (!dest) return GLOB_NOSPACE;
-       if (!(flags & GLOB_APPEND)) {
-               pglob->gl_pathv=NULL;
-               pglob->gl_pathc=0;
-               pglob->gl_offs=0;
-               pglob->gl_offs=0;
-       }
-       pathc = ++pglob->gl_pathc;
-       pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
-       if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
-       pglob->gl_pathv[pathc-1]=dest;
-       pglob->gl_pathv[pathc]=NULL;
-       for (s=src; s && *s; s++, dest++) {
-               if (*s == '\\') s++;
-               *dest = *s;
-       }
-       *dest='\0';
-       return 0;
-}
-
-/* XXX broken if the last character is '\\', check that before calling */
-static int glob_needed(const char *s)
-{
-       for (; *s; s++) {
-               if (*s == '\\') s++;
-               if (strchr("*[?",*s)) return 1;
-       }
-       return 0;
-}
-
-#if 0
-static void globprint(glob_t *pglob)
-{
-       int i;
-       debug_printf("glob_t at %p:\n", pglob);
-       debug_printf("  gl_pathc=%d  gl_pathv=%p  gl_offs=%d  gl_flags=%d\n",
-               pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
-       for (i=0; i<pglob->gl_pathc; i++)
-               debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
-                       pglob->gl_pathv[i], pglob->gl_pathv[i]);
-}
-#endif
-
-static int xglob(o_string *dest, int flags, glob_t *pglob)
-{
-       int gr;
-
-       /* short-circuit for null word */
-       /* we can code this better when the debug_printf's are gone */
-       if (dest->length == 0) {
-               if (dest->nonnull) {
-                       /* bash man page calls this an "explicit" null */
-                       gr = globhack(dest->data, flags, pglob);
-                       debug_printf("globhack returned %d\n",gr);
-               } else {
-                       return 0;
-               }
-       } else if (glob_needed(dest->data)) {
-               gr = glob(dest->data, flags, NULL, pglob);
-               debug_printf("glob returned %d\n",gr);
-               if (gr == GLOB_NOMATCH) {
-                       /* quote removal, or more accurately, backslash removal */
-                       gr = globhack(dest->data, flags, pglob);
-                       debug_printf("globhack returned %d\n",gr);
-               }
-       } else {
-               gr = globhack(dest->data, flags, pglob);
-               debug_printf("globhack returned %d\n",gr);
-       }
-       if (gr == GLOB_NOSPACE)
-               error_msg_and_die("out of memory during glob");
-       if (gr != 0) { /* GLOB_ABORTED ? */
-               error_msg("glob(3) error %d",gr);
-       }
-       /* globprint(glob_target); */
-       return gr;
-}
-
-/* This is used to get/check local shell variables */
-static char *get_local_var(const char *s)
-{
-       struct variables *cur;
-
-       if (!s)
-               return NULL;
-       for (cur = top_vars; cur; cur=cur->next)
-               if(strcmp(cur->name, s)==0)
-                       return cur->value;
-       return NULL;
-}
-
-/* This is used to set local shell variables
-   flg_export==0 if only local (not exporting) variable
-   flg_export==1 if "new" exporting environ
-   flg_export>1  if current startup environ (not call putenv()) */
-static int set_local_var(const char *s, int flg_export)
-{
-       char *name, *value;
-       int result=0;
-       struct variables *cur;
-
-       name=strdup(s);
-
-       /* Assume when we enter this function that we are already in
-        * NAME=VALUE format.  So the first order of business is to
-        * split 's' on the '=' into 'name' and 'value' */ 
-       value = strchr(name, '=');
-       if (value==0 && ++value==0) {
-               free(name);
-               return -1;
-       }
-       *value++ = 0;
-
-       for(cur = top_vars; cur; cur = cur->next) {
-               if(strcmp(cur->name, name)==0)
-                       break;
-       }
-
-       if(cur) {
-               if(strcmp(cur->value, value)==0) {
-                       if(flg_export>0 && cur->flg_export==0)
-                               cur->flg_export=flg_export;
-                       else
-                               result++;
-               } else {
-                       if(cur->flg_read_only) {
-                               error_msg("%s: readonly variable", name);
-                               result = -1;
-                       } else {
-                               if(flg_export>0 || cur->flg_export>1)
-                                       cur->flg_export=1;
-                               free(cur->value);
-
-                               cur->value = strdup(value);
-                       }
-               }
-       } else {
-               cur = malloc(sizeof(struct variables));
-               if(!cur) {
-                       result = -1;
-               } else {
-                       cur->name = strdup(name);
-                       if(cur->name == 0) {
-                               free(cur);
-                               result = -1;
-                       } else {
-                               struct variables *bottom = top_vars;
-                               cur->value = strdup(value);
-                               cur->next = 0;
-                               cur->flg_export = flg_export;
-                               cur->flg_read_only = 0;
-                               while(bottom->next) bottom=bottom->next;
-                               bottom->next = cur;
-                       }
-               }
-       }
-
-       if(result==0 && cur->flg_export==1) {
-               *(value-1) = '=';
-               result = putenv(name);
-       } else {
-               free(name);
-               if(result>0)            /* equivalent to previous set */
-                       result = 0;
-       }
-       return result;
-}
-
-static void unset_local_var(const char *name)
-{
-       struct variables *cur;
-
-       if (name) {
-               for (cur = top_vars; cur; cur=cur->next) {
-                       if(strcmp(cur->name, name)==0)
-                               break;
-               }
-               if(cur!=0) {
-                       struct variables *next = top_vars;
-                       if(cur->flg_read_only) {
-                               error_msg("%s: readonly variable", name);
-                               return;
-                       } else {
-                               if(cur->flg_export)
-                                       unsetenv(cur->name);
-                               free(cur->name);
-                               free(cur->value);
-                               while (next->next != cur)
-                                       next = next->next;
-                               next->next = cur->next;
-                       }
-                       free(cur);
-               }
-       }
-}
-
-static int is_assignment(const char *s)
-{
-       if (s==NULL || !isalpha(*s)) return 0;
-       ++s;
-       while(isalnum(*s) || *s=='_') ++s;
-       return *s=='=';
-}
-
-/* the src parameter allows us to peek forward to a possible &n syntax
- * for file descriptor duplication, e.g., "2>&1".
- * Return code is 0 normally, 1 if a syntax error is detected in src.
- * Resource errors (in xmalloc) cause the process to exit */
-static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
-       struct in_str *input)
-{
-       struct child_prog *child=ctx->child;
-       struct redir_struct *redir = child->redirects;
-       struct redir_struct *last_redir=NULL;
-
-       /* Create a new redir_struct and drop it onto the end of the linked list */
-       while(redir) {
-               last_redir=redir;
-               redir=redir->next;
-       }
-       redir = xmalloc(sizeof(struct redir_struct));
-       redir->next=NULL;
-       redir->word.gl_pathv=NULL;
-       if (last_redir) {
-               last_redir->next=redir;
-       } else {
-               child->redirects=redir;
-       }
-
-       redir->type=style;
-       redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
-
-       debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
-
-       /* Check for a '2>&1' type redirect */ 
-       redir->dup = redirect_dup_num(input);
-       if (redir->dup == -2) return 1;  /* syntax error */
-       if (redir->dup != -1) {
-               /* Erik had a check here that the file descriptor in question
-                * is legit; I postpone that to "run time"
-                * A "-" representation of "close me" shows up as a -3 here */
-               debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
-       } else {
-               /* We do _not_ try to open the file that src points to,
-                * since we need to return and let src be expanded first.
-                * Set ctx->pending_redirect, so we know what to do at the
-                * end of the next parsed word.
-                */
-               ctx->pending_redirect = redir;
-       }
-       return 0;
-}
-
-struct pipe *new_pipe(void) {
-       struct pipe *pi;
-       pi = xmalloc(sizeof(struct pipe));
-       pi->num_progs = 0;
-       pi->progs = NULL;
-       pi->next = NULL;
-       pi->followup = 0;  /* invalid */
-       return pi;
-}
-
-static void initialize_context(struct p_context *ctx)
-{
-       ctx->pipe=NULL;
-       ctx->pending_redirect=NULL;
-       ctx->child=NULL;
-       ctx->list_head=new_pipe();
-       ctx->pipe=ctx->list_head;
-       ctx->w=RES_NONE;
-       ctx->stack=NULL;
-       done_command(ctx);   /* creates the memory for working child */
-}
-
-/* normal return is 0
- * if a reserved word is found, and processed, return 1
- * should handle if, then, elif, else, fi, for, while, until, do, done.
- * case, function, and select are obnoxious, save those for later.
- */
-int reserved_word(o_string *dest, struct p_context *ctx)
-{
-       struct reserved_combo {
-               char *literal;
-               int code;
-               long flag;
-       };
-       /* Mostly a list of accepted follow-up reserved words.
-        * FLAG_END means we are done with the sequence, and are ready
-        * to turn the compound list into a command.
-        * FLAG_START means the word must start a new compound list.
-        */
-       static struct reserved_combo reserved_list[] = {
-               { "if",    RES_IF,    FLAG_THEN | FLAG_START },
-               { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
-               { "elif",  RES_ELIF,  FLAG_THEN },
-               { "else",  RES_ELSE,  FLAG_FI   },
-               { "fi",    RES_FI,    FLAG_END  },
-               { "for",   RES_FOR,   FLAG_DO   | FLAG_START },
-               { "while", RES_WHILE, FLAG_DO   | FLAG_START },
-               { "until", RES_UNTIL, FLAG_DO   | FLAG_START },
-               { "do",    RES_DO,    FLAG_DONE },
-               { "done",  RES_DONE,  FLAG_END  }
-       };
-       struct reserved_combo *r;
-       for (r=reserved_list;
-#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
-               r<reserved_list+NRES; r++) {
-               if (strcmp(dest->data, r->literal) == 0) {
-                       debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
-                       if (r->flag & FLAG_START) {
-                               struct p_context *new = xmalloc(sizeof(struct p_context));
-                               debug_printf("push stack\n");
-                               *new = *ctx;   /* physical copy */
-                               initialize_context(ctx);
-                               ctx->stack=new;
-                       } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
-                               syntax();
-                               ctx->w = RES_SNTX;
-                               b_reset (dest);
-                               return 1;
-                       }
-                       ctx->w=r->code;
-                       ctx->old_flag = r->flag;
-                       if (ctx->old_flag & FLAG_END) {
-                               struct p_context *old;
-                               debug_printf("pop stack\n");
-                               old = ctx->stack;
-                               old->child->group = ctx->list_head;
-                               old->child->subshell = 0;
-                               *ctx = *old;   /* physical copy */
-                               free(old);
-                       }
-                       b_reset (dest);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/* normal return is 0.
- * Syntax or xglob errors return 1. */
-static int done_word(o_string *dest, struct p_context *ctx)
-{
-       struct child_prog *child=ctx->child;
-       glob_t *glob_target;
-       int gr, flags = 0;
-
-       debug_printf("done_word: %s %p\n", dest->data, child);
-       if (dest->length == 0 && !dest->nonnull) {
-               debug_printf("  true null, ignored\n");
-               return 0;
-       }
-       if (ctx->pending_redirect) {
-               glob_target = &ctx->pending_redirect->word;
-       } else {
-               if (child->group) {
-                       syntax();
-                       return 1;  /* syntax error, groups and arglists don't mix */
-               }
-               if (!child->argv) {
-                       debug_printf("checking %s for reserved-ness\n",dest->data);
-                       if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
-               }
-               glob_target = &child->glob_result;
-               if (child->argv) flags |= GLOB_APPEND;
-       }
-       gr = xglob(dest, flags, glob_target);
-       if (gr != 0) return 1;
-
-       b_reset(dest);
-       if (ctx->pending_redirect) {
-               ctx->pending_redirect=NULL;
-               if (glob_target->gl_pathc != 1) {
-                       error_msg("ambiguous redirect");
-                       return 1;
-               }
-       } else {
-               child->argv = glob_target->gl_pathv;
-       }
-       return 0;
-}
-
-/* The only possible error here is out of memory, in which case
- * xmalloc exits. */
-static int done_command(struct p_context *ctx)
-{
-       /* The child is really already in the pipe structure, so
-        * advance the pipe counter and make a new, null child.
-        * Only real trickiness here is that the uncommitted
-        * child structure, to which ctx->child points, is not
-        * counted in pi->num_progs. */
-       struct pipe *pi=ctx->pipe;
-       struct child_prog *prog=ctx->child;
-
-       if (prog && prog->group == NULL
-                && prog->argv == NULL
-                && prog->redirects == NULL) {
-               debug_printf("done_command: skipping null command\n");
-               return 0;
-       } else if (prog) {
-               pi->num_progs++;
-               debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
-       } else {
-               debug_printf("done_command: initializing\n");
-       }
-       pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
-
-       prog = pi->progs + pi->num_progs;
-       prog->redirects = NULL;
-       prog->argv = NULL;
-       prog->is_stopped = 0;
-       prog->group = NULL;
-       prog->glob_result.gl_pathv = NULL;
-       prog->family = pi;
-
-       ctx->child=prog;
-       /* but ctx->pipe and ctx->list_head remain unchanged */
-       return 0;
-}
-
-static int done_pipe(struct p_context *ctx, pipe_style type)
-{
-       struct pipe *new_p;
-       done_command(ctx);  /* implicit closure of previous command */
-       debug_printf("done_pipe, type %d\n", type);
-       ctx->pipe->followup = type;
-       ctx->pipe->r_mode = ctx->w;
-       new_p=new_pipe();
-       ctx->pipe->next = new_p;
-       ctx->pipe = new_p;
-       ctx->child = NULL;
-       done_command(ctx);  /* set up new pipe to accept commands */
-       return 0;
-}
-
-/* peek ahead in the in_str to find out if we have a "&n" construct,
- * as in "2>&1", that represents duplicating a file descriptor.
- * returns either -2 (syntax error), -1 (no &), or the number found.
- */
-static int redirect_dup_num(struct in_str *input)
-{
-       int ch, d=0, ok=0;
-       ch = b_peek(input);
-       if (ch != '&') return -1;
-
-       b_getch(input);  /* get the & */
-       ch=b_peek(input);
-       if (ch == '-') {
-               b_getch(input);
-               return -3;  /* "-" represents "close me" */
-       }
-       while (isdigit(ch)) {
-               d = d*10+(ch-'0');
-               ok=1;
-               b_getch(input);
-               ch = b_peek(input);
-       }
-       if (ok) return d;
-
-       error_msg("ambiguous redirect");
-       return -2;
-}
-
-/* If a redirect is immediately preceded by a number, that number is
- * supposed to tell which file descriptor to redirect.  This routine
- * looks for such preceding numbers.  In an ideal world this routine
- * needs to handle all the following classes of redirects...
- *     echo 2>foo     # redirects fd  2 to file "foo", nothing passed to echo
- *     echo 49>foo    # redirects fd 49 to file "foo", nothing passed to echo
- *     echo -2>foo    # redirects fd  1 to file "foo",    "-2" passed to echo
- *     echo 49x>foo   # redirects fd  1 to file "foo",   "49x" passed to echo
- * A -1 output from this program means no valid number was found, so the
- * caller should use the appropriate default for this redirection.
- */
-static int redirect_opt_num(o_string *o)
-{
-       int num;
-
-       if (o->length==0) return -1;
-       for(num=0; num<o->length; num++) {
-               if (!isdigit(*(o->data+num))) {
-                       return -1;
-               }
-       }
-       /* reuse num (and save an int) */
-       num=atoi(o->data);
-       b_reset(o);
-       return num;
-}
-
-FILE *generate_stream_from_list(struct pipe *head)
-{
-       FILE *pf;
-#if 1
-       int pid, channel[2];
-       if (pipe(channel)<0) perror_msg_and_die("pipe");
-       pid=fork();
-       if (pid<0) {
-               perror_msg_and_die("fork");
-       } else if (pid==0) {
-               close(channel[0]);
-               if (channel[1] != 1) {
-                       dup2(channel[1],1);
-                       close(channel[1]);
-               }
-#if 0
-#define SURROGATE "surrogate response"
-               write(1,SURROGATE,sizeof(SURROGATE));
-               _exit(run_list(head));
-#else
-               _exit(run_list_real(head));   /* leaks memory */
-#endif
-       }
-       debug_printf("forked child %d\n",pid);
-       close(channel[1]);
-       pf = fdopen(channel[0],"r");
-       debug_printf("pipe on FILE *%p\n",pf);
-#else
-       free_pipe_list(head,0);
-       pf=popen("echo surrogate response","r");
-       debug_printf("started fake pipe on FILE *%p\n",pf);
-#endif
-       return pf;
-}
-
-/* this version hacked for testing purposes */
-/* return code is exit status of the process that is run. */
-static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
-{
-       int retcode;
-       o_string result=NULL_O_STRING;
-       struct p_context inner;
-       FILE *p;
-       struct in_str pipe_str;
-       initialize_context(&inner);
-
-       /* recursion to generate command */
-       retcode = parse_stream(&result, &inner, input, subst_end);
-       if (retcode != 0) return retcode;  /* syntax error or EOF */
-       done_word(&result, &inner);
-       done_pipe(&inner, PIPE_SEQ);
-       b_free(&result);
-
-       p=generate_stream_from_list(inner.list_head);
-       if (p==NULL) return 1;
-       mark_open(fileno(p));
-       setup_file_in_str(&pipe_str, p);
-
-       /* now send results of command back into original context */
-       retcode = parse_stream(dest, ctx, &pipe_str, '\0');
-       /* XXX In case of a syntax error, should we try to kill the child?
-        * That would be tough to do right, so just read until EOF. */
-       if (retcode == 1) {
-               while (b_getch(&pipe_str)!=EOF) { /* discard */ };
-       }
-
-       debug_printf("done reading from pipe, pclose()ing\n");
-       /* This is the step that wait()s for the child.  Should be pretty
-        * safe, since we just read an EOF from its stdout.  We could try
-        * to better, by using wait(), and keeping track of background jobs
-        * at the same time.  That would be a lot of work, and contrary
-        * to the KISS philosophy of this program. */
-       mark_closed(fileno(p));
-       retcode=pclose(p);
-       free_pipe_list(inner.list_head,0);
-       debug_printf("pclosed, retcode=%d\n",retcode);
-       /* XXX this process fails to trim a single trailing newline */
-       return retcode;
-}
-
-static int parse_group(o_string *dest, struct p_context *ctx,
-       struct in_str *input, int ch)
-{
-       int rcode, endch=0;
-       struct p_context sub;
-       struct child_prog *child = ctx->child;
-       if (child->argv) {
-               syntax();
-               return 1;  /* syntax error, groups and arglists don't mix */
-       }
-       initialize_context(&sub);
-       switch(ch) {
-               case '(': endch=')'; child->subshell=1; break;
-               case '{': endch='}'; break;
-               default: syntax();   /* really logic error */
-       }
-       rcode=parse_stream(dest,&sub,input,endch);
-       done_word(dest,&sub); /* finish off the final word in the subcontext */
-       done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
-       child->group = sub.list_head;
-       return rcode;
-       /* child remains "open", available for possible redirects */
-}
-
-/* basically useful version until someone wants to get fancier,
- * see the bash man page under "Parameter Expansion" */
-static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src)
-{
-       const char *p=NULL;
-       if (src->data) { 
-               p = getenv(src->data);
-               if (!p) 
-                       p = get_local_var(src->data);
-       }
-       if (p) parse_string(dest, ctx, p);   /* recursion */
-       b_free(src);
-}
-
-/* return code: 0 for OK, 1 for syntax error */
-static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
-{
-       int i, advance=0;
-       o_string alt=NULL_O_STRING;
-       char sep[]=" ";
-       int ch = input->peek(input);  /* first character after the $ */
-       debug_printf("handle_dollar: ch=%c\n",ch);
-       if (isalpha(ch)) {
-               while(ch=b_peek(input),isalnum(ch) || ch=='_') {
-                       b_getch(input);
-                       b_addchr(&alt,ch);
-               }
-               lookup_param(dest, ctx, &alt);
-       } else if (isdigit(ch)) {
-               i = ch-'0';  /* XXX is $0 special? */
-               if (i<global_argc) {
-                       parse_string(dest, ctx, global_argv[i]); /* recursion */
-               }
-               advance = 1;
-       } else switch (ch) {
-               case '$':
-                       b_adduint(dest,getpid());
-                       advance = 1;
-                       break;
-               case '!':
-                       if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
-                       advance = 1;
-                       break;
-               case '?':
-                       b_adduint(dest,last_return_code);
-                       advance = 1;
-                       break;
-               case '#':
-                       b_adduint(dest,global_argc ? global_argc-1 : 0);
-                       advance = 1;
-                       break;
-               case '{':
-                       b_getch(input);
-                       /* XXX maybe someone will try to escape the '}' */
-                       while(ch=b_getch(input),ch!=EOF && ch!='}') {
-                               b_addchr(&alt,ch);
-                       }
-                       if (ch != '}') {
-                               syntax();
-                               return 1;
-                       }
-                       lookup_param(dest, ctx, &alt);
-                       break;
-               case '(':
-                       b_getch(input);
-                       process_command_subs(dest, ctx, input, ')');
-                       break;
-               case '*':
-                       sep[0]=ifs[0];
-                       for (i=1; i<global_argc; i++) {
-                               parse_string(dest, ctx, global_argv[i]);
-                               if (i+1 < global_argc) parse_string(dest, ctx, sep);
-                       }
-                       break;
-               case '@':
-               case '-':
-               case '_':
-                       /* still unhandled, but should be eventually */
-                       error_msg("unhandled syntax: $%c",ch);
-                       return 1;
-                       break;
-               default:
-                       b_addqchr(dest,'$',dest->quote);
-       }
-       /* Eat the character if the flag was set.  If the compiler
-        * is smart enough, we could substitute "b_getch(input);"
-        * for all the "advance = 1;" above, and also end up with
-        * a nice size-optimized program.  Hah!  That'll be the day.
-        */
-       if (advance) b_getch(input);
-       return 0;
-}
-
-int parse_string(o_string *dest, struct p_context *ctx, const char *src)
-{
-       struct in_str foo;
-       setup_string_in_str(&foo, src);
-       return parse_stream(dest, ctx, &foo, '\0');
-}
-
-/* return code is 0 for normal exit, 1 for syntax error */
-int parse_stream(o_string *dest, struct p_context *ctx,
-       struct in_str *input, int end_trigger)
-{
-       unsigned int ch, m;
-       int redir_fd;
-       redir_type redir_style;
-       int next;
-
-       /* Only double-quote state is handled in the state variable dest->quote.
-        * A single-quote triggers a bypass of the main loop until its mate is
-        * found.  When recursing, quote state is passed in via dest->quote. */
-
-       debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
-       while ((ch=b_getch(input))!=EOF) {
-               m = map[ch];
-               next = (ch == '\n') ? 0 : b_peek(input);
-               debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
-                       ch,ch,m,dest->quote);
-               if (m==0 || ((m==1 || m==2) && dest->quote)) {
-                       b_addqchr(dest, ch, dest->quote);
-               } else {
-                       if (m==2) {  /* unquoted IFS */
-                               done_word(dest, ctx);
-                               /* If we aren't performing a substitution, treat a newline as a
-                                * command separator.  */
-                               if (end_trigger != '\0' && ch=='\n')
-                                       done_pipe(ctx,PIPE_SEQ);
-                       }
-                       if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
-                               debug_printf("leaving parse_stream (triggered)\n");
-                               return 0;
-                       }
-#if 0
-                       if (ch=='\n') {
-                               /* Yahoo!  Time to run with it! */
-                               done_pipe(ctx,PIPE_SEQ);
-                               run_list(ctx->list_head);
-                               initialize_context(ctx);
-                       }
-#endif
-                       if (m!=2) switch (ch) {
-               case '#':
-                       if (dest->length == 0 && !dest->quote) {
-                               while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
-                       } else {
-                               b_addqchr(dest, ch, dest->quote);
-                       }
-                       break;
-               case '\\':
-                       if (next == EOF) {
-                               syntax();
-                               return 1;
-                       }
-                       b_addqchr(dest, '\\', dest->quote);
-                       b_addqchr(dest, b_getch(input), dest->quote);
-                       break;
-               case '$':
-                       if (handle_dollar(dest, ctx, input)!=0) return 1;
-                       break;
-               case '\'':
-                       dest->nonnull = 1;
-                       while(ch=b_getch(input),ch!=EOF && ch!='\'') {
-                               b_addchr(dest,ch);
-                       }
-                       if (ch==EOF) {
-                               syntax();
-                               return 1;
-                       }
-                       break;
-               case '"':
-                       dest->nonnull = 1;
-                       dest->quote = !dest->quote;
-                       break;
-               case '`':
-                       process_command_subs(dest, ctx, input, '`');
-                       break;
-               case '>':
-                       redir_fd = redirect_opt_num(dest);
-                       done_word(dest, ctx);
-                       redir_style=REDIRECT_OVERWRITE;
-                       if (next == '>') {
-                               redir_style=REDIRECT_APPEND;
-                               b_getch(input);
-                       } else if (next == '(') {
-                               syntax();   /* until we support >(list) Process Substitution */
-                               return 1;
-                       }
-                       setup_redirect(ctx, redir_fd, redir_style, input);
-                       break;
-               case '<':
-                       redir_fd = redirect_opt_num(dest);
-                       done_word(dest, ctx);
-                       redir_style=REDIRECT_INPUT;
-                       if (next == '<') {
-                               redir_style=REDIRECT_HEREIS;
-                               b_getch(input);
-                       } else if (next == '>') {
-                               redir_style=REDIRECT_IO;
-                               b_getch(input);
-                       } else if (next == '(') {
-                               syntax();   /* until we support <(list) Process Substitution */
-                               return 1;
-                       }
-                       setup_redirect(ctx, redir_fd, redir_style, input);
-                       break;
-               case ';':
-                       done_word(dest, ctx);
-                       done_pipe(ctx,PIPE_SEQ);
-                       break;
-               case '&':
-                       done_word(dest, ctx);
-                       if (next=='&') {
-                               b_getch(input);
-                               done_pipe(ctx,PIPE_AND);
-                       } else {
-                               done_pipe(ctx,PIPE_BG);
-                       }
-                       break;
-               case '|':
-                       done_word(dest, ctx);
-                       if (next=='|') {
-                               b_getch(input);
-                               done_pipe(ctx,PIPE_OR);
-                       } else {
-                               /* we could pick up a file descriptor choice here
-                                * with redirect_opt_num(), but bash doesn't do it.
-                                * "echo foo 2| cat" yields "foo 2". */
-                               done_command(ctx);
-                       }
-                       break;
-               case '(':
-               case '{':
-                       if (parse_group(dest, ctx, input, ch)!=0) return 1;
-                       break;
-               case ')':
-               case '}':
-                       syntax();   /* Proper use of this character caught by end_trigger */
-                       return 1;
-                       break;
-               default:
-                       syntax();   /* this is really an internal logic error */
-                       return 1;
-                       }
-               }
-       }
-       /* complain if quote?  No, maybe we just finished a command substitution
-        * that was quoted.  Example:
-        * $ echo "`cat foo` plus more" 
-        * and we just got the EOF generated by the subshell that ran "cat foo"
-        * The only real complaint is if we got an EOF when end_trigger != '\0',
-        * that is, we were really supposed to get end_trigger, and never got
-        * one before the EOF.  Can't use the standard "syntax error" return code,
-        * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
-       debug_printf("leaving parse_stream (EOF)\n");
-       if (end_trigger != '\0') return -1;
-       return 0;
-}
-
-void mapset(const unsigned char *set, int code)
-{
-       const unsigned char *s;
-       for (s=set; *s; s++) map[*s] = code;
-}
-
-void update_ifs_map(void)
-{
-       /* char *ifs and char map[256] are both globals. */
-       ifs = getenv("IFS");
-       if (ifs == NULL) ifs=" \t\n";
-       /* Precompute a list of 'flow through' behavior so it can be treated
-        * quickly up front.  Computation is necessary because of IFS.
-        * Special case handling of IFS == " \t\n" is not implemented.
-        * The map[] array only really needs two bits each, and on most machines
-        * that would be faster because of the reduced L1 cache footprint.
-        */
-       memset(map,0,sizeof(map)); /* most characters flow through always */
-       mapset("\\$'\"`", 3);      /* never flow through */
-       mapset("<>;&|(){}#", 1);   /* flow through if quoted */
-       mapset(ifs, 2);            /* also flow through if quoted */
-}
-
-/* most recursion does not come through here, the exeception is
- * from builtin_source() */
-int parse_stream_outer(struct in_str *inp)
-{
-
-       struct p_context ctx;
-       o_string temp=NULL_O_STRING;
-       int rcode;
-       do {
-               initialize_context(&ctx);
-               update_ifs_map();
-               inp->promptmode=1;
-               rcode = parse_stream(&temp, &ctx, inp, '\n');
-               done_word(&temp, &ctx);
-               done_pipe(&ctx,PIPE_SEQ);
-               run_list(ctx.list_head);
-               b_free(&temp);
-       } while (rcode != -1);   /* loop on syntax errors, return on EOF */
-       return 0;
-}
-
-static int parse_string_outer(const char *s)
-{
-       struct in_str input;
-       setup_string_in_str(&input, s);
-       return parse_stream_outer(&input);
-}
-
-static int parse_file_outer(FILE *f)
-{
-       int rcode;
-       struct in_str input;
-       setup_file_in_str(&input, f);
-       rcode = parse_stream_outer(&input);
-       return rcode;
-}
-
-/* Make sure we have a controlling tty.  If we get started under a job
- * aware app (like bash for example), make sure we are now in charge so
- * we don't fight over who gets the foreground */
-static void setup_job_control()
-{
-       static pid_t shell_pgrp;
-       /* Loop until we are in the foreground.  */
-       while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
-               kill (- shell_pgrp, SIGTTIN);
-
-       /* Ignore interactive and job-control signals.  */
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGTERM, SIG_IGN);
-       signal(SIGTSTP, SIG_IGN);
-       signal(SIGTTIN, SIG_IGN);
-       signal(SIGTTOU, SIG_IGN);
-       signal(SIGCHLD, SIG_IGN);
-
-       /* Put ourselves in our own process group.  */
-       setsid();
-       shell_pgrp = getpid ();
-       setpgid (shell_pgrp, shell_pgrp);
-
-       /* Grab control of the terminal.  */
-       tcsetpgrp(shell_terminal, shell_pgrp);
-}
-
-int hush_main(int argc, char **argv)
-{
-       int opt;
-       FILE *input;
-       char **e = environ;
-
-       /* XXX what should these be while sourcing /etc/profile? */
-       global_argc = argc;
-       global_argv = argv;
-       
-       /* (re?) initialize globals.  Sometimes hush_main() ends up calling
-        * hush_main(), therefore we cannot rely on the BSS to zero out this 
-        * stuff.  Reset these to 0 every time. */
-       ifs = NULL;
-       /* map[] is taken care of with call to update_ifs_map() */
-       fake_mode = 0;
-       interactive = 0;
-       close_me_head = NULL;
-       last_bg_pid = 0;
-       job_list = NULL;
-       last_jobid = 0;
-
-       /* Initialize some more globals to non-zero values */
-       set_cwd();
-#ifdef BB_FEATURE_COMMAND_EDITING
-       cmdedit_set_initial_prompt();
-#else
-       PS1 = NULL;
-#endif
-       PS2 = "> ";
-
-       /* initialize our shell local variables with the values 
-        * currently living in the environment */
-       if (e) {
-               for (; *e; e++)
-                       set_local_var(*e, 2);   /* without call putenv() */
-       }
-
-       last_return_code=EXIT_SUCCESS;
-
-
-       if (argv[0] && argv[0][0] == '-') {
-               debug_printf("\nsourcing /etc/profile\n");
-               if ((input = fopen("/etc/profile", "r")) != NULL) {
-                       mark_open(fileno(input));
-                       parse_file_outer(input);
-                       mark_closed(fileno(input));
-                       fclose(input);
-               }
-       }
-       input=stdin;
-       
-       while ((opt = getopt(argc, argv, "c:xif")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               {
-                                       global_argv = argv+optind;
-                                       global_argc = argc-optind;
-                                       opt = parse_string_outer(optarg);
-                                       goto final_return;
-                               }
-                               break;
-                       case 'i':
-                               interactive++;
-                               break;
-                       case 'f':
-                               fake_mode++;
-                               break;
-                       default:
-#ifndef BB_VER
-                               fprintf(stderr, "Usage: sh [FILE]...\n"
-                                               "   or: sh -c command [args]...\n\n");
-                               exit(EXIT_FAILURE);
-#else
-                               show_usage();
-#endif
-               }
-       }
-       /* A shell is interactive if the `-i' flag was given, or if all of
-        * the following conditions are met:
-        *        no -c command
-        *    no arguments remaining or the -s flag given
-        *    standard input is a terminal
-        *    standard output is a terminal
-        *    Refer to Posix.2, the description of the `sh' utility. */
-       if (argv[optind]==NULL && input==stdin &&
-                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
-               interactive++;
-       }
-
-       debug_printf("\ninteractive=%d\n", interactive);
-       if (interactive) {
-               /* Looks like they want an interactive shell */
-               fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
-               setup_job_control();
-       }
-       
-       if (argv[optind]==NULL) {
-               opt=parse_file_outer(stdin);
-               goto final_return;
-       }
-
-       debug_printf("\nrunning script '%s'\n", argv[optind]);
-       global_argv = argv+optind;
-       global_argc = argc-optind;
-       input = xfopen(argv[optind], "r");
-       opt = parse_file_outer(input);
-
-#ifdef BB_FEATURE_CLEAN_UP
-       fclose(input);
-       if (cwd && cwd != unknown)
-               free((char*)cwd);
-       {
-               struct variables *cur, *tmp;
-               for(cur = top_vars; cur; cur = tmp) {
-                       tmp = cur->next;
-                       if (!cur->flg_read_only) {
-                               free(cur->name);
-                               free(cur->value);
-                               free(cur);
-                       }
-               }
-       }
-#endif
-
-final_return:
-       return(opt?opt:last_return_code);
-}
diff --git a/busybox/id.c b/busybox/id.c
deleted file mode 100644 (file)
index 85b288c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini id implementation for busybox
- *
- * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <string.h>
-#include <sys/types.h>
-
-extern int id_main(int argc, char **argv)
-{
-       int no_user = 0, no_group = 0, print_real = 0;
-       int name_not_number = 0;
-       char user[9], group[9];
-       long gid;
-       long pwnam, grnam;
-       int opt;
-       
-       gid = 0;
-
-       while ((opt = getopt(argc, argv, "ugrn")) > 0) {
-               switch (opt) {
-                       case 'u':
-                               no_group++;
-                               break;
-                       case 'g':
-                               no_user++;
-                               break;
-                       case 'r':
-                               print_real++;
-                               break;
-                       case 'n':
-                               name_not_number++;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (no_user && no_group) show_usage();
-
-       if (argv[optind] == NULL) {
-               if (print_real) {
-                       my_getpwuid(user, getuid());
-                       my_getgrgid(group, getgid());
-               } else {
-                       my_getpwuid(user, geteuid());
-                       my_getgrgid(group, getegid());
-               }
-       } else {
-               strncpy(user, argv[optind], 8);
-               user[8] = '\0';
-           gid = my_getpwnamegid(user);
-               my_getgrgid(group, gid);
-       }
-
-       pwnam=my_getpwnam(user);
-       grnam=my_getgrnam(group);
-
-       if (no_group) {
-               if(name_not_number && user)
-                       puts(user);
-               else
-                       printf("%ld\n", pwnam);
-       } else if (no_user) {
-               if(name_not_number && group)
-                       puts(group);
-               else
-                       printf("%ld\n", grnam);
-       } else {
-               printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group);
-       }
-       return(0);
-}
-
-
-/* END CODE */
diff --git a/busybox/ifconfig.c b/busybox/ifconfig.c
deleted file mode 100644 (file)
index 5f8b0ee..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/* ifconfig
- *
- * Similar to the standard Unix ifconfig, but with only the necessary
- * parts for AF_INET, and without any printing of if info (for now).
- *
- * Bjorn Wesen, Axis Communications AB
- *
- *
- * Authors of the original ifconfig was:      
- *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * This program is free software; you can redistribute it
- * and/or  modify it under  the terms of  the GNU General
- * Public  License as  published  by  the  Free  Software
- * Foundation;  either  version 2 of the License, or  (at
- * your option) any later version.
- *
- * $Id: ifconfig.c,v 1.11.2.1 2001/08/10 18:22:15 andersen Exp $
- *
- */
-
-/*
- * Heavily modified by Manuel Novoa III       Mar 6, 2001
- *
- * From initial port to busybox, removed most of the redundancy by
- * converting to a table-driven approach.  Added several (optional)
- * args missing from initial port.
- *
- * Still missing:  media, tunnel.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>   // strcmp and friends
-#include <ctype.h>    // isdigit and friends
-#include <stddef.h>                            /* offsetof */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <linux/if_ether.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_IFCONFIG_SLIP
-#include <linux/if_slip.h>
-#endif
-
-/* I don't know if this is needed for busybox or not.  Anyone? */
-#define QUESTIONABLE_ALIAS_CASE
-
-
-/* Defines for glibc2.0 users. */
-#ifndef SIOCSIFTXQLEN
-#define SIOCSIFTXQLEN      0x8943
-#define SIOCGIFTXQLEN      0x8942
-#endif
-
-/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
-#ifndef ifr_qlen
-#define ifr_qlen        ifr_ifru.ifru_mtu
-#endif
-
-#ifndef IFF_DYNAMIC
-#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
-#endif
-
-/*
- * Here are the bit masks for the "flags" member of struct options below.
- * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
- * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
- */
-#define N_CLR            0x01
-#define M_CLR            0x02
-#define N_SET            0x04
-#define M_SET            0x08
-#define N_ARG            0x10
-#define M_ARG            0x20
-
-#define M_MASK           (M_CLR | M_SET | M_ARG)
-#define N_MASK           (N_CLR | N_SET | N_ARG)
-#define SET_MASK         (N_SET | M_SET)
-#define CLR_MASK         (N_CLR | M_CLR)
-#define SET_CLR_MASK     (SET_MASK | CLR_MASK)
-#define ARG_MASK         (M_ARG | N_ARG)
-
-/*
- * Here are the bit masks for the "arg_flags" member of struct options below.
- */
-
-/*
- * cast type:
- *   00 int
- *   01 char *
- *   02 HOST_COPY in_ether
- *   03 HOST_COPY INET_resolve
- */
-#define A_CAST_TYPE      0x03
-/*
- * map type:
- *   00 not a map type (mem_start, io_addr, irq)
- *   04 memstart (unsigned long)
- *   08 io_addr  (unsigned short)
- *   0C irq      (unsigned char)
- */
-#define A_MAP_TYPE       0x0C
-#define A_ARG_REQ        0x10  /* Set if an arg is required. */
-#define A_NETMASK        0x20  /* Set if netmask (check for multiple sets). */
-#define A_SET_AFTER      0x40  /* Set a flag at the end. */
-#define A_COLON_CHK      0x80  /* Is this needed?  See below. */
-
-/*
- * These defines are for dealing with the A_CAST_TYPE field.
- */
-#define A_CAST_CHAR_PTR  0x01
-#define A_CAST_RESOLVE   0x01
-#define A_CAST_HOST_COPY 0x02
-#define A_CAST_HOST_COPY_IN_ETHER    A_CAST_HOST_COPY
-#define A_CAST_HOST_COPY_RESOLVE     (A_CAST_HOST_COPY | A_CAST_RESOLVE)
-
-/*
- * These defines are for dealing with the A_MAP_TYPE field.
- */
-#define A_MAP_ULONG      0x04  /* memstart */
-#define A_MAP_USHORT     0x08  /* io_addr */
-#define A_MAP_UCHAR      0x0C  /* irq */
-
-/*
- * Define the bit masks signifying which operations to perform for each arg.
- */
-
-#define ARG_METRIC       (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_MTU          (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_TXQUEUELEN   (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_MEM_START    (A_ARG_REQ | A_MAP_ULONG)
-#define ARG_IO_ADDR      (A_ARG_REQ | A_MAP_USHORT)
-#define ARG_IRQ          (A_ARG_REQ | A_MAP_UCHAR)
-#define ARG_DSTADDR      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
-#define ARG_NETMASK      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
-#define ARG_BROADCAST    (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
-#define ARG_HW           (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
-#define ARG_POINTOPOINT  (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
-#define ARG_KEEPALIVE    (A_ARG_REQ | A_CAST_CHAR_PTR)
-#define ARG_OUTFILL      (A_ARG_REQ | A_CAST_CHAR_PTR)
-#define ARG_HOSTNAME     (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
-
-
-/*
- * Set up the tables.  Warning!  They must have corresponding order!
- */
-
-struct arg1opt {
-       const char *name;
-       unsigned short selector;
-       unsigned short ifr_offset;
-};
-
-struct options {
-       const char *name;
-       const unsigned char flags;
-       const unsigned char arg_flags;
-       const unsigned short selector;
-};
-
-#define ifreq_offsetof(x)  offsetof(struct ifreq, x)
-
-static const struct arg1opt Arg1Opt[] = {
-       {"SIOCSIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric)},
-       {"SIOCSIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu)},
-       {"SIOCSIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen)},
-       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
-       {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
-       {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
-#ifdef BB_FEATURE_IFCONFIG_HW
-       {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
-#endif
-       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
-#ifdef SIOCSKEEPALIVE
-       {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
-#endif
-#ifdef SIOCSOUTFILL
-       {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)},
-#endif
-       /* Last entry if for unmatched (possibly hostname) arg. */
-       {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)},
-};
-
-static const struct options OptArray[] = {
-       {"metric",       N_ARG,         ARG_METRIC,      0},
-    {"mtu",          N_ARG,         ARG_MTU,         0},
-       {"txqueuelen",   N_ARG,         ARG_TXQUEUELEN,  0},
-       {"dstaddr",      N_ARG,         ARG_DSTADDR,     0},
-       {"netmask",      N_ARG,         ARG_NETMASK,     0},
-       {"broadcast",    N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
-#ifdef BB_FEATURE_IFCONFIG_HW
-       {"hw",           N_ARG,         ARG_HW,          0},
-#endif
-       {"pointopoint",  N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
-#ifdef SIOCSKEEPALIVE
-       {"keepalive",    N_ARG,         ARG_KEEPALIVE,   0},
-#endif
-#ifdef SIOCSOUTFILL
-       {"outfill",      N_ARG,         ARG_OUTFILL,     0},
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-       {"mem_start",    N_ARG,         ARG_MEM_START,   0},
-       {"io_addr",      N_ARG,         ARG_IO_ADDR,     0},
-       {"irq",          N_ARG,         ARG_IRQ,         0},
-#endif
-       {"arp",          N_CLR | M_SET, 0,               IFF_NOARP},
-       {"trailers",     N_CLR | M_SET, 0,               IFF_NOTRAILERS},
-       {"promisc",      N_SET | M_CLR, 0,               IFF_PROMISC},
-       {"multicast",    N_SET | M_CLR, 0,               IFF_MULTICAST},
-       {"allmulti",     N_SET | M_CLR, 0,               IFF_ALLMULTI},
-       {"dynamic",      N_SET | M_CLR, 0,               IFF_DYNAMIC},
-       {"up",           N_SET        , 0,               (IFF_UP | IFF_RUNNING)},
-       {"down",         N_CLR        , 0,               IFF_UP},
-       { NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING)}
-};
-
-/*
- * A couple of prototypes.
- */
-
-#ifdef BB_FEATURE_IFCONFIG_HW
-static int in_ether(char *bufp, struct sockaddr *sap);
-#endif
-
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-extern int interface_opt_a;
-extern int display_interfaces(char *ifname);
-#endif
-
-/*
- * Our main function.
- */
-
-int ifconfig_main(int argc, char **argv)
-{
-       struct ifreq ifr;
-       struct sockaddr_in sai;
-#ifdef BB_FEATURE_IFCONFIG_HW
-       struct sockaddr sa;
-#endif
-       const struct arg1opt *a1op;
-       const struct options *op;
-       int sockfd;  /* socket fd we use to manipulate stuff with */
-       int goterr;
-       int selector;
-       char *p;
-       char host[128];
-       unsigned char mask;
-       unsigned char did_flags;
-
-       goterr = 0;
-       did_flags = 0;
-
-       /* skip argv[0] */
-       ++argv;
-       --argc;
-
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-       if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
-               interface_opt_a = 1;
-               --argc;
-               ++argv;
-       }
-#endif
-
-       if(argc <= 1) {
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-               return display_interfaces(argc ? *argv : NULL);
-#else
-               error_msg_and_die( "ifconfig was not compiled with interface status display support.");
-#endif
-       }
-
-       /* Create a channel to the NET kernel. */
-       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror_msg_and_die("socket");
-       }
-
-       /* get interface name */
-       safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
-
-       /* Process the remaining arguments. */
-       while (*++argv != (char *) NULL) {
-               p = *argv;
-               mask = N_MASK;
-               if (*p == '-') {                /* If the arg starts with '-'... */
-                       ++p;                            /*    advance past it and */
-                       mask = M_MASK;          /*    set the appropriate mask. */
-               }
-               for (op = OptArray ; op->name ; op++) { /* Find table entry. */
-                       if (strcmp(p,op->name) == 0) { /* If name matches... */
-                               if ((mask &= op->flags)) { /* set the mask and go. */
-                                   goto FOUND_ARG;;
-                               }
-                               /* If we get here, there was a valid arg with an */
-                               /* invalid '-' prefix. */
-                               ++goterr;
-                               goto LOOP;
-                       }
-               }
-               
-               /* We fell through, so treat as possible hostname. */
-               a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
-               mask = op->arg_flags;
-               goto HOSTNAME;
-
-       FOUND_ARG:
-               if (mask & ARG_MASK) {
-                       mask = op->arg_flags;
-                       a1op = Arg1Opt + (op - OptArray);
-                       if (mask & A_NETMASK & did_flags) {
-                               show_usage();
-                       }
-                       if (*++argv == NULL) {
-                               if (mask & A_ARG_REQ) {
-                                       show_usage();
-                               } else {
-                                       --argv;
-                                       mask &= A_SET_AFTER; /* just for broadcast */
-                               }
-                       } else {                        /* got an arg so process it */
-                       HOSTNAME:
-                               did_flags |= (mask & A_NETMASK);
-                               if (mask & A_CAST_HOST_COPY) {
-#ifdef BB_FEATURE_IFCONFIG_HW
-                                       if (mask & A_CAST_RESOLVE) {
-#endif
-                                               safe_strncpy(host, *argv, (sizeof host));
-                                               sai.sin_family = AF_INET;
-                                               sai.sin_port = 0;
-                                               if (!strcmp(host, "default")) {
-                                                       /* Default is special, meaning 0.0.0.0. */
-                                                       sai.sin_addr.s_addr = INADDR_ANY;
-                                               } else if (inet_aton(host, &sai.sin_addr) == 0) {
-                                                       /* It's not a dotted quad. */
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               p = (char *) &sai;
-#ifdef BB_FEATURE_IFCONFIG_HW
-                                       } else { /* A_CAST_HOST_COPY_IN_ETHER */
-                                               /* This is the "hw" arg case. */
-                                               if (strcmp("ether", *argv) || (*++argv == NULL)) {
-                                                       show_usage();
-                                               }
-                                               safe_strncpy(host, *argv, (sizeof host));
-                                               if (in_ether(host, &sa)) {
-                                                       fprintf(stderr, "invalid hw-addr %s\n", host);
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               p = (char *) &sa;
-                                       }
-#endif
-                                       memcpy((((char *)(&ifr)) + a1op->ifr_offset),
-                                                  p, sizeof(struct sockaddr));
-                               } else {
-                                       unsigned int i = strtoul(*argv,NULL,0);
-                                       p = ((char *)(&ifr)) + a1op->ifr_offset;
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-                                       if (mask & A_MAP_TYPE) {
-                                               if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
-                                                       *((unsigned char *) p) = i;
-                                               } else if (mask & A_MAP_USHORT) {
-                                                       *((unsigned short *) p) = i;
-                                               } else {
-                                                       *((unsigned long *) p) = i;
-                                               }
-                                       } else
-#endif
-                                       if (mask & A_CAST_CHAR_PTR) {
-                                               *((caddr_t *) p) = (caddr_t) i;
-                                       } else { /* A_CAST_INT */
-                                               *((int *) p) = i;
-                                       }
-                               }
-                                               
-                               if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
-                                       perror(a1op->name);
-                                       ++goterr;
-                                       continue;
-                               }
-
-#ifdef QUESTIONABLE_ALIAS_CASE
-                               if (mask & A_COLON_CHK) {
-                                       /*
-                                        * Don't do the set_flag() if the address is an alias with
-                                        * a - at the end, since it's deleted already! - Roman
-                                        *
-                                        * Should really use regex.h here, not sure though how well
-                                        * it'll go with the cross-platform support etc. 
-                                        */
-                                       char *ptr;
-                                       short int found_colon = 0;
-                                       for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
-                                               if (*ptr == ':') {
-                                                       found_colon++;
-                                               }
-                                       }
-                       
-                                       if (found_colon && *(ptr - 1) == '-') {
-                                               continue;
-                                       }
-                               }
-#endif
-                       }
-                       if (!(mask & A_SET_AFTER)) {
-                               continue;
-                       }
-                       mask = N_SET;
-               }
-
-               if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
-                       perror("SIOCGIFFLAGS"); 
-                       ++goterr;
-               } else {
-                       selector = op->selector;
-                       if (mask & SET_MASK) {
-                               ifr.ifr_flags |= selector;
-                       } else {
-                               ifr.ifr_flags &= ~selector;
-                       }
-                       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
-                               perror("SIOCSIFFLAGS"); 
-                               ++goterr;
-                       }
-               }
-       LOOP:
-       } /* end of while-loop */
-
-       return goterr;
-}
-
-#ifdef BB_FEATURE_IFCONFIG_HW
-/* Input an Ethernet address and convert to binary. */
-static int
-in_ether(char *bufp, struct sockaddr *sap)
-{
-       unsigned char *ptr;
-       int i, j;
-       unsigned char val;
-       unsigned char c;
-       
-       sap->sa_family = ARPHRD_ETHER;
-       ptr = sap->sa_data;
-       
-       for (i = 0 ; i < ETH_ALEN ; i++) {
-               val = 0;
-
-               /* We might get a semicolon here - not required. */
-               if (i && (*bufp == ':')) {
-                       bufp++;
-               }
-
-               for (j=0 ; j<2 ; j++) {
-                       c = *bufp;
-                       if (c >= '0' && c <= '9') {
-                               c -= '0';
-                       } else if (c >= 'a' && c <= 'f') {
-                               c -= ('a' - 10);
-                       } else if (c >= 'A' && c <= 'F') {
-                               c -= ('A' - 10);
-                       } else if (j && (c == ':' || c == 0)) {
-                               break;
-                       } else {
-                               return -1;
-                       }
-                       ++bufp;
-                       val <<= 4;
-                       val += c;
-               }
-               *ptr++ = val;
-       }
-
-       return (int) (*bufp);           /* Error if we don't end at end of string. */
-}
-#endif
diff --git a/busybox/include/applets.h b/busybox/include/applets.h
deleted file mode 100644 (file)
index 7d75173..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * applets.h - a listing of all busybox applets.
- *
- * If you write a new applet, you need to add an entry to this list to make
- * busybox aware of it.
- *
- * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary
- * search lookup contributed by Gaute B Strokkenes stops working. If you value
- * your kneecaps, you'll be sure to *make sure* that any changes made to this
- * file result in the listing remaining in ascii order. You have been warned.
- */
-
-#undef APPLET
-#undef APPLET_ODDNAME
-#undef APPLET_NOUSAGE
-
-
-#if defined(PROTOTYPES)
-  #define APPLET(a,b,c) extern int b(int argc, char **argv);
-  #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv);
-  #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv);
-  extern const char usage_messages[];
-#elif defined(MAKE_USAGE)
-  #ifdef BB_FEATURE_VERBOSE_USAGE
-    #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0"
-    #define APPLET_NOUSAGE(a,b,c) "\0"
-    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0"
-  #else
-    #define APPLET(a,b,c) a##_trivial_usage "\0"
-    #define APPLET_NOUSAGE(a,b,c) "\0"
-    #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0"
-  #endif
-#elif defined(MAKE_LINKS)
-#  define APPLET(a,b,c) LINK c a
-#  define APPLET_NOUSAGE(a,b,c) LINK c a
-#  define APPLET_ODDNAME(a,b,c,d) LINK c a
-#else
-  const struct BB_applet applets[] = {
-  #define APPLET(a,b,c) {#a,b,c},
-  #define APPLET_NOUSAGE(a,b,c) {a,b,c},
-  #define APPLET_ODDNAME(a,b,c,d) {a,b,c},
-#endif
-
-
-
-#ifdef BB_TEST
-       APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_ADJTIMEX
-       APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_AR
-       APPLET(ar, ar_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_ASH
-       APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_BASENAME
-       APPLET(basename, basename_main, _BB_DIR_USR_BIN)
-#endif
-       APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN)
-#ifdef BB_CAT
-       APPLET(cat, cat_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHGRP
-       APPLET(chgrp, chgrp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHMOD
-       APPLET(chmod, chmod_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHOWN
-       APPLET(chown, chown_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CHROOT
-       APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_CHVT
-       APPLET(chvt, chvt_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CLEAR
-       APPLET(clear, clear_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CMP
-       APPLET(cmp, cmp_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_CP
-       APPLET(cp, cp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CPIO
-       APPLET(cpio, cpio_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_CUT
-       APPLET(cut, cut_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DATE
-       APPLET(date, date_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DC
-       APPLET(dc, dc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DD
-       APPLET(dd, dd_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DEALLOCVT
-       APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DF
-       APPLET(df, df_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DIRNAME
-       APPLET(dirname, dirname_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DMESG
-       APPLET(dmesg, dmesg_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DOS2UNIX
-       APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DPKG
-       APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DPKG_DEB
-       APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb)
-#endif
-#ifdef BB_DU
-       APPLET(du, du_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_DUMPKMAP
-       APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_DUTMP
-       APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_ECHO
-       APPLET(echo, echo_main, _BB_DIR_BIN)
-#endif
-#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP)
-       APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_ENV
-       APPLET(env, env_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_EXPR
-       APPLET(expr, expr_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRUE_FALSE
-       APPLET(false, false_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_FBSET
-       APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN)
-#endif
-#ifdef BB_FDFLUSH
-       APPLET(fdflush, fdflush_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_FIND
-       APPLET(find, find_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FREE
-       APPLET(free, free_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FREERAMDISK
-       APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_FSCK_MINIX
-       APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix)
-#endif
-#ifdef BB_GETOPT
-       APPLET(getopt, getopt_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GREP
-       APPLET(grep, grep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GUNZIP
-       APPLET(gunzip, gunzip_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_GZIP
-       APPLET(gzip, gzip_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_HALT
-       APPLET(halt, halt_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_HEAD
-       APPLET(head, head_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_HOSTID
-       APPLET(hostid, hostid_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_HOSTNAME
-       APPLET(hostname, hostname_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_HUSH
-       APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_ID
-       APPLET(id, id_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_IFCONFIG
-       APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_INIT
-       APPLET(init, init_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_INSMOD
-       APPLET(insmod, insmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_KILL
-       APPLET(kill, kill_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_KILLALL
-       APPLET(killall, kill_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_KLOGD
-       APPLET(klogd, klogd_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LASH
-       APPLET(lash, lash_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LENGTH
-       APPLET(length, length_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_FEATURE_LINUXRC
-       APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT)
-#endif
-#ifdef BB_LN
-       APPLET(ln, ln_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LOADACM
-       APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOADFONT
-       APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOADKMAP
-       APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LOGGER
-       APPLET(logger, logger_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOGNAME
-       APPLET(logname, logname_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_LOGREAD
-       APPLET(logread, logread_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_LS
-       APPLET(ls, ls_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_LSMOD
-       APPLET(lsmod, lsmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MAKEDEVS
-       APPLET(makedevs, makedevs_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MD5SUM
-       APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_MKDIR
-       APPLET(mkdir, mkdir_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MKFIFO
-       APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_MKFS_MINIX
-       APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix)
-#endif
-#ifdef BB_MKNOD
-       APPLET(mknod, mknod_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MKSWAP
-       APPLET(mkswap, mkswap_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MKTEMP
-       APPLET(mktemp, mktemp_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MODPROBE
-       APPLET(modprobe, modprobe_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_MORE
-       APPLET(more, more_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MOUNT
-       APPLET(mount, mount_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MSH
-       APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MT
-       APPLET(mt, mt_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_MV
-       APPLET(mv, mv_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_NC
-       APPLET(nc, nc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_NSLOOKUP
-       APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_PIDOF
-       APPLET(pidof, pidof_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PING
-       APPLET(ping, ping_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PIVOT_ROOT
-       APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_POWEROFF
-       APPLET(poweroff, poweroff_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_PRINTF
-       APPLET(printf, printf_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_PS
-       APPLET(ps, ps_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_PWD
-       APPLET(pwd, pwd_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RDATE
-       APPLET(rdate, rdate_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_READLINK
-       APPLET(readlink, readlink_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_REBOOT
-       APPLET(reboot, reboot_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_RENICE
-       APPLET(renice, renice_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_RESET
-       APPLET(reset, reset_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_RM
-       APPLET(rm, rm_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RMDIR
-       APPLET(rmdir, rmdir_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_RMMOD
-       APPLET(rmmod, rmmod_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_ROUTE
-       APPLET(route, route_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_RPM2CPIO
-       APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_SED
-       APPLET(sed, sed_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SETKEYCODES
-       APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN)
-#endif
-#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH)
-       APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH)
-       APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH)
-       APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN)
-#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH)
-       APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SLEEP
-       APPLET(sleep, sleep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SORT
-       APPLET(sort, sort_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_STTY
-       APPLET(stty, stty_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SWAPONOFF
-       APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_SWAPONOFF
-       APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_SYNC
-       APPLET(sync, sync_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_SYSLOGD
-       APPLET(syslogd, syslogd_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_TAIL
-       APPLET(tail, tail_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TAR
-       APPLET(tar, tar_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TEE
-       APPLET(tee, tee_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TELNET
-       APPLET(telnet, telnet_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TEST
-       APPLET(test, test_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TFTP
-       APPLET(tftp, tftp_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TOUCH
-       APPLET(touch, touch_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TR
-       APPLET(tr, tr_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRACEROUTE
-       APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_TRUE_FALSE
-       APPLET(true, true_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_TTY
-       APPLET(tty, tty_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UMOUNT
-       APPLET(umount, umount_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UNAME
-       APPLET(uname, uname_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UNIQ
-       APPLET(uniq, uniq_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UNIX2DOS
-       APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UPDATE
-       APPLET(update, update_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_UPTIME
-       APPLET(uptime, uptime_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_USLEEP
-       APPLET(usleep, usleep_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_UUDECODE
-       APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_UUENCODE
-       APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_VI
-       APPLET(vi, vi_main, _BB_DIR_BIN)
-#endif
-#ifdef BB_WATCHDOG
-       APPLET(watchdog, watchdog_main, _BB_DIR_SBIN)
-#endif
-#ifdef BB_WC
-       APPLET(wc, wc_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WGET
-       APPLET(wget, wget_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WHICH
-       APPLET(which, which_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_WHOAMI
-       APPLET(whoami, whoami_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_XARGS
-       APPLET(xargs, xargs_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_YES
-       APPLET(yes, yes_main, _BB_DIR_USR_BIN)
-#endif
-#ifdef BB_GUNZIP
-       APPLET(zcat, gunzip_main, _BB_DIR_BIN)
-#endif
-
-#if !defined(PROTOTYPES) && !defined(MAKE_USAGE)
-       { 0,NULL,0 }
-};
-
-#endif
diff --git a/busybox/include/busybox.h b/busybox/include/busybox.h
deleted file mode 100644 (file)
index f79dac8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Busybox main internal header file
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-#ifndef        _BB_INTERNAL_H_
-#define        _BB_INTERNAL_H_    1
-
-#include "Config.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")"
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#include <features.h>
-
-
-enum Location {
-       _BB_DIR_ROOT = 0,
-       _BB_DIR_BIN,
-       _BB_DIR_SBIN,
-       _BB_DIR_USR_BIN,
-       _BB_DIR_USR_SBIN
-};
-
-struct BB_applet {
-       const   char*   name;
-       int     (*main)(int argc, char** argv);
-       enum    Location        location;
-};
-/* From busybox.c */
-extern const struct BB_applet applets[];
-
-/* Automagically pull in all the applet function prototypes and
- * applet usage strings.  These are all of the form:
- *             extern int foo_main(int argc, char **argv);
- *             extern const char foo_usage[];
- * These are all autogenerated from the set of currently defined applets. 
- */
-#define PROTOTYPES
-#include "applets.h"
-#undef PROTOTYPES
-
-#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK
-#define RESERVE_BB_BUFFER(buffer,len)           char buffer[len]
-#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len]
-#define RELEASE_BB_BUFFER(buffer)      ((void)0)
-#else
-#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS
-#define RESERVE_BB_BUFFER(buffer,len)  static          char buffer[len]
-#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len]
-#define RELEASE_BB_BUFFER(buffer)      ((void)0)
-#else
-#define RESERVE_BB_BUFFER(buffer,len)           char *buffer=xmalloc(len)
-#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len)
-#define RELEASE_BB_BUFFER(buffer)      free (buffer)
-#endif
-#endif
-
-
-/* Bit map related macros -- libc5 doens't provide these... sigh.  */
-#ifndef setbit
-#define NBBY            CHAR_BIT
-#define setbit(a,i)     ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
-#define clrbit(a,i)     ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
-#define isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
-#define isclr(a,i)      (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
-#endif
-
-#ifndef RB_POWER_OFF
-/* Stop system and switch power off if possible.  */
-#define RB_POWER_OFF   0x4321fedc
-#endif
-
-
-/* Pull in the utility routines from libbb */
-#include "libbb/libbb.h"
-
-
-
-#endif /* _BB_INTERNAL_H_ */
diff --git a/busybox/include/grp.h b/busybox/include/grp.h
deleted file mode 100644 (file)
index 87d4115..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef        __BB_GRP_H
-#define        __BB_GRP_H
-
-#if defined USE_SYSTEM_PWD_GRP
-#include <grp.h>
-#else
-
-#include <sys/types.h>
-#include <features.h>
-#include <stdio.h>
-
-/* The group structure */
-struct group
-{
-  char *gr_name;               /* Group name.  */
-  char *gr_passwd;             /* Password.    */
-  gid_t gr_gid;                        /* Group ID.    */
-  char **gr_mem;               /* Member list. */
-};
-
-extern void setgrent __P ((void));
-extern void endgrent __P ((void));
-extern struct group * getgrent __P ((void));
-
-extern struct group * getgrgid __P ((__const gid_t gid));
-extern struct group * getgrnam __P ((__const char * name));
-
-extern struct group * fgetgrent __P ((FILE * file));
-
-extern int setgroups __P ((size_t n, __const gid_t * groups));
-extern int initgroups __P ((__const char * user, gid_t gid));
-
-extern struct group * __getgrent __P ((int grp_fd));
-
-#endif /* USE_SYSTEM_PWD_GRP */
-#endif /* __BB_GRP_H */
-
diff --git a/busybox/include/libbb.h b/busybox/include/libbb.h
deleted file mode 100644 (file)
index 30f0bb9..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Busybox main internal header file
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-#ifndef        __LIBBB_H__
-#define        __LIBBB_H__    1
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <netdb.h>
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#include <features.h>
-
-#ifndef _BB_INTERNAL_H_
-#include "../busybox.h"
-#endif
-
-#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
-/* libc5 doesn't define socklen_t */
-typedef unsigned int socklen_t;
-/* libc5 doesn't implement BSD 4.4 daemon() */
-extern int daemon (int nochdir, int noclose);
-/* libc5 doesn't implement strtok_r */
-char *strtok_r(char *s, const char *delim, char **ptrptr);
-#endif 
-
-/* Some useful definitions */
-#define FALSE   ((int) 0)
-#define TRUE    ((int) 1)
-#define SKIP   ((int) 2)
-
-/* for mtab.c */
-#define MTAB_GETMOUNTPT '1'
-#define MTAB_GETDEVICE  '2'
-
-#define BUF_SIZE        8192
-#define EXPAND_ALLOC    1024
-
-static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); }
-static inline int is_octal(int ch)   { return ((ch >= '0') && (ch <= '7')); }
-
-/* Macros for min/max.  */
-#ifndef MIN
-#define        MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-#ifndef MAX
-#define        MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-
-
-extern void show_usage(void) __attribute__ ((noreturn));
-extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
-extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
-extern void perror_msg(const char *s, ...);
-extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-extern void vherror_msg(const char *s, va_list p);
-extern void herror_msg(const char *s, ...);
-extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-
-/* These two are used internally -- you shouldn't need to use them */
-extern void verror_msg(const char *s, va_list p);
-extern void vperror_msg(const char *s, va_list p);
-
-const char *mode_string(int mode);
-const char *time_string(time_t timeVal);
-int is_directory(const char *name, int followLinks, struct stat *statBuf);
-int isDevice(const char *name);
-
-int remove_file(const char *path, int flags);
-int copy_file(const char *source, const char *dest, int flags);
-int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
-char *buildName(const char *dirName, const char *fileName);
-int makeString(int argc, const char **argv, char *buf, int bufLen);
-char *getChunk(int size);
-char *chunkstrdup(const char *str);
-void freeChunks(void);
-ssize_t safe_read(int fd, void *buf, size_t count);
-int full_write(int fd, const char *buf, int len);
-int full_read(int fd, char *buf, int len);
-int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst,
-         int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
-         int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
-         void* userData);
-
-extern int parse_mode( const char* s, mode_t* theMode);
-
-extern int get_kernel_revision(void);
-
-extern int get_console_fd(char* tty_name);
-extern struct mntent *find_mount_point(const char *name, const char *table);
-extern void write_mtab(char* blockDevice, char* directory, 
-       char* filesystemType, long flags, char* string_flags);
-extern void erase_mtab(const char * name);
-extern long atoi_w_units (const char *cp);
-extern pid_t* find_pid_by_name( char* pidName);
-extern char *find_real_root_device_name(const char* name);
-extern char *get_line_from_file(FILE *file);
-extern void print_file(FILE *file);
-extern int copyfd(int fd1, int fd2);
-extern int print_file_by_name(char *filename);
-extern char process_escape_sequence(const char **ptr);
-extern char *get_last_path_component(char *path);
-extern FILE *wfopen(const char *path, const char *mode);
-extern FILE *xfopen(const char *path, const char *mode);
-extern void chomp(char *s);
-extern void trim(char *s);
-extern struct BB_applet *find_applet_by_name(const char *name);
-void run_applet_by_name(const char *name, int argc, char **argv);
-
-#ifndef DMALLOC
-extern void *xmalloc (size_t size);
-extern void *xrealloc(void *old, size_t size);
-extern void *xcalloc(size_t nmemb, size_t size);
-extern char *xstrdup (const char *s);
-#endif
-extern char *xstrndup (const char *s, int n);
-extern char * safe_strncpy(char *dst, const char *src, size_t size);
-
-struct suffix_mult {
-       const char *suffix;
-       int mult;
-};
-
-extern unsigned long parse_number(const char *numstr,
-               const struct suffix_mult *suffixes);
-
-
-/* These parse entries in /etc/passwd and /etc/group.  This is desirable
- * for BusyBox since we want to avoid using the glibc NSS stuff, which
- * increases target size and is often not needed embedded systems.  */
-extern long my_getpwnam(const char *name);
-extern long my_getgrnam(const char *name);
-extern void my_getpwuid(char *name, long uid);
-extern void my_getgrgid(char *group, long gid);
-extern long my_getpwnamegid(const char *name);
-
-extern int device_open(char *device, int mode);
-
-extern int del_loop(const char *device);
-extern int set_loop(const char *device, const char *file, int offset, int *loopro);
-extern char *find_unused_loop_device (void);
-
-
-#if (__GLIBC__ < 2)
-extern int vdprintf(int d, const char *format, va_list ap);
-#endif
-
-int nfsmount(const char *spec, const char *node, int *flags,
-            char **extra_opts, char **mount_opts, int running_bg);
-
-void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg);
-void syslog_msg(int facility, int pri, const char *msg);
-
-/* Include our own copy of struct sysinfo to avoid binary compatability
- * problems with Linux 2.4, which changed things.  Grumble, grumble. */
-struct sysinfo {
-       long uptime;                    /* Seconds since boot */
-       unsigned long loads[3];         /* 1, 5, and 15 minute load averages */
-       unsigned long totalram;         /* Total usable main memory size */
-       unsigned long freeram;          /* Available memory size */
-       unsigned long sharedram;        /* Amount of shared memory */
-       unsigned long bufferram;        /* Memory used by buffers */
-       unsigned long totalswap;        /* Total swap space size */
-       unsigned long freeswap;         /* swap space still available */
-       unsigned short procs;           /* Number of current processes */
-       unsigned short pad;                     /* Padding needed for m68k */
-       unsigned long totalhigh;        /* Total high memory size */
-       unsigned long freehigh;         /* Available high memory size */
-       unsigned int mem_unit;          /* Memory unit size in bytes */
-       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
-};
-extern int sysinfo (struct sysinfo* info);
-
-enum {
-       KILOBYTE = 1024,
-       MEGABYTE = (KILOBYTE*1024),
-       GIGABYTE = (MEGABYTE*1024)
-};
-const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit);
-
-int ask_confirmation(void);
-int klogctl(int type, char * b, int len);
-
-char *xgetcwd(char *cwd);
-char *xreadlink(const char *path);
-char *concat_path_file(const char *path, const char *filename);
-char *last_char_is(const char *s, int c);
-
-extern long arith (const char *startbuf, int *errcode);
-
-typedef struct file_headers_s {
-       char *name;
-       char *link_name;
-       off_t size;
-       uid_t uid;
-       gid_t gid;
-       mode_t mode;
-       time_t mtime;
-       dev_t device;
-} file_header_t;
-file_header_t *get_header_ar(FILE *in_file);
-file_header_t *get_header_cpio(FILE *src_stream);
-file_header_t *get_header_tar(FILE *tar_stream);
-
-enum extract_functions_e {
-       extract_verbose_list = 1,
-       extract_list = 2,
-       extract_one_to_buffer = 4,
-       extract_to_stdout = 8,
-       extract_all_to_fs = 16,
-       extract_preserve_date = 32,
-       extract_data_tar_gz = 64,
-       extract_control_tar_gz = 128,
-       extract_unzip_only = 256,
-       extract_unconditional = 512,
-       extract_create_leading_dirs = 1024,
-       extract_quiet = 2048,
-       extract_exclude_list = 4096
-};
-char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *),
-       const int extract_function, const char *prefix, char **extract_names);
-char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function,
-       const char *prefix, const char *filename);
-int read_package_field(const char *package_buffer, char **field_name, char **field_value);
-char *fgets_str(FILE *file, const char *terminating_string);
-
-extern int unzip(FILE *l_in_file, FILE *l_out_file);
-extern void gz_close(int gunzip_pid);
-extern FILE *gz_open(FILE *compressed_file, int *pid);
-
-extern struct hostent *xgethostbyname(const char *name);
-extern int create_icmp_socket(void);
-
-char *dirname (char *path);
-
-int make_directory (char *path, long mode, int flags);
-
-const char *u_signal_names(const char *str_sig, int *signo, int startnum);
-char *simplify_path(const char *path);
-
-#define CT_AUTO        0
-#define CT_UNIX2DOS    1
-#define CT_DOS2UNIX    2
-/* extern int convert(char *fn, int ConvType); */
-
-enum {
-       FILEUTILS_PRESERVE_STATUS = 1,
-       FILEUTILS_PRESERVE_SYMLINKS = 2,
-       FILEUTILS_RECUR = 4,
-       FILEUTILS_FORCE = 8,
-       FILEUTILS_INTERACTIVE = 16
-};
-
-extern const char *applet_name;
-extern const char * const full_version;
-extern const char * const name_too_long;
-extern const char * const omitting_directory;
-extern const char * const not_a_directory;
-extern const char * const memory_exhausted;
-extern const char * const invalid_date;
-extern const char * const invalid_option;
-extern const char * const io_error;
-extern const char * const dash_dash_help;
-extern const char * const write_error;
-extern const char * const too_few_args;
-extern const char * const name_longer_than_foo;
-extern const char * const unknown;
-extern const char * const can_not_create_raw_socket;
-
-#ifdef BB_FEATURE_DEVFS
-# define CURRENT_VC "/dev/vc/0"
-# define VC_1 "/dev/vc/1"
-# define VC_2 "/dev/vc/2"
-# define VC_3 "/dev/vc/3"
-# define VC_4 "/dev/vc/4"
-# define VC_5 "/dev/vc/5"
-# define SC_0 "/dev/tts/0"
-# define SC_1 "/dev/tts/1"
-# define VC_FORMAT "/dev/vc/%d"
-# define SC_FORMAT "/dev/tts/%d"
-#else
-# define CURRENT_VC "/dev/tty0"
-# define VC_1 "/dev/tty1"
-# define VC_2 "/dev/tty2"
-# define VC_3 "/dev/tty3"
-# define VC_4 "/dev/tty4"
-# define VC_5 "/dev/tty5"
-# define SC_0 "/dev/ttyS0"
-# define SC_1 "/dev/ttyS1"
-# define VC_FORMAT "/dev/tty%d"
-# define SC_FORMAT "/dev/ttyS%d"
-#endif
-
-/* The following devices are the same on devfs and non-devfs systems.  */
-#define CURRENT_TTY "/dev/tty"
-#define CONSOLE_DEV "/dev/console"
-
-#endif /* __LIBBB_H__ */
diff --git a/busybox/include/pwd.h b/busybox/include/pwd.h
deleted file mode 100644 (file)
index e603a96..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef        __BB_PWD_H
-#define        __BB_PWD_H
-
-#if defined USE_SYSTEM_PWD_GRP
-#include <pwd.h>
-#else
-
-#include <sys/types.h>
-#include <features.h>
-#include <stdio.h>
-
-/* The passwd structure.  */
-struct passwd
-{
-  char *pw_name;               /* Username.  */
-  char *pw_passwd;             /* Password.  */
-  uid_t pw_uid;                        /* User ID.  */
-  gid_t pw_gid;                        /* Group ID.  */
-  char *pw_gecos;              /* Real name.  */
-  char *pw_dir;                        /* Home directory.  */
-  char *pw_shell;              /* Shell program.  */
-};
-
-extern void setpwent __P ((void));
-extern void endpwent __P ((void));
-extern struct passwd * getpwent __P ((void));
-
-extern int putpwent __P ((__const struct passwd * __p, FILE * __f));
-extern int getpw __P ((uid_t uid, char *buf));
-
-extern struct passwd * fgetpwent __P ((FILE * file));
-
-extern struct passwd * getpwuid __P ((__const uid_t));
-extern struct passwd * getpwnam __P ((__const char *));
-
-extern struct passwd * __getpwent __P ((__const int passwd_fd));
-
-#endif /* USE_SYSTEM_PWD_GRP */
-#endif /* __BB_PWD_H  */
-
diff --git a/busybox/include/usage.h b/busybox/include/usage.h
deleted file mode 100644 (file)
index 4d38c43..0000000
+++ /dev/null
@@ -1,1826 +0,0 @@
-#define adjtimex_trivial_usage \
-       "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
-#define adjtimex_full_usage \
-       "Reads and optionally sets system timebase parameters.\n" \
-       "See adjtimex(2).\n\n" \
-       "Options:\n" \
-       "\t-q\t\tquiet mode - do not print\n" \
-       "\t-o offset\ttime offset, microseconds\n" \
-       "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \
-       "\t\t\t(positive values make the system clock run fast)\n" \
-       "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \
-       "\t-p timeconstant\n"
-
-#define ar_trivial_usage \
-       "-[ov][ptx] ARCHIVE FILES"
-#define ar_full_usage \
-       "Extract or list FILES from an ar archive.\n\n" \
-       "Options:\n" \
-       "\t-o\t\tpreserve original dates\n" \
-       "\t-p\t\textract to stdout\n" \
-       "\t-t\t\tlist\n" \
-       "\t-x\t\textract\n" \
-       "\t-v\t\tverbosely list files processed\n"
-
-#define basename_trivial_usage \
-       "FILE [SUFFIX]"
-#define basename_full_usage \
-       "Strips directory path and suffixes from FILE.\n" \
-       "If specified, also removes any trailing SUFFIX."
-#define basename_example_usage \
-       "$ basename /usr/local/bin/foo\n" \
-       "foo\n" \
-       "$ basename /usr/local/bin/\n" \
-       "bin\n" \
-       "$ basename /foo/bar.txt .txt\n" \
-       "bar"
-
-#define cat_trivial_usage \
-       "[FILE]..."
-#define cat_full_usage \
-       "Concatenates FILE(s) and prints them to stdout."
-#define cat_example_usage \
-       "$ cat /proc/uptime\n" \
-       "110716.72 17.67"
-
-#define chgrp_trivial_usage \
-       "[OPTION]... GROUP FILE..."
-#define chgrp_full_usage \
-       "Change the group membership of each FILE to GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chgrp_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chgrp root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chmod_trivial_usage \
-       "[-R] MODE[,MODE]... FILE..."
-#define chmod_full_usage \
-       "Each MODE is one or more of the letters ugoa, one of the\n" \
-       "symbols +-= and one or more of the letters rwxst.\n\n" \
-       "Options:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chmod_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chmod u+x /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*\n" \
-       "$ chmod 444 /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chown_trivial_usage \
-       "[ -Rh ]...  OWNER[<.|:>[GROUP]] FILE..."
-#define chown_full_usage \
-       "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively.\n" \
-       "\t-h\tDo not dereference symbolic links."
-#define chown_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root.root /tmp/foo\n" \
-       "ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chroot_trivial_usage \
-       "NEWROOT [COMMAND...]"
-#define chroot_full_usage \
-       "Run COMMAND with root directory set to NEWROOT."
-#define chroot_example_usage \
-       "$ ls -l /bin/ls\n" \
-       "lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
-       "$ mount /dev/hdc1 /mnt -t minix\n" \
-       "$ chroot /mnt\n" \
-       "$ ls -l /bin/ls\n" \
-       "-rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*\n"
-
-#define chvt_trivial_usage \
-       "N"
-#define chvt_full_usage \
-       "Changes the foreground virtual terminal to /dev/ttyN"
-
-#define clear_trivial_usage \
-       ""
-#define clear_full_usage \
-       "Clear screen."
-
-#define cmp_trivial_usage \
-       "FILE1 [FILE2]"
-#define cmp_full_usage \
-       "\t-s\tquiet mode - do not print\n" \
-       "Compare files."
-
-#define cp_trivial_usage \
-       "[OPTION]... SOURCE DEST"
-#define cp_full_usage \
-       "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
-       "\n" \
-       "\t-a\tSame as -dpR\n" \
-       "\t-d\tPreserves links\n" \
-       "\t-p\tPreserves file attributes if possible\n" \
-       "\t-f\tforce (implied; ignored) - always set\n" \
-       "\t-R\tCopies directories recursively"
-
-#define cpio_trivial_usage \
-       "-[dimtuv][F cpiofile]"
-#define cpio_full_usage \
-       "Extract or list files from a cpio archive\n" \
-       "Main operation mode:\n" \
-       "\td\t\tmake leading directories\n" \
-       "\ti\t\textract\n" \
-       "\tm\t\tpreserve mtime\n" \
-       "\tt\t\tlist\n" \
-       "\tu\t\tunconditional overwrite\t" \
-       "\tF\t\tinput from file\t"
-       
-#define cut_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define cut_full_usage \
-       "Prints selected fields from each input FILE to standard output.\n\n" \
-       "Options:\n" \
-       "\t-b LIST\t\tOutput only bytes from LIST\n" \
-       "\t-c LIST\t\tOutput only characters from LIST\n" \
-       "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \
-       "\t-s\t\tOutput only the lines containing delimiter\n" \
-       "\t-f N\t\tPrint only these fields\n" \
-       "\t-n\t\tIgnored"
-#define cut_example_usage \
-       "$ echo "Hello world" | cut -f 1 -d ' '\n" \
-       "Hello\n" \
-       "$ echo "Hello world" | cut -f 2 -d ' '\n" \
-       "world\n"
-
-#define date_trivial_usage \
-       "[OPTION]... [+FORMAT]"
-#define date_full_usage \
-       "Displays the current time in the given FORMAT, or sets the system date.\n" \
-       "\nOptions:\n" \
-       "\t-R\t\tOutputs RFC-822 compliant date string\n" \
-       "\t-d STRING\tdisplay time described by STRING, not `now'\n" \
-       "\t-s\t\tSets time described by STRING\n" \
-       "\t-u\t\tPrints or sets Coordinated Universal Time"
-#define date_example_usage \
-       "$ date\n" \
-       "Wed Apr 12 18:52:41 MDT 2000\n"
-
-#define dc_trivial_usage \
-       "expression ..."
-#define dc_full_usage \
-       "This is a Tiny RPN calculator that understands the\n" \
-       "following operations: +, -, /, *, and, or, not, eor.\n" \
-       "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16"
-#define dc_example_usage \
-       "$ dc 2 2 +\n" \
-       "4\n" \
-       "$ dc 8 8 \* 2 2 + /\n" \
-       "16\n" \
-       "$ dc 0 1 and\n" \
-       "0\n" \
-       "$ dc 0 1 or\n" \
-       "1\n" \
-       "$ echo 72 9 div 8 mul | dc\n" \
-       "64\n"
-
-#define dd_trivial_usage \
-       "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \
-       "\t  [seek=N] [conv=notrunc|sync]"
-#define dd_full_usage \
-       "Copy a file, converting and formatting according to options\n\n" \
-       "\tif=FILE\t\tread from FILE instead of stdin\n" \
-       "\tof=FILE\t\twrite to FILE instead of stdout\n" \
-       "\tbs=N\t\tread and write N bytes at a time\n" \
-       "\tcount=N\t\tcopy only N input blocks\n" \
-       "\tskip=N\t\tskip N input blocks\n" \
-       "\tseek=N\t\tskip N output blocks\n" \
-       "\tconv=notrunc\tdon't truncate output file\n" \
-       "\tconv=sync\tpad blocks with zeros\n" \
-       "\n" \
-       "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
-       "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
-#define dd_example_usage \
-       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
-       "4+0 records in\n" \
-       "4+0 records out\n"
-
-#define deallocvt_trivial_usage \
-       "N"
-#define deallocvt_full_usage \
-        "Deallocate unused virtual terminal /dev/ttyN"
-
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-  #define USAGE_HUMAN_READABLE(a) a
-  #define USAGE_NOT_HUMAN_READABLE(a)
-#else
-  #define USAGE_HUMAN_READABLE(a) 
-  #define USAGE_NOT_HUMAN_READABLE(a) a
-#endif
-#define df_trivial_usage \
-       "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
-#define df_full_usage \
-       "Print the filesystem space used and space available.\n\n" \
-       "Options:\n" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define df_example_usage \
-       "$ df\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n" \
-       "/dev/sda1                64216     36364     27852  57% /boot\n" \
-       "$ df /dev/sda3\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n"
-
-#define dirname_trivial_usage \
-       "[FILENAME ...]"
-#define dirname_full_usage \
-       "Strips non-directory suffix from FILENAME"
-#define dirname_example_usage \
-       "$ dirname /tmp/foo\n" \
-       "/tmp\n" \
-       "$ dirname /tmp/foo/\n" \
-       "/tmp\n"
-
-#define dmesg_trivial_usage \
-       "[-c] [-n LEVEL] [-s SIZE]"
-#define dmesg_full_usage \
-       "Prints or controls the kernel ring buffer\n\n" \
-       "Options:\n" \
-       "\t-c\t\tClears the ring buffer's contents after printing\n" \
-       "\t-n LEVEL\tSets console logging level\n" \
-       "\t-s SIZE\t\tUse a buffer of size SIZE"
-
-#define dos2unix_trivial_usage \
-       "[option] [FILE]"
-#define dos2unix_full_usage \
-       "Converts FILE from dos format to unix format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define dpkg_trivial_usage \
-       "-i package_file\n"
-       "[-CPru] package_name"
-#define dpkg_full_usage \
-       "\t-i\tInstall the package\n" \
-       "\t-C\tConfigure an unpackaged package\n" \
-       "\t-P\tPurge all files of a package\n" \
-       "\t-r\tRemove all but the configuration files for a package\n" \
-       "\t-u\tUnpack a package, but dont configure it\n"
-
-#define dpkg_deb_trivial_usage \
-       "[-cefItxX] FILE [argument]"
-#define dpkg_deb_full_usage \
-       "Perform actions on debian packages (.debs)\n\n" \
-       "Options:\n" \
-       "\t-c\tList contents of filesystem tree\n" \
-       "\t-e\tExtract control files to [argument] directory\n" \
-       "\t-f\tDisplay control field name starting with [argument]\n" \
-       "\t-I\tDisplay the control filenamed [argument]\n" \
-       "\t-t\tExtract filesystem tree to stdout in tar format\n" \
-       "\t-x\tExtract packages filesystem tree to directory\n" \
-       "\t-X\tVerbose extract"
-#define dpkg_deb_example_usage \
-       "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
-
-#define du_trivial_usage \
-       "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..."
-#define du_full_usage \
-       "Summarizes disk space used for each FILE and/or directory.\n" \
-       "Disk space is printed in units of 1024 bytes.\n\n" \
-       "Options:\n" \
-       "\t-l\tcount sizes many times if hard linked\n" \
-       "\t-s\tdisplay only a total for each argument" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define du_example_usage \
-       "$ du\n" \
-       "16      ./CVS\n" \
-       "12      ./kernel-patches/CVS\n" \
-       "80      ./kernel-patches\n" \
-       "12      ./tests/CVS\n" \
-       "36      ./tests\n" \
-       "12      ./scripts/CVS\n" \
-       "16      ./scripts\n" \
-       "12      ./docs/CVS\n" \
-       "104     ./docs\n" \
-       "2417    .\n"
-
-#define dumpkmap_trivial_usage \
-       "> keymap"
-#define dumpkmap_full_usage \
-       "Prints out a binary keyboard translation table to standard output."
-#define dumpkmap_example_usage \
-       "$ dumpkmap > keymap\n"
-
-#define dutmp_trivial_usage \
-       "[FILE]"
-#define dutmp_full_usage \
-       "Dump utmp file format (pipe delimited) from FILE\n" \
-       "or stdin to stdout.  (i.e., 'dutmp /var/run/utmp')"
-#define dutmp_example_usage \
-       "$ dutmp /var/run/utmp\n" \
-       "8|7||si|||0|0|0|955637625|760097|0\n" \
-       "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \
-       "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \
-       "8|125||l4|||0|0|0|955637629|998367|0\n" \
-       "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \
-       "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \
-       "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n"
-
-#define echo_trivial_usage \
-       "[-neE] [ARG ...]"
-#define echo_full_usage \
-       "Prints the specified ARGs to stdout\n\n" \
-       "Options:\n" \
-       "\t-n\tsuppress trailing newline\n" \
-       "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
-       "\t-E\tdisable interpretation of backslash-escaped characters"
-#define echo_example_usage \
-       "$ echo "Erik is cool"\n" \
-       "Erik is cool\n" \
-       "$  echo -e "Erik\\nis\\ncool"\n" \
-       "Erik\n" \
-       "is\n" \
-       "cool\n" \
-       "$ echo "Erik\\nis\\ncool"\n" \
-       "Erik\\nis\\ncool\n"
-
-#define env_trivial_usage \
-       "[-iu] [-] [name=value]... [command]"
-#define env_full_usage \
-       "Prints the current environment or runs a program after setting\n" \
-       "up the specified environment.\n\n" \
-       "Options:\n" \
-       "\t-, -i\tstart with an empty environment\n" \
-       "\t-u\tremove variable from the environment\n"
-
-#define expr_trivial_usage \
-       "EXPRESSION"
-#define expr_full_usage \
-       "Prints the value of EXPRESSION to standard output.\n\n" \
-       "EXPRESSION may be:\n" \
-       "\tARG1 |  ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
-       "\tARG1 &  ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
-       "\tARG1 <  ARG2 ARG1 is less than ARG2\n" \
-       "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \
-       "\tARG1 =  ARG2 ARG1 is equal to ARG2\n" \
-       "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \
-       "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \
-       "\tARG1 >  ARG2 ARG1 is greater than ARG2\n" \
-       "\tARG1 +  ARG2 arithmetic sum of ARG1 and ARG2\n" \
-       "\tARG1 -  ARG2 arithmetic difference of ARG1 and ARG2\n" \
-       "\tARG1 *  ARG2 arithmetic product of ARG1 and ARG2\n" \
-       "\tARG1 /  ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \
-       "\tARG1 %  ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \
-       "\tSTRING : REGEXP             anchored pattern match of REGEXP in STRING\n" \
-       "\tmatch STRING REGEXP         same as STRING : REGEXP\n" \
-       "\tsubstr STRING POS LENGTH    substring of STRING, POS counted from 1\n" \
-       "\tindex STRING CHARS          index in STRING where any CHARS is found,\n" \
-       "\t                            or 0\n" \
-       "\tlength STRING               length of STRING\n" \
-       "\tquote TOKEN                 interpret TOKEN as a string, even if\n" \
-       "\t                            it is a keyword like `match' or an\n" \
-       "\t                            operator like `/'\n" \
-       "\t( EXPRESSION )              value of EXPRESSION\n\n" \
-       "Beware that many operators need to be escaped or quoted for shells.\n" \
-       "Comparisons are arithmetic if both ARGs are numbers, else\n" \
-       "lexicographical.  Pattern matches return the string matched between \n" \
-       "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
-       "of characters matched or 0."
-
-#define false_trivial_usage \
-       ""
-#define false_full_usage \
-       "Return an exit code of FALSE (1)."
-#define false_example_usage \
-       "$ false\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#define fbset_trivial_usage \
-       "[options] [mode]"
-#define fbset_full_usage \
-       "Show and modify frame buffer settings"
-#define fbset_example_usage \
-       "$ fbset\n" \
-       "mode "1024x768-76"\n" \
-       "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
-       "\tgeometry 1024 768 1024 768 16\n" \
-       "\ttimings 12714 128 32 16 4 128 4\n" \
-       "\taccel false\n" \
-       "\trgba 5/11,6/5,5/0,0/0\n" \
-       "endmode\n"
-
-#define fdflush_trivial_usage \
-       "DEVICE"
-#define fdflush_full_usage \
-       "Forces floppy disk drive to detect disk change"
-
-#ifdef BB_FEATURE_FIND_TYPE
-  #define USAGE_FIND_TYPE(a) a
-#else
-  #define USAGE_FIND_TYPE(a)
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-  #define USAGE_FIND_PERM(a) a
-#else
-  #define USAGE_FIND_PERM(a)
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-  #define USAGE_FIND_MTIME(a) a
-#else
-  #define USAGE_FIND_MTIME(a)
-#endif
-
-#define find_trivial_usage \
-       "[PATH...] [EXPRESSION]"
-#define find_full_usage \
-       "Search for files in a directory hierarchy.  The default PATH is\n" \
-       "the current directory; default EXPRESSION is '-print'\n" \
-       "\nEXPRESSION may consist of:\n" \
-       "\t-follow\t\tDereference symbolic links.\n" \
-       "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
-       "\t-print\t\tPrint (default and assumed).\n" \
-       USAGE_FIND_TYPE( \
-       "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
-) USAGE_FIND_PERM( \
-       "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \
-) USAGE_FIND_MTIME( \
-       "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days")
-#define find_example_usage \
-       "$ find / -name /etc/passwd\n" \
-       "/etc/passwd\n"
-
-#define free_trivial_usage \
-       ""
-#define free_full_usage \
-       "Displays the amount of free and used system memory"
-#define free_example_usage \
-       "$ free\n" \
-       "              total         used         free       shared      buffers\n" \
-       "  Mem:       257628       248724         8904        59644        93124\n" \
-       " Swap:       128516         8404       120112\n" \
-       "Total:       386144       257128       129016\n" \
-
-#define freeramdisk_trivial_usage \
-       "DEVICE"
-#define freeramdisk_full_usage \
-       "Frees all memory used by the specified ramdisk."
-#define freeramdisk_example_usage \
-       "$ freeramdisk /dev/ram2\n"
-
-#define fsck_minix_trivial_usage \
-       "[-larvsmf] /dev/name"
-#define fsck_minix_full_usage \
-       "Performs a consistency check for MINIX filesystems.\n\n" \
-       "Options:\n" \
-       "\t-l\tLists all filenames\n" \
-       "\t-r\tPerform interactive repairs\n" \
-       "\t-a\tPerform automatic repairs\n" \
-       "\t-v\tverbose\n" \
-       "\t-s\tOutputs super-block information\n" \
-       "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
-       "\t-f\tForce file system check."
-
-#define getopt_trivial_usage \
-       "[OPTIONS]..."
-#define getopt_full_usage \
-       "Parse command options\n" \
-       "\t-a, --alternative            Allow long options starting with single -\n" \
-       "\t-l, --longoptions=longopts   Long options to be recognized\n" \
-       "\t-n, --name=progname          The name under which errors are reported\n" \
-       "\t-o, --options=optstring      Short options to be recognized\n" \
-       "\t-q, --quiet                  Disable error reporting by getopt(3)\n" \
-       "\t-Q, --quiet-output           No normal output\n" \
-       "\t-s, --shell=shell            Set shell quoting conventions\n" \
-       "\t-T, --test                   Test for getopt(1) version\n" \
-       "\t-u, --unqote                 Do not quote the output"
-#define getopt_example_usage \
-        "$ cat getopt.test\n" \
-        "#!/bin/sh\n" \
-        "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
-        "       -n 'example.busybox' -- "$@"`\n" \
-        "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
-        "eval set -- "$GETOPT"\n" \
-        "while true ; do\n" \
-        " case $1 in\n" \
-        "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
-        "   -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \
-        "   -c|--c-long)\n" \
-        "     case "$2" in\n" \
-        "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
-        "       *)  echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \
-        "     esac ;;\n" \
-        "   --) shift ; break ;;\n" \
-        "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
-        " esac\n" \
-        "done\n"
-
-#define grep_trivial_usage \
-       "[-ihHnqvs] PATTERN [FILEs...]"
-#define grep_full_usage \
-       "Search for PATTERN in each FILE or standard input.\n\n" \
-       "Options:\n" \
-       "\t-H\tprefix output lines with filename where match was found\n" \
-       "\t-h\tsuppress the prefixing filename on output\n" \
-       "\t-i\tignore case distinctions\n" \
-       "\t-l\tlist names of files that match\n" \
-       "\t-n\tprint line number with output lines\n" \
-       "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \
-       "\t-v\tselect non-matching lines\n" \
-       "\t-s\tsuppress file open/read error messages"
-#define grep_example_usage \
-       "$ grep root /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "$ grep ^[rR]oo. /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n"
-
-#define gunzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gunzip_full_usage \
-       "Uncompress FILE (or standard input if FILE is '-').\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output\n" \
-       "\t-t\tTest compressed file integrity"
-#define gunzip_example_usage \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
-
-#define gzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gzip_full_usage \
-       "Compress FILE with maximum compression.\n" \
-       "When FILE is '-', reads standard input.  Implies -c.\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output instead of FILE.gz\n" \
-       "\t-d\tdecompress"
-#define gzip_example_usage \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
-       "$ gzip /tmp/busybox.tar\n" \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
-
-#define halt_trivial_usage \
-       ""
-#define halt_full_usage \
-       "Halt the system."
-
-#define head_trivial_usage \
-       "[OPTION] [FILE]..."
-#define head_full_usage \
-       "Print first 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-n NUM\t\tPrint first NUM lines instead of first 10"
-#define head_example_usage \
-       "$ head -n 2 /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
-
-#define hostid_trivial_usage \
-       ""
-#define hostid_full_usage \
-       "Print out a unique 32-bit identifier for the machine."
-
-#define hostname_trivial_usage \
-       "[OPTION] {hostname | -F FILE}"
-#define hostname_full_usage \
-       "Get or set the hostname or DNS domain name. If a hostname is given\n" \
-       "(or FILE with the -F parameter), the host name will be set.\n\n" \
-       "Options:\n" \
-       "\t-s\t\tShort\n" \
-       "\t-i\t\tAddresses for the hostname\n" \
-       "\t-d\t\tDNS domain name\n" \
-       "\t-F, --file FILE\tUse the contents of FILE to specify the hostname"
-#define hostname_example_usage \
-       "$ hostname\n" \
-       "sage \n"
-
-#define id_trivial_usage \
-       "[OPTIONS]... [USERNAME]"
-#define id_full_usage \
-       "Print information for USERNAME or the current user\n\n" \
-       "Options:\n" \
-       "\t-g\tprints only the group ID\n" \
-       "\t-u\tprints only the user ID\n" \
-       "\t-n\tprint a name instead of a number (with for -ug)\n" \
-       "\t-r\tprints the real user ID instead of the effective ID (with -ug)"
-#define id_example_usage \
-       "$ id\n" \
-       "uid=1000(andersen) gid=1000(andersen)\n"
-
-#ifdef BB_FEATURE_IFCONFIG_SLIP
-  #define USAGE_SIOCSKEEPALIVE(a) a
-#else
-  #define USAGE_SIOCSKEEPALIVE(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-  #define USAGE_IFCONFIG_MII(a) a
-#else
-  #define USAGE_IFCONFIG_MII(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_HW
-  #define USAGE_IFCONFIG_HW(a) a
-#else
-  #define USAGE_IFCONFIG_HW(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-  #define USAGE_IFCONFIG_OPT_A(a) a
-#else
-  #define USAGE_IFCONFIG_OPT_A(a)
-#endif
-
-#define ifconfig_trivial_usage \
-       USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
-#define ifconfig_full_usage \
-       "configure a network interface\n\n" \
-       "Options:\n" \
-       "\t[[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n" \
-       "\t[netmask <address>]  [dstaddr <address>]\n" \
-       USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
-       "\t" USAGE_IFCONFIG_HW("[hw ether <address>]  ") \
-    "[metric <NN>]  [mtu <NN>]\n" \
-       "\t[[-]trailers]  [[-]arp]  [[-]allmulti]\n" \
-       "\t[multicast]  [[-]promisc]  [txqueuelen <NN>]  [[-]dynamic]\n" \
-       USAGE_IFCONFIG_MII("\t[mem_start <NN>]  [io_addr <NN>]  [irq <NN>]\n") \
-       "\t[up|down] ..."
-
-#define init_trivial_usage \
-       ""
-#define init_full_usage \
-       "Init is the parent of all processes."
-#define init_notes_usage \
-"This version of init is designed to be run only by the kernel.\n" \
-"\n" \
-"BusyBox init doesn't support multiple runlevels.  The runlevels field of\n" \
-"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \
-"runlevels, use sysvinit.\n" \
-"\n" \
-"BusyBox init works just fine without an inittab.  If no inittab is found, \n" \
-"it has the following default behavior:\n" \
-"\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      ::askfirst:/bin/sh\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/sbin/swapoff -a\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"\n" \
-"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
-"\n" \
-"      tty2::askfirst:/bin/sh\n" \
-"      tty3::askfirst:/bin/sh\n" \
-"      tty4::askfirst:/bin/sh\n" \
-"\n" \
-"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
-"\n" \
-"      <id>:<runlevels>:<action>:<process>\n" \
-"\n" \
-"      <id>: \n" \
-"\n" \
-"              WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
-"              The id field is used by BusyBox init to specify the controlling tty for\n" \
-"              the specified process to run on.  The contents of this field are\n" \
-"              appended to "/dev/" and used as-is.  There is no need for this field to\n" \
-"              be unique, although if it isn't you may have strange results.  If this\n" \
-"              field is left blank, the controlling tty is set to the console.  Also\n" \
-"              note that if BusyBox detects that a serial console is in use, then only\n" \
-"              entries whose controlling tty is either the serial console or /dev/null\n" \
-"              will be run.  BusyBox init does nothing with utmp.  We don't need no\n" \
-"              stinkin' utmp.\n" \
-"\n" \
-"      <runlevels>: \n" \
-"\n" \
-"              The runlevels field is completely ignored.\n" \
-"\n" \
-"      <action>: \n" \
-"\n" \
-"              Valid actions include: sysinit, respawn, askfirst, wait, \n" \
-"              once, ctrlaltdel, and shutdown.\n" \
-"\n" \
-"              The available actions can be classified into two groups: actions\n" \
-"              that are run only once, and actions that are re-run when the specified\n" \
-"              process exits.\n" \
-"\n" \
-"              Run only-once actions:\n" \
-"\n" \
-"                      'sysinit' is the first item run on boot.  init waits until all\n" \
-"                      sysinit actions are completed before continuing.  Following the\n" \
-"                      completion of all sysinit actions, all 'wait' actions are run.\n" \
-"                      'wait' actions, like  'sysinit' actions, cause init to wait until\n" \
-"                      the specified task completes.  'once' actions are asynchronous,\n" \
-"                      therefore, init does not wait for them to complete.  'ctrlaltdel'\n" \
-"                      actions are run when the system detects that someone on the system\n" \
-"                       console has pressed the CTRL-ALT-DEL key combination.  Typically one\n" \
-"                       wants to run 'reboot' at this point to cause the system to reboot.\n" \
-"                      Finally the 'shutdown' action specifies the actions to taken when\n" \
-"                       init is told to reboot.  Unmounting filesystems and disabling swap\n" \
-"                       is a very good here\n" \
-"\n" \
-"              Run repeatedly actions:\n" \
-"\n" \
-"                      'respawn' actions are run after the 'once' actions.  When a process\n" \
-"                      started with a 'respawn' action exits, init automatically restarts\n" \
-"                      it.  Unlike sysvinit, BusyBox init does not stop processes from\n" \
-"                      respawning out of control.  The 'askfirst' actions acts just like\n" \
-"                      respawn, except that before running the specified process it\n" \
-"                      displays the line "Please press Enter to activate this console."\n" \
-"                      and then waits for the user to press enter before starting the\n" \
-"                      specified process.  \n" \
-"\n" \
-"              Unrecognized actions (like initdefault) will cause init to emit an\n" \
-"              error message, and then go along with its business.  All actions are\n" \
-"              run in the reverse order from how they appear in /etc/inittab.\n" \
-"\n" \
-"      <process>: \n" \
-"\n" \
-"              Specifies the process to be executed and it's command line.\n" \
-"\n" \
-"Example /etc/inittab file:\n" \
-"\n" \
-"      # This is run first except when booting in single-user mode.\n" \
-"      #\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      \n" \
-"      # /bin/sh invocations on selected ttys\n" \
-"      #\n" \
-"      # Start an "askfirst" shell on the console (whatever that may be)\n" \
-"      ::askfirst:-/bin/sh\n" \
-"      # Start an "askfirst" shell on /dev/tty2-4\n" \
-"      tty2::askfirst:-/bin/sh\n" \
-"      tty3::askfirst:-/bin/sh\n" \
-"      tty4::askfirst:-/bin/sh\n" \
-"      \n" \
-"      # /sbin/getty invocations for selected ttys\n" \
-"      #\n" \
-"      tty4::respawn:/sbin/getty 38400 tty5\n" \
-"      tty5::respawn:/sbin/getty 38400 tty6\n" \
-"      \n" \
-"      \n" \
-"      # Example of how to put a getty on a serial line (for a terminal)\n" \
-"      #\n" \
-"      #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
-"      #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
-"      #\n" \
-"      # Example how to put a getty on a modem line.\n" \
-"      #::respawn:/sbin/getty 57600 ttyS2\n" \
-"      \n" \
-"      # Stuff to do before rebooting\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"      ::shutdown:/sbin/swapoff -a\n"
-
-#define insmod_trivial_usage \
-       "[OPTION]... MODULE [symbol=value]..."
-#define insmod_full_usage \
-       "Loads the specified kernel modules into the kernel.\n\n" \
-       "Options:\n" \
-       "\t-f\tForce module to load into the wrong kernel version.\n" \
-       "\t-k\tMake module autoclean-able.\n" \
-       "\t-v\tverbose output\n"  \
-       "\t-L\tLock to prevent simultaneous loads of a module\n" \
-       "\t-x\tdo not export externs"
-
-#define kill_trivial_usage \
-       "[-signal] process-id [process-id ...]"
-#define kill_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define kill_example_usage \
-       "$ ps | grep apache\n" \
-       "252 root     root     S [apache]\n" \
-       "263 www-data www-data S [apache]\n" \
-       "264 www-data www-data S [apache]\n" \
-       "265 www-data www-data S [apache]\n" \
-       "266 www-data www-data S [apache]\n" \
-       "267 www-data www-data S [apache]\n" \
-       "$ kill 252\n"
-
-#define killall_trivial_usage \
-       "[-signal] process-name [process-name ...]"
-#define killall_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define killall_example_usage \
-       "$ killall apache\n" 
-
-#define klogd_trivial_usage \
-       "-n"
-#define klogd_full_usage \
-       "Kernel logger.\n"\
-       "Options:\n"\
-       "\t-n\tRun as a foreground process."
-
-#define length_trivial_usage \
-       "STRING"
-#define length_full_usage \
-       "Prints out the length of the specified STRING."
-#define length_example_usage \
-       "$ length Hello\n" \
-       "5\n"
-
-#define ln_trivial_usage \
-       "[OPTION] TARGET... LINK_NAME|DIRECTORY"
-#define ln_full_usage \
-       "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
-       "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-s\tmake symbolic links instead of hard links\n" \
-       "\t-f\tremove existing destination files\n" \
-       "\t-n\tno dereference symlinks - treat like normal file"
-#define ln_example_usage \
-       "$ ln -s BusyBox /tmp/ls\n" \
-       "$ ls -l /tmp/ls\n" \
-       "lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -> BusyBox*\n" 
-
-#define loadacm_trivial_usage \
-       "< mapfile"
-#define loadacm_full_usage \
-       "Loads an acm from standard input."
-#define loadacm_example_usage \
-       "$ loadacm < /etc/i18n/acmname\n" 
-
-#define loadfont_trivial_usage \
-       "< font"
-#define loadfont_full_usage \
-       "Loads a console font from standard input."
-#define loadfont_example_usage \
-       "$ loadfont < /etc/i18n/fontname\n" 
-
-#define loadkmap_trivial_usage \
-       "< keymap"
-#define loadkmap_full_usage \
-       "Loads a binary keyboard translation table from standard input."
-#define loadkmap_example_usage \
-       "$ loadkmap < /etc/i18n/lang-keymap\n" 
-
-#define logger_trivial_usage \
-       "[OPTION]... [MESSAGE]"
-#define logger_full_usage \
-       "Write MESSAGE to the system log.  If MESSAGE is omitted, log stdin.\n\n" \
-       "Options:\n" \
-       "\t-s\tLog to stderr as well as the system log.\n" \
-       "\t-t\tLog using the specified tag (defaults to user name).\n" \
-       "\t-p\tEnter the message with the specified priority.\n" \
-       "\t\tThis may be numerical or a ``facility.level'' pair."
-#define logger_example_usage \
-       "$ logger "hello"\n" 
-
-#define logname_trivial_usage \
-       ""
-#define logname_full_usage \
-       "Print the name of the current user."
-#define logname_example_usage \
-       "$ logname\n" \
-       "root\n" 
-
-#define logread_trivial_usage \
-        ""
-
-#define logread_full_usage \
-        "Shows the messages from syslogd (using circular buffer)."
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-  #define USAGE_LS_TIMESTAMPS(a) a
-#else
-  #define USAGE_LS_TIMESTAMPS(a)
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-  #define USAGE_LS_FILETYPES(a) a
-#else
-  #define USAGE_LS_FILETYPES(a)
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-  #define USAGE_LS_FOLLOWLINKS(a) a
-#else
-  #define USAGE_LS_FOLLOWLINKS(a)
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-  #define USAGE_LS_RECURSIVE(a) a
-#else
-  #define USAGE_LS_RECURSIVE(a)
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-  #define USAGE_LS_SORTFILES(a) a
-#else
-  #define USAGE_LS_SORTFILES(a)
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-  #define USAGE_AUTOWIDTH(a) a
-#else
-  #define USAGE_AUTOWIDTH(a)
-#endif
-#define ls_trivial_usage \
-       "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]"
-#define ls_full_usage \
-       "List directory contents\n\n" \
-       "Options:\n" \
-       "\t-1\tlist files in a single column\n" \
-       "\t-A\tdo not list implied . and ..\n" \
-       "\t-a\tdo not hide entries starting with .\n" \
-       "\t-C\tlist entries by columns\n" \
-       USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \
-       "\t-d\tlist directory entries instead of contents\n" \
-       USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \
-       USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \
-       "\t-i\tlist the i-node for each file\n" \
-       "\t-l\tuse a long listing format\n" \
-       "\t-n\tlist numeric UIDs and GIDs instead of names\n" \
-       USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \
-       USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \
-       USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \
-       USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \
-       USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \
-       "\t-s\tlist the size of each file, in blocks\n" \
-       USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \
-       USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \
-       USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \
-       USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \
-       USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \
-       "\t-x\tlist entries by lines instead of by columns\n" \
-       USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \
-       USAGE_HUMAN_READABLE( \
-       "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\t-k\tprint sizes in kilobytes(compatibility)") 
-
-#define lsmod_trivial_usage \
-       ""
-#define lsmod_full_usage \
-       "List the currently loaded kernel modules."
-
-#define makedevs_trivial_usage \
-       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
-#define makedevs_full_usage \
-       "Creates a range of block or character special files\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
-       "FIRST specifies the number appended to NAME to create the first device.\n" \
-       "LAST specifies the number of the last item that should be created.\n" \
-       "If 's' is the last argument, the base device is created as well.\n\n" \
-       "For example:\n" \
-       "\tmakedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63\n" \
-       "\tmakedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8"
-#define makedevs_example_usage \
-       "$ makedevs /dev/ttyS c 4 66 2 63\n" \
-       "[creates ttyS2-ttyS63]\n" \
-       "$ makedevs /dev/hda b 3 0 0 8 s\n" \
-       "[creates hda,hda1-hda8]\n" 
-
-#define md5sum_trivial_usage \
-       "[OPTION] [FILE]...\n" \
-       "or: md5sum [OPTION] -c [FILE]"
-#define md5sum_full_usage \
-       "Print or check MD5 checksums.\n\n" \
-       "Options:\n" \
-       "With no FILE, or when FILE is -, read standard input.\n\n" \
-       "\t-b\tread files in binary mode\n" \
-       "\t-c\tcheck MD5 sums against given list\n" \
-       "\t-t\tread files in text mode (default)\n" \
-       "\t-g\tread a string\n" \
-       "\nThe following two options are useful only when verifying checksums:\n" \
-       "\t-s\tdon't output anything, status code shows success\n" \
-       "\t-w\twarn about improperly formated MD5 checksum lines"
-#define md5sum_example_usage \
-       "$ md5sum < busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003\n" \
-       "$ md5sum busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "$ md5sum -c -\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "busybox: OK\n" \
-       "^D\n"
-
-#define mkdir_trivial_usage \
-       "[OPTION] DIRECTORY..."
-#define mkdir_full_usage \
-       "Create the DIRECTORY(ies) if they do not already exist\n\n" \
-       "Options:\n" \
-       "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \
-       "\t-p\tno error if existing, make parent directories as needed"
-#define mkdir_example_usage \
-       "$ mkdir /tmp/foo\n" \
-       "$ mkdir /tmp/foo\n" \
-       "/tmp/foo: File exists\n" \
-       "$ mkdir /tmp/foo/bar/baz\n" \
-       "/tmp/foo/bar/baz: No such file or directory\n" \
-       "$ mkdir -p /tmp/foo/bar/baz\n" 
-
-#define mkfifo_trivial_usage \
-       "[OPTIONS] name"
-#define mkfifo_full_usage \
-       "Creates a named pipe (identical to 'mknod name p')\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the pipe using the specified mode (default a=rw)"
-
-#define mkfs_minix_trivial_usage \
-       "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
-#define mkfs_minix_full_usage \
-       "Make a MINIX filesystem.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck the device for bad blocks\n" \
-       "\t-n [14|30]\tSpecify the maximum length of filenames\n" \
-       "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \
-       "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \
-       "\t-v\t\tMake a Minix version 2 filesystem"
-
-#define mknod_trivial_usage \
-       "[OPTIONS] NAME TYPE MAJOR MINOR"
-#define mknod_full_usage \
-       "Create a special file (block, character, or pipe).\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
-#define mknod_example_usage \
-       "$ mknod /dev/fd0 b 2 0 \n" \
-       "$ mknod -m 644 /tmp/pipe p\n" 
-
-#define mkswap_trivial_usage \
-       "[-c] [-v0|-v1] device [block-count]"
-#define mkswap_full_usage \
-       "Prepare a disk partition to be used as a swap partition.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck for read-ability.\n" \
-       "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
-       "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
-       "\tblock-count\tNumber of block to use (default is entire partition)."
-
-#define mktemp_trivial_usage \
-       "[-q] TEMPLATE"
-#define mktemp_full_usage \
-       "Creates a temporary file with its name based on TEMPLATE.\n" \
-       "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)."
-#define mktemp_example_usage \
-       "$ mktemp /tmp/temp.XXXXXX\n" \
-       "/tmp/temp.mWiLjM\n" \
-       "$ ls -la /tmp/temp.mWiLjM\n" \
-       "-rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM\n" 
-
-#define modprobe_trivial_usage \
-       "[FILE ...]"
-#define modprobe_full_usage \
-       "Used for hight level module loading and unloading."
-#define modprobe_example_usage \
-       "$ modprobe cdrom\n" 
-
-#define more_trivial_usage \
-       "[FILE ...]"
-#define more_full_usage \
-       "More is a filter for viewing FILE one screenful at a time."
-#define more_example_usage \
-       "$ dmesg | more\n" 
-
-#ifdef BB_FEATURE_MOUNT_LOOP
-  #define USAGE_MOUNT_LOOP(a) a
-#else
-  #define USAGE_MOUNT_LOOP(a)
-#endif
-#ifdef BB_FEATURE_MTAB_SUPPORT
-  #define USAGE_MTAB(a) a
-#else
-  #define USAGE_MTAB(a)
-#endif
-#define mount_trivial_usage \
-       "[flags] DEVICE NODE [-o options,more-options]"
-#define mount_full_usage \
-       "Mount a filesystem\n\n" \
-       "Flags:\n"  \
-       "\t-a:\t\tMount all filesystems in fstab.\n" \
-       USAGE_MTAB( \
-       "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
-       "\t-n:\t\tDon't write a mount table entry.\n" \
-       ) \
-       "\t-o option:\tOne of many filesystem options, listed below.\n" \
-       "\t-r:\t\tMount the filesystem read-only.\n" \
-       "\t-t fs-type:\tSpecify the filesystem type.\n" \
-       "\t-w:\t\tMount for reading and writing (default).\n" \
-       "\n" \
-       "Options for use with the \"-o\" flag:\n" \
-       "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
-       "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
-       "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
-       "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
-       USAGE_MOUNT_LOOP( \
-       "\tloop:\t\tMounts a file via loop device.\n" \
-       ) \
-       "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
-       "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
-       "\tro/rw:\t\tMount for read-only / read-write.\n" \
-       "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
-       "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
-       "You'll have to see the written documentation for those filesystems."
-#define mount_example_usage \
-       "$ mount\n" \
-       "/dev/hda3 on / type minix (rw)\n" \
-       "proc on /proc type proc (rw)\n" \
-       "devpts on /dev/pts type devpts (rw)\n" \
-       "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
-       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" 
-
-#define mt_trivial_usage \
-       "[-f device] opcode value"
-#define mt_full_usage \
-       "Control magnetic tape drive operation\n" \
-       "\nAvailable Opcodes:\n\n" \
-       "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
-       "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
-       "ras3 reset retension rew rewoffline seek setblk setdensity\n" \
-       "setpart tell unload unlock weof wset"
-
-#define mv_trivial_usage \
-       "SOURCE DEST\n" \
-       "or: mv SOURCE... DIRECTORY"
-#define mv_full_usage \
-       "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY."
-#define mv_example_usage \
-       "$ mv /tmp/foo /bin/bar\n" 
-
-#define nc_trivial_usage \
-       "[IP] [port]" 
-#define nc_full_usage \
-       "Netcat opens a pipe to IP:port"
-#define nc_example_usage \
-       "$ nc foobar.somedomain.com 25\n" \
-       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
-       "help\n" \
-       "214-Commands supported:\n" \
-       "214-    HELO EHLO MAIL RCPT DATA AUTH\n" \
-       "214     NOOP QUIT RSET HELP\n" \
-       "quit\n" \
-       "221 foobar closing connection\n" 
-
-#define nslookup_trivial_usage \
-       "[HOST] [SERVER]"
-#define nslookup_full_usage \
-       "Queries the nameserver for the IP address of the given HOST\n" \
-       "optionally using a specified DNS server"
-#define nslookup_example_usage \
-       "$ nslookup localhost\n" \
-       "Server:     default\n" \
-       "Address:    default\n" \
-       "\n" \
-       "Name:       debian\n" \
-       "Address:    127.0.0.1\n" 
-
-#define pidof_trivial_usage \
-       "process-name [process-name ...]"
-#define pidof_full_usage \
-       "Lists the PIDs of all processes with names that match the names on the command line"
-#define pidof_example_usage \
-       "$ pidof init\n" \
-       "1\n"
-
-#ifndef BB_FEATURE_FANCY_PING
-#define ping_trivial_usage "host"
-#define ping_full_usage    "Send ICMP ECHO_REQUEST packets to network hosts"
-#else
-#define ping_trivial_usage \
-       "[OPTION]... host"
-#define ping_full_usage \
-       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
-       "Options:\n" \
-       "\t-c COUNT\tSend only COUNT pings.\n" \
-       "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
-       "\t-q\t\tQuiet mode, only displays output at start\n" \
-       "\t\t\tand when finished."
-#endif
-#define ping_example_usage \
-       "$ ping localhost\n" \
-       "PING slag (127.0.0.1): 56 data bytes\n" \
-       "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
-       "\n" \
-       "--- debian ping statistics ---\n" \
-       "1 packets transmitted, 1 packets received, 0% packet loss\n" \
-       "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 
-
-#define pivot_root_trivial_usage \
-       "NEW_ROOT PUT_OLD"
-#define pivot_root_full_usage \
-       "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
-       "the new root file system."
-
-#define poweroff_trivial_usage \
-       ""
-#define poweroff_full_usage \
-       "Halt the system and request that the kernel shut off the power."
-
-#define printf_trivial_usage \
-       "FORMAT [ARGUMENT...]"
-#define printf_full_usage \
-       "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
-       "Where FORMAT controls the output exactly as in C printf."
-#define printf_example_usage \
-       "$ printf "Val=%d\\n" 5\n" \
-       "Val=5\n" 
-
-#define ps_trivial_usage \
-       ""
-#define ps_full_usage \
-       "Report process status\n" \
-       "\nThis version of ps accepts no options."
-#define ps_example_usage \
-       "$ ps\n" \
-       "  PID  Uid      Gid State Command\n" \
-       "    1 root     root     S init\n" \
-       "    2 root     root     S [kflushd]\n" \
-       "    3 root     root     S [kupdate]\n" \
-       "    4 root     root     S [kpiod]\n" \
-       "    5 root     root     S [kswapd]\n" \
-       "  742 andersen andersen S [bash]\n" \
-       "  743 andersen andersen S -bash\n" \
-       "  745 root     root     S [getty]\n" \
-       " 2990 andersen andersen R ps\n"
-
-#define pwd_trivial_usage \
-       ""
-#define pwd_full_usage \
-       "Print the full filename of the current working directory."
-#define pwd_example_usage \
-       "$ pwd\n" \
-       "/root\n"
-
-#define rdate_trivial_usage \
-       "[OPTION] HOST"
-#define rdate_full_usage \
-       "Get and possibly set the system date and time from a remote HOST.\n\n" \
-       "Options:\n" \
-       "\t-s\tSet the system date and time (default).\n" \
-       "\t-p\tPrint the date and time."
-
-#define readlink_trivial_usage \
-       ""
-#define readlink_full_usage \
-       "Read a symbolic link."
-
-#define reboot_trivial_usage \
-       ""
-#define reboot_full_usage \
-       "Reboot the system."
-
-#define renice_trivial_usage \
-       "priority pid [pid ...]"
-#define renice_full_usage \
-       "Changes priority of running processes. Allowed priorities range\n" \
-       "from 20 (the process runs only when nothing else is running) to 0\n" \
-       "(default priority) to -20 (almost nothing else ever gets to run)."
-
-#define reset_trivial_usage \
-       ""
-#define reset_full_usage \
-       "Resets the screen."
-
-#define rm_trivial_usage \
-       "[OPTION]... FILE..."
-#define rm_full_usage \
-       "Remove (unlink) the FILE(s).  You may use '--' to\n" \
-       "indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-i\t\talways prompt before removing each destination" \
-       "\t-f\t\tremove existing destinations, never prompt\n" \
-       "\t-r or -R\tremove the contents of directories recursively"
-#define rm_example_usage \
-       "$ rm -rf /tmp/foo\n"
-
-#define rmdir_trivial_usage \
-       "[OPTION]... DIRECTORY..."
-#define rmdir_full_usage \
-       "Remove the DIRECTORY(ies), if they are empty."
-#define rmdir_example_usage \
-       "# rmdir /tmp/foo\n"
-
-#define rmmod_trivial_usage \
-       "[OPTION]... [MODULE]..."
-#define rmmod_full_usage \
-       "Unloads the specified kernel modules from the kernel.\n\n" \
-       "Options:\n" \
-       "\t-a\tTry to remove all unused kernel modules."
-#define rmmod_example_usage \
-       "$ rmmod tulip\n"
-
-#define route_trivial_usage \
-       "[{add|del|flush}]"
-#define route_full_usage \
-       "Edit the kernel's routing tables"
-
-#define rpm2cpio_trivial_usage \
-       "package.rpm"
-#define rpm2cpio_full_usage \
-       "Outputs a cpio archive of the rpm file."
-
-#define sed_trivial_usage \
-       "[-nef] pattern [files...]"
-#define sed_full_usage \
-       "Options:\n" \
-       "\t-n\t\tsuppress automatic printing of pattern space\n" \
-       "\t-e script\tadd the script to the commands to be executed\n" \
-       "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \
-       "\n" \
-       "If no -e or -f is given, the first non-option argument is taken as the\n" \
-       "sed script to interpret. All remaining arguments are names of input\n" \
-       "files; if no input files are specified, then the standard input is read."
-#define sed_example_usage \
-       "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
-       "bar\n"
-
-#define setkeycodes_trivial_usage \
-       "SCANCODE KEYCODE ..."
-#define setkeycodes_full_usage \
-       "Set entries into the kernel's scancode-to-keycode map,\n" \
-       "allowing unusual keyboards to generate usable keycodes.\n\n" \
-       "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
-       "and KEYCODE is given in decimal"
-#define setkeycodes_example_usage \
-       "$ setkeycodes e030 127\n"
-
-#define lash_trivial_usage \
-       "[FILE]...\n" \
-       "or: sh -c command [args]..."
-#define lash_full_usage \
-       "lash: The BusyBox LAme SHell (command interpreter)"
-#define lash_notes_usage \
-"This command does not yet have proper documentation.\n" \
-"\n" \
-"Use lash just as you would use any other shell.  It properly handles pipes,\n" \
-"redirects, job control, can be used as the shell for scripts, and has a\n" \
-"sufficient set of builtins to do what is needed.  It does not (yet) support\n" \
-"Bourne Shell syntax.  If you need things like "if-then-else", "while", and such\n" \
-"use ash or bash.  If you just need a very simple and extremely small shell,\n" \
-"this will do the job."
-
-#define sleep_trivial_usage \
-       "N"
-#define sleep_full_usage \
-       "Pause for N seconds."
-#define sleep_example_usage \
-       "$ sleep 2\n" \
-       "[2 second delay results]\n"
-
-
-#ifdef BB_FEATURE_SORT_UNIQUE
-  #define USAGE_SORT_UNIQUE(a) a
-#else
-  #define USAGE_SORT_UNIQUE(a)
-#endif
-#ifdef BB_FEATURE_SORT_REVERSE
-  #define USAGE_SORT_REVERSE(a) a
-#else
-  #define USAGE_SORT_REVERSE(a)
-#endif
-#define sort_trivial_usage \
-       "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
-#define sort_full_usage \
-       "Sorts lines of text in the specified files\n\n"\
-       "Options:\n" \
-       USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
-       USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
-       "\t-n\tsort numerics"
-#define sort_example_usage \
-       "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
-       "a\n" \
-       "b\n" \
-       "c\n" \
-       "d\n" \
-       "e\n" \
-       "f\n"
-
-#define stty_trivial_usage \
-       "[-a|g] [-F DEVICE] [SETTING]..."
-#define stty_full_usage \
-       "Without arguments, prints baud rate, line discipline," \
-       "\nand deviations from stty sane." \
-       "\n\nOptions:" \
-       "\n\t-F DEVICE\topen device instead of stdin" \
-       "\n\t-a\t\tprint all current settings in human-readable form" \
-       "\n\t-g\t\tprint in stty-readable form" \
-       "\n\t[SETTING]\tsee manpage"
-
-#define swapoff_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapoff_full_usage \
-       "Stop swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStop swapping on all swap devices"
-
-#define swapon_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapon_full_usage \
-       "Start swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStart swapping on all swap devices"
-
-#define sync_trivial_usage \
-       ""
-#define sync_full_usage \
-       "Write all buffered filesystem blocks to disk."
-
-
-#ifdef BB_FEATURE_REMOTE_LOG
-  #define USAGE_REMOTE_LOG(a) a
-#else
-  #define USAGE_REMOTE_LOG(a)
-#endif
-#define syslogd_trivial_usage \
-       "[OPTION]..."
-#define syslogd_full_usage \
-       "Linux system and kernel logging utility.\n" \
-       "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \
-       "Options:\n" \
-       "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \
-       "\t-n\t\tRun as a foreground process\n" \
-       "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \
-       USAGE_REMOTE_LOG( \
-       "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \
-       "\t-L\t\tLog locally and via network logging (default is network only)")
-#define syslogd_example_usage \
-       "$ syslogd -R masterlog:514\n" \
-       "$ syslogd -R 192.168.1.1:601\n"
-
-
-#ifndef BB_FEATURE_FANCY_TAIL
-  #define USAGE_UNSIMPLE_TAIL(a)
-#else
-  #define USAGE_UNSIMPLE_TAIL(a) a
-#endif
-#define tail_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tail_full_usage \
-       "Print last 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \
-       "\t-n N[kbm]\tprint last N lines instead of last 10\n" \
-       "\t-f\t\toutput data as the file grows" \
-       USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \
-       "\t-s SEC\t\twait SEC seconds between reads with -f\n" \
-       "\t-v\t\talways output headers giving file names\n\n" \
-       "If the first character of N (bytes or lines) is a '+', output begins with \n" \
-       "the Nth item from the start of each file, otherwise, print the last N items\n" \
-       "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." )
-#define tail_example_usage \
-       "$ tail -n 1 /etc/resolv.conf\n" \
-       "nameserver 10.0.0.1\n"
-
-#ifdef BB_FEATURE_TAR_CREATE
-  #define USAGE_TAR_CREATE(a) a
-#else
-  #define USAGE_TAR_CREATE(a)
-#endif
-#ifdef BB_FEATURE_TAR_EXCLUDE
-  #define USAGE_TAR_EXCLUDE(a) a
-#else
-  #define USAGE_TAR_EXCLUDE(a)
-#endif
-#define tar_trivial_usage \
-       "-[" USAGE_TAR_CREATE("c") "xtvO] " \
-       USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \
-       "[-f TARFILE] [-C DIR] [FILE(s)] ..."
-#define tar_full_usage \
-       "Create, extract, or list files from a tar file.\n\n" \
-       "Options:\n" \
-       USAGE_TAR_CREATE("\tc\t\tcreate\n") \
-       "\tx\t\textract\n" \
-       "\tt\t\tlist\n" \
-       "\nFile selection:\n" \
-       "\tf\t\tname of TARFILE or \"-\" for stdin\n" \
-       "\tO\t\textract to stdout\n" \
-       USAGE_TAR_EXCLUDE( \
-       "\texclude\t\tfile to exclude\n" \
-        "\tX\t\tfile with names to exclude\n" \
-       ) \
-       "\tC\t\tchange to directory DIR before operation\n" \
-       "\tv\t\tverbosely list files processed"
-#define tar_example_usage \
-       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
-       "$ tar -cf /tmp/tarball.tar /usr/local\n"
-
-#define tee_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tee_full_usage \
-       "Copy standard input to each FILE, and also to standard output.\n\n" \
-       "Options:\n" \
-       "\t-a\tappend to the given FILEs, do not overwrite"
-#define tee_example_usage \
-       "$ echo "Hello" | tee /tmp/foo\n" \
-       "$ cat /tmp/foo\n" \
-       "Hello\n"
-
-#define telnet_trivial_usage \
-       "HOST [PORT]"
-#define telnet_full_usage \
-       "Telnet is used to establish interactive communication with another\n"\
-       "computer over a network using the TELNET protocol."
-
-#define test_trivial_usage \
-       "EXPRESSION\n  or   [ EXPRESSION ]"
-#define test_full_usage \
-       "Checks file types and compares values returning an exit\n" \
-       "code determined by the value of EXPRESSION."
-#define test_example_usage \
-       "$ test 1 -eq 2\n" \
-       "$ echo $?\n" \
-       "1\n" \
-       "$ test 1 -eq 1\n" \
-       "$ echo $? \n" \
-       "0\n" \
-       "$ [ -d /etc ]\n" \
-       "$ echo $?\n" \
-       "0\n" \
-       "$ [ -d /junk ]\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#ifdef BB_FEATURE_TFTP_GET
-  #define USAGE_TFTP_GET(a) a
-#else
-  #define USAGE_TFTP_GET(a)
-#endif
-#ifdef BB_FEATURE_TFTP_PUT
-  #define USAGE_TFTP_PUT(a) a
-#else
-  #define USAGE_TFTP_PUT(a)
-#endif
-
-#define tftp_trivial_usage \
-       "[OPTION]... HOST [PORT]"
-#define tftp_full_usage \
-       "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
-       "Options:\n" \
-       "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
-        USAGE_TFTP_GET(        \
-        "\t-g\tGet file.\n" \
-        ) \
-       "\t-l FILE\tTransfer local FILE.\n" \
-        USAGE_TFTP_PUT(        \
-       "\t-p\tPut file.\n" \
-       ) \
-       "\t-r FILE\tTransfer remote FILE.\n"
-
-#define touch_trivial_usage \
-       "[-c] FILE [FILE ...]"
-#define touch_full_usage \
-       "Update the last-modified date on the given FILE[s].\n\n" \
-       "Options:\n" \
-       "\t-c\tDo not create any files"
-#define touch_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "/bin/ls: /tmp/foo: No such file or directory\n" \
-       "$ touch /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo\n" 
-
-#define tr_trivial_usage \
-       "[-cds] STRING1 [STRING2]"
-#define tr_full_usage \
-       "Translate, squeeze, and/or delete characters from\n" \
-       "standard input, writing to standard output.\n\n" \
-       "Options:\n" \
-       "\t-c\ttake complement of STRING1\n" \
-       "\t-d\tdelete input characters coded STRING1\n" \
-       "\t-s\tsqueeze multiple output characters of STRING2 into one character"
-#define tr_example_usage \
-       "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
-       "hello world\n" 
-
-#define traceroute_trivial_usage \
-       "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\
-       [-s src_addr] [-t tos] [-w wait] host [data size]"
-#define traceroute_full_usage \
-       "trace the route ip packets follow going to \"host\"\n" \
-       "Options:\n" \
-       "\t-d\tset SO_DEBUG options to socket\n" \
-       "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
-       "\t-r\tBypass the normal routing tables and send directly to a host\n" \
-       "\t-v\tVerbose output\n" \
-       "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \
-       "\t-p port#\tSet the base UDP port number used in probes\n" \
-       "\t\t(default is 33434)\n" \
-       "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \
-       "\t\t(default is 3)\n" \
-       "\t-s src_addr\tUse the following IP address as the source address\n" \
-       "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
-       "\t\t(default 0)\n" \
-       "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
-       "\t\t(default 3 sec.)."
-
-
-#define true_trivial_usage \
-       ""
-#define true_full_usage \
-       "Return an exit code of TRUE (0)."
-#define true_example_usage \
-       "$ true\n" \
-       "$ echo $?\n" \
-       "0\n"
-
-#define tty_trivial_usage \
-       ""
-#define tty_full_usage \
-       "Print the file name of the terminal connected to standard input.\n\n"\
-       "Options:\n" \
-       "\t-s\tprint nothing, only return an exit status"
-#define tty_example_usage \
-       "$ tty\n" \
-       "/dev/tty2\n"
-
-#ifdef BB_FEATURE_MOUNT_FORCE
-  #define USAGE_MOUNT_FORCE(a) a
-#else
-  #define USAGE_MOUNT_FORCE(a)
-#endif
-#define umount_trivial_usage \
-       "[flags] FILESYSTEM|DIRECTORY"
-#define umount_full_usage \
-       "Unmount file systems\n" \
-       "\nFlags:\n" "\t-a\tUnmount all file systems" \
-       USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \
-       "\n\t-r\tTry to remount devices as read-only if mount is busy" \
-       USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \
-       USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)")
-#define umount_example_usage \
-       "$ umount /dev/hdc1 \n"
-
-#define uname_trivial_usage \
-       "[OPTION]..."
-#define uname_full_usage \
-       "Print certain system information.  With no OPTION, same as -s.\n\n" \
-       "Options:\n" \
-       "\t-a\tprint all information\n" \
-       "\t-m\tthe machine (hardware) type\n" \
-       "\t-n\tprint the machine's network node hostname\n" \
-       "\t-r\tprint the operating system release\n" \
-       "\t-s\tprint the operating system name\n" \
-       "\t-p\tprint the host processor type\n" \
-       "\t-v\tprint the operating system version"
-#define uname_example_usage \
-       "$ uname -a\n" \
-       "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" 
-
-#define uniq_trivial_usage \
-       "[OPTION]... [INPUT [OUTPUT]]"
-#define uniq_full_usage \
-       "Discard all but one of successive identical lines from INPUT\n" \
-       "(or standard input), writing to OUTPUT (or standard output).\n\n" \
-       "Options:\n" \
-       "\t-c\tprefix lines by the number of occurrences\n" \
-       "\t-d\tonly print duplicate lines\n" \
-       "\t-u\tonly print unique lines"
-#define uniq_example_usage \
-       "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
-       "a\n" \
-       "b\n" \
-       "c\n"
-
-#define unix2dos_trivial_usage \
-       "[option] [FILE]"
-#define unix2dos_full_usage \
-       "Converts FILE from unix format to dos format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define update_trivial_usage \
-       "[options]"
-#define update_full_usage \
-       "Periodically flushes filesystem buffers.\n\n" \
-       "Options:\n" \
-       "\t-S\tforce use of sync(2) instead of flushing\n" \
-       "\t-s SECS\tcall sync this often (default 30)\n" \
-       "\t-f SECS\tflush some buffers this often (default 5)"
-
-#define uptime_trivial_usage \
-       ""
-#define uptime_full_usage \
-       "Display the time since the last boot."
-#define uptime_example_usage \
-       "$ uptime\n" \
-       "  1:55pm  up  2:30, load average: 0.09, 0.04, 0.00\n" 
-
-#define usleep_trivial_usage \
-       "N" 
-#define usleep_full_usage \
-       "Pause for N microseconds."
-#define usleep_example_usage \
-       "$ usleep 1000000\n" \
-       "[pauses for 1 second]\n"
-
-#define uudecode_trivial_usage \
-       "[FILE]..."
-#define uudecode_full_usage \
-       "Uudecode a file that is uuencoded.\n\n" \
-       "Options:\n" \
-       "\t-o FILE\tdirect output to FILE" 
-#define uudecode_example_usage \
-       "$ uudecode -o busybox busybox.uu\n" \
-       "$ ls -l busybox\n" \
-       "-rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox\n" 
-
-#define uuencode_trivial_usage \
-       "[OPTION] [INFILE] REMOTEFILE"
-#define uuencode_full_usage \
-       "Uuencode a file.\n\n" \
-       "Options:\n" \
-       "\t-m\tuse base64 encoding per RFC1521"
-#define uuencode_example_usage \
-       "$ uuencode busybox busybox\n" \
-       "begin 755 busybox\n" \
-       "<encoded file snipped>\n" \
-       "$ uudecode busybox busybox > busybox.uu\n" \
-       "$\n"
-
-#define vi_trivial_usage \
-       "[OPTION] [FILE]..."
-#define vi_full_usage \
-       "edit FILE.\n\n" \
-       "Options:\n" \
-       "\t-R\tRead-only- do not write to the file." 
-
-#define watchdog_trivial_usage \
-       "DEV"
-#define watchdog_full_usage \
-       "Periodically write to watchdog device DEV"
-
-#define wc_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define wc_full_usage \
-       "Print line, word, and byte counts for each FILE, and a total line if\n" \
-       "more than one FILE is specified.  With no FILE, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-c\tprint the byte counts\n" \
-       "\t-l\tprint the newline counts\n" \
-       "\t-L\tprint the length of the longest line\n" \
-       "\t-w\tprint the word counts"
-#define wc_example_usage \
-       "$ wc /etc/passwd\n" \
-       "     31      46    1365 /etc/passwd\n" 
-
-#define wget_trivial_usage \
-       "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url"
-#define wget_full_usage \
-       "wget retrieves files via HTTP or FTP\n\n" \
-       "Options:\n" \
-       "\t-c\tcontinue retrieval of aborted transfers\n" \
-       "\t-q\tquiet mode - do not print\n" \
-       "\t-P\tSet directory prefix to DIR\n" \
-       "\t-O\tsave to filename ('-' for stdout)"
-
-#define which_trivial_usage \
-       "[COMMAND ...]"
-#define which_full_usage \
-       "Locates a COMMAND."
-#define which_example_usage \
-       "$ which login\n" \
-       "/bin/login\n"
-
-#define whoami_trivial_usage \
-       ""
-#define whoami_full_usage \
-       "Prints the user name associated with the current effective user id."
-
-#define xargs_trivial_usage \
-       "[COMMAND] [ARGS...]"
-#define xargs_full_usage \
-       "Executes COMMAND on every item given by standard input."
-#define xargs_example_usage \
-       "$ ls | xargs gzip\n" \
-       "$ find . -name '*.c' -print | xargs rm\n" 
-
-#define yes_trivial_usage \
-       "[OPTION]... [STRING]..."
-#define yes_full_usage \
-       "Repeatedly outputs a line with all specified STRING(s), or 'y'."
-
-#define zcat_trivial_usage \
-       "FILE"
-#define zcat_full_usage \
-       "Uncompress to stdout."
diff --git a/busybox/init.c b/busybox/init.c
deleted file mode 100644 (file)
index 45b510f..0000000
+++ /dev/null
@@ -1,1031 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini init implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Adjusted by so many folks, it's impossible to keep track.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* Turn this on to disable all the dangerous 
-   rebooting stuff when debugging.
-#define DEBUG_INIT
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include "busybox.h"
-#ifdef BB_SYSLOGD
-# include <sys/syslog.h>
-#endif
-
-
-/* From <linux/vt.h> */
-struct vt_stat {
-       unsigned short v_active;        /* active vt */
-       unsigned short v_signal;        /* signal to send */
-       unsigned short v_state;         /* vt bitmask */
-};
-static const int VT_GETSTATE = 0x5603;  /* get global vt state info */
-
-/* From <linux/serial.h> */
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-
-
-#ifndef RB_HALT_SYSTEM
-static const int RB_HALT_SYSTEM = 0xcdef0123;
-static const int RB_ENABLE_CAD = 0x89abcdef;
-static const int RB_DISABLE_CAD = 0;
-#define RB_POWER_OFF    0x4321fedc
-static const int RB_AUTOBOOT = 0x01234567;
-#endif
-
-#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) 
-  #include <sys/reboot.h>
-  #define init_reboot(magic) reboot(magic)
-#else
-  #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
-#endif
-
-#ifndef _PATH_STDPATH
-#define _PATH_STDPATH  "/usr/bin:/bin:/usr/sbin:/sbin"
-#endif
-
-
-#if defined BB_FEATURE_INIT_COREDUMPS
-/*
- * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called 
- * before processes are spawned to set core file size as unlimited.
- * This is for debugging only.  Don't use this is production, unless
- * you want core dumps lying about....
- */
-#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
-#include <sys/resource.h>
-#include <sys/time.h>
-#endif
-
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
-#if __GNU_LIBRARY__ > 5
-       #include <sys/kdaemon.h>
-#else
-       extern int bdflush (int func, long int data);
-#endif
-
-
-#define SHELL        "/bin/sh"      /* Default shell */
-#define LOGIN_SHELL  "-" SHELL      /* Default login shell */
-#define INITTAB      "/etc/inittab"  /* inittab file location */
-#ifndef INIT_SCRIPT
-#define INIT_SCRIPT  "/etc/init.d/rcS"   /* Default sysinit script. */
-#endif
-
-#define MAXENV 16              /* Number of env. vars */
-//static const int MAXENV = 16;        /* Number of env. vars */
-static const int LOG = 0x1;
-static const int CONSOLE = 0x2;
-
-/* Allowed init action types */
-typedef enum {
-       SYSINIT = 1,
-       RESPAWN,
-       ASKFIRST,
-       WAIT,
-       ONCE,
-       CTRLALTDEL,
-       SHUTDOWN
-} initActionEnum;
-
-/* A mapping between "inittab" action name strings and action type codes. */
-typedef struct initActionType {
-       const char *name;
-       initActionEnum action;
-} initActionType;
-
-static const struct initActionType actions[] = {
-       {"sysinit", SYSINIT},
-       {"respawn", RESPAWN},
-       {"askfirst", ASKFIRST},
-       {"wait", WAIT},
-       {"once", ONCE},
-       {"ctrlaltdel", CTRLALTDEL},
-       {"shutdown", SHUTDOWN},
-       {0, 0}
-};
-
-/* Set up a linked list of initActions, to be read from inittab */
-typedef struct initActionTag initAction;
-struct initActionTag {
-       pid_t pid;
-       char process[256];
-       char console[256];
-       initAction *nextPtr;
-       initActionEnum action;
-};
-static initAction *initActionList = NULL;
-
-
-static char *secondConsole = VC_2;
-static char *thirdConsole  = VC_3;
-static char *fourthConsole = VC_4;
-static char *log           = VC_5;
-static int  kernelVersion  = 0;
-static char termType[32]   = "TERM=linux";
-static char console[32]    = _PATH_CONSOLE;
-
-static void delete_initAction(initAction * action);
-
-static void loop_forever()
-{
-       while (1)
-               sleep (1);
-}
-
-/* Print a message to the specified device.
- * Device may be bitwise-or'd from LOG | CONSOLE */
-static void message(int device, char *fmt, ...)
-                  __attribute__ ((format (printf, 2, 3)));
-static void message(int device, char *fmt, ...)
-{
-       va_list arguments;
-       int fd;
-
-#ifdef BB_SYSLOGD
-
-       /* Log the message to syslogd */
-       if (device & LOG) {
-               char msg[1024];
-
-               va_start(arguments, fmt);
-               vsnprintf(msg, sizeof(msg), fmt, arguments);
-               va_end(arguments);
-               openlog(applet_name, 0, LOG_USER);
-               syslog(LOG_USER|LOG_INFO, msg);
-               closelog();
-       }
-#else
-       static int log_fd = -1;
-
-       /* Take full control of the log tty, and never close it.
-        * It's mine, all mine!  Muhahahaha! */
-       if (log_fd < 0) {
-               if (log == NULL) {
-                       /* don't even try to log, because there is no such console */
-                       log_fd = -2;
-                       /* log to main console instead */
-                       device = CONSOLE;
-               } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
-                       log_fd = -2;
-                       fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log);
-                       log = NULL;
-                       device = CONSOLE;
-               }
-       }
-       if ((device & LOG) && (log_fd >= 0)) {
-               va_start(arguments, fmt);
-               vdprintf(log_fd, fmt, arguments);
-               va_end(arguments);
-       }
-#endif
-
-       if (device & CONSOLE) {
-               /* Always send console messages to /dev/console so people will see them. */
-               if (
-                       (fd =
-                        device_open(_PATH_CONSOLE,
-                                                O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {
-                       va_start(arguments, fmt);
-                       vdprintf(fd, fmt, arguments);
-                       va_end(arguments);
-                       close(fd);
-               } else {
-                       fprintf(stderr, "Bummer, can't print: ");
-                       va_start(arguments, fmt);
-                       vfprintf(stderr, fmt, arguments);
-                       va_end(arguments);
-               }
-       }
-}
-
-/* Set terminal settings to reasonable defaults */
-static void set_term(int fd)
-{
-       struct termios tty;
-
-       tcgetattr(fd, &tty);
-
-       /* set control chars */
-       tty.c_cc[VINTR]  = 3;   /* C-c */
-       tty.c_cc[VQUIT]  = 28;  /* C-\ */
-       tty.c_cc[VERASE] = 127; /* C-? */
-       tty.c_cc[VKILL]  = 21;  /* C-u */
-       tty.c_cc[VEOF]   = 4;   /* C-d */
-       tty.c_cc[VSTART] = 17;  /* C-q */
-       tty.c_cc[VSTOP]  = 19;  /* C-s */
-       tty.c_cc[VSUSP]  = 26;  /* C-z */
-
-       /* use line dicipline 0 */
-       tty.c_line = 0;
-
-       /* Make it be sane */
-       tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
-       tty.c_cflag |= CREAD|HUPCL|CLOCAL;
-
-
-       /* input modes */
-       tty.c_iflag = ICRNL | IXON | IXOFF;
-
-       /* output modes */
-       tty.c_oflag = OPOST | ONLCR;
-
-       /* local modes */
-       tty.c_lflag =
-               ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
-
-       tcsetattr(fd, TCSANOW, &tty);
-}
-
-/* How much memory does this machine have?
-   Units are kBytes to avoid overflow on 4GB machines */
-static int check_free_memory()
-{
-       struct sysinfo info;
-       unsigned int result, u, s=10;
-
-       if (sysinfo(&info) != 0) {
-               perror_msg("Error checking free memory");
-               return -1;
-       }
-
-       /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes.
-        * Kernels 2.4.0 return info.mem_unit in bytes. */
-       u = info.mem_unit;
-       if (u==0) u=1;
-       while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; }
-       result = (info.totalram>>s) + (info.totalswap>>s);
-       result = result*u;
-       if (result < 0) result = INT_MAX;
-       return result;
-}
-
-static void console_init()
-{
-       int fd;
-       int tried_devcons = 0;
-       int tried_vtprimary = 0;
-       struct vt_stat vt;
-       struct serial_struct sr;
-       char *s;
-
-       if ((s = getenv("TERM")) != NULL) {
-               snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);
-       }
-
-       if ((s = getenv("CONSOLE")) != NULL) {
-               safe_strncpy(console, s, sizeof(console));
-       }
-#if #cpu(sparc)
-       /* sparc kernel supports console=tty[ab] parameter which is also 
-        * passed to init, so catch it here */
-       else if ((s = getenv("console")) != NULL) {
-               /* remap tty[ab] to /dev/ttyS[01] */
-               if (strcmp(s, "ttya") == 0)
-                       safe_strncpy(console, SC_0, sizeof(console));
-               else if (strcmp(s, "ttyb") == 0)
-                       safe_strncpy(console, SC_1, sizeof(console));
-       }
-#endif
-       else {
-               /* 2.2 kernels: identify the real console backend and try to use it */
-               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
-                       /* this is a serial console */
-                       snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line);
-               } else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
-                       /* this is linux virtual tty */
-                       snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);
-               } else {
-                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
-                       tried_devcons++;
-               }
-       }
-
-       while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
-               /* Can't open selected console -- try /dev/console */
-               if (!tried_devcons) {
-                       tried_devcons++;
-                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
-                       continue;
-               }
-               /* Can't open selected console -- try vt1 */
-               if (!tried_vtprimary) {
-                       tried_vtprimary++;
-                       safe_strncpy(console, VC_1, sizeof(console));
-                       continue;
-               }
-               break;
-       }
-       if (fd < 0) {
-               /* Perhaps we should panic here? */
-               safe_strncpy(console, "/dev/null", sizeof(console));
-       } else {
-               /* check for serial console and disable logging to tty5 & running a
-                  * shell to tty2-4 */
-               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
-                       log = NULL;
-                       secondConsole = NULL;
-                       thirdConsole = NULL;
-                       fourthConsole = NULL;
-                       /* Force the TERM setting to vt102 for serial console --
-                        * iff TERM is set to linux (the default) */
-                       if (strcmp( termType, "TERM=linux" ) == 0)
-                               safe_strncpy(termType, "TERM=vt102", sizeof(termType));
-                       message(LOG | CONSOLE,
-                                       "serial console detected.  Disabling virtual terminals.\r\n");
-               }
-               close(fd);
-       }
-       message(LOG, "console=%s\n", console);
-}
-       
-static void fixup_argv(int argc, char **argv, char *new_argv0)
-{
-       int len;
-       /* Fix up argv[0] to be certain we claim to be init */
-       len = strlen(argv[0]);
-       memset(argv[0], 0, len);
-       strncpy(argv[0], new_argv0, len);
-
-       /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
-       len = 1;
-       while (argc > len) {
-               memset(argv[len], 0, strlen(argv[len]));
-               len++;
-       }
-}
-
-
-static pid_t run(char *command, char *terminal, int get_enter)
-{
-       int i, j;
-       int fd;
-       pid_t pid;
-       char *tmpCmd, *s;
-       char *cmd[255], *cmdpath;
-       char buf[255];
-       struct stat sb;
-       static const char press_enter[] =
-
-#ifdef CUSTOMIZED_BANNER
-#include CUSTOMIZED_BANNER
-#endif
-
-               "\nPlease press Enter to activate this console. ";
-       char *environment[MAXENV+1] = {
-               termType,
-               "HOME=/",
-               "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
-               "SHELL=" SHELL,
-               "USER=root",
-               NULL
-       };
-
-       /* inherit environment to the child, merging our values -andy */
-       for (i=0; environ[i]; i++) {
-               for (j=0; environment[j]; j++) {
-                       s = strchr(environment[j], '=');
-                       if (!strncmp(environ[i], environment[j], s - environment[j]))
-                               break;
-               }
-               if (!environment[j]) {
-                       environment[j++] = environ[i];
-                       environment[j] = NULL;
-               }
-       }
-
-       if ((pid = fork()) == 0) {
-               /* Clean up */
-               ioctl(0, TIOCNOTTY, 0);
-               close(0);
-               close(1);
-               close(2);
-               setsid();
-
-               /* Reset signal handlers set for parent process */
-               signal(SIGUSR1, SIG_DFL);
-               signal(SIGUSR2, SIG_DFL);
-               signal(SIGINT, SIG_DFL);
-               signal(SIGTERM, SIG_DFL);
-               signal(SIGHUP, SIG_DFL);
-
-               if ((fd = device_open(terminal, O_RDWR)) < 0) {
-                       if (stat(terminal, &sb) != 0) {
-                               message(LOG | CONSOLE, "device '%s' does not exist.\n",
-                                               terminal);
-                               exit(1);
-                       }
-                       message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal);
-                       exit(1);
-               }
-               dup2(fd, 0);
-               dup2(fd, 1);
-               dup2(fd, 2);
-               ioctl(0, TIOCSCTTY, 1);
-               tcsetpgrp(0, getpgrp());
-               set_term(0);
-
-               /* See if any special /bin/sh requiring characters are present */
-               if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
-                       cmd[0] = SHELL;
-                       cmd[1] = "-c";
-                       strcpy(buf, "exec ");
-                       strncat(buf, command, sizeof(buf) - strlen(buf) - 1);
-                       cmd[2] = buf;
-                       cmd[3] = NULL;
-               } else {
-                       /* Convert command (char*) into cmd (char**, one word per string) */
-                       for (tmpCmd = command, i = 0;
-                                       (tmpCmd = strsep(&command, " \t")) != NULL;) {
-                               if (*tmpCmd != '\0') {
-                                       cmd[i] = tmpCmd;
-                                       tmpCmd++;
-                                       i++;
-                               }
-                       }
-                       cmd[i] = NULL;
-               }
-
-               cmdpath = cmd[0];
-
-               /*
-                  Interactive shells want to see a dash in argv[0].  This
-                  typically is handled by login, argv will be setup this 
-                  way if a dash appears at the front of the command path 
-                  (like "-/bin/sh").
-                */
-
-               if (*cmdpath == '-') {
-
-                       /* skip over the dash */
-                       ++cmdpath;
-
-                       /* find the last component in the command pathname */
-                       s = get_last_path_component(cmdpath);
-
-                       /* make a new argv[0] */
-                       if ((cmd[0] = malloc(strlen(s)+2)) == NULL) {
-                               message(LOG | CONSOLE, "malloc failed");
-                               cmd[0] = cmdpath;
-                       } else {
-                               cmd[0][0] = '-';
-                               strcpy(cmd[0]+1, s);
-                       }
-               }
-
-               if (get_enter == TRUE) {
-                       /*
-                        * Save memory by not exec-ing anything large (like a shell)
-                        * before the user wants it. This is critical if swap is not
-                        * enabled and the system has low memory. Generally this will
-                        * be run on the second virtual console, and the first will
-                        * be allowed to start a shell or whatever an init script 
-                        * specifies.
-                        */
-#ifdef DEBUG_INIT
-                       message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
-                                       cmd[0], getpid(), terminal);
-#endif
-                       write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
-                       getc(stdin);
-               }
-
-#ifdef DEBUG_INIT
-               /* Log the process name and args */
-               message(LOG, "Starting pid %d, console %s: '%s'\r\n",
-                               getpid(), terminal, command);
-#endif
-
-#if defined BB_FEATURE_INIT_COREDUMPS
-               if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
-                       struct rlimit limit;
-                       limit.rlim_cur = RLIM_INFINITY;
-                       limit.rlim_max = RLIM_INFINITY;
-                       setrlimit(RLIMIT_CORE, &limit);
-               }
-#endif
-
-               /* Now run it.  The new program will take over this PID, 
-                * so nothing further in init.c should be run. */
-               execve(cmdpath, cmd, environment);
-
-               /* We're still here?  Some error happened. */
-               message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath,
-                               strerror(errno));
-               exit(-1);
-       }
-       return pid;
-}
-
-static int waitfor(char *command, char *terminal, int get_enter)
-{
-       int status, wpid;
-       int pid = run(command, terminal, get_enter);
-
-       while (1) {
-               wpid = wait(&status);
-               if (wpid > 0 && wpid != pid) {
-                       continue;
-               }
-               if (wpid == pid)
-                       break;
-       }
-       return wpid;
-}
-
-/* Make sure there is enough memory to do something useful. *
- * Calls "swapon -a" if needed so be sure /etc/fstab is present... */
-static void check_memory()
-{
-       struct stat statBuf;
-
-       if (check_free_memory() > 1000)
-               return;
-
-       if (stat("/etc/fstab", &statBuf) == 0) {
-               /* swapon -a requires /proc typically */
-               waitfor("mount proc /proc -t proc", console, FALSE);
-               /* Try to turn on swap */
-               waitfor("swapon -a", console, FALSE);
-               if (check_free_memory() < 1000)
-                       goto goodnight;
-       } else
-               goto goodnight;
-       return;
-
-  goodnight:
-       message(CONSOLE,
-                       "Sorry, your computer does not have enough memory.\r\n");
-       loop_forever();
-}
-
-/* Run all commands to be run right before halt/reboot */
-static void run_actions(initActionEnum action)
-{
-       initAction *a, *tmp;
-       for (a = initActionList; a; a = tmp) {
-               tmp = a->nextPtr;
-               if (a->action == action) {
-                       waitfor(a->process, a->console, FALSE);
-                       delete_initAction(a);
-               }
-       }
-}
-
-
-#ifndef DEBUG_INIT
-static void shutdown_system(void)
-{
-
-       /* first disable our SIGHUP signal */
-       signal(SIGHUP, SIG_DFL);
-
-       /* Allow Ctrl-Alt-Del to reboot system. */
-       init_reboot(RB_ENABLE_CAD);
-
-       message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n");
-       sync();
-
-       /* Send signals to every process _except_ pid 1 */
-       message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n");
-       kill(-1, SIGTERM);
-       sleep(1);
-       sync();
-
-       message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n");
-       kill(-1, SIGKILL);
-       sleep(1);
-
-       /* run everything to be run at "shutdown" */
-       run_actions(SHUTDOWN);
-
-       sync();
-       if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) {
-               /* bdflush, kupdate not needed for kernels >2.2.11 */
-               bdflush(1, 0);
-               sync();
-       }
-}
-
-static void halt_signal(int sig)
-{
-       shutdown_system();
-       message(CONSOLE|LOG,
-                       "The system is halted. Press %s or turn off power\r\n",
-                       (secondConsole == NULL) /* serial console */
-                       ? "Reset" : "CTRL-ALT-DEL");
-       sync();
-
-       /* allow time for last message to reach serial console */
-       sleep(2);
-
-       if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0))
-               init_reboot(RB_POWER_OFF);
-       else
-               init_reboot(RB_HALT_SYSTEM);
-
-       loop_forever();
-}
-
-static void reboot_signal(int sig)
-{
-       shutdown_system();
-       message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n");
-       sync();
-
-       /* allow time for last message to reach serial console */
-       sleep(2);
-
-       init_reboot(RB_AUTOBOOT);
-
-       loop_forever();
-}
-
-static void ctrlaltdel_signal(int sig)
-{
-       run_actions(CTRLALTDEL);
-}
-
-#endif                                                 /* ! DEBUG_INIT */
-
-static void new_initAction(initActionEnum action, char *process, char *cons)
-{
-       initAction *newAction;
-
-       if (*cons == '\0')
-               cons = console;
-
-       /* If BusyBox detects that a serial console is in use, 
-        * then entries not refering to the console or null devices will _not_ be run.
-        * The exception to this rule is the null device.
-        */
-       if (secondConsole == NULL && strcmp(cons, console)
-               && strcmp(cons, "/dev/null"))
-               return;
-       if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST)
-               return;
-
-
-       newAction = calloc((size_t) (1), sizeof(initAction));
-       if (!newAction) {
-               message(LOG | CONSOLE, "Memory allocation failure\n");
-               loop_forever();
-       }
-       newAction->nextPtr = initActionList;
-       initActionList = newAction;
-       strncpy(newAction->process, process, 255);
-       newAction->action = action;
-       strncpy(newAction->console, cons, 255);
-       newAction->pid = 0;
-//    message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
-//      newAction->process, newAction->action, newAction->console);
-}
-
-static void delete_initAction(initAction * action)
-{
-       initAction *a, *b = NULL;
-
-       for (a = initActionList; a; b = a, a = a->nextPtr) {
-               if (a == action) {
-                       if (b == NULL) {
-                               initActionList = a->nextPtr;
-                       } else {
-                               b->nextPtr = a->nextPtr;
-                       }
-                       free(a);
-                       break;
-               }
-       }
-}
-
-/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
- * then parse_inittab() simply adds in some default
- * actions(i.e., runs INIT_SCRIPT and then starts a pair 
- * of "askfirst" shells).  If BB_FEATURE_USE_INITTAB 
- * _is_ defined, but /etc/inittab is missing, this 
- * results in the same set of default behaviors.
- * */
-static void parse_inittab(void)
-{
-#ifdef BB_FEATURE_USE_INITTAB
-       FILE *file;
-       char buf[256], lineAsRead[256], tmpConsole[256];
-       char *id, *runlev, *action, *process, *eol;
-       const struct initActionType *a = actions;
-       int foundIt;
-
-
-       file = fopen(INITTAB, "r");
-       if (file == NULL) {
-               /* No inittab file -- set up some default behavior */
-#endif
-               /* Reboot on Ctrl-Alt-Del */
-               new_initAction(CTRLALTDEL, "/sbin/reboot", console);
-               /* Swapoff on halt/reboot */
-               new_initAction(SHUTDOWN, "/sbin/swapoff -a", console);
-               /* Umount all filesystems on halt/reboot */
-               new_initAction(SHUTDOWN, "/bin/umount -a -r", console);
-               /* Askfirst shell on tty1 */
-               new_initAction(ASKFIRST, LOGIN_SHELL, console);
-               /* Askfirst shell on tty2 */
-               if (secondConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
-               /* Askfirst shell on tty3 */
-               if (thirdConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
-               /* Askfirst shell on tty4 */
-               if (fourthConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
-               /* sysinit */
-               new_initAction(SYSINIT, INIT_SCRIPT, console);
-
-               return;
-#ifdef BB_FEATURE_USE_INITTAB
-       }
-
-       while (fgets(buf, 255, file) != NULL) {
-               foundIt = FALSE;
-               /* Skip leading spaces */
-               for (id = buf; *id == ' ' || *id == '\t'; id++);
-
-               /* Skip the line if it's a comment */
-               if (*id == '#' || *id == '\n')
-                       continue;
-
-               /* Trim the trailing \n */
-               eol = strrchr(id, '\n');
-               if (eol != NULL)
-                       *eol = '\0';
-
-               /* Keep a copy around for posterity's sake (and error msgs) */
-               strcpy(lineAsRead, buf);
-
-               /* Separate the ID field from the runlevels */
-               runlev = strchr(id, ':');
-               if (runlev == NULL || *(runlev + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *runlev = '\0';
-                       ++runlev;
-               }
-
-               /* Separate the runlevels from the action */
-               action = strchr(runlev, ':');
-               if (action == NULL || *(action + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *action = '\0';
-                       ++action;
-               }
-
-               /* Separate the action from the process */
-               process = strchr(action, ':');
-               if (process == NULL || *(process + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *process = '\0';
-                       ++process;
-               }
-
-               /* Ok, now process it */
-               a = actions;
-               while (a->name != 0) {
-                       if (strcmp(a->name, action) == 0) {
-                               if (*id != '\0') {
-                                       strcpy(tmpConsole, "/dev/");
-                                       strncat(tmpConsole, id, 200);
-                                       id = tmpConsole;
-                               }
-                               new_initAction(a->action, process, id);
-                               foundIt = TRUE;
-                       }
-                       a++;
-               }
-               if (foundIt == TRUE)
-                       continue;
-               else {
-                       /* Choke on an unknown action */
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-               }
-       }
-       return;
-#endif /* BB_FEATURE_USE_INITTAB */
-}
-
-
-
-extern int init_main(int argc, char **argv)
-{
-       initAction *a, *tmp;
-       pid_t wpid;
-       int status;
-
-#ifndef DEBUG_INIT
-       /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
-       if (getpid() != 1
-#ifdef BB_FEATURE_LINUXRC
-                       && strstr(applet_name, "linuxrc") == NULL
-#endif
-                         )
-       {
-                       show_usage();
-       }
-       /* Set up sig handlers  -- be sure to
-        * clear all of these in run() */
-       signal(SIGUSR1, halt_signal);
-       signal(SIGUSR2, halt_signal);
-       signal(SIGINT, ctrlaltdel_signal);
-       signal(SIGTERM, reboot_signal);
-
-       /* Turn off rebooting via CTL-ALT-DEL -- we get a 
-        * SIGINT on CAD so we can shut things down gracefully... */
-       init_reboot(RB_DISABLE_CAD);
-#endif
-
-       /* Figure out what kernel this is running */
-       kernelVersion = get_kernel_revision();
-
-       /* Figure out where the default console should be */
-       console_init();
-
-       /* Close whatever files are open, and reset the console. */
-       close(0);
-       close(1);
-       close(2);
-       set_term(0);
-       chdir("/");
-       setsid();
-
-       /* Make sure PATH is set to something sane */
-       putenv("PATH="_PATH_STDPATH);
-
-       /* Hello world */
-#ifndef DEBUG_INIT
-       message(
-#if ! defined BB_FEATURE_EXTRA_QUIET
-                       CONSOLE|
-#endif
-                       LOG,
-                       "init started:  %s\r\n", full_version);
-#else
-       message(
-#if ! defined BB_FEATURE_EXTRA_QUIET
-                       CONSOLE|
-#endif
-                       LOG,
-                       "init(%d) started:  %s\r\n", getpid(), full_version);
-#endif
-
-
-       /* Make sure there is enough memory to do something useful. */
-       check_memory();
-
-       /* Check if we are supposed to be in single user mode */
-       if (argc > 1 && (!strcmp(argv[1], "single") ||
-                                        !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
-               /* Ask first then start a shell on tty2-4 */
-               if (secondConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
-               if (thirdConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
-               if (fourthConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
-               /* Start a shell on tty1 */
-               new_initAction(RESPAWN, LOGIN_SHELL, console);
-       } else {
-               /* Not in single user mode -- see what inittab says */
-
-               /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
-                * then parse_inittab() simply adds in some default
-                * actions(i.e., runs INIT_SCRIPT and then starts a pair 
-                * of "askfirst" shells */
-               parse_inittab();
-       }
-
-       /* Make the command line just say "init"  -- thats all, nothing else */
-       fixup_argv(argc, argv, "init");
-
-       /* Now run everything that needs to be run */
-
-       /* First run the sysinit command */
-       run_actions(SYSINIT);
-
-       /* Next run anything that wants to block */
-       run_actions(WAIT);
-
-       /* Next run anything to be run only once */
-       for (a = initActionList; a; a = tmp) {
-               tmp = a->nextPtr;
-               if (a->action == ONCE) {
-                       run(a->process, a->console, FALSE);
-                       /* Now remove the "once" entry from the list */
-                       delete_initAction(a);
-               }
-       }
-       /* If there is nothing else to do, stop */
-       if (initActionList == NULL) {
-               message(LOG | CONSOLE,
-                               "No more tasks for init -- sleeping forever.\n");
-               loop_forever();
-       }
-
-       /* Now run the looping stuff for the rest of forever */
-       while (1) {
-               for (a = initActionList; a; a = a->nextPtr) {
-                       /* Only run stuff with pid==0.  If they have
-                        * a pid, that means they are still running */
-                       if (a->pid == 0) {
-                               switch (a->action) {
-                               case RESPAWN:
-                                       /* run the respawn stuff */
-                                       a->pid = run(a->process, a->console, FALSE);
-                                       break;
-                               case ASKFIRST:
-                                       /* run the askfirst stuff */
-                                       a->pid = run(a->process, a->console, TRUE);
-                                       break;
-                                       /* silence the compiler's incessant whining */
-                               default:
-                                       break;
-                               }
-                       }
-               }
-               /* Wait for a child process to exit */
-               wpid = wait(&status);
-               if (wpid > 0) {
-                       /* Find out who died and clean up their corpse */
-                       for (a = initActionList; a; a = a->nextPtr) {
-                               if (a->pid == wpid) {
-                                       a->pid = 0;
-                                       message(LOG,
-                                                       "Process '%s' (pid %d) exited.  Scheduling it for restart.\n",
-                                                       a->process, wpid);
-                               }
-                       }
-               }
-               sleep(1);
-       }
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/init/halt.c b/busybox/init/halt.c
deleted file mode 100644 (file)
index d66e28d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini halt implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int halt_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGUSR1));
-#else
-       return(kill(1, SIGUSR1));
-#endif
-}
diff --git a/busybox/init/init.c b/busybox/init/init.c
deleted file mode 100644 (file)
index 45b510f..0000000
+++ /dev/null
@@ -1,1031 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini init implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Adjusted by so many folks, it's impossible to keep track.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* Turn this on to disable all the dangerous 
-   rebooting stuff when debugging.
-#define DEBUG_INIT
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include "busybox.h"
-#ifdef BB_SYSLOGD
-# include <sys/syslog.h>
-#endif
-
-
-/* From <linux/vt.h> */
-struct vt_stat {
-       unsigned short v_active;        /* active vt */
-       unsigned short v_signal;        /* signal to send */
-       unsigned short v_state;         /* vt bitmask */
-};
-static const int VT_GETSTATE = 0x5603;  /* get global vt state info */
-
-/* From <linux/serial.h> */
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-
-
-#ifndef RB_HALT_SYSTEM
-static const int RB_HALT_SYSTEM = 0xcdef0123;
-static const int RB_ENABLE_CAD = 0x89abcdef;
-static const int RB_DISABLE_CAD = 0;
-#define RB_POWER_OFF    0x4321fedc
-static const int RB_AUTOBOOT = 0x01234567;
-#endif
-
-#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) 
-  #include <sys/reboot.h>
-  #define init_reboot(magic) reboot(magic)
-#else
-  #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
-#endif
-
-#ifndef _PATH_STDPATH
-#define _PATH_STDPATH  "/usr/bin:/bin:/usr/sbin:/sbin"
-#endif
-
-
-#if defined BB_FEATURE_INIT_COREDUMPS
-/*
- * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called 
- * before processes are spawned to set core file size as unlimited.
- * This is for debugging only.  Don't use this is production, unless
- * you want core dumps lying about....
- */
-#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
-#include <sys/resource.h>
-#include <sys/time.h>
-#endif
-
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
-#if __GNU_LIBRARY__ > 5
-       #include <sys/kdaemon.h>
-#else
-       extern int bdflush (int func, long int data);
-#endif
-
-
-#define SHELL        "/bin/sh"      /* Default shell */
-#define LOGIN_SHELL  "-" SHELL      /* Default login shell */
-#define INITTAB      "/etc/inittab"  /* inittab file location */
-#ifndef INIT_SCRIPT
-#define INIT_SCRIPT  "/etc/init.d/rcS"   /* Default sysinit script. */
-#endif
-
-#define MAXENV 16              /* Number of env. vars */
-//static const int MAXENV = 16;        /* Number of env. vars */
-static const int LOG = 0x1;
-static const int CONSOLE = 0x2;
-
-/* Allowed init action types */
-typedef enum {
-       SYSINIT = 1,
-       RESPAWN,
-       ASKFIRST,
-       WAIT,
-       ONCE,
-       CTRLALTDEL,
-       SHUTDOWN
-} initActionEnum;
-
-/* A mapping between "inittab" action name strings and action type codes. */
-typedef struct initActionType {
-       const char *name;
-       initActionEnum action;
-} initActionType;
-
-static const struct initActionType actions[] = {
-       {"sysinit", SYSINIT},
-       {"respawn", RESPAWN},
-       {"askfirst", ASKFIRST},
-       {"wait", WAIT},
-       {"once", ONCE},
-       {"ctrlaltdel", CTRLALTDEL},
-       {"shutdown", SHUTDOWN},
-       {0, 0}
-};
-
-/* Set up a linked list of initActions, to be read from inittab */
-typedef struct initActionTag initAction;
-struct initActionTag {
-       pid_t pid;
-       char process[256];
-       char console[256];
-       initAction *nextPtr;
-       initActionEnum action;
-};
-static initAction *initActionList = NULL;
-
-
-static char *secondConsole = VC_2;
-static char *thirdConsole  = VC_3;
-static char *fourthConsole = VC_4;
-static char *log           = VC_5;
-static int  kernelVersion  = 0;
-static char termType[32]   = "TERM=linux";
-static char console[32]    = _PATH_CONSOLE;
-
-static void delete_initAction(initAction * action);
-
-static void loop_forever()
-{
-       while (1)
-               sleep (1);
-}
-
-/* Print a message to the specified device.
- * Device may be bitwise-or'd from LOG | CONSOLE */
-static void message(int device, char *fmt, ...)
-                  __attribute__ ((format (printf, 2, 3)));
-static void message(int device, char *fmt, ...)
-{
-       va_list arguments;
-       int fd;
-
-#ifdef BB_SYSLOGD
-
-       /* Log the message to syslogd */
-       if (device & LOG) {
-               char msg[1024];
-
-               va_start(arguments, fmt);
-               vsnprintf(msg, sizeof(msg), fmt, arguments);
-               va_end(arguments);
-               openlog(applet_name, 0, LOG_USER);
-               syslog(LOG_USER|LOG_INFO, msg);
-               closelog();
-       }
-#else
-       static int log_fd = -1;
-
-       /* Take full control of the log tty, and never close it.
-        * It's mine, all mine!  Muhahahaha! */
-       if (log_fd < 0) {
-               if (log == NULL) {
-                       /* don't even try to log, because there is no such console */
-                       log_fd = -2;
-                       /* log to main console instead */
-                       device = CONSOLE;
-               } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
-                       log_fd = -2;
-                       fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log);
-                       log = NULL;
-                       device = CONSOLE;
-               }
-       }
-       if ((device & LOG) && (log_fd >= 0)) {
-               va_start(arguments, fmt);
-               vdprintf(log_fd, fmt, arguments);
-               va_end(arguments);
-       }
-#endif
-
-       if (device & CONSOLE) {
-               /* Always send console messages to /dev/console so people will see them. */
-               if (
-                       (fd =
-                        device_open(_PATH_CONSOLE,
-                                                O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {
-                       va_start(arguments, fmt);
-                       vdprintf(fd, fmt, arguments);
-                       va_end(arguments);
-                       close(fd);
-               } else {
-                       fprintf(stderr, "Bummer, can't print: ");
-                       va_start(arguments, fmt);
-                       vfprintf(stderr, fmt, arguments);
-                       va_end(arguments);
-               }
-       }
-}
-
-/* Set terminal settings to reasonable defaults */
-static void set_term(int fd)
-{
-       struct termios tty;
-
-       tcgetattr(fd, &tty);
-
-       /* set control chars */
-       tty.c_cc[VINTR]  = 3;   /* C-c */
-       tty.c_cc[VQUIT]  = 28;  /* C-\ */
-       tty.c_cc[VERASE] = 127; /* C-? */
-       tty.c_cc[VKILL]  = 21;  /* C-u */
-       tty.c_cc[VEOF]   = 4;   /* C-d */
-       tty.c_cc[VSTART] = 17;  /* C-q */
-       tty.c_cc[VSTOP]  = 19;  /* C-s */
-       tty.c_cc[VSUSP]  = 26;  /* C-z */
-
-       /* use line dicipline 0 */
-       tty.c_line = 0;
-
-       /* Make it be sane */
-       tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
-       tty.c_cflag |= CREAD|HUPCL|CLOCAL;
-
-
-       /* input modes */
-       tty.c_iflag = ICRNL | IXON | IXOFF;
-
-       /* output modes */
-       tty.c_oflag = OPOST | ONLCR;
-
-       /* local modes */
-       tty.c_lflag =
-               ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
-
-       tcsetattr(fd, TCSANOW, &tty);
-}
-
-/* How much memory does this machine have?
-   Units are kBytes to avoid overflow on 4GB machines */
-static int check_free_memory()
-{
-       struct sysinfo info;
-       unsigned int result, u, s=10;
-
-       if (sysinfo(&info) != 0) {
-               perror_msg("Error checking free memory");
-               return -1;
-       }
-
-       /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes.
-        * Kernels 2.4.0 return info.mem_unit in bytes. */
-       u = info.mem_unit;
-       if (u==0) u=1;
-       while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; }
-       result = (info.totalram>>s) + (info.totalswap>>s);
-       result = result*u;
-       if (result < 0) result = INT_MAX;
-       return result;
-}
-
-static void console_init()
-{
-       int fd;
-       int tried_devcons = 0;
-       int tried_vtprimary = 0;
-       struct vt_stat vt;
-       struct serial_struct sr;
-       char *s;
-
-       if ((s = getenv("TERM")) != NULL) {
-               snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);
-       }
-
-       if ((s = getenv("CONSOLE")) != NULL) {
-               safe_strncpy(console, s, sizeof(console));
-       }
-#if #cpu(sparc)
-       /* sparc kernel supports console=tty[ab] parameter which is also 
-        * passed to init, so catch it here */
-       else if ((s = getenv("console")) != NULL) {
-               /* remap tty[ab] to /dev/ttyS[01] */
-               if (strcmp(s, "ttya") == 0)
-                       safe_strncpy(console, SC_0, sizeof(console));
-               else if (strcmp(s, "ttyb") == 0)
-                       safe_strncpy(console, SC_1, sizeof(console));
-       }
-#endif
-       else {
-               /* 2.2 kernels: identify the real console backend and try to use it */
-               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
-                       /* this is a serial console */
-                       snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line);
-               } else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
-                       /* this is linux virtual tty */
-                       snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);
-               } else {
-                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
-                       tried_devcons++;
-               }
-       }
-
-       while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
-               /* Can't open selected console -- try /dev/console */
-               if (!tried_devcons) {
-                       tried_devcons++;
-                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
-                       continue;
-               }
-               /* Can't open selected console -- try vt1 */
-               if (!tried_vtprimary) {
-                       tried_vtprimary++;
-                       safe_strncpy(console, VC_1, sizeof(console));
-                       continue;
-               }
-               break;
-       }
-       if (fd < 0) {
-               /* Perhaps we should panic here? */
-               safe_strncpy(console, "/dev/null", sizeof(console));
-       } else {
-               /* check for serial console and disable logging to tty5 & running a
-                  * shell to tty2-4 */
-               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
-                       log = NULL;
-                       secondConsole = NULL;
-                       thirdConsole = NULL;
-                       fourthConsole = NULL;
-                       /* Force the TERM setting to vt102 for serial console --
-                        * iff TERM is set to linux (the default) */
-                       if (strcmp( termType, "TERM=linux" ) == 0)
-                               safe_strncpy(termType, "TERM=vt102", sizeof(termType));
-                       message(LOG | CONSOLE,
-                                       "serial console detected.  Disabling virtual terminals.\r\n");
-               }
-               close(fd);
-       }
-       message(LOG, "console=%s\n", console);
-}
-       
-static void fixup_argv(int argc, char **argv, char *new_argv0)
-{
-       int len;
-       /* Fix up argv[0] to be certain we claim to be init */
-       len = strlen(argv[0]);
-       memset(argv[0], 0, len);
-       strncpy(argv[0], new_argv0, len);
-
-       /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
-       len = 1;
-       while (argc > len) {
-               memset(argv[len], 0, strlen(argv[len]));
-               len++;
-       }
-}
-
-
-static pid_t run(char *command, char *terminal, int get_enter)
-{
-       int i, j;
-       int fd;
-       pid_t pid;
-       char *tmpCmd, *s;
-       char *cmd[255], *cmdpath;
-       char buf[255];
-       struct stat sb;
-       static const char press_enter[] =
-
-#ifdef CUSTOMIZED_BANNER
-#include CUSTOMIZED_BANNER
-#endif
-
-               "\nPlease press Enter to activate this console. ";
-       char *environment[MAXENV+1] = {
-               termType,
-               "HOME=/",
-               "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
-               "SHELL=" SHELL,
-               "USER=root",
-               NULL
-       };
-
-       /* inherit environment to the child, merging our values -andy */
-       for (i=0; environ[i]; i++) {
-               for (j=0; environment[j]; j++) {
-                       s = strchr(environment[j], '=');
-                       if (!strncmp(environ[i], environment[j], s - environment[j]))
-                               break;
-               }
-               if (!environment[j]) {
-                       environment[j++] = environ[i];
-                       environment[j] = NULL;
-               }
-       }
-
-       if ((pid = fork()) == 0) {
-               /* Clean up */
-               ioctl(0, TIOCNOTTY, 0);
-               close(0);
-               close(1);
-               close(2);
-               setsid();
-
-               /* Reset signal handlers set for parent process */
-               signal(SIGUSR1, SIG_DFL);
-               signal(SIGUSR2, SIG_DFL);
-               signal(SIGINT, SIG_DFL);
-               signal(SIGTERM, SIG_DFL);
-               signal(SIGHUP, SIG_DFL);
-
-               if ((fd = device_open(terminal, O_RDWR)) < 0) {
-                       if (stat(terminal, &sb) != 0) {
-                               message(LOG | CONSOLE, "device '%s' does not exist.\n",
-                                               terminal);
-                               exit(1);
-                       }
-                       message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal);
-                       exit(1);
-               }
-               dup2(fd, 0);
-               dup2(fd, 1);
-               dup2(fd, 2);
-               ioctl(0, TIOCSCTTY, 1);
-               tcsetpgrp(0, getpgrp());
-               set_term(0);
-
-               /* See if any special /bin/sh requiring characters are present */
-               if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
-                       cmd[0] = SHELL;
-                       cmd[1] = "-c";
-                       strcpy(buf, "exec ");
-                       strncat(buf, command, sizeof(buf) - strlen(buf) - 1);
-                       cmd[2] = buf;
-                       cmd[3] = NULL;
-               } else {
-                       /* Convert command (char*) into cmd (char**, one word per string) */
-                       for (tmpCmd = command, i = 0;
-                                       (tmpCmd = strsep(&command, " \t")) != NULL;) {
-                               if (*tmpCmd != '\0') {
-                                       cmd[i] = tmpCmd;
-                                       tmpCmd++;
-                                       i++;
-                               }
-                       }
-                       cmd[i] = NULL;
-               }
-
-               cmdpath = cmd[0];
-
-               /*
-                  Interactive shells want to see a dash in argv[0].  This
-                  typically is handled by login, argv will be setup this 
-                  way if a dash appears at the front of the command path 
-                  (like "-/bin/sh").
-                */
-
-               if (*cmdpath == '-') {
-
-                       /* skip over the dash */
-                       ++cmdpath;
-
-                       /* find the last component in the command pathname */
-                       s = get_last_path_component(cmdpath);
-
-                       /* make a new argv[0] */
-                       if ((cmd[0] = malloc(strlen(s)+2)) == NULL) {
-                               message(LOG | CONSOLE, "malloc failed");
-                               cmd[0] = cmdpath;
-                       } else {
-                               cmd[0][0] = '-';
-                               strcpy(cmd[0]+1, s);
-                       }
-               }
-
-               if (get_enter == TRUE) {
-                       /*
-                        * Save memory by not exec-ing anything large (like a shell)
-                        * before the user wants it. This is critical if swap is not
-                        * enabled and the system has low memory. Generally this will
-                        * be run on the second virtual console, and the first will
-                        * be allowed to start a shell or whatever an init script 
-                        * specifies.
-                        */
-#ifdef DEBUG_INIT
-                       message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
-                                       cmd[0], getpid(), terminal);
-#endif
-                       write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
-                       getc(stdin);
-               }
-
-#ifdef DEBUG_INIT
-               /* Log the process name and args */
-               message(LOG, "Starting pid %d, console %s: '%s'\r\n",
-                               getpid(), terminal, command);
-#endif
-
-#if defined BB_FEATURE_INIT_COREDUMPS
-               if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
-                       struct rlimit limit;
-                       limit.rlim_cur = RLIM_INFINITY;
-                       limit.rlim_max = RLIM_INFINITY;
-                       setrlimit(RLIMIT_CORE, &limit);
-               }
-#endif
-
-               /* Now run it.  The new program will take over this PID, 
-                * so nothing further in init.c should be run. */
-               execve(cmdpath, cmd, environment);
-
-               /* We're still here?  Some error happened. */
-               message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath,
-                               strerror(errno));
-               exit(-1);
-       }
-       return pid;
-}
-
-static int waitfor(char *command, char *terminal, int get_enter)
-{
-       int status, wpid;
-       int pid = run(command, terminal, get_enter);
-
-       while (1) {
-               wpid = wait(&status);
-               if (wpid > 0 && wpid != pid) {
-                       continue;
-               }
-               if (wpid == pid)
-                       break;
-       }
-       return wpid;
-}
-
-/* Make sure there is enough memory to do something useful. *
- * Calls "swapon -a" if needed so be sure /etc/fstab is present... */
-static void check_memory()
-{
-       struct stat statBuf;
-
-       if (check_free_memory() > 1000)
-               return;
-
-       if (stat("/etc/fstab", &statBuf) == 0) {
-               /* swapon -a requires /proc typically */
-               waitfor("mount proc /proc -t proc", console, FALSE);
-               /* Try to turn on swap */
-               waitfor("swapon -a", console, FALSE);
-               if (check_free_memory() < 1000)
-                       goto goodnight;
-       } else
-               goto goodnight;
-       return;
-
-  goodnight:
-       message(CONSOLE,
-                       "Sorry, your computer does not have enough memory.\r\n");
-       loop_forever();
-}
-
-/* Run all commands to be run right before halt/reboot */
-static void run_actions(initActionEnum action)
-{
-       initAction *a, *tmp;
-       for (a = initActionList; a; a = tmp) {
-               tmp = a->nextPtr;
-               if (a->action == action) {
-                       waitfor(a->process, a->console, FALSE);
-                       delete_initAction(a);
-               }
-       }
-}
-
-
-#ifndef DEBUG_INIT
-static void shutdown_system(void)
-{
-
-       /* first disable our SIGHUP signal */
-       signal(SIGHUP, SIG_DFL);
-
-       /* Allow Ctrl-Alt-Del to reboot system. */
-       init_reboot(RB_ENABLE_CAD);
-
-       message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n");
-       sync();
-
-       /* Send signals to every process _except_ pid 1 */
-       message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n");
-       kill(-1, SIGTERM);
-       sleep(1);
-       sync();
-
-       message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n");
-       kill(-1, SIGKILL);
-       sleep(1);
-
-       /* run everything to be run at "shutdown" */
-       run_actions(SHUTDOWN);
-
-       sync();
-       if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) {
-               /* bdflush, kupdate not needed for kernels >2.2.11 */
-               bdflush(1, 0);
-               sync();
-       }
-}
-
-static void halt_signal(int sig)
-{
-       shutdown_system();
-       message(CONSOLE|LOG,
-                       "The system is halted. Press %s or turn off power\r\n",
-                       (secondConsole == NULL) /* serial console */
-                       ? "Reset" : "CTRL-ALT-DEL");
-       sync();
-
-       /* allow time for last message to reach serial console */
-       sleep(2);
-
-       if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0))
-               init_reboot(RB_POWER_OFF);
-       else
-               init_reboot(RB_HALT_SYSTEM);
-
-       loop_forever();
-}
-
-static void reboot_signal(int sig)
-{
-       shutdown_system();
-       message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n");
-       sync();
-
-       /* allow time for last message to reach serial console */
-       sleep(2);
-
-       init_reboot(RB_AUTOBOOT);
-
-       loop_forever();
-}
-
-static void ctrlaltdel_signal(int sig)
-{
-       run_actions(CTRLALTDEL);
-}
-
-#endif                                                 /* ! DEBUG_INIT */
-
-static void new_initAction(initActionEnum action, char *process, char *cons)
-{
-       initAction *newAction;
-
-       if (*cons == '\0')
-               cons = console;
-
-       /* If BusyBox detects that a serial console is in use, 
-        * then entries not refering to the console or null devices will _not_ be run.
-        * The exception to this rule is the null device.
-        */
-       if (secondConsole == NULL && strcmp(cons, console)
-               && strcmp(cons, "/dev/null"))
-               return;
-       if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST)
-               return;
-
-
-       newAction = calloc((size_t) (1), sizeof(initAction));
-       if (!newAction) {
-               message(LOG | CONSOLE, "Memory allocation failure\n");
-               loop_forever();
-       }
-       newAction->nextPtr = initActionList;
-       initActionList = newAction;
-       strncpy(newAction->process, process, 255);
-       newAction->action = action;
-       strncpy(newAction->console, cons, 255);
-       newAction->pid = 0;
-//    message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
-//      newAction->process, newAction->action, newAction->console);
-}
-
-static void delete_initAction(initAction * action)
-{
-       initAction *a, *b = NULL;
-
-       for (a = initActionList; a; b = a, a = a->nextPtr) {
-               if (a == action) {
-                       if (b == NULL) {
-                               initActionList = a->nextPtr;
-                       } else {
-                               b->nextPtr = a->nextPtr;
-                       }
-                       free(a);
-                       break;
-               }
-       }
-}
-
-/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
- * then parse_inittab() simply adds in some default
- * actions(i.e., runs INIT_SCRIPT and then starts a pair 
- * of "askfirst" shells).  If BB_FEATURE_USE_INITTAB 
- * _is_ defined, but /etc/inittab is missing, this 
- * results in the same set of default behaviors.
- * */
-static void parse_inittab(void)
-{
-#ifdef BB_FEATURE_USE_INITTAB
-       FILE *file;
-       char buf[256], lineAsRead[256], tmpConsole[256];
-       char *id, *runlev, *action, *process, *eol;
-       const struct initActionType *a = actions;
-       int foundIt;
-
-
-       file = fopen(INITTAB, "r");
-       if (file == NULL) {
-               /* No inittab file -- set up some default behavior */
-#endif
-               /* Reboot on Ctrl-Alt-Del */
-               new_initAction(CTRLALTDEL, "/sbin/reboot", console);
-               /* Swapoff on halt/reboot */
-               new_initAction(SHUTDOWN, "/sbin/swapoff -a", console);
-               /* Umount all filesystems on halt/reboot */
-               new_initAction(SHUTDOWN, "/bin/umount -a -r", console);
-               /* Askfirst shell on tty1 */
-               new_initAction(ASKFIRST, LOGIN_SHELL, console);
-               /* Askfirst shell on tty2 */
-               if (secondConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
-               /* Askfirst shell on tty3 */
-               if (thirdConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
-               /* Askfirst shell on tty4 */
-               if (fourthConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
-               /* sysinit */
-               new_initAction(SYSINIT, INIT_SCRIPT, console);
-
-               return;
-#ifdef BB_FEATURE_USE_INITTAB
-       }
-
-       while (fgets(buf, 255, file) != NULL) {
-               foundIt = FALSE;
-               /* Skip leading spaces */
-               for (id = buf; *id == ' ' || *id == '\t'; id++);
-
-               /* Skip the line if it's a comment */
-               if (*id == '#' || *id == '\n')
-                       continue;
-
-               /* Trim the trailing \n */
-               eol = strrchr(id, '\n');
-               if (eol != NULL)
-                       *eol = '\0';
-
-               /* Keep a copy around for posterity's sake (and error msgs) */
-               strcpy(lineAsRead, buf);
-
-               /* Separate the ID field from the runlevels */
-               runlev = strchr(id, ':');
-               if (runlev == NULL || *(runlev + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *runlev = '\0';
-                       ++runlev;
-               }
-
-               /* Separate the runlevels from the action */
-               action = strchr(runlev, ':');
-               if (action == NULL || *(action + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *action = '\0';
-                       ++action;
-               }
-
-               /* Separate the action from the process */
-               process = strchr(action, ':');
-               if (process == NULL || *(process + 1) == '\0') {
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-                       continue;
-               } else {
-                       *process = '\0';
-                       ++process;
-               }
-
-               /* Ok, now process it */
-               a = actions;
-               while (a->name != 0) {
-                       if (strcmp(a->name, action) == 0) {
-                               if (*id != '\0') {
-                                       strcpy(tmpConsole, "/dev/");
-                                       strncat(tmpConsole, id, 200);
-                                       id = tmpConsole;
-                               }
-                               new_initAction(a->action, process, id);
-                               foundIt = TRUE;
-                       }
-                       a++;
-               }
-               if (foundIt == TRUE)
-                       continue;
-               else {
-                       /* Choke on an unknown action */
-                       message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
-               }
-       }
-       return;
-#endif /* BB_FEATURE_USE_INITTAB */
-}
-
-
-
-extern int init_main(int argc, char **argv)
-{
-       initAction *a, *tmp;
-       pid_t wpid;
-       int status;
-
-#ifndef DEBUG_INIT
-       /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
-       if (getpid() != 1
-#ifdef BB_FEATURE_LINUXRC
-                       && strstr(applet_name, "linuxrc") == NULL
-#endif
-                         )
-       {
-                       show_usage();
-       }
-       /* Set up sig handlers  -- be sure to
-        * clear all of these in run() */
-       signal(SIGUSR1, halt_signal);
-       signal(SIGUSR2, halt_signal);
-       signal(SIGINT, ctrlaltdel_signal);
-       signal(SIGTERM, reboot_signal);
-
-       /* Turn off rebooting via CTL-ALT-DEL -- we get a 
-        * SIGINT on CAD so we can shut things down gracefully... */
-       init_reboot(RB_DISABLE_CAD);
-#endif
-
-       /* Figure out what kernel this is running */
-       kernelVersion = get_kernel_revision();
-
-       /* Figure out where the default console should be */
-       console_init();
-
-       /* Close whatever files are open, and reset the console. */
-       close(0);
-       close(1);
-       close(2);
-       set_term(0);
-       chdir("/");
-       setsid();
-
-       /* Make sure PATH is set to something sane */
-       putenv("PATH="_PATH_STDPATH);
-
-       /* Hello world */
-#ifndef DEBUG_INIT
-       message(
-#if ! defined BB_FEATURE_EXTRA_QUIET
-                       CONSOLE|
-#endif
-                       LOG,
-                       "init started:  %s\r\n", full_version);
-#else
-       message(
-#if ! defined BB_FEATURE_EXTRA_QUIET
-                       CONSOLE|
-#endif
-                       LOG,
-                       "init(%d) started:  %s\r\n", getpid(), full_version);
-#endif
-
-
-       /* Make sure there is enough memory to do something useful. */
-       check_memory();
-
-       /* Check if we are supposed to be in single user mode */
-       if (argc > 1 && (!strcmp(argv[1], "single") ||
-                                        !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
-               /* Ask first then start a shell on tty2-4 */
-               if (secondConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole);
-               if (thirdConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole);
-               if (fourthConsole != NULL)
-                       new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole);
-               /* Start a shell on tty1 */
-               new_initAction(RESPAWN, LOGIN_SHELL, console);
-       } else {
-               /* Not in single user mode -- see what inittab says */
-
-               /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
-                * then parse_inittab() simply adds in some default
-                * actions(i.e., runs INIT_SCRIPT and then starts a pair 
-                * of "askfirst" shells */
-               parse_inittab();
-       }
-
-       /* Make the command line just say "init"  -- thats all, nothing else */
-       fixup_argv(argc, argv, "init");
-
-       /* Now run everything that needs to be run */
-
-       /* First run the sysinit command */
-       run_actions(SYSINIT);
-
-       /* Next run anything that wants to block */
-       run_actions(WAIT);
-
-       /* Next run anything to be run only once */
-       for (a = initActionList; a; a = tmp) {
-               tmp = a->nextPtr;
-               if (a->action == ONCE) {
-                       run(a->process, a->console, FALSE);
-                       /* Now remove the "once" entry from the list */
-                       delete_initAction(a);
-               }
-       }
-       /* If there is nothing else to do, stop */
-       if (initActionList == NULL) {
-               message(LOG | CONSOLE,
-                               "No more tasks for init -- sleeping forever.\n");
-               loop_forever();
-       }
-
-       /* Now run the looping stuff for the rest of forever */
-       while (1) {
-               for (a = initActionList; a; a = a->nextPtr) {
-                       /* Only run stuff with pid==0.  If they have
-                        * a pid, that means they are still running */
-                       if (a->pid == 0) {
-                               switch (a->action) {
-                               case RESPAWN:
-                                       /* run the respawn stuff */
-                                       a->pid = run(a->process, a->console, FALSE);
-                                       break;
-                               case ASKFIRST:
-                                       /* run the askfirst stuff */
-                                       a->pid = run(a->process, a->console, TRUE);
-                                       break;
-                                       /* silence the compiler's incessant whining */
-                               default:
-                                       break;
-                               }
-                       }
-               }
-               /* Wait for a child process to exit */
-               wpid = wait(&status);
-               if (wpid > 0) {
-                       /* Find out who died and clean up their corpse */
-                       for (a = initActionList; a; a = a->nextPtr) {
-                               if (a->pid == wpid) {
-                                       a->pid = 0;
-                                       message(LOG,
-                                                       "Process '%s' (pid %d) exited.  Scheduling it for restart.\n",
-                                                       a->process, wpid);
-                               }
-                       }
-               }
-               sleep(1);
-       }
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/init/poweroff.c b/busybox/init/poweroff.c
deleted file mode 100644 (file)
index db20a45..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini poweroff implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int poweroff_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGUSR2));
-#else
-       return(kill(1, SIGUSR2));
-#endif
-}
diff --git a/busybox/init/reboot.c b/busybox/init/reboot.c
deleted file mode 100644 (file)
index 35afd74..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini reboot implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int reboot_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGTERM));
-#else
-       return(kill(1, SIGTERM));
-#endif
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/insmod.c b/busybox/insmod.c
deleted file mode 100644 (file)
index 413af5c..0000000
+++ /dev/null
@@ -1,3481 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini insmod implementation for busybox
- *
- * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 
- * and MIPS.
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>
- * and Ron Alder <alder@lineo.com>
- *
- * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
- * and (theoretically) SH3. I have only tested SH4 in little endian mode.
- *
- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI.  Only
- * very minor changes required to also work with StrongArm and presumably
- * all ARM based systems.
- *
- * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
- *   PowerPC specific code stolen from modutils-2.3.16, 
- *   written by Paul Mackerras, Copyright 1996, 1997 Linux International.
- *   I've only tested the code on mpc8xx platforms in big-endian mode.
- *   Did some cleanup and added BB_USE_xxx_ENTRIES...
- *
- * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
- *   based on modutils-2.4.2
- *   MIPS specific support for Elf loading and relocation.
- *   Copyright 1996, 1997 Linux International.
- *   Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
- *
- * Based almost entirely on the Linux modutils-2.3.11 implementation.
- *   Copyright 1996, 1997 Linux International.
- *   New implementation contributed by Richard Henderson <rth@tamu.edu>
- *   Based on original work by Bjorn Ekwall <bj0rn@blox.se>
- *   Restructured (and partly rewritten) by:
- *   Björn Ekwall <bj0rn@blox.se> February 1999
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <assert.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/utsname.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-# undef BB_FEATURE_OLD_MODULE_INTERFACE
-# define new_sys_init_module   init_module
-#else
-# define old_sys_init_module   init_module
-#endif
-
-#ifdef BB_FEATURE_INSMOD_LOADINKMEM
-#define LOADBITS 0     
-#else
-#define LOADBITS 1
-#endif
-
-#if defined(__powerpc__)
-#define BB_USE_PLT_ENTRIES
-#define BB_PLT_ENTRY_SIZE 16
-#endif
-
-#if defined(__arm__)
-#define BB_USE_PLT_ENTRIES
-#define BB_PLT_ENTRY_SIZE 8
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 8
-#endif
-
-#if defined(__sh__)
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 4
-#endif
-
-#if defined(__i386__)
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 4
-#endif
-
-#if defined(__mips__)
-// neither used
-#endif
-
-//----------------------------------------------------------------------------
-//--------modutils module.h, lines 45-242
-//----------------------------------------------------------------------------
-
-/* Definitions for the Linux module syscall interface.
-   Copyright 1996, 1997 Linux International.
-
-   Contributed by Richard Henderson <rth@tamu.edu>
-
-   This file is part of the Linux modutils.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2 of the License, or (at your
-   option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-
-#ifndef MODUTILS_MODULE_H
-static const int MODUTILS_MODULE_H = 1;
-
-/* This file contains the structures used by the 2.0 and 2.1 kernels.
-   We do not use the kernel headers directly because we do not wish
-   to be dependant on a particular kernel version to compile insmod.  */
-
-
-/*======================================================================*/
-/* The structures used by Linux 2.0.  */
-
-/* The symbol format used by get_kernel_syms(2).  */
-struct old_kernel_sym
-{
-  unsigned long value;
-  char name[60];
-};
-
-struct old_module_ref
-{
-  unsigned long module;                /* kernel addresses */
-  unsigned long next;
-};
-
-struct old_module_symbol
-{
-  unsigned long addr;
-  unsigned long name;
-};
-
-struct old_symbol_table
-{
-  int size;                    /* total, including string table!!! */
-  int n_symbols;
-  int n_refs;
-  struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
-  struct old_module_ref ref[0];        /* actual size defined by n_refs */
-};
-
-struct old_mod_routines
-{
-  unsigned long init;
-  unsigned long cleanup;
-};
-
-struct old_module
-{
-  unsigned long next;
-  unsigned long ref;           /* the list of modules that refer to me */
-  unsigned long symtab;
-  unsigned long name;
-  int size;                    /* size of module in pages */
-  unsigned long addr;          /* address of module */
-  int state;
-  unsigned long cleanup;       /* cleanup routine */
-};
-
-/* Sent to init_module(2) or'ed into the code size parameter.  */
-static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */
-
-int get_kernel_syms(struct old_kernel_sym *);
-int old_sys_init_module(const char *name, char *code, unsigned codesize,
-                       struct old_mod_routines *, struct old_symbol_table *);
-
-/*======================================================================*/
-/* For sizeof() which are related to the module platform and not to the
-   environment isnmod is running in, use sizeof_xx instead of sizeof(xx).  */
-
-#define tgt_sizeof_char                sizeof(char)
-#define tgt_sizeof_short       sizeof(short)
-#define tgt_sizeof_int         sizeof(int)
-#define tgt_sizeof_long                sizeof(long)
-#define tgt_sizeof_char_p      sizeof(char *)
-#define tgt_sizeof_void_p      sizeof(void *)
-#define tgt_long               long
-
-#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
-#undef tgt_sizeof_long
-#undef tgt_sizeof_char_p
-#undef tgt_sizeof_void_p
-#undef tgt_long
-static const int tgt_sizeof_long = 8;
-static const int tgt_sizeof_char_p = 8;
-static const int tgt_sizeof_void_p = 8;
-#define tgt_long               long long
-#endif
-
-/*======================================================================*/
-/* The structures used in Linux 2.1.  */
-
-/* Note: new_module_symbol does not use tgt_long intentionally */
-struct new_module_symbol
-{
-  unsigned long value;
-  unsigned long name;
-};
-
-struct new_module_persist;
-
-struct new_module_ref
-{
-  unsigned tgt_long dep;               /* kernel addresses */
-  unsigned tgt_long ref;
-  unsigned tgt_long next_ref;
-};
-
-struct new_module
-{
-  unsigned tgt_long size_of_struct;    /* == sizeof(module) */
-  unsigned tgt_long next;
-  unsigned tgt_long name;
-  unsigned tgt_long size;
-
-  tgt_long usecount;
-  unsigned tgt_long flags;             /* AUTOCLEAN et al */
-
-  unsigned nsyms;
-  unsigned ndeps;
-
-  unsigned tgt_long syms;
-  unsigned tgt_long deps;
-  unsigned tgt_long refs;
-  unsigned tgt_long init;
-  unsigned tgt_long cleanup;
-  unsigned tgt_long ex_table_start;
-  unsigned tgt_long ex_table_end;
-#ifdef __alpha__
-  unsigned tgt_long gp;
-#endif
-  /* Everything after here is extension.  */
-  unsigned tgt_long persist_start;
-  unsigned tgt_long persist_end;
-  unsigned tgt_long can_unload;
-  unsigned tgt_long runsize;
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-  const char *kallsyms_start;     /* All symbols for kernel debugging */
-  const char *kallsyms_end;
-  const char *archdata_start;     /* arch specific data for module */
-  const char *archdata_end;
-  const char *kernel_data;        /* Reserved for kernel internal use */
-#endif
-};
-
-#define ARCHDATA_SEC_NAME "__archdata"
-#define KALLSYMS_SEC_NAME "__kallsyms"
-
-
-struct new_module_info
-{
-  unsigned long addr;
-  unsigned long size;
-  unsigned long flags;
-          long usecount;
-};
-
-/* Bits of module.flags.  */
-static const int NEW_MOD_RUNNING = 1;
-static const int NEW_MOD_DELETED = 2;
-static const int NEW_MOD_AUTOCLEAN = 4;
-static const int NEW_MOD_VISITED = 8;
-static const int NEW_MOD_USED_ONCE = 16;
-
-int new_sys_init_module(const char *name, const struct new_module *);
-int query_module(const char *name, int which, void *buf, size_t bufsize,
-                size_t *ret);
-
-/* Values for query_module's which.  */
-
-static const int QM_MODULES = 1;
-static const int QM_DEPS = 2;
-static const int QM_REFS = 3;
-static const int QM_SYMBOLS = 4;
-static const int QM_INFO = 5;
-
-/*======================================================================*/
-/* The system calls unchanged between 2.0 and 2.1.  */
-
-unsigned long create_module(const char *, size_t);
-int delete_module(const char *);
-
-
-#endif /* module.h */
-
-//----------------------------------------------------------------------------
-//--------end of modutils module.h
-//----------------------------------------------------------------------------
-
-
-
-//----------------------------------------------------------------------------
-//--------modutils obj.h, lines 253-462
-//----------------------------------------------------------------------------
-
-/* Elf object file loading and relocation routines.
-   Copyright 1996, 1997 Linux International.
-
-   Contributed by Richard Henderson <rth@tamu.edu>
-
-   This file is part of the Linux modutils.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2 of the License, or (at your
-   option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-
-#ifndef MODUTILS_OBJ_H
-static const int MODUTILS_OBJ_H = 1;
-
-/* The relocatable object is manipulated using elfin types.  */
-
-#include <stdio.h>
-#include <elf.h>
-
-
-/* Machine-specific elf macros for i386 et al.  */
-
-/* the SH changes have only been tested on the SH4 in =little endian= mode */
-/* I'm not sure about big endian, so let's warn: */
-
-#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
-#error insmod.c may require changes for use on big endian SH4/SH3
-#endif
-
-/* it may or may not work on the SH1/SH2... So let's error on those
-   also */
-#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
-#error insmod.c may require changes for non-SH3/SH4 use
-#endif
-
-#define ELFCLASSM      ELFCLASS32
-
-#if (defined(__mc68000__))                                     
-#define ELFDATAM       ELFDATA2MSB
-#endif
-
-
-
-#if defined(__sh__)
-
-#define MATCH_MACHINE(x) (x == EM_SH)
-#define SHT_RELM       SHT_RELA
-#define Elf32_RelM     Elf32_Rela
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__arm__)
-
-#define MATCH_MACHINE(x) (x == EM_ARM)
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__powerpc__)
-
-#define MATCH_MACHINE(x) (x == EM_PPC)
-#define SHT_RELM       SHT_RELA
-#define Elf32_RelM     Elf32_Rela
-#define ELFDATAM    ELFDATA2MSB
-
-#elif defined(__mips__)
-
-/* Account for ELF spec changes.  */
-#ifndef EM_MIPS_RS3_LE
-#ifdef EM_MIPS_RS4_BE
-#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
-#else
-#define EM_MIPS_RS3_LE 10
-#endif
-#endif /* !EM_MIPS_RS3_LE */
-
-#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#ifdef __MIPSEB__
-#define ELFDATAM        ELFDATA2MSB
-#endif
-#ifdef __MIPSEL__
-#define ELFDATAM        ELFDATA2LSB
-#endif
-
-#elif defined(__i386__)
-
-/* presumably we can use these for anything but the SH and ARM*/
-/* this is the previous behavior, but it does result in
-   insmod.c being broken on anything except i386 */
-#ifndef EM_486
-#define MATCH_MACHINE(x)  (x == EM_386)
-#else
-#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
-#endif
-
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__mc68000__) 
-
-#define MATCH_MACHINE(x)       (x == EM_68K)
-#define SHT_RELM                       SHT_RELA
-#define Elf32_RelM                     Elf32_Rela
-
-#else
-#error Sorry, but insmod.c does not yet support this architecture...
-#endif
-
-#ifndef ElfW
-# if ELFCLASSM == ELFCLASS32
-#  define ElfW(x)  Elf32_ ## x
-#  define ELFW(x)  ELF32_ ## x
-# else
-#  define ElfW(x)  Elf64_ ## x
-#  define ELFW(x)  ELF64_ ## x
-# endif
-#endif
-
-/* For some reason this is missing from libc5.  */
-#ifndef ELF32_ST_INFO
-# define ELF32_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
-#endif
-
-#ifndef ELF64_ST_INFO
-# define ELF64_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
-#endif
-
-struct obj_string_patch;
-struct obj_symbol_patch;
-
-struct obj_section
-{
-  ElfW(Shdr) header;
-  const char *name;
-  char *contents;
-  struct obj_section *load_next;
-  int idx;
-};
-
-struct obj_symbol
-{
-  struct obj_symbol *next;     /* hash table link */
-  const char *name;
-  unsigned long value;
-  unsigned long size;
-  int secidx;                  /* the defining section index/module */
-  int info;
-  int ksymidx;                 /* for export to the kernel symtab */
-  int referenced;              /* actually used in the link */
-};
-
-/* Hardcode the hash table size.  We shouldn't be needing so many
-   symbols that we begin to degrade performance, and we get a big win
-   by giving the compiler a constant divisor.  */
-
-#define HASH_BUCKETS  521
-
-struct obj_file
-{
-  ElfW(Ehdr) header;
-  ElfW(Addr) baseaddr;
-  struct obj_section **sections;
-  struct obj_section *load_order;
-  struct obj_section **load_order_search_start;
-  struct obj_string_patch *string_patches;
-  struct obj_symbol_patch *symbol_patches;
-  int (*symbol_cmp)(const char *, const char *);
-  unsigned long (*symbol_hash)(const char *);
-  unsigned long local_symtab_size;
-  struct obj_symbol **local_symtab;
-  struct obj_symbol *symtab[HASH_BUCKETS];
-};
-
-enum obj_reloc
-{
-  obj_reloc_ok,
-  obj_reloc_overflow,
-  obj_reloc_dangerous,
-  obj_reloc_unhandled
-};
-
-struct obj_string_patch
-{
-  struct obj_string_patch *next;
-  int reloc_secidx;
-  ElfW(Addr) reloc_offset;
-  ElfW(Addr) string_offset;
-};
-
-struct obj_symbol_patch
-{
-  struct obj_symbol_patch *next;
-  int reloc_secidx;
-  ElfW(Addr) reloc_offset;
-  struct obj_symbol *sym;
-};
-
-
-/* Generic object manipulation routines.  */
-
-static unsigned long obj_elf_hash(const char *);
-
-static unsigned long obj_elf_hash_n(const char *, unsigned long len);
-
-static struct obj_symbol *obj_find_symbol (struct obj_file *f,
-                                        const char *name);
-
-static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
-                                 struct obj_symbol *sym);
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static void obj_set_symbol_compare(struct obj_file *f,
-                           int (*cmp)(const char *, const char *),
-                           unsigned long (*hash)(const char *));
-#endif
-
-static struct obj_section *obj_find_section (struct obj_file *f,
-                                          const char *name);
-
-static void obj_insert_section_load_order (struct obj_file *f,
-                                   struct obj_section *sec);
-
-static struct obj_section *obj_create_alloced_section (struct obj_file *f,
-                                               const char *name,
-                                               unsigned long align,
-                                               unsigned long size);
-
-static struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
-                                                     const char *name,
-                                                     unsigned long align,
-                                                     unsigned long size);
-
-static void *obj_extend_section (struct obj_section *sec, unsigned long more);
-
-static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                    const char *string);
-
-static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                    struct obj_symbol *sym);
-
-static int obj_check_undefineds(struct obj_file *f);
-
-static void obj_allocate_commons(struct obj_file *f);
-
-static unsigned long obj_load_size (struct obj_file *f);
-
-static int obj_relocate (struct obj_file *f, ElfW(Addr) base);
-
-static struct obj_file *obj_load(FILE *f, int loadprogbits);
-
-static int obj_create_image (struct obj_file *f, char *image);
-
-/* Architecture specific manipulation routines.  */
-
-static struct obj_file *arch_new_file (void);
-
-static struct obj_section *arch_new_section (void);
-
-static struct obj_symbol *arch_new_symbol (void);
-
-static enum obj_reloc arch_apply_relocation (struct obj_file *f,
-                                     struct obj_section *targsec,
-                                     struct obj_section *symsec,
-                                     struct obj_symbol *sym,
-                                     ElfW(RelM) *rel, ElfW(Addr) value);
-
-static int arch_create_got (struct obj_file *f);
-
-static int arch_init_module (struct obj_file *f, struct new_module *);
-
-#endif /* obj.h */
-//----------------------------------------------------------------------------
-//--------end of modutils obj.h
-//----------------------------------------------------------------------------
-
-
-
-
-
-#define _PATH_MODULES  "/lib/modules"
-static const int STRVERSIONLEN = 32;
-
-/*======================================================================*/
-
-static int flag_force_load = 0;
-static int flag_autoclean = 0;
-static int flag_verbose = 0;
-static int flag_export = 1;
-
-
-/*======================================================================*/
-
-/* previously, these were named i386_* but since we could be
-   compiling for the sh, I've renamed them to the more general
-   arch_* These structures are the same between the x86 and SH, 
-   and we can't support anything else right now anyway. In the
-   future maybe they should be #if defined'd */
-
-/* Done ;-) */
-
-
-
-#if defined(BB_USE_PLT_ENTRIES)
-struct arch_plt_entry
-{
-  int offset;
-  int allocated:1;
-  int inited:1;                /* has been set up */
-};
-#endif
-
-#if defined(BB_USE_GOT_ENTRIES)
-struct arch_got_entry {
-       int offset;
-       unsigned offset_done:1;
-       unsigned reloc_done:1;
-};
-#endif
-
-#if defined(__mips__)
-struct mips_hi16
-{
-  struct mips_hi16 *next;
-  Elf32_Addr *addr;
-  Elf32_Addr value;
-};
-#endif
-
-struct arch_file {
-       struct obj_file root;
-#if defined(BB_USE_PLT_ENTRIES)
-       struct obj_section *plt;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       struct obj_section *got;
-#endif
-#if defined(__mips__)
-       struct mips_hi16 *mips_hi16_list;
-#endif
-};
-
-struct arch_symbol {
-       struct obj_symbol root;
-#if defined(BB_USE_PLT_ENTRIES)
-       struct arch_plt_entry pltent;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       struct arch_got_entry gotent;
-#endif
-};
-
-
-struct external_module {
-       const char *name;
-       ElfW(Addr) addr;
-       int used;
-       size_t nsyms;
-       struct new_module_symbol *syms;
-};
-
-static struct new_module_symbol *ksyms;
-static size_t nksyms;
-
-static struct external_module *ext_modules;
-static int n_ext_modules;
-static int n_ext_modules_used;
-extern int delete_module(const char *);
-
-static char m_filename[FILENAME_MAX + 1];
-static char m_fullName[FILENAME_MAX + 1];
-
-
-
-/*======================================================================*/
-
-
-static int check_module_name_match(const char *filename, struct stat *statbuf,
-                                                  void *userdata)
-{
-       char *fullname = (char *) userdata;
-
-       if (fullname[0] == '\0')
-               return (FALSE);
-       else {
-               char *tmp, *tmp1 = strdup(filename);
-               tmp = get_last_path_component(tmp1);
-               if (strcmp(tmp, fullname) == 0) {
-                       free(tmp1);
-                       /* Stop searching if we find a match */
-                       safe_strncpy(m_filename, filename, sizeof(m_filename));
-                       return (TRUE);
-               }
-               free(tmp1);
-       }
-       return (FALSE);
-}
-
-
-/*======================================================================*/
-
-static struct obj_file *arch_new_file(void)
-{
-       struct arch_file *f;
-       f = xmalloc(sizeof(*f));
-
-#if defined(BB_USE_PLT_ENTRIES)
-       f->plt = NULL;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       f->got = NULL;
-#endif
-#if defined(__mips__)
-       f->mips_hi16_list = NULL;
-#endif
-
-       return &f->root;
-}
-
-static struct obj_section *arch_new_section(void)
-{
-       return xmalloc(sizeof(struct obj_section));
-}
-
-static struct obj_symbol *arch_new_symbol(void)
-{
-       struct arch_symbol *sym;
-       sym = xmalloc(sizeof(*sym));
-
-#if defined(BB_USE_PLT_ENTRIES)
-       memset(&sym->pltent, 0, sizeof(sym->pltent));
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       memset(&sym->gotent, 0, sizeof(sym->gotent));
-#endif
-
-       return &sym->root;
-}
-
-static enum obj_reloc
-arch_apply_relocation(struct obj_file *f,
-                                         struct obj_section *targsec,
-                                         struct obj_section *symsec,
-                                         struct obj_symbol *sym,
-                                     ElfW(RelM) *rel, ElfW(Addr) v)
-{
-       struct arch_file *ifile = (struct arch_file *) f;
-#if !(defined(__mips__))
-       struct arch_symbol *isym = (struct arch_symbol *) sym;
-#endif
-
-       ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
-       ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
-#if defined(BB_USE_GOT_ENTRIES)
-       ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-       ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
-       struct arch_plt_entry *pe;
-       unsigned long *ip;
-#endif
-       enum obj_reloc ret = obj_reloc_ok;
-
-       switch (ELF32_R_TYPE(rel->r_info)) {
-
-/* even though these constants seem to be the same for
-   the i386 and the sh, we "#if define" them for clarity
-   and in case that ever changes */
-#if defined(__sh__)
-       case R_SH_NONE:
-#elif defined(__arm__)
-       case R_ARM_NONE:
-#elif defined(__i386__)
-       case R_386_NONE:
-#elif defined(__mc68000__) 
-       case R_68K_NONE:
-#elif defined(__powerpc__)
-       case R_PPC_NONE:
-#elif defined(__mips__)
-       case R_MIPS_NONE:
-#endif
-               break;
-
-#if defined(__sh__)
-       case R_SH_DIR32:
-#elif defined(__arm__)
-       case R_ARM_ABS32:
-#elif defined(__i386__)
-       case R_386_32:  
-#elif defined(__mc68000__) 
-       case R_68K_32:
-#elif defined(__powerpc__)
-       case R_PPC_ADDR32:
-#elif defined(__mips__)
-       case R_MIPS_32:
-#endif
-               *loc += v;
-               break;
-#if defined(__mc68000__)
-    case R_68K_8:
-               if (v > 0xff)
-               ret = obj_reloc_overflow;
-               *(char *)loc = v;
-               break;
-    case R_68K_16:
-               if (v > 0xffff)
-               ret = obj_reloc_overflow;
-               *(short *)loc = v;
-               break;
-#endif /* __mc68000__   */
-
-#if defined(__powerpc__)
-       case R_PPC_ADDR16_HA:
-               *(unsigned short *)loc = (v + 0x8000) >> 16;
-               break;
-
-       case R_PPC_ADDR16_HI:
-               *(unsigned short *)loc = v >> 16;
-               break;
-
-       case R_PPC_ADDR16_LO:
-               *(unsigned short *)loc = v;
-               break;
-#endif
-
-#if defined(__mips__)
-       case R_MIPS_26:
-               if (v % 4)
-                       ret = obj_reloc_dangerous;
-               if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
-                       ret = obj_reloc_overflow;
-               *loc =
-                   (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
-                                           0x03ffffff);
-               break;
-
-       case R_MIPS_HI16:
-               {
-                       struct mips_hi16 *n;
-
-                       /* We cannot relocate this one now because we don't know the value
-                          of the carry we need to add.  Save the information, and let LO16
-                          do the actual relocation.  */
-                       n = (struct mips_hi16 *) xmalloc(sizeof *n);
-                       n->addr = loc;
-                       n->value = v;
-                       n->next = ifile->mips_hi16_list;
-                       ifile->mips_hi16_list = n;
-                       break;
-               }
-
-       case R_MIPS_LO16:
-               {
-                       unsigned long insnlo = *loc;
-                       Elf32_Addr val, vallo;
-
-                       /* Sign extend the addend we extract from the lo insn.  */
-                       vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
-
-                       if (ifile->mips_hi16_list != NULL) {
-                               struct mips_hi16 *l;
-
-                               l = ifile->mips_hi16_list;
-                               while (l != NULL) {
-                                       struct mips_hi16 *next;
-                                       unsigned long insn;
-
-                                       /* The value for the HI16 had best be the same. */
-                                       assert(v == l->value);
-
-                                       /* Do the HI16 relocation.  Note that we actually don't
-                                          need to know anything about the LO16 itself, except where
-                                          to find the low 16 bits of the addend needed by the LO16.  */
-                                       insn = *l->addr;
-                                       val =
-                                           ((insn & 0xffff) << 16) +
-                                           vallo;
-                                       val += v;
-
-                                       /* Account for the sign extension that will happen in the
-                                          low bits.  */
-                                       val =
-                                           ((val >> 16) +
-                                            ((val & 0x8000) !=
-                                             0)) & 0xffff;
-
-                                       insn = (insn & ~0xffff) | val;
-                                       *l->addr = insn;
-
-                                       next = l->next;
-                                       free(l);
-                                       l = next;
-                               }
-
-                               ifile->mips_hi16_list = NULL;
-                       }
-
-                       /* Ok, we're done with the HI16 relocs.  Now deal with the LO16.  */
-                       val = v + vallo;
-                       insnlo = (insnlo & ~0xffff) | (val & 0xffff);
-                       *loc = insnlo;
-                       break;
-               }
-#endif
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_REL32:
-               *loc += v - dot;
-               break;
-#elif defined(__i386__)
-       case R_386_PLT32:
-       case R_386_PC32:
-               *loc += v - dot;
-               break;
-#elif defined(__mc68000__)
-    case R_68K_PC8:
-               v -= dot;
-               if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80)
-               ret = obj_reloc_overflow;
-               *(char *)loc = v;
-    break;
-               case R_68K_PC16:
-               v -= dot;
-               if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000)
-               ret = obj_reloc_overflow;
-               *(short *)loc = v;
-               break;
-    case R_68K_PC32:
-               *(int *)loc = v - dot;
-               break;
-#elif defined(__powerpc__)
-       case R_PPC_REL32:
-               *loc = v - dot;
-               break;
-#endif
-
-#if defined(__sh__)
-        case R_SH_PLT32:
-                *loc = v - dot;
-                break;
-#elif defined(__i386__)
-#endif
-
-#if defined(BB_USE_PLT_ENTRIES)
-
-#if defined(__arm__)
-    case R_ARM_PC24:
-    case R_ARM_PLT32:
-#endif
-#if defined(__powerpc__)
-       case R_PPC_REL24:
-#endif
-      /* find the plt entry and initialize it if necessary */
-      assert(isym != NULL);
-
-      pe = (struct arch_plt_entry*) &isym->pltent;
-
-      if (! pe->inited) {
-               ip = (unsigned long *) (ifile->plt->contents + pe->offset);
-
-               /* generate some machine code */
-
-#if defined(__arm__)
-               ip[0] = 0xe51ff004;                     /* ldr pc,[pc,#-4] */
-               ip[1] = v;                              /* sym@ */
-#endif
-#if defined(__powerpc__)
-         ip[0] = 0x3d600000 + ((v + 0x8000) >> 16);  /* lis r11,sym@ha */
-         ip[1] = 0x396b0000 + (v & 0xffff);          /* addi r11,r11,sym@l */
-         ip[2] = 0x7d6903a6;                         /* mtctr r11 */
-         ip[3] = 0x4e800420;                         /* bctr */
-#endif
-               pe->inited = 1;
-         }
-
-      /* relative distance to target */
-      v -= dot;
-      /* if the target is too far away.... */
-      if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
-           /* go via the plt */
-           v = plt + pe->offset - dot;
-         }
-      if (v & 3)
-           ret = obj_reloc_dangerous;
-
-      /* merge the offset into the instruction. */
-#if defined(__arm__)
-      /* Convert to words. */
-      v >>= 2;
-
-      *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
-#endif
-#if defined(__powerpc__)
-      *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
-#endif
-      break;
-#endif /* BB_USE_PLT_ENTRIES */
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_GLOB_DAT:
-        case R_SH_JMP_SLOT:
-                       *loc = v;
-                break;
-#elif defined(__i386__)
-       case R_386_GLOB_DAT:
-       case R_386_JMP_SLOT:
-               *loc = v;
-               break;
-#elif defined(__mc68000__)
-       case R_68K_GLOB_DAT:
-       case R_68K_JMP_SLOT:
-               *loc = v;
-               break;
-#endif
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_RELATIVE:
-               *loc += f->baseaddr + rel->r_addend;
-                break;
-#elif defined(__i386__)
-        case R_386_RELATIVE:
-               *loc += f->baseaddr;
-               break;
-#elif defined(__mc68000__)
-    case R_68K_RELATIVE:
-       *(int *)loc += f->baseaddr;
-       break;
-#endif
-
-#if defined(BB_USE_GOT_ENTRIES)
-
-#if !defined(__68k__)
-#if defined(__sh__)
-        case R_SH_GOTPC:
-#elif defined(__arm__)
-    case R_ARM_GOTPC:
-#elif defined(__i386__)
-       case R_386_GOTPC:
-#endif
-               assert(got != 0);
-#if defined(__sh__)
-               *loc += got - dot + rel->r_addend;;
-#elif defined(__i386__) || defined(__arm__) || defined(__m68k_)
-               *loc += got - dot;
-#endif
-               break;
-#endif // __68k__
-
-#if defined(__sh__)
-       case R_SH_GOT32:
-#elif defined(__arm__)
-       case R_ARM_GOT32:
-#elif defined(__i386__)
-       case R_386_GOT32:
-#elif defined(__mc68000__)
-       case R_68K_GOT32:
-#endif
-               assert(isym != NULL);
-        /* needs an entry in the .got: set it, once */
-               if (!isym->gotent.reloc_done) {
-                       isym->gotent.reloc_done = 1;
-                       *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
-               }
-        /* make the reloc with_respect_to_.got */
-#if defined(__sh__)
-               *loc += isym->gotent.offset + rel->r_addend;
-#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
-               *loc += isym->gotent.offset;
-#endif
-               break;
-
-    /* address relative to the got */
-#if !defined(__mc68000__)
-#if defined(__sh__)
-       case R_SH_GOTOFF:
-#elif defined(__arm__)
-       case R_ARM_GOTOFF:
-#elif defined(__i386__)
-       case R_386_GOTOFF:
-#elif defined(__mc68000__)
-       case R_68K_GOTOFF:
-#endif
-               assert(got != 0);
-               *loc += v - got;
-               break;
-#endif // __mc68000__
-
-#endif /* BB_USE_GOT_ENTRIES */
-
-       default:
-        printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
-               ret = obj_reloc_unhandled;
-               break;
-       }
-
-       return ret;
-}
-
-static int arch_create_got(struct obj_file *f)
-{
-#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
-       struct arch_file *ifile = (struct arch_file *) f;
-       int i;
-#if defined(BB_USE_GOT_ENTRIES)
-       int got_offset = 0, gotneeded = 0;
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-       int plt_offset = 0, pltneeded = 0;
-#endif
-    struct obj_section *relsec, *symsec, *strsec;
-       ElfW(RelM) *rel, *relend;
-       ElfW(Sym) *symtab, *extsym;
-       const char *strtab, *name;
-       struct arch_symbol *intsym;
-
-       for (i = 0; i < f->header.e_shnum; ++i) {
-               relsec = f->sections[i];
-               if (relsec->header.sh_type != SHT_RELM)
-                       continue;
-
-               symsec = f->sections[relsec->header.sh_link];
-               strsec = f->sections[symsec->header.sh_link];
-
-               rel = (ElfW(RelM) *) relsec->contents;
-               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
-               symtab = (ElfW(Sym) *) symsec->contents;
-               strtab = (const char *) strsec->contents;
-
-               for (; rel < relend; ++rel) {
-                       extsym = &symtab[ELF32_R_SYM(rel->r_info)];
-
-                       switch (ELF32_R_TYPE(rel->r_info)) {
-#if defined(__arm__)
-                       case R_ARM_GOT32:
-                               break;
-#elif defined(__sh__)
-                       case R_SH_GOT32:
-                               break;
-#elif defined(__i386__)
-                       case R_386_GOT32:
-                               break;
-#elif defined(__mc68000__)
-                       case R_68K_GOT32:
-                               break;
-#endif
-
-#if defined(__powerpc__)
-                       case R_PPC_REL24:
-                               pltneeded = 1;
-                               break;
-#endif
-
-#if defined(__arm__)
-                       case R_ARM_PC24:
-                       case R_ARM_PLT32:
-                               pltneeded = 1;
-                               break;
-
-                       case R_ARM_GOTPC:
-                       case R_ARM_GOTOFF:
-                               gotneeded = 1;
-                               if (got_offset == 0)
-                                       got_offset = 4;
-#elif defined(__sh__)
-                       case R_SH_GOTPC:
-                       case R_SH_GOTOFF:
-                               gotneeded = 1;
-#elif defined(__i386__)
-                       case R_386_GOTPC:
-                       case R_386_GOTOFF:
-                               gotneeded = 1;
-#endif
-
-                       default:
-                               continue;
-                       }
-
-                       if (extsym->st_name != 0) {
-                               name = strtab + extsym->st_name;
-                       } else {
-                               name = f->sections[extsym->st_shndx]->name;
-                       }
-                       intsym = (struct arch_symbol *) obj_find_symbol(f, name);
-#if defined(BB_USE_GOT_ENTRIES)
-                       if (!intsym->gotent.offset_done) {
-                               intsym->gotent.offset_done = 1;
-                               intsym->gotent.offset = got_offset;
-                               got_offset += BB_GOT_ENTRY_SIZE;
-                       }
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-                       if (pltneeded && intsym->pltent.allocated == 0) {
-                               intsym->pltent.allocated = 1;
-                               intsym->pltent.offset = plt_offset;
-                               plt_offset += BB_PLT_ENTRY_SIZE;
-                               intsym->pltent.inited = 0;
-                               pltneeded = 0;
-                       }
-#endif
-                       }
-               }
-
-#if defined(BB_USE_GOT_ENTRIES)
-       if (got_offset) {
-               struct obj_section* myrelsec = obj_find_section(f, ".got");
-
-               if (myrelsec) {
-                       obj_extend_section(myrelsec, got_offset);
-               } else {
-                       myrelsec = obj_create_alloced_section(f, ".got", 
-                                                           BB_GOT_ENTRY_SIZE,
-                                                           got_offset);
-                       assert(myrelsec);
-               }
-
-               ifile->got = myrelsec;
-       }
-#endif
-
-#if defined(BB_USE_PLT_ENTRIES)
-       if (plt_offset)
-               ifile->plt = obj_create_alloced_section(f, ".plt", 
-                                                       BB_PLT_ENTRY_SIZE, 
-                                                       plt_offset);
-#endif
-#endif
-       return 1;
-}
-
-static int arch_init_module(struct obj_file *f, struct new_module *mod)
-{
-       return 1;
-}
-
-
-/*======================================================================*/
-
-/* Standard ELF hash function.  */
-static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n)
-{
-       unsigned long h = 0;
-       unsigned long g;
-       unsigned char ch;
-
-       while (n > 0) {
-               ch = *name++;
-               h = (h << 4) + ch;
-               if ((g = (h & 0xf0000000)) != 0) {
-                       h ^= g >> 24;
-                       h &= ~g;
-               }
-               n--;
-       }
-       return h;
-}
-
-static unsigned long obj_elf_hash(const char *name)
-{
-       return obj_elf_hash_n(name, strlen(name));
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-/* String comparison for non-co-versioned kernel and module.  */
-
-static int ncv_strcmp(const char *a, const char *b)
-{
-       size_t alen = strlen(a), blen = strlen(b);
-
-       if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
-               return strncmp(a, b, alen);
-       else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
-               return strncmp(a, b, blen);
-       else
-               return strcmp(a, b);
-}
-
-/* String hashing for non-co-versioned kernel and module.  Here
-   we are simply forced to drop the crc from the hash.  */
-
-static unsigned long ncv_symbol_hash(const char *str)
-{
-       size_t len = strlen(str);
-       if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
-               len -= 10;
-       return obj_elf_hash_n(str, len);
-}
-
-static void
-obj_set_symbol_compare(struct obj_file *f,
-                                          int (*cmp) (const char *, const char *),
-                                          unsigned long (*hash) (const char *))
-{
-       if (cmp)
-               f->symbol_cmp = cmp;
-       if (hash) {
-               struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
-               int i;
-
-               f->symbol_hash = hash;
-
-               memcpy(tmptab, f->symtab, sizeof(tmptab));
-               memset(f->symtab, 0, sizeof(f->symtab));
-
-               for (i = 0; i < HASH_BUCKETS; ++i)
-                       for (sym = tmptab[i]; sym; sym = next) {
-                               unsigned long h = hash(sym->name) % HASH_BUCKETS;
-                               next = sym->next;
-                               sym->next = f->symtab[h];
-                               f->symtab[h] = sym;
-                       }
-       }
-}
-
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-static struct obj_symbol *
-obj_add_symbol(struct obj_file *f, const char *name,
-                                                                 unsigned long symidx, int info,
-                                                                 int secidx, ElfW(Addr) value,
-                                                                 unsigned long size)
-{
-       struct obj_symbol *sym;
-       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
-       int n_type = ELFW(ST_TYPE) (info);
-       int n_binding = ELFW(ST_BIND) (info);
-
-       for (sym = f->symtab[hash]; sym; sym = sym->next)
-               if (f->symbol_cmp(sym->name, name) == 0) {
-                       int o_secidx = sym->secidx;
-                       int o_info = sym->info;
-                       int o_type = ELFW(ST_TYPE) (o_info);
-                       int o_binding = ELFW(ST_BIND) (o_info);
-
-                       /* A redefinition!  Is it legal?  */
-
-                       if (secidx == SHN_UNDEF)
-                               return sym;
-                       else if (o_secidx == SHN_UNDEF)
-                               goto found;
-                       else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
-                               /* Cope with local and global symbols of the same name
-                                  in the same object file, as might have been created
-                                  by ld -r.  The only reason locals are now seen at this
-                                  level at all is so that we can do semi-sensible things
-                                  with parameters.  */
-
-                               struct obj_symbol *nsym, **p;
-
-                               nsym = arch_new_symbol();
-                               nsym->next = sym->next;
-                               nsym->ksymidx = -1;
-
-                               /* Excise the old (local) symbol from the hash chain.  */
-                               for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
-                                       continue;
-                               *p = sym = nsym;
-                               goto found;
-                       } else if (n_binding == STB_LOCAL) {
-                               /* Another symbol of the same name has already been defined.
-                                  Just add this to the local table.  */
-                               sym = arch_new_symbol();
-                               sym->next = NULL;
-                               sym->ksymidx = -1;
-                               f->local_symtab[symidx] = sym;
-                               goto found;
-                       } else if (n_binding == STB_WEAK)
-                               return sym;
-                       else if (o_binding == STB_WEAK)
-                               goto found;
-                       /* Don't unify COMMON symbols with object types the programmer
-                          doesn't expect.  */
-                       else if (secidx == SHN_COMMON
-                                        && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
-                               return sym;
-                       else if (o_secidx == SHN_COMMON
-                                        && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
-                               goto found;
-                       else {
-                               /* Don't report an error if the symbol is coming from
-                                  the kernel or some external module.  */
-                               if (secidx <= SHN_HIRESERVE)
-                                       error_msg("%s multiply defined", name);
-                               return sym;
-                       }
-               }
-
-       /* Completely new symbol.  */
-       sym = arch_new_symbol();
-       sym->next = f->symtab[hash];
-       f->symtab[hash] = sym;
-       sym->ksymidx = -1;
-
-       if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
-               if (symidx >= f->local_symtab_size)
-                       error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
-                                       name, (long) symidx, (long) f->local_symtab_size);
-               else
-                       f->local_symtab[symidx] = sym;
-       }
-
-  found:
-       sym->name = name;
-       sym->value = value;
-       sym->size = size;
-       sym->secidx = secidx;
-       sym->info = info;
-
-       return sym;
-}
-
-static struct obj_symbol *
-obj_find_symbol(struct obj_file *f, const char *name)
-{
-       struct obj_symbol *sym;
-       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
-
-       for (sym = f->symtab[hash]; sym; sym = sym->next)
-               if (f->symbol_cmp(sym->name, name) == 0)
-                       return sym;
-
-       return NULL;
-}
-
-static ElfW(Addr)
-       obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
-{
-       if (sym) {
-               if (sym->secidx >= SHN_LORESERVE)
-                       return sym->value;
-
-               return sym->value + f->sections[sym->secidx]->header.sh_addr;
-       } else {
-               /* As a special case, a NULL sym has value zero.  */
-               return 0;
-       }
-}
-
-static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
-{
-       int i, n = f->header.e_shnum;
-
-       for (i = 0; i < n; ++i)
-               if (strcmp(f->sections[i]->name, name) == 0)
-                       return f->sections[i];
-
-       return NULL;
-}
-
-static int obj_load_order_prio(struct obj_section *a)
-{
-       unsigned long af, ac;
-
-       af = a->header.sh_flags;
-
-       ac = 0;
-       if (a->name[0] != '.' || strlen(a->name) != 10 ||
-               strcmp(a->name + 5, ".init"))
-               ac |= 32;
-       if (af & SHF_ALLOC)
-               ac |= 16;
-       if (!(af & SHF_WRITE))
-               ac |= 8;
-       if (af & SHF_EXECINSTR)
-               ac |= 4;
-       if (a->header.sh_type != SHT_NOBITS)
-               ac |= 2;
-
-       return ac;
-}
-
-static void
-obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
-{
-       struct obj_section **p;
-       int prio = obj_load_order_prio(sec);
-       for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
-               if (obj_load_order_prio(*p) < prio)
-                       break;
-       sec->load_next = *p;
-       *p = sec;
-}
-
-static struct obj_section *obj_create_alloced_section(struct obj_file *f,
-                                                                                          const char *name,
-                                                                                          unsigned long align,
-                                                                                          unsigned long size)
-{
-       int newidx = f->header.e_shnum++;
-       struct obj_section *sec;
-
-       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
-       f->sections[newidx] = sec = arch_new_section();
-
-       memset(sec, 0, sizeof(*sec));
-       sec->header.sh_type = SHT_PROGBITS;
-       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-       sec->header.sh_size = size;
-       sec->header.sh_addralign = align;
-       sec->name = name;
-       sec->idx = newidx;
-       if (size)
-               sec->contents = xmalloc(size);
-
-       obj_insert_section_load_order(f, sec);
-
-       return sec;
-}
-
-static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
-                                                                                                        const char *name,
-                                                                                                        unsigned long align,
-                                                                                                        unsigned long size)
-{
-       int newidx = f->header.e_shnum++;
-       struct obj_section *sec;
-
-       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
-       f->sections[newidx] = sec = arch_new_section();
-
-       memset(sec, 0, sizeof(*sec));
-       sec->header.sh_type = SHT_PROGBITS;
-       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-       sec->header.sh_size = size;
-       sec->header.sh_addralign = align;
-       sec->name = name;
-       sec->idx = newidx;
-       if (size)
-               sec->contents = xmalloc(size);
-
-       sec->load_next = f->load_order;
-       f->load_order = sec;
-       if (f->load_order_search_start == &f->load_order)
-               f->load_order_search_start = &sec->load_next;
-
-       return sec;
-}
-
-static void *obj_extend_section(struct obj_section *sec, unsigned long more)
-{
-       unsigned long oldsize = sec->header.sh_size;
-       if (more) { 
-               sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
-       }
-       return sec->contents + oldsize;
-}
-
-
-/* Conditionally add the symbols from the given symbol set to the
-   new module.  */
-
-static int
-add_symbols_from(
-                                struct obj_file *f,
-                                int idx, struct new_module_symbol *syms, size_t nsyms)
-{
-       struct new_module_symbol *s;
-       size_t i;
-       int used = 0;
-
-       for (i = 0, s = syms; i < nsyms; ++i, ++s) {
-
-               /* Only add symbols that are already marked external.  If we
-                  override locals we may cause problems for argument initialization.
-                  We will also create a false dependency on the module.  */
-               struct obj_symbol *sym;
-
-               sym = obj_find_symbol(f, (char *) s->name);
-               if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
-                       sym = obj_add_symbol(f, (char *) s->name, -1,
-                                                                ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
-                                                                idx, s->value, 0);
-                       /* Did our symbol just get installed?  If so, mark the
-                          module as "used".  */
-                       if (sym->secidx == idx)
-                               used = 1;
-               }
-       }
-
-       return used;
-}
-
-static void add_kernel_symbols(struct obj_file *f)
-{
-       struct external_module *m;
-       int i, nused = 0;
-
-       /* Add module symbols first.  */
-
-       for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m)
-               if (m->nsyms
-                       && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms,
-                                                               m->nsyms)) m->used = 1, ++nused;
-
-       n_ext_modules_used = nused;
-
-       /* And finally the symbols from the kernel proper.  */
-
-       if (nksyms)
-               add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
-}
-
-static char *get_modinfo_value(struct obj_file *f, const char *key)
-{
-       struct obj_section *sec;
-       char *p, *v, *n, *ep;
-       size_t klen = strlen(key);
-
-       sec = obj_find_section(f, ".modinfo");
-       if (sec == NULL)
-               return NULL;
-       p = sec->contents;
-       ep = p + sec->header.sh_size;
-       while (p < ep) {
-               v = strchr(p, '=');
-               n = strchr(p, '\0');
-               if (v) {
-                       if (p + klen == v && strncmp(p, key, klen) == 0)
-                               return v + 1;
-               } else {
-                       if (p + klen == n && strcmp(p, key) == 0)
-                               return n;
-               }
-               p = n + 1;
-       }
-
-       return NULL;
-}
-
-
-/*======================================================================*/
-/* Functions relating to module loading in pre 2.1 kernels.  */
-
-static int
-old_process_module_arguments(struct obj_file *f, int argc, char **argv)
-{
-       while (argc > 0) {
-               char *p, *q;
-               struct obj_symbol *sym;
-               int *loc;
-
-               p = *argv;
-               if ((q = strchr(p, '=')) == NULL) {
-                       argc--;
-                       continue;
-                }
-               *q++ = '\0';
-
-               sym = obj_find_symbol(f, p);
-
-               /* Also check that the parameter was not resolved from the kernel.  */
-               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
-                       error_msg("symbol for parameter %s not found", p);
-                       return 0;
-               }
-
-               loc = (int *) (f->sections[sym->secidx]->contents + sym->value);
-
-               /* Do C quoting if we begin with a ".  */
-               if (*q == '"') {
-                       char *r, *str;
-
-                       str = alloca(strlen(q));
-                       for (r = str, q++; *q != '"'; ++q, ++r) {
-                               if (*q == '\0') {
-                                       error_msg("improperly terminated string argument for %s", p);
-                                       return 0;
-                               } else if (*q == '\\')
-                                       switch (*++q) {
-                                       case 'a':
-                                               *r = '\a';
-                                               break;
-                                       case 'b':
-                                               *r = '\b';
-                                               break;
-                                       case 'e':
-                                               *r = '\033';
-                                               break;
-                                       case 'f':
-                                               *r = '\f';
-                                               break;
-                                       case 'n':
-                                               *r = '\n';
-                                               break;
-                                       case 'r':
-                                               *r = '\r';
-                                               break;
-                                       case 't':
-                                               *r = '\t';
-                                               break;
-
-                                       case '0':
-                                       case '1':
-                                       case '2':
-                                       case '3':
-                                       case '4':
-                                       case '5':
-                                       case '6':
-                                       case '7':
-                                               {
-                                                       int c = *q - '0';
-                                                       if (q[1] >= '0' && q[1] <= '7') {
-                                                               c = (c * 8) + *++q - '0';
-                                                               if (q[1] >= '0' && q[1] <= '7')
-                                                                       c = (c * 8) + *++q - '0';
-                                                       }
-                                                       *r = c;
-                                               }
-                                               break;
-
-                                       default:
-                                               *r = *q;
-                                               break;
-                               } else
-                                       *r = *q;
-                       }
-                       *r = '\0';
-                       obj_string_patch(f, sym->secidx, sym->value, str);
-               } else if (*q >= '0' && *q <= '9') {
-                       do
-                               *loc++ = strtoul(q, &q, 0);
-                       while (*q++ == ',');
-               } else {
-                       char *contents = f->sections[sym->secidx]->contents;
-                       char *myloc = contents + sym->value;
-                       char *r;                        /* To search for commas */
-
-                       /* Break the string with comas */
-                       while ((r = strchr(q, ',')) != (char *) NULL) {
-                               *r++ = '\0';
-                               obj_string_patch(f, sym->secidx, myloc - contents, q);
-                               myloc += sizeof(char *);
-                               q = r;
-                       }
-
-                       /* last part */
-                       obj_string_patch(f, sym->secidx, myloc - contents, q);
-               }
-
-               argc--, argv++;
-       }
-
-       return 1;
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static int old_is_module_checksummed(struct obj_file *f)
-{
-       return obj_find_symbol(f, "Using_Versions") != NULL;
-}
-/* Get the module's kernel version in the canonical integer form.  */
-
-static int
-old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
-{
-       struct obj_symbol *sym;
-       char *p, *q;
-       int a, b, c;
-
-       sym = obj_find_symbol(f, "kernel_version");
-       if (sym == NULL)
-               return -1;
-
-       p = f->sections[sym->secidx]->contents + sym->value;
-       strncpy(str, p, STRVERSIONLEN);
-
-       a = strtoul(p, &p, 10);
-       if (*p != '.')
-               return -1;
-       b = strtoul(p + 1, &p, 10);
-       if (*p != '.')
-               return -1;
-       c = strtoul(p + 1, &q, 10);
-       if (p + 1 == q)
-               return -1;
-
-       return a << 16 | b << 8 | c;
-}
-
-#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
-
-/* Fetch all the symbols and divvy them up as appropriate for the modules.  */
-
-static int old_get_kernel_symbols(const char *m_name)
-{
-       struct old_kernel_sym *ks, *k;
-       struct new_module_symbol *s;
-       struct external_module *mod;
-       int nks, nms, nmod, i;
-
-       nks = get_kernel_syms(NULL);
-       if (nks <= 0) {
-               if (nks)
-                       perror_msg("get_kernel_syms: %s", m_name);
-               else
-                       error_msg("No kernel symbols");
-               return 0;
-       }
-
-       ks = k = xmalloc(nks * sizeof(*ks));
-
-       if (get_kernel_syms(ks) != nks) {
-               perror("inconsistency with get_kernel_syms -- is someone else "
-                          "playing with modules?");
-               free(ks);
-               return 0;
-       }
-
-       /* Collect the module information.  */
-
-       mod = NULL;
-       nmod = -1;
-
-       while (k->name[0] == '#' && k->name[1]) {
-               struct old_kernel_sym *k2;
-
-               /* Find out how many symbols this module has.  */
-               for (k2 = k + 1; k2->name[0] != '#'; ++k2)
-                       continue;
-               nms = k2 - k - 1;
-
-               mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod));
-               mod[nmod].name = k->name + 1;
-               mod[nmod].addr = k->value;
-               mod[nmod].used = 0;
-               mod[nmod].nsyms = nms;
-               mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
-
-               for (i = 0, ++k; i < nms; ++i, ++s, ++k) {
-                       s->name = (unsigned long) k->name;
-                       s->value = k->value;
-               }
-
-               k = k2;
-       }
-
-       ext_modules = mod;
-       n_ext_modules = nmod + 1;
-
-       /* Now collect the symbols for the kernel proper.  */
-
-       if (k->name[0] == '#')
-               ++k;
-
-       nksyms = nms = nks - (k - ks);
-       ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
-
-       for (i = 0; i < nms; ++i, ++s, ++k) {
-               s->name = (unsigned long) k->name;
-               s->value = k->value;
-       }
-
-       return 1;
-}
-
-/* Return the kernel symbol checksum version, or zero if not used.  */
-
-static int old_is_kernel_checksummed(void)
-{
-       /* Using_Versions is the first symbol.  */
-       if (nksyms > 0
-               && strcmp((char *) ksyms[0].name,
-                                 "Using_Versions") == 0) return ksyms[0].value;
-       else
-               return 0;
-}
-
-
-static int old_create_mod_use_count(struct obj_file *f)
-{
-       struct obj_section *sec;
-
-       sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long),
-                                                                                  sizeof(long));
-
-       obj_add_symbol(f, "mod_use_count_", -1,
-                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
-                                  sizeof(long));
-
-       return 1;
-}
-
-static int
-old_init_module(const char *m_name, struct obj_file *f,
-                               unsigned long m_size)
-{
-       char *image;
-       struct old_mod_routines routines;
-       struct old_symbol_table *symtab;
-       int ret;
-
-       /* Create the symbol table */
-       {
-               int nsyms = 0, strsize = 0, total;
-
-               /* Size things first... */
-               if (flag_export) {
-                       int i;
-                       for (i = 0; i < HASH_BUCKETS; ++i) {
-                               struct obj_symbol *sym;
-                               for (sym = f->symtab[i]; sym; sym = sym->next)
-                                       if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
-                                               && sym->secidx <= SHN_HIRESERVE) 
-                                       {
-                                               sym->ksymidx = nsyms++;
-                                               strsize += strlen(sym->name) + 1;
-                                       }
-                       }
-               }
-
-               total = (sizeof(struct old_symbol_table)
-                                + nsyms * sizeof(struct old_module_symbol)
-                                + n_ext_modules_used * sizeof(struct old_module_ref)
-                                + strsize);
-               symtab = xmalloc(total);
-               symtab->size = total;
-               symtab->n_symbols = nsyms;
-               symtab->n_refs = n_ext_modules_used;
-
-               if (flag_export && nsyms) {
-                       struct old_module_symbol *ksym;
-                       char *str;
-                       int i;
-
-                       ksym = symtab->symbol;
-                       str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol)
-                                  + n_ext_modules_used * sizeof(struct old_module_ref));
-
-                       for (i = 0; i < HASH_BUCKETS; ++i) {
-                               struct obj_symbol *sym;
-                               for (sym = f->symtab[i]; sym; sym = sym->next)
-                                       if (sym->ksymidx >= 0) {
-                                               ksym->addr = obj_symbol_final_value(f, sym);
-                                               ksym->name =
-                                                       (unsigned long) str - (unsigned long) symtab;
-
-                                               strcpy(str, sym->name);
-                                               str += strlen(sym->name) + 1;
-                                               ksym++;
-                                       }
-                       }
-               }
-
-               if (n_ext_modules_used) {
-                       struct old_module_ref *ref;
-                       int i;
-
-                       ref = (struct old_module_ref *)
-                               ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
-
-                       for (i = 0; i < n_ext_modules; ++i)
-                               if (ext_modules[i].used)
-                                       ref++->module = ext_modules[i].addr;
-               }
-       }
-
-       /* Fill in routines.  */
-
-       routines.init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
-       routines.cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
-
-       /* Whew!  All of the initialization is complete.  Collect the final
-          module image and give it to the kernel.  */
-
-       image = xmalloc(m_size);
-       obj_create_image(f, image);
-
-       /* image holds the complete relocated module, accounting correctly for
-          mod_use_count.  However the old module kernel support assume that
-          it is receiving something which does not contain mod_use_count.  */
-       ret = old_sys_init_module(m_name, image + sizeof(long),
-                                                         m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN
-                                                                               : 0), &routines, symtab);
-       if (ret)
-               perror_msg("init_module: %s", m_name);
-
-       free(image);
-       free(symtab);
-
-       return ret == 0;
-}
-
-#else
-
-#define old_create_mod_use_count(x) TRUE
-#define old_init_module(x, y, z) TRUE
-
-#endif                                                 /* BB_FEATURE_OLD_MODULE_INTERFACE */
-
-
-
-/*======================================================================*/
-/* Functions relating to module loading after 2.1.18.  */
-
-static int
-new_process_module_arguments(struct obj_file *f, int argc, char **argv)
-{
-       while (argc > 0) {
-               char *p, *q, *key;
-               struct obj_symbol *sym;
-               char *contents, *loc;
-               int min, max, n;
-
-               p = *argv;
-               if ((q = strchr(p, '=')) == NULL) {
-                       argc--;
-                       continue;
-                }
-
-               key = alloca(q - p + 6);
-               memcpy(key, "parm_", 5);
-               memcpy(key + 5, p, q - p);
-               key[q - p + 5] = 0;
-
-               p = get_modinfo_value(f, key);
-               key += 5;
-               if (p == NULL) {
-                       error_msg("invalid parameter %s", key);
-                       return 0;
-               }
-
-               sym = obj_find_symbol(f, key);
-
-               /* Also check that the parameter was not resolved from the kernel.  */
-               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
-                       error_msg("symbol for parameter %s not found", key);
-                       return 0;
-               }
-
-               if (isdigit(*p)) {
-                       min = strtoul(p, &p, 10);
-                       if (*p == '-')
-                               max = strtoul(p + 1, &p, 10);
-                       else
-                               max = min;
-               } else
-                       min = max = 1;
-
-               contents = f->sections[sym->secidx]->contents;
-               loc = contents + sym->value;
-               n = (*++q != '\0');
-
-               while (1) {
-                       if ((*p == 's') || (*p == 'c')) {
-                               char *str;
-
-                               /* Do C quoting if we begin with a ", else slurp the lot.  */
-                               if (*q == '"') {
-                                       char *r;
-
-                                       str = alloca(strlen(q));
-                                       for (r = str, q++; *q != '"'; ++q, ++r) {
-                                               if (*q == '\0') {
-                                                       error_msg("improperly terminated string argument for %s",
-                                                                       key);
-                                                       return 0;
-                                               } else if (*q == '\\')
-                                                       switch (*++q) {
-                                                       case 'a':
-                                                               *r = '\a';
-                                                               break;
-                                                       case 'b':
-                                                               *r = '\b';
-                                                               break;
-                                                       case 'e':
-                                                               *r = '\033';
-                                                               break;
-                                                       case 'f':
-                                                               *r = '\f';
-                                                               break;
-                                                       case 'n':
-                                                               *r = '\n';
-                                                               break;
-                                                       case 'r':
-                                                               *r = '\r';
-                                                               break;
-                                                       case 't':
-                                                               *r = '\t';
-                                                               break;
-
-                                                       case '0':
-                                                       case '1':
-                                                       case '2':
-                                                       case '3':
-                                                       case '4':
-                                                       case '5':
-                                                       case '6':
-                                                       case '7':
-                                                               {
-                                                                       int c = *q - '0';
-                                                                       if (q[1] >= '0' && q[1] <= '7') {
-                                                                               c = (c * 8) + *++q - '0';
-                                                                               if (q[1] >= '0' && q[1] <= '7')
-                                                                                       c = (c * 8) + *++q - '0';
-                                                                       }
-                                                                       *r = c;
-                                                               }
-                                                               break;
-
-                                                       default:
-                                                               *r = *q;
-                                                               break;
-                                               } else
-                                                       *r = *q;
-                                       }
-                                       *r = '\0';
-                                       ++q;
-                               } else {
-                                       char *r;
-
-                                       /* In this case, the string is not quoted. We will break
-                                          it using the coma (like for ints). If the user wants to
-                                          include comas in a string, he just has to quote it */
-
-                                       /* Search the next coma */
-                                       r = strchr(q, ',');
-
-                                       /* Found ? */
-                                       if (r != (char *) NULL) {
-                                               /* Recopy the current field */
-                                               str = alloca(r - q + 1);
-                                               memcpy(str, q, r - q);
-
-                                               /* I don't know if it is usefull, as the previous case
-                                                  doesn't null terminate the string ??? */
-                                               str[r - q] = '\0';
-
-                                               /* Keep next fields */
-                                               q = r;
-                                       } else {
-                                               /* last string */
-                                               str = q;
-                                               q = "";
-                                       }
-                               }
-
-                               if (*p == 's') {
-                                       /* Normal string */
-                                       obj_string_patch(f, sym->secidx, loc - contents, str);
-                                       loc += tgt_sizeof_char_p;
-                               } else {
-                                       /* Array of chars (in fact, matrix !) */
-                                       unsigned long charssize;        /* size of each member */
-
-                                       /* Get the size of each member */
-                                       /* Probably we should do that outside the loop ? */
-                                       if (!isdigit(*(p + 1))) {
-                                               error_msg("parameter type 'c' for %s must be followed by"
-                                                               " the maximum size", key);
-                                               return 0;
-                                       }
-                                       charssize = strtoul(p + 1, (char **) NULL, 10);
-
-                                       /* Check length */
-                                       if (strlen(str) >= charssize) {
-                                               error_msg("string too long for %s (max %ld)", key,
-                                                               charssize - 1);
-                                               return 0;
-                                       }
-
-                                       /* Copy to location */
-                                       strcpy((char *) loc, str);
-                                       loc += charssize;
-                               }
-                       } else {
-                               long v = strtoul(q, &q, 0);
-                               switch (*p) {
-                               case 'b':
-                                       *loc++ = v;
-                                       break;
-                               case 'h':
-                                       *(short *) loc = v;
-                                       loc += tgt_sizeof_short;
-                                       break;
-                               case 'i':
-                                       *(int *) loc = v;
-                                       loc += tgt_sizeof_int;
-                                       break;
-                               case 'l':
-                                       *(long *) loc = v;
-                                       loc += tgt_sizeof_long;
-                                       break;
-
-                               default:
-                                       error_msg("unknown parameter type '%c' for %s", *p, key);
-                                       return 0;
-                               }
-                       }
-
-                 retry_end_of_value:
-                       switch (*q) {
-                       case '\0':
-                               goto end_of_arg;
-
-                       case ' ':
-                       case '\t':
-                       case '\n':
-                       case '\r':
-                               ++q;
-                               goto retry_end_of_value;
-
-                       case ',':
-                               if (++n > max) {
-                                       error_msg("too many values for %s (max %d)", key, max);
-                                       return 0;
-                               }
-                               ++q;
-                               break;
-
-                       default:
-                               error_msg("invalid argument syntax for %s", key);
-                               return 0;
-                       }
-               }
-
-         end_of_arg:
-               if (n < min) {
-                       error_msg("too few values for %s (min %d)", key, min);
-                       return 0;
-               }
-
-               argc--, argv++;
-       }
-
-       return 1;
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static int new_is_module_checksummed(struct obj_file *f)
-{
-       const char *p = get_modinfo_value(f, "using_checksums");
-       if (p)
-               return atoi(p);
-       else
-               return 0;
-}
-
-/* Get the module's kernel version in the canonical integer form.  */
-
-static int
-new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
-{
-       char *p, *q;
-       int a, b, c;
-
-       p = get_modinfo_value(f, "kernel_version");
-       if (p == NULL)
-               return -1;
-       strncpy(str, p, STRVERSIONLEN);
-
-       a = strtoul(p, &p, 10);
-       if (*p != '.')
-               return -1;
-       b = strtoul(p + 1, &p, 10);
-       if (*p != '.')
-               return -1;
-       c = strtoul(p + 1, &q, 10);
-       if (p + 1 == q)
-               return -1;
-
-       return a << 16 | b << 8 | c;
-}
-
-#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-
-/* Fetch the loaded modules, and all currently exported symbols.  */
-
-static int new_get_kernel_symbols(void)
-{
-       char *module_names, *mn;
-       struct external_module *modules, *m;
-       struct new_module_symbol *syms, *s;
-       size_t ret, bufsize, nmod, nsyms, i, j;
-
-       /* Collect the loaded modules.  */
-
-       module_names = xmalloc(bufsize = 256);
-  retry_modules_load:
-       if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
-               if (errno == ENOSPC && bufsize < ret) {
-                       module_names = xrealloc(module_names, bufsize = ret);
-                       goto retry_modules_load;
-               }
-               perror_msg("QM_MODULES");
-               return 0;
-       }
-
-       n_ext_modules = nmod = ret;
-
-       /* Collect the modules' symbols.  */
-
-       if (nmod){
-               ext_modules = modules = xmalloc(nmod * sizeof(*modules));
-               memset(modules, 0, nmod * sizeof(*modules));
-               for (i = 0, mn = module_names, m = modules;
-                        i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
-                       struct new_module_info info;
-       
-                       if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
-                               if (errno == ENOENT) {
-                                       /* The module was removed out from underneath us.  */
-                                       continue;
-                               }
-                               perror_msg("query_module: QM_INFO: %s", mn);
-                               return 0;
-                       }
-       
-                       syms = xmalloc(bufsize = 1024);
-                 retry_mod_sym_load:
-                       if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
-                               switch (errno) {
-                               case ENOSPC:
-                                       syms = xrealloc(syms, bufsize = ret);
-                                       goto retry_mod_sym_load;
-                               case ENOENT:
-                                       /* The module was removed out from underneath us.  */
-                                       continue;
-                               default:
-                                       perror_msg("query_module: QM_SYMBOLS: %s", mn);
-                                       return 0;
-                               }
-                       }
-                       nsyms = ret;
-       
-                       m->name = mn;
-                       m->addr = info.addr;
-                       m->nsyms = nsyms;
-                       m->syms = syms;
-       
-                       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
-                               s->name += (unsigned long) syms;
-                       }
-               }
-       }
-
-       /* Collect the kernel's symbols.  */
-
-       syms = xmalloc(bufsize = 16 * 1024);
-  retry_kern_sym_load:
-       if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
-               if (errno == ENOSPC && bufsize < ret) {
-                       syms = xrealloc(syms, bufsize = ret);
-                       goto retry_kern_sym_load;
-               }
-               perror_msg("kernel: QM_SYMBOLS");
-               return 0;
-       }
-       nksyms = nsyms = ret;
-       ksyms = syms;
-
-       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
-               s->name += (unsigned long) syms;
-       }
-       return 1;
-}
-
-
-/* Return the kernel symbol checksum version, or zero if not used.  */
-
-static int new_is_kernel_checksummed(void)
-{
-       struct new_module_symbol *s;
-       size_t i;
-
-       /* Using_Versions is not the first symbol, but it should be in there.  */
-
-       for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
-               if (strcmp((char *) s->name, "Using_Versions") == 0)
-                       return s->value;
-
-       return 0;
-}
-
-
-static int new_create_this_module(struct obj_file *f, const char *m_name)
-{
-       struct obj_section *sec;
-
-       sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
-                                                                                  sizeof(struct new_module));
-       memset(sec->contents, 0, sizeof(struct new_module));
-
-       obj_add_symbol(f, "__this_module", -1,
-                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
-                                  sizeof(struct new_module));
-
-       obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
-                                        m_name);
-
-       return 1;
-}
-
-
-static int new_create_module_ksymtab(struct obj_file *f)
-{
-       struct obj_section *sec;
-       int i;
-
-       /* We must always add the module references.  */
-
-       if (n_ext_modules_used) {
-               struct new_module_ref *dep;
-               struct obj_symbol *tm;
-
-               sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
-                                                                                (sizeof(struct new_module_ref)
-                                                                                 * n_ext_modules_used));
-               if (!sec)
-                       return 0;
-
-               tm = obj_find_symbol(f, "__this_module");
-               dep = (struct new_module_ref *) sec->contents;
-               for (i = 0; i < n_ext_modules; ++i)
-                       if (ext_modules[i].used) {
-                               dep->dep = ext_modules[i].addr;
-                               obj_symbol_patch(f, sec->idx,
-                                                                (char *) &dep->ref - sec->contents, tm);
-                               dep->next_ref = 0;
-                               ++dep;
-                       }
-       }
-
-       if (flag_export && !obj_find_section(f, "__ksymtab")) {
-               size_t nsyms;
-               int *loaded;
-
-               sec =
-                       obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p,
-                                                                          0);
-
-               /* We don't want to export symbols residing in sections that
-                  aren't loaded.  There are a number of these created so that
-                  we make sure certain module options don't appear twice.  */
-
-               loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
-               while (--i >= 0)
-                       loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
-
-               for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
-                       struct obj_symbol *sym;
-                       for (sym = f->symtab[i]; sym; sym = sym->next)
-                               if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
-                                       && sym->secidx <= SHN_HIRESERVE
-                                       && (sym->secidx >= SHN_LORESERVE
-                                               || loaded[sym->secidx])) {
-                                       ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
-
-                                       obj_symbol_patch(f, sec->idx, ofs, sym);
-                                       obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
-                                                                        sym->name);
-
-                                       nsyms++;
-                               }
-               }
-
-               obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
-       }
-
-       return 1;
-}
-
-
-static int
-new_init_module(const char *m_name, struct obj_file *f,
-                               unsigned long m_size)
-{
-       struct new_module *module;
-       struct obj_section *sec;
-       void *image;
-       int ret;
-       tgt_long m_addr;
-
-       sec = obj_find_section(f, ".this");
-       if (!sec || !sec->contents) { 
-               perror_msg_and_die("corrupt module %s?",m_name);
-       }
-       module = (struct new_module *) sec->contents;
-       m_addr = sec->header.sh_addr;
-
-       module->size_of_struct = sizeof(*module);
-       module->size = m_size;
-       module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
-
-       sec = obj_find_section(f, "__ksymtab");
-       if (sec && sec->header.sh_size) {
-               module->syms = sec->header.sh_addr;
-               module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
-       }
-
-       if (n_ext_modules_used) {
-               sec = obj_find_section(f, ".kmodtab");
-               module->deps = sec->header.sh_addr;
-               module->ndeps = n_ext_modules_used;
-       }
-
-       module->init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
-       module->cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
-
-       sec = obj_find_section(f, "__ex_table");
-       if (sec) {
-               module->ex_table_start = sec->header.sh_addr;
-               module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
-       }
-
-       sec = obj_find_section(f, ".text.init");
-       if (sec) {
-               module->runsize = sec->header.sh_addr - m_addr;
-       }
-       sec = obj_find_section(f, ".data.init");
-       if (sec) {
-               if (!module->runsize ||
-                       module->runsize > sec->header.sh_addr - m_addr)
-                               module->runsize = sec->header.sh_addr - m_addr;
-       }
-       sec = obj_find_section(f, ARCHDATA_SEC_NAME);
-       if (sec && sec->header.sh_size) {
-               module->archdata_start = (void*)sec->header.sh_addr;
-               module->archdata_end = module->archdata_start + sec->header.sh_size;
-       }
-       sec = obj_find_section(f, KALLSYMS_SEC_NAME);
-       if (sec && sec->header.sh_size) {
-               module->kallsyms_start = (void*)sec->header.sh_addr;
-               module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
-       }
-
-       if (!arch_init_module(f, module))
-               return 0;
-
-       /* Whew!  All of the initialization is complete.  Collect the final
-          module image and give it to the kernel.  */
-
-       image = xmalloc(m_size);
-       obj_create_image(f, image);
-
-       ret = new_sys_init_module(m_name, (struct new_module *) image);
-       if (ret)
-               perror_msg("init_module: %s", m_name);
-
-       free(image);
-
-       return ret == 0;
-}
-
-#else
-
-#define new_init_module(x, y, z) TRUE
-#define new_create_this_module(x, y) 0
-#define new_create_module_ksymtab(x)
-#define query_module(v, w, x, y, z) -1
-
-#endif                                                 /* BB_FEATURE_NEW_MODULE_INTERFACE */
-
-
-/*======================================================================*/
-
-static int
-obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                                const char *string)
-{
-       struct obj_string_patch *p;
-       struct obj_section *strsec;
-       size_t len = strlen(string) + 1;
-       char *loc;
-
-       p = xmalloc(sizeof(*p));
-       p->next = f->string_patches;
-       p->reloc_secidx = secidx;
-       p->reloc_offset = offset;
-       f->string_patches = p;
-
-       strsec = obj_find_section(f, ".kstrtab");
-       if (strsec == NULL) {
-               strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
-               p->string_offset = 0;
-               loc = strsec->contents;
-       } else {
-               p->string_offset = strsec->header.sh_size;
-               loc = obj_extend_section(strsec, len);
-       }
-       memcpy(loc, string, len);
-
-       return 1;
-}
-
-static int
-obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                                struct obj_symbol *sym)
-{
-       struct obj_symbol_patch *p;
-
-       p = xmalloc(sizeof(*p));
-       p->next = f->symbol_patches;
-       p->reloc_secidx = secidx;
-       p->reloc_offset = offset;
-       p->sym = sym;
-       f->symbol_patches = p;
-
-       return 1;
-}
-
-static int obj_check_undefineds(struct obj_file *f)
-{
-       unsigned long i;
-       int ret = 1;
-
-       for (i = 0; i < HASH_BUCKETS; ++i) {
-               struct obj_symbol *sym;
-               for (sym = f->symtab[i]; sym; sym = sym->next)
-                       if (sym->secidx == SHN_UNDEF) {
-                               if (ELFW(ST_BIND) (sym->info) == STB_WEAK) {
-                                       sym->secidx = SHN_ABS;
-                                       sym->value = 0;
-                               } else {
-                                       error_msg("unresolved symbol %s", sym->name);
-                                       ret = 0;
-                               }
-                       }
-       }
-
-       return ret;
-}
-
-static void obj_allocate_commons(struct obj_file *f)
-{
-       struct common_entry {
-               struct common_entry *next;
-               struct obj_symbol *sym;
-       } *common_head = NULL;
-
-       unsigned long i;
-
-       for (i = 0; i < HASH_BUCKETS; ++i) {
-               struct obj_symbol *sym;
-               for (sym = f->symtab[i]; sym; sym = sym->next)
-                       if (sym->secidx == SHN_COMMON) {
-                               /* Collect all COMMON symbols and sort them by size so as to
-                                  minimize space wasted by alignment requirements.  */
-                               {
-                                       struct common_entry **p, *n;
-                                       for (p = &common_head; *p; p = &(*p)->next)
-                                               if (sym->size <= (*p)->sym->size)
-                                                       break;
-
-                                       n = alloca(sizeof(*n));
-                                       n->next = *p;
-                                       n->sym = sym;
-                                       *p = n;
-                               }
-                       }
-       }
-
-       for (i = 1; i < f->local_symtab_size; ++i) {
-               struct obj_symbol *sym = f->local_symtab[i];
-               if (sym && sym->secidx == SHN_COMMON) {
-                       struct common_entry **p, *n;
-                       for (p = &common_head; *p; p = &(*p)->next)
-                               if (sym == (*p)->sym)
-                                       break;
-                               else if (sym->size < (*p)->sym->size) {
-                                       n = alloca(sizeof(*n));
-                                       n->next = *p;
-                                       n->sym = sym;
-                                       *p = n;
-                                       break;
-                               }
-               }
-       }
-
-       if (common_head) {
-               /* Find the bss section.  */
-               for (i = 0; i < f->header.e_shnum; ++i)
-                       if (f->sections[i]->header.sh_type == SHT_NOBITS)
-                               break;
-
-               /* If for some reason there hadn't been one, create one.  */
-               if (i == f->header.e_shnum) {
-                       struct obj_section *sec;
-
-                       f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
-                       f->sections[i] = sec = arch_new_section();
-                       f->header.e_shnum = i + 1;
-
-                       memset(sec, 0, sizeof(*sec));
-                       sec->header.sh_type = SHT_PROGBITS;
-                       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-                       sec->name = ".bss";
-                       sec->idx = i;
-               }
-
-               /* Allocate the COMMONS.  */
-               {
-                       ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
-                       ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
-                       struct common_entry *c;
-
-                       for (c = common_head; c; c = c->next) {
-                               ElfW(Addr) align = c->sym->value;
-
-                               if (align > max_align)
-                                       max_align = align;
-                               if (bss_size & (align - 1))
-                                       bss_size = (bss_size | (align - 1)) + 1;
-
-                               c->sym->secidx = i;
-                               c->sym->value = bss_size;
-
-                               bss_size += c->sym->size;
-                       }
-
-                       f->sections[i]->header.sh_size = bss_size;
-                       f->sections[i]->header.sh_addralign = max_align;
-               }
-       }
-
-       /* For the sake of patch relocation and parameter initialization,
-          allocate zeroed data for NOBITS sections now.  Note that after
-          this we cannot assume NOBITS are really empty.  */
-       for (i = 0; i < f->header.e_shnum; ++i) {
-               struct obj_section *s = f->sections[i];
-               if (s->header.sh_type == SHT_NOBITS) {
-                       if (s->header.sh_size != 0)
-                       s->contents = memset(xmalloc(s->header.sh_size),
-                                                                0, s->header.sh_size);
-                       else
-                               s->contents = NULL;
-
-                       s->header.sh_type = SHT_PROGBITS;
-               }
-       }
-}
-
-static unsigned long obj_load_size(struct obj_file *f)
-{
-       unsigned long dot = 0;
-       struct obj_section *sec;
-
-       /* Finalize the positions of the sections relative to one another.  */
-
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-               ElfW(Addr) align;
-
-               align = sec->header.sh_addralign;
-               if (align && (dot & (align - 1)))
-                       dot = (dot | (align - 1)) + 1;
-
-               sec->header.sh_addr = dot;
-               dot += sec->header.sh_size;
-       }
-
-       return dot;
-}
-
-static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
-{
-       int i, n = f->header.e_shnum;
-       int ret = 1;
-
-       /* Finalize the addresses of the sections.  */
-
-       f->baseaddr = base;
-       for (i = 0; i < n; ++i)
-               f->sections[i]->header.sh_addr += base;
-
-       /* And iterate over all of the relocations.  */
-
-       for (i = 0; i < n; ++i) {
-               struct obj_section *relsec, *symsec, *targsec, *strsec;
-               ElfW(RelM) * rel, *relend;
-               ElfW(Sym) * symtab;
-               const char *strtab;
-
-               relsec = f->sections[i];
-               if (relsec->header.sh_type != SHT_RELM)
-                       continue;
-
-               symsec = f->sections[relsec->header.sh_link];
-               targsec = f->sections[relsec->header.sh_info];
-               strsec = f->sections[symsec->header.sh_link];
-
-               rel = (ElfW(RelM) *) relsec->contents;
-               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
-               symtab = (ElfW(Sym) *) symsec->contents;
-               strtab = (const char *) strsec->contents;
-
-               for (; rel < relend; ++rel) {
-                       ElfW(Addr) value = 0;
-                       struct obj_symbol *intsym = NULL;
-                       unsigned long symndx;
-                       ElfW(Sym) * extsym = 0;
-                       const char *errmsg;
-
-                       /* Attempt to find a value to use for this relocation.  */
-
-                       symndx = ELFW(R_SYM) (rel->r_info);
-                       if (symndx) {
-                               /* Note we've already checked for undefined symbols.  */
-
-                               extsym = &symtab[symndx];
-                               if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) {
-                                       /* Local symbols we look up in the local table to be sure
-                                          we get the one that is really intended.  */
-                                       intsym = f->local_symtab[symndx];
-                               } else {
-                                       /* Others we look up in the hash table.  */
-                                       const char *name;
-                                       if (extsym->st_name)
-                                               name = strtab + extsym->st_name;
-                                       else
-                                               name = f->sections[extsym->st_shndx]->name;
-                                       intsym = obj_find_symbol(f, name);
-                               }
-
-                               value = obj_symbol_final_value(f, intsym);
-                               intsym->referenced = 1;
-                       }
-#if SHT_RELM == SHT_RELA
-#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
-                       /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9.  */
-                       if (!extsym || !extsym->st_name ||
-                               ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL)
-#endif
-                               value += rel->r_addend;
-#endif
-
-                       /* Do it! */
-                       switch (arch_apply_relocation
-                                       (f, targsec, symsec, intsym, rel, value)) {
-                       case obj_reloc_ok:
-                               break;
-
-                       case obj_reloc_overflow:
-                               errmsg = "Relocation overflow";
-                               goto bad_reloc;
-                       case obj_reloc_dangerous:
-                               errmsg = "Dangerous relocation";
-                               goto bad_reloc;
-                       case obj_reloc_unhandled:
-                               errmsg = "Unhandled relocation";
-                         bad_reloc:
-                               if (extsym) {
-                                       error_msg("%s of type %ld for %s", errmsg,
-                                                       (long) ELFW(R_TYPE) (rel->r_info),
-                                                       strtab + extsym->st_name);
-                               } else {
-                                       error_msg("%s of type %ld", errmsg,
-                                                       (long) ELFW(R_TYPE) (rel->r_info));
-                               }
-                               ret = 0;
-                               break;
-                       }
-               }
-       }
-
-       /* Finally, take care of the patches.  */
-
-       if (f->string_patches) {
-               struct obj_string_patch *p;
-               struct obj_section *strsec;
-               ElfW(Addr) strsec_base;
-               strsec = obj_find_section(f, ".kstrtab");
-               strsec_base = strsec->header.sh_addr;
-
-               for (p = f->string_patches; p; p = p->next) {
-                       struct obj_section *targsec = f->sections[p->reloc_secidx];
-                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
-                               = strsec_base + p->string_offset;
-               }
-       }
-
-       if (f->symbol_patches) {
-               struct obj_symbol_patch *p;
-
-               for (p = f->symbol_patches; p; p = p->next) {
-                       struct obj_section *targsec = f->sections[p->reloc_secidx];
-                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
-                               = obj_symbol_final_value(f, p->sym);
-               }
-       }
-
-       return ret;
-}
-
-static int obj_create_image(struct obj_file *f, char *image)
-{
-       struct obj_section *sec;
-       ElfW(Addr) base = f->baseaddr;
-
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-               char *secimg;
-
-               if (sec->contents == 0 || sec->header.sh_size == 0)
-                       continue;
-
-               secimg = image + (sec->header.sh_addr - base);
-
-               /* Note that we allocated data for NOBITS sections earlier.  */
-               memcpy(secimg, sec->contents, sec->header.sh_size);
-       }
-
-       return 1;
-}
-
-/*======================================================================*/
-
-static struct obj_file *obj_load(FILE * fp, int loadprogbits)
-{
-       struct obj_file *f;
-       ElfW(Shdr) * section_headers;
-       int shnum, i;
-       char *shstrtab;
-
-       /* Read the file header.  */
-
-       f = arch_new_file();
-       memset(f, 0, sizeof(*f));
-       f->symbol_cmp = strcmp;
-       f->symbol_hash = obj_elf_hash;
-       f->load_order_search_start = &f->load_order;
-
-       fseek(fp, 0, SEEK_SET);
-       if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
-               perror_msg("error reading ELF header");
-               return NULL;
-       }
-
-       if (f->header.e_ident[EI_MAG0] != ELFMAG0
-               || f->header.e_ident[EI_MAG1] != ELFMAG1
-               || f->header.e_ident[EI_MAG2] != ELFMAG2
-               || f->header.e_ident[EI_MAG3] != ELFMAG3) {
-               error_msg("not an ELF file");
-               return NULL;
-       }
-       if (f->header.e_ident[EI_CLASS] != ELFCLASSM
-               || f->header.e_ident[EI_DATA] != ELFDATAM
-               || f->header.e_ident[EI_VERSION] != EV_CURRENT
-               || !MATCH_MACHINE(f->header.e_machine)) {
-               error_msg("ELF file not for this architecture");
-               return NULL;
-       }
-       if (f->header.e_type != ET_REL) {
-               error_msg("ELF file not a relocatable object");
-               return NULL;
-       }
-
-       /* Read the section headers.  */
-
-       if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
-               error_msg("section header size mismatch: %lu != %lu",
-                               (unsigned long) f->header.e_shentsize,
-                               (unsigned long) sizeof(ElfW(Shdr)));
-               return NULL;
-       }
-
-       shnum = f->header.e_shnum;
-       f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
-       memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
-
-       section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
-       fseek(fp, f->header.e_shoff, SEEK_SET);
-       if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
-               perror_msg("error reading ELF section headers");
-               return NULL;
-       }
-
-       /* Read the section data.  */
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec;
-
-               f->sections[i] = sec = arch_new_section();
-               memset(sec, 0, sizeof(*sec));
-
-               sec->header = section_headers[i];
-               sec->idx = i;
-
-               if(sec->header.sh_size) switch (sec->header.sh_type) {
-               case SHT_NULL:
-               case SHT_NOTE:
-               case SHT_NOBITS:
-                       /* ignore */
-                       break;
-
-               case SHT_PROGBITS:
-#if LOADBITS
-                       if (!loadprogbits) {
-                               sec->contents = NULL;
-                               break;
-                       }
-#endif                 
-               case SHT_SYMTAB:
-               case SHT_STRTAB:
-               case SHT_RELM:
-                       if (sec->header.sh_size > 0) {
-                               sec->contents = xmalloc(sec->header.sh_size);
-                               fseek(fp, sec->header.sh_offset, SEEK_SET);
-                               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
-                                       perror_msg("error reading ELF section data");
-                                       return NULL;
-                               }
-                       } else {
-                               sec->contents = NULL;
-                       }
-                       break;
-
-#if SHT_RELM == SHT_REL
-               case SHT_RELA:
-                       error_msg("RELA relocations not supported on this architecture");
-                       return NULL;
-#else
-               case SHT_REL:
-                       error_msg("REL relocations not supported on this architecture");
-                       return NULL;
-#endif
-
-               default:
-                       if (sec->header.sh_type >= SHT_LOPROC) {
-                               /* Assume processor specific section types are debug
-                                  info and can safely be ignored.  If this is ever not
-                                  the case (Hello MIPS?), don't put ifdefs here but
-                                  create an arch_load_proc_section().  */
-                               break;
-                       }
-
-                       error_msg("can't handle sections of type %ld",
-                                       (long) sec->header.sh_type);
-                       return NULL;
-               }
-       }
-
-       /* Do what sort of interpretation as needed by each section.  */
-
-       shstrtab = f->sections[f->header.e_shstrndx]->contents;
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec = f->sections[i];
-               sec->name = shstrtab + sec->header.sh_name;
-       }
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec = f->sections[i];
-
-               /* .modinfo should be contents only but gcc has no attribute for that.
-                * The kernel may have marked .modinfo as ALLOC, ignore this bit.
-                */
-               if (strcmp(sec->name, ".modinfo") == 0)
-                       sec->header.sh_flags &= ~SHF_ALLOC;
-
-               if (sec->header.sh_flags & SHF_ALLOC)
-                       obj_insert_section_load_order(f, sec);
-
-               switch (sec->header.sh_type) {
-               case SHT_SYMTAB:
-                       {
-                               unsigned long nsym, j;
-                               char *strtab;
-                               ElfW(Sym) * sym;
-
-                               if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
-                                       error_msg("symbol size mismatch: %lu != %lu",
-                                                       (unsigned long) sec->header.sh_entsize,
-                                                       (unsigned long) sizeof(ElfW(Sym)));
-                                       return NULL;
-                               }
-
-                               nsym = sec->header.sh_size / sizeof(ElfW(Sym));
-                               strtab = f->sections[sec->header.sh_link]->contents;
-                               sym = (ElfW(Sym) *) sec->contents;
-
-                               /* Allocate space for a table of local symbols.  */
-                               j = f->local_symtab_size = sec->header.sh_info;
-                               f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *));
-
-                               /* Insert all symbols into the hash table.  */
-                               for (j = 1, ++sym; j < nsym; ++j, ++sym) {
-                                       const char *name;
-                                       if (sym->st_name)
-                                               name = strtab + sym->st_name;
-                                       else
-                                               name = f->sections[sym->st_shndx]->name;
-
-                                       obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
-                                                                  sym->st_value, sym->st_size);
-                               }
-                       }
-                       break;
-
-               case SHT_RELM:
-                       if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
-                               error_msg("relocation entry size mismatch: %lu != %lu",
-                                               (unsigned long) sec->header.sh_entsize,
-                                               (unsigned long) sizeof(ElfW(RelM)));
-                               return NULL;
-                       }
-                       break;
-                       /* XXX  Relocation code from modutils-2.3.19 is not here.
-                        * Why?  That's about 20 lines of code from obj/obj_load.c,
-                        * which gets done in a second pass through the sections.
-                        * This BusyBox insmod does similar work in obj_relocate(). */
-               }
-       }
-
-       return f;
-}
-
-#ifdef BB_FEATURE_INSMOD_LOADINKMEM
-/*
- * load the unloaded sections directly into the memory allocated by
- * kernel for the module
- */
-
-static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
-{
-       ElfW(Addr) base = f->baseaddr;
-       struct obj_section* sec;
-       
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-
-               /* section already loaded? */
-               if (sec->contents != NULL)
-                       continue;
-               
-               if (sec->header.sh_size == 0)
-                       continue;
-
-               sec->contents = imagebase + (sec->header.sh_addr - base);
-               fseek(fp, sec->header.sh_offset, SEEK_SET);
-               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
-                       error_msg("error reading ELF section data: %s\n", strerror(errno));
-                       return 0;
-               }
-
-       }
-       return 1;
-}
-#endif
-
-static void hide_special_symbols(struct obj_file *f)
-{
-       static const char *const specials[] = {
-               "cleanup_module",
-               "init_module",
-               "kernel_version",
-               NULL
-       };
-
-       struct obj_symbol *sym;
-       const char *const *p;
-
-       for (p = specials; *p; ++p)
-               if ((sym = obj_find_symbol(f, *p)) != NULL)
-                       sym->info =
-                               ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
-}
-
-
-
-extern int insmod_main( int argc, char **argv)
-{
-       int opt;
-       int k_crcs;
-       int k_new_syscalls;
-       int len;
-       char *tmp;
-       unsigned long m_size;
-       ElfW(Addr) m_addr;
-       FILE *fp;
-       struct obj_file *f;
-       struct stat st;
-       char m_name[FILENAME_MAX + 1] = "\0";
-       int exit_status = EXIT_FAILURE;
-       int m_has_modinfo;
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       struct utsname uts_info;
-       char m_strversion[STRVERSIONLEN];
-       int m_version;
-       int m_crcs;
-#endif
-
-       /* Parse any options */
-       while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) {
-               switch (opt) {
-                       case 'f':                       /* force loading */
-                               flag_force_load = 1;
-                               break;
-                       case 'k':                       /* module loaded by kerneld, auto-cleanable */
-                               flag_autoclean = 1;
-                               break;
-                       case 'v':                       /* verbose output */
-                               flag_verbose = 1;
-                               break;
-                       case 'x':                       /* do not export externs */
-                               flag_export = 0;
-                               break;
-                       case 'o':                       /* name the output module */
-                               strncpy(m_name, optarg, FILENAME_MAX);
-                               break;
-                       case 'L':                       /* Stub warning */
-                               /* This is needed for compatibility with modprobe.
-                                * In theory, this does locking, but we don't do
-                                * that.  So be careful and plan your life around not
-                                * loading the same module 50 times concurrently. */
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       
-       if (argv[optind] == NULL) {
-               show_usage();
-       }
-
-       /* Grab the module name */
-       if ((tmp = strrchr(argv[optind], '/')) != NULL) {
-               tmp++;
-       } else {
-               tmp = argv[optind];
-       }
-       len = strlen(tmp);
-
-       if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o')
-               len -= 2;
-       memcpy(m_fullName, tmp, len);
-       m_fullName[len]='\0';
-       if (*m_name == '\0') {
-               strcpy(m_name, m_fullName);
-       }
-       strcat(m_fullName, ".o");
-
-       /* Get a filedesc for the module.  Check we we have a complete path */
-       if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) ||
-                       (fp = fopen(argv[optind], "r")) == NULL) {
-               struct utsname myuname;
-
-               /* Hmm.  Could not open it.  First search under /lib/modules/`uname -r`,
-                * but do not error out yet if we fail to find it... */
-               if (uname(&myuname) == 0) {
-                       char module_dir[FILENAME_MAX];
-                       char real_module_dir[FILENAME_MAX];
-                       snprintf (module_dir, sizeof(module_dir), "%s/%s", 
-                                       _PATH_MODULES, myuname.release);
-                       /* Jump through hoops in case /lib/modules/`uname -r`
-                        * is a symlink.  We do not want recursive_action to
-                        * follow symlinks, but we do want to follow the
-                        * /lib/modules/`uname -r` dir, So resolve it ourselves
-                        * if it is a link... */
-                       if (realpath (module_dir, real_module_dir) == NULL)
-                               strcpy(real_module_dir, module_dir);
-                       recursive_action(real_module_dir, TRUE, FALSE, FALSE,
-                                       check_module_name_match, 0, m_fullName);
-               }
-
-               /* Check if we have found anything yet */
-               if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) 
-               {
-                       char module_dir[FILENAME_MAX];
-                       if (realpath (_PATH_MODULES, module_dir) == NULL)
-                               strcpy(module_dir, _PATH_MODULES);
-                       /* No module found under /lib/modules/`uname -r`, this
-                        * time cast the net a bit wider.  Search /lib/modules/ */
-                       if (recursive_action(module_dir, TRUE, FALSE, FALSE,
-                                               check_module_name_match, 0, m_fullName) == FALSE) 
-                       {
-                               if (m_filename[0] == '\0'
-                                               || ((fp = fopen(m_filename, "r")) == NULL)) 
-                               {
-                                       error_msg("%s: no module by that name found", m_fullName);
-                                       return EXIT_FAILURE;
-                               }
-                       } else
-                               error_msg_and_die("%s: no module by that name found", m_fullName);
-               }
-       } else 
-               safe_strncpy(m_filename, argv[optind], sizeof(m_filename));
-
-       printf("Using %s\n", m_filename);
-
-       if ((f = obj_load(fp, LOADBITS)) == NULL)
-               perror_msg_and_die("Could not load the module");
-
-       if (get_modinfo_value(f, "kernel_version") == NULL)
-               m_has_modinfo = 0;
-       else
-               m_has_modinfo = 1;
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       /* Version correspondence?  */
-
-       if (uname(&uts_info) < 0)
-               uts_info.release[0] = '\0';
-       if (m_has_modinfo) {
-               m_version = new_get_module_version(f, m_strversion);
-       } else {
-               m_version = old_get_module_version(f, m_strversion);
-               if (m_version == -1) {
-                       error_msg("couldn't find the kernel version the module was "
-                                       "compiled for");
-                       goto out;
-               }
-       }
-
-       if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
-               if (flag_force_load) {
-                       error_msg("Warning: kernel-module version mismatch\n"
-                                       "\t%s was compiled for kernel version %s\n"
-                                       "\twhile this kernel is version %s",
-                                       m_filename, m_strversion, uts_info.release);
-               } else {
-                       error_msg("kernel-module version mismatch\n"
-                                       "\t%s was compiled for kernel version %s\n"
-                                       "\twhile this kernel is version %s.",
-                                       m_filename, m_strversion, uts_info.release);
-                       goto out;
-               }
-       }
-       k_crcs = 0;
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-       k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
-
-       if (k_new_syscalls) {
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-               if (!new_get_kernel_symbols())
-                       goto out;
-               k_crcs = new_is_kernel_checksummed();
-#else
-               error_msg("Not configured to support new kernels");
-               goto out;
-#endif
-       } else {
-#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
-               if (!old_get_kernel_symbols(m_name))
-                       goto out;
-               k_crcs = old_is_kernel_checksummed();
-#else
-               error_msg("Not configured to support old kernels");
-               goto out;
-#endif
-       }
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       if (m_has_modinfo)
-               m_crcs = new_is_module_checksummed(f);
-       else
-               m_crcs = old_is_module_checksummed(f);
-
-       if (m_crcs != k_crcs)
-               obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-       /* Let the module know about the kernel symbols.  */
-       add_kernel_symbols(f);
-
-       /* Allocate common symbols, symbol tables, and string tables.  */
-
-       if (k_new_syscalls 
-               ? !new_create_this_module(f, m_name)
-               : !old_create_mod_use_count(f)) 
-       {
-               goto out;
-       }
-
-       if (!obj_check_undefineds(f)) {
-               goto out;
-       }
-       obj_allocate_commons(f);
-
-       /* done with the module name, on to the optional var=value arguments */
-       ++optind;
-
-       if (optind < argc) {
-               if (m_has_modinfo
-                       ? !new_process_module_arguments(f, argc - optind, argv + optind) 
-                       : !old_process_module_arguments(f, argc - optind, argv + optind)) 
-               {
-                       goto out;
-               }
-       }
-
-       arch_create_got(f);
-       hide_special_symbols(f);
-
-       if (k_new_syscalls)
-               new_create_module_ksymtab(f);
-
-       /* Find current size of the module */
-       m_size = obj_load_size(f);
-
-
-       m_addr = create_module(m_name, m_size);
-       if (m_addr==-1) switch (errno) {
-       case EEXIST:
-               error_msg("A module named %s already exists", m_name);
-               goto out;
-       case ENOMEM:
-               error_msg("Can't allocate kernel memory for module; needed %lu bytes",
-                               m_size);
-               goto out;
-       default:
-               perror_msg("create_module: %s", m_name);
-               goto out;
-       }
-
-#if  !LOADBITS
-       /*
-        * the PROGBITS section was not loaded by the obj_load
-        * now we can load them directly into the kernel memory
-        */
-       if (!obj_load_progbits(fp, f, (char*)m_addr)) {
-               delete_module(m_name);
-               goto out;
-       }
-#endif 
-
-       if (!obj_relocate(f, m_addr)) {
-               delete_module(m_name);
-               goto out;
-       }
-
-       if (k_new_syscalls 
-               ? !new_init_module(m_name, f, m_size)
-               : !old_init_module(m_name, f, m_size)) 
-       {
-               delete_module(m_name);
-               goto out;
-       }
-
-       exit_status = EXIT_SUCCESS;
-
-out:
-       fclose(fp);
-       return(exit_status);
-}
diff --git a/busybox/install.sh b/busybox/install.sh
deleted file mode 100755 (executable)
index d163a2e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-prefix=$1
-if [ "$prefix" = "" ]; then
-    echo "No installation directory, aborting."
-    exit 1;
-fi
-if [ "$2" = "--hardlinks" ]; then
-    linkopts="-f"
-else
-    linkopts="-fs"
-fi
-h=`sort busybox.links | uniq`
-
-
-rm -f $prefix/bin/busybox || exit 1
-mkdir -p $prefix/bin || exit 1
-install -m 755 busybox $prefix/bin/busybox || exit 1
-
-for i in $h ; do
-       appdir=`dirname $i`
-       mkdir -p $prefix/$appdir || exit 1
-       if [ "$2" = "--hardlinks" ]; then
-           bb_path="$prefix/bin/busybox"
-       else
-           case "$appdir" in
-               /)
-                   bb_path="bin/busybox"
-               ;;
-               /bin)
-                   bb_path="busybox"
-               ;;
-               /sbin)
-                   bb_path="../bin/busybox"
-               ;;
-               /usr/bin|/usr/sbin)
-                   bb_path="../../bin/busybox"
-               ;;
-               *)
-               echo "Unknown installation directory: $appdir"
-               exit 1
-               ;;
-           esac
-       fi
-       echo "  $prefix$i -> $bb_path"
-       ln $linkopts $bb_path $prefix$i || exit 1
-done
-
-exit 0
diff --git a/busybox/kill.c b/busybox/kill.c
deleted file mode 100644 (file)
index 3884ebd..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini kill/killall implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-static const int KILL = 0;
-static const int KILLALL = 1;
-
-
-extern int kill_main(int argc, char **argv)
-{
-       int whichApp, sig = SIGTERM;
-       const char *name;
-
-#ifdef BB_KILLALL
-       /* Figure out what we are trying to do here */
-       whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; 
-#else
-       whichApp = KILL;
-#endif
-
-       argc--;
-       argv++;
-       /* Parse any options */
-       if (argc < 1)
-               show_usage();
-
-       while (argc > 0 && **argv == '-') {
-               while (*++(*argv)) {
-                       switch (**argv) {
-                       case 'l':
-                               if(argc>1) {
-                                       for(argv++; *argv; argv++) {
-                                               name = u_signal_names(*argv, &sig, -1);
-                                               if(name!=NULL)
-                                                       printf("%s\n", name);
-                                       }
-                               } else {
-                                       int col = 0;
-                                       for(sig=1; sig < NSIG; sig++) {
-                                               name = u_signal_names(0, &sig, 1);
-                                               if(name==NULL)  /* unnamed */
-                                                       continue;
-                                               col += printf("%2d) %-16s", sig, name);
-                                               if (col > 60) {
-                                                       printf("\n");
-                                                       col = 0;
-                                               }
-                                       }
-                                       printf("\n");
-                               }
-                               return EXIT_SUCCESS;
-                       case '-':
-                               show_usage();
-                       default:
-                               name = u_signal_names(*argv, &sig, 0);
-                               if(name==NULL)
-                                       error_msg_and_die( "bad signal name: %s", *argv);
-                                                               argc--;
-                                                               argv++;
-                                                               goto do_it_now;
-                                                       }
-                       argc--;
-                       argv++;
-               }
-       }
-
-  do_it_now:
-
-       if (whichApp == KILL) {
-               /* Looks like they want to do a kill. Do that */
-               while (--argc >= 0) {
-                       int pid;
-
-                       if (!isdigit(**argv))
-                               perror_msg_and_die( "Bad PID");
-                       pid = strtol(*argv, NULL, 0);
-                       if (kill(pid, sig) != 0) 
-                               perror_msg_and_die( "Could not kill pid '%d'", pid);
-                       argv++;
-               }
-       } 
-#ifdef BB_KILLALL
-       else {
-               int all_found = TRUE;
-               pid_t myPid=getpid();
-               /* Looks like they want to do a killall.  Do that */
-               while (--argc >= 0) {
-                       pid_t* pidList;
-
-                       pidList = find_pid_by_name( *argv);
-                       if (!pidList || *pidList<=0) {
-                               all_found = FALSE;
-                               error_msg_and_die( "%s: no process killed", *argv);
-                       }
-
-                       for(; pidList && *pidList!=0; pidList++) {
-                               if (*pidList==myPid)
-                                       continue;
-                               if (kill(*pidList, sig) != 0) 
-                                       perror_msg_and_die( "Could not kill pid '%d'", *pidList);
-                       }
-                       /* Note that we don't bother to free the memory
-                        * allocated in find_pid_by_name().  It will be freed
-                        * upon exit, so we can save a byte or two */
-                       argv++;
-               }
-               if (all_found == FALSE)
-                       return EXIT_FAILURE;
-       }
-#endif
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/klogd.c b/busybox/klogd.c
deleted file mode 100644 (file)
index d7b54e9..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini klogd implementation for busybox
- *
- * Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>.
- * Changes: Made this a standalone busybox module which uses standalone
- *                                     syslog() client interface.
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@mail.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h> /* for our signal() handlers */
-#include <string.h> /* strncpy() */
-#include <errno.h>  /* errno and friends */
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/syslog.h>
-
-#if __GNU_LIBRARY__ < 5
-# ifdef __alpha__
-#   define klogctl syslog
-# endif
-#else
-# include <sys/klog.h>
-#endif
-
-#include "busybox.h"
-
-static void klogd_signal(int sig)
-{
-       klogctl(7, NULL, 0);
-       klogctl(0, 0, 0);
-       //logMessage(0, "Kernel log daemon exiting.");
-       syslog_msg(LOG_DAEMON, 0, "Kernel log daemon exiting.");
-       exit(TRUE);
-}
-
-static void doKlogd (void) __attribute__ ((noreturn));
-static void doKlogd (void)
-{
-       int priority = LOG_INFO;
-       char log_buffer[4096];
-       int i, n, lastc;
-       char *start;
-
-       /* Set up sig handlers */
-       signal(SIGINT, klogd_signal);
-       signal(SIGKILL, klogd_signal);
-       signal(SIGTERM, klogd_signal);
-       signal(SIGHUP, SIG_IGN);
-
-       /* "Open the log. Currently a NOP." */
-       klogctl(1, NULL, 0);
-
-       syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER);
-
-       while (1) {
-               /* Use kernel syscalls */
-               memset(log_buffer, '\0', sizeof(log_buffer));
-               n = klogctl(2, log_buffer, sizeof(log_buffer));
-               if (n < 0) {
-                       char message[80];
-
-                       if (errno == EINTR)
-                               continue;
-                       snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", 
-                                                                                               errno, strerror(errno));
-                       syslog_msg(LOG_DAEMON, LOG_SYSLOG | LOG_ERR, message);
-                       exit(1);
-               }
-
-               /* klogctl buffer parsing modelled after code in dmesg.c */
-               start=&log_buffer[0];
-               lastc='\0';
-               for (i=0; i<n; i++) {
-                       if (lastc == '\0' && log_buffer[i] == '<') {
-                               priority = 0;
-                               i++;
-                               while (isdigit(log_buffer[i])) {
-                                       priority = priority*10+(log_buffer[i]-'0');
-                                       i++;
-                               }
-                               if (log_buffer[i] == '>') i++;
-                               start = &log_buffer[i];
-                       }
-                       if (log_buffer[i] == '\n') {
-                               log_buffer[i] = '\0';  /* zero terminate this message */
-                               syslog_msg(LOG_DAEMON, LOG_KERN | priority, start);
-                               start = &log_buffer[i+1];
-                               priority = LOG_INFO;
-                       }
-                       lastc = log_buffer[i];
-               }
-       }
-}
-
-extern int klogd_main(int argc, char **argv)
-{
-       /* no options, no getopt */
-       int opt;
-       int doFork = TRUE;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "n")) > 0) {
-               switch (opt) {
-                       case 'n':
-                               doFork = FALSE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (doFork == TRUE) {
-               if (daemon(0, 1) < 0)
-                       perror_msg_and_die("daemon");
-       }
-       doKlogd();
-       
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/lash.c b/busybox/lash.c
deleted file mode 100644 (file)
index b3f7cb6..0000000
+++ /dev/null
@@ -1,1638 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * lash -- the BusyBox Lame-Ass SHell
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
- * under the following liberal license: "We have placed this source code in the
- * public domain. Use it in any project, free or commercial."
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* This shell's parsing engine is officially at a dead-end.
- * Future work shell work should be done using hush.c
- */
-
-//For debugging/development on the shell only...
-//#define DEBUG_SHELL
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <termios.h>
-#include "busybox.h"
-#include "cmdedit.h"
-
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-#endif
-
-#include <glob.h>
-#define expand_t       glob_t
-
-
-static const int MAX_READ = 128;       /* size of input buffer for `read' builtin */
-#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
-
-
-enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
-       REDIRECT_APPEND
-};
-
-static const unsigned int DEFAULT_CONTEXT=0x1;
-static const unsigned int IF_TRUE_CONTEXT=0x2;
-static const unsigned int IF_FALSE_CONTEXT=0x4;
-static const unsigned int THEN_EXP_CONTEXT=0x8;
-static const unsigned int ELSE_EXP_CONTEXT=0x10;
-
-
-struct jobset {
-       struct job *head;                       /* head of list of running jobs */
-       struct job *fg;                         /* current foreground job */
-};
-
-struct redir_struct {
-       enum redir_type type;   /* type of redirection */
-       int fd;                                         /* file descriptor being redirected */
-       char *filename;                         /* file to redirect fd to */
-};
-
-struct child_prog {
-       pid_t pid;                                      /* 0 if exited */
-       char **argv;                            /* program name and arguments */
-       int num_redirects;                      /* elements in redirection array */
-       struct redir_struct *redirects; /* I/O redirects */
-       int is_stopped;                         /* is the program currently running? */
-       struct job *family;                     /* pointer back to the child's parent job */
-};
-
-struct job {
-       int jobid;                                      /* job number */
-       int num_progs;                          /* total number of programs in job */
-       int running_progs;                      /* number of programs running */
-       char *text;                                     /* name of job */
-       char *cmdbuf;                           /* buffer various argv's point into */
-       pid_t pgrp;                                     /* process group ID for the job */
-       struct child_prog *progs;       /* array of programs in job */
-       struct job *next;                       /* to track background commands */
-       int stopped_progs;                      /* number of programs alive, but stopped */
-       unsigned int job_context;       /* bitmask defining current context */
-       struct jobset *job_list;
-};
-
-struct built_in_command {
-       char *cmd;                                      /* name */
-       char *descr;                            /* description */
-       int (*function) (struct child_prog *);  /* function ptr */
-};
-
-struct close_me {
-       int fd;
-       struct close_me *next;
-};
-
-/* function prototypes for builtins */
-static int builtin_cd(struct child_prog *cmd);
-static int builtin_exec(struct child_prog *cmd);
-static int builtin_exit(struct child_prog *cmd);
-static int builtin_fg_bg(struct child_prog *cmd);
-static int builtin_help(struct child_prog *cmd);
-static int builtin_jobs(struct child_prog *dummy);
-static int builtin_pwd(struct child_prog *dummy);
-static int builtin_export(struct child_prog *cmd);
-static int builtin_source(struct child_prog *cmd);
-static int builtin_unset(struct child_prog *cmd);
-static int builtin_read(struct child_prog *cmd);
-
-
-/* function prototypes for shell stuff */
-static void mark_open(int fd);
-static void mark_closed(int fd);
-static void close_all(void);
-static void checkjobs(struct jobset *job_list);
-static void remove_job(struct jobset *j_list, struct job *job);
-static int get_command(FILE * source, char *command);
-static int parse_command(char **command_ptr, struct job *job, int *inbg);
-static int run_command(struct job *newjob, int inbg, int outpipe[2]);
-static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
-static int busy_loop(FILE * input);
-
-
-/* Table of built-in functions (these are non-forking builtins, meaning they
- * can change global variables in the parent shell process but they will not
- * work with pipes and redirects; 'unset foo | whatever' will not work) */
-static struct built_in_command bltins[] = {
-       {"bg", "Resume a job in the background", builtin_fg_bg},
-       {"cd", "Change working directory", builtin_cd},
-       {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
-       {"exit", "Exit from shell()", builtin_exit},
-       {"fg", "Bring job into the foreground", builtin_fg_bg},
-       {"jobs", "Lists the active jobs", builtin_jobs},
-       {"export", "Set environment variable", builtin_export},
-       {"unset", "Unset environment variable", builtin_unset},
-       {"read", "Input environment variable", builtin_read},
-       {".", "Source-in and run commands in a file", builtin_source},
-       /* to do: add ulimit */
-       {NULL, NULL, NULL}
-};
-
-/* Table of forking built-in functions (things that fork cannot change global
- * variables in the parent process, such as the current working directory) */
-static struct built_in_command bltins_forking[] = {
-       {"pwd", "Print current directory", builtin_pwd},
-       {"help", "List shell built-in commands", builtin_help},
-       {NULL, NULL, NULL}
-};
-
-
-static int shell_context;  /* Type prompt trigger (PS1 or PS2) */
-
-
-/* Globals that are static to this file */
-static const char *cwd;
-static char *local_pending_command = NULL;
-static struct jobset job_list = { NULL, NULL };
-static int argc;
-static char **argv;
-static struct close_me *close_me_head;
-static int last_return_code;
-static int last_bg_pid;
-static unsigned int last_jobid;
-static int shell_terminal;
-static pid_t shell_pgrp;
-static char *PS1;
-static char *PS2 = "> ";
-
-
-#ifdef DEBUG_SHELL
-static inline void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-}
-#else
-static inline void debug_printf(const char *format, ...) { }
-#endif
-
-/*
-       Most builtins need access to the struct child_prog that has
-       their arguments, previously coded as cmd->progs[0].  That coding
-       can exhibit a bug, if the builtin is not the first command in
-       a pipeline: "echo foo | exec sort" will attempt to exec foo.
-
-builtin   previous use      notes
------- -----------------  ---------
-cd      cmd->progs[0]
-exec    cmd->progs[0]  squashed bug: didn't look for applets or forking builtins
-exit    cmd->progs[0]
-fg_bg   cmd->progs[0], job_list->head, job_list->fg
-help    0
-jobs    job_list->head
-pwd     0
-export  cmd->progs[0]
-source  cmd->progs[0]
-unset   cmd->progs[0]
-read    cmd->progs[0]
-
-I added "struct job *family;" to struct child_prog,
-and switched API to builtin_foo(struct child_prog *child);
-So   cmd->text        becomes  child->family->text
-     cmd->job_context  becomes  child->family->job_context
-     cmd->progs[0]    becomes  *child
-     job_list          becomes  child->family->job_list
- */
-
-/* built-in 'cd <path>' handler */
-static int builtin_cd(struct child_prog *child)
-{
-       char *newdir;
-
-       if (child->argv[1] == NULL)
-               newdir = getenv("HOME");
-       else
-               newdir = child->argv[1];
-       if (chdir(newdir)) {
-               printf("cd: %s: %m\n", newdir);
-               return EXIT_FAILURE;
-       }
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'exec' handler */
-static int builtin_exec(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               return EXIT_SUCCESS;   /* Really? */
-       child->argv++;
-       close_all();
-       pseudo_exec(child);
-       /* never returns */
-}
-
-/* built-in 'exit' handler */
-static int builtin_exit(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               exit(EXIT_SUCCESS);
-
-       exit (atoi(child->argv[1]));
-}
-
-/* built-in 'fg' and 'bg' handler */
-static int builtin_fg_bg(struct child_prog *child)
-{
-       int i, jobnum;
-       struct job *job=NULL;
-
-       /* If they gave us no args, assume they want the last backgrounded task */
-       if (!child->argv[1]) {
-               for (job = child->family->job_list->head; job; job = job->next) {
-                       if (job->jobid == last_jobid) {
-                               break;
-                       }
-               }
-               if (!job) {
-                       error_msg("%s: no current job", child->argv[0]);
-                       return EXIT_FAILURE;
-               }
-       } else {
-               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
-                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
-                       return EXIT_FAILURE;
-               }
-               for (job = child->family->job_list->head; job; job = job->next) {
-                       if (job->jobid == jobnum) {
-                               break;
-                       }
-               }
-               if (!job) {
-                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       if (*child->argv[0] == 'f') {
-               /* Put the job into the foreground.  */
-               tcsetpgrp(shell_terminal, job->pgrp);
-
-               child->family->job_list->fg = job;
-       }
-
-       /* Restart the processes in the job */
-       for (i = 0; i < job->num_progs; i++)
-               job->progs[i].is_stopped = 0;
-
-       job->stopped_progs = 0;
-
-       if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
-               if (i == ESRCH) {
-                       remove_job(&job_list, job);
-               } else {
-                       perror_msg("kill (SIGCONT)");
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'help' handler */
-static int builtin_help(struct child_prog *dummy)
-{
-       struct built_in_command *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-       for (x = bltins; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       for (x = bltins_forking; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'jobs' handler */
-static int builtin_jobs(struct child_prog *child)
-{
-       struct job *job;
-       char *status_string;
-
-       for (job = child->family->job_list->head; job; job = job->next) {
-               if (job->running_progs == job->stopped_progs)
-                       status_string = "Stopped";
-               else
-                       status_string = "Running";
-
-               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
-       }
-       return EXIT_SUCCESS;
-}
-
-
-/* built-in 'pwd' handler */
-static int builtin_pwd(struct child_prog *dummy)
-{
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       puts(cwd);
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'export VAR=value' handler */
-static int builtin_export(struct child_prog *child)
-{
-       int res;
-       char *v = child->argv[1];
-
-       if (v == NULL) {
-               char **e;
-               for (e = environ; *e; e++) {
-                       puts(*e);
-               }
-               return 0;
-       }
-       res = putenv(v);
-       if (res)
-               fprintf(stderr, "export: %m\n");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (strncmp(v, "PS1=", 4)==0)
-               PS1 = getenv("PS1");
-#endif
-
-#ifdef BB_LOCALE_SUPPORT
-       if(strncmp(v, "LC_ALL=", 7)==0)
-               setlocale(LC_ALL, getenv("LC_ALL"));
-       if(strncmp(v, "LC_CTYPE=", 9)==0)
-               setlocale(LC_CTYPE, getenv("LC_CTYPE"));
-#endif
-
-       return (res);
-}
-
-/* built-in 'read VAR' handler */
-static int builtin_read(struct child_prog *child)
-{
-       int res = 0, len, newlen;
-       char *s;
-       char string[MAX_READ];
-
-       if (child->argv[1]) {
-               /* argument (VAR) given: put "VAR=" into buffer */
-               strcpy(string, child->argv[1]);
-               len = strlen(string);
-               string[len++] = '=';
-               string[len]   = '\0';
-               fgets(&string[len], sizeof(string) - len, stdin);       /* read string */
-               newlen = strlen(string);
-               if(newlen > len)
-                       string[--newlen] = '\0';        /* chomp trailing newline */
-               /*
-               ** string should now contain "VAR=<value>"
-               ** copy it (putenv() won't do that, so we must make sure
-               ** the string resides in a static buffer!)
-               */
-               res = -1;
-               if((s = strdup(string)))
-                       res = putenv(s);
-               if (res)
-                       fprintf(stderr, "read: %m\n");
-       }
-       else
-               fgets(string, sizeof(string), stdin);
-
-       return (res);
-}
-
-/* Built-in '.' handler (read-in and execute commands from file) */
-static int builtin_source(struct child_prog *child)
-{
-       FILE *input;
-       int status;
-       int fd;
-
-       if (child->argv[1] == NULL)
-               return EXIT_FAILURE;
-
-       input = fopen(child->argv[1], "r");
-       if (!input) {
-               printf( "Couldn't open file '%s'\n", child->argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       fd=fileno(input);
-       mark_open(fd);
-       /* Now run the file */
-       status = busy_loop(input);
-       fclose(input);
-       mark_closed(fd);
-       return (status);
-}
-
-/* built-in 'unset VAR' handler */
-static int builtin_unset(struct child_prog *child)
-{
-       if (child->argv[1] == NULL) {
-               printf( "unset: parameter required.\n");
-               return EXIT_FAILURE;
-       }
-       unsetenv(child->argv[1]);
-       return EXIT_SUCCESS;
-}
-
-static void mark_open(int fd)
-{
-       struct close_me *new = xmalloc(sizeof(struct close_me));
-       new->fd = fd;
-       new->next = close_me_head;
-       close_me_head = new;
-}
-
-static void mark_closed(int fd)
-{
-       struct close_me *tmp;
-       if (close_me_head == NULL || close_me_head->fd != fd)
-               error_msg_and_die("corrupt close_me");
-       tmp = close_me_head;
-       close_me_head = close_me_head->next;
-       free(tmp);
-}
-
-static void close_all()
-{
-       struct close_me *c, *tmp;
-       for (c=close_me_head; c; c=tmp) {
-               close(c->fd);
-               tmp=c->next;
-               free(c);
-       }
-       close_me_head = NULL;
-}
-
-
-/* free up all memory from a job */
-static void free_job(struct job *cmd)
-{
-       int i;
-       struct jobset *keep;
-
-       for (i = 0; i < cmd->num_progs; i++) {
-               free(cmd->progs[i].argv);
-               if (cmd->progs[i].redirects)
-                       free(cmd->progs[i].redirects);
-       }
-       if (cmd->progs)
-               free(cmd->progs);
-       if (cmd->text)
-               free(cmd->text);
-       if (cmd->cmdbuf)
-               free(cmd->cmdbuf);
-       keep = cmd->job_list;
-       memset(cmd, 0, sizeof(struct job));
-       cmd->job_list = keep;
-}
-
-/* remove a job from a jobset */
-static void remove_job(struct jobset *j_list, struct job *job)
-{
-       struct job *prevjob;
-
-       free_job(job);
-       if (job == j_list->head) {
-               j_list->head = job->next;
-       } else {
-               prevjob = j_list->head;
-               while (prevjob->next != job)
-                       prevjob = prevjob->next;
-               prevjob->next = job->next;
-       }
-
-       if (j_list->head)
-               last_jobid = j_list->head->jobid;
-       else
-               last_jobid = 0;
-
-       free(job);
-}
-
-/* Checks to see if any background processes have exited -- if they 
-   have, figure out why and see if a job has completed */
-static void checkjobs(struct jobset *j_list)
-{
-       struct job *job;
-       pid_t childpid;
-       int status;
-       int prognum = 0;
-
-       while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
-               for (job = j_list->head; job; job = job->next) {
-                       prognum = 0;
-                       while (prognum < job->num_progs &&
-                                  job->progs[prognum].pid != childpid) prognum++;
-                       if (prognum < job->num_progs)
-                               break;
-               }
-
-               /* This happens on backticked commands */
-               if(job==NULL)
-                       return;
-
-               if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                       /* child exited */
-                       job->running_progs--;
-                       job->progs[prognum].pid = 0;
-
-                       if (!job->running_progs) {
-                               printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
-                               last_jobid=0;
-                               remove_job(j_list, job);
-                       }
-               } else {
-                       /* child stopped */
-                       job->stopped_progs++;
-                       job->progs[prognum].is_stopped = 1;
-
-#if 0
-                       /* Printing this stuff is a pain, since it tends to
-                        * overwrite the prompt an inconveinient moments.  So
-                        * don't do that.  */
-                       if (job->stopped_progs == job->num_progs) {
-                               printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
-                                          job->text);
-                       }
-#endif 
-               }
-       }
-
-       if (childpid == -1 && errno != ECHILD)
-               perror_msg("waitpid");
-}
-
-/* squirrel != NULL means we squirrel away copies of stdin, stdout,
- * and stderr if they are redirected. */
-static int setup_redirects(struct child_prog *prog, int squirrel[])
-{
-       int i;
-       int openfd;
-       int mode = O_RDONLY;
-       struct redir_struct *redir = prog->redirects;
-
-       for (i = 0; i < prog->num_redirects; i++, redir++) {
-               switch (redir->type) {
-               case REDIRECT_INPUT:
-                       mode = O_RDONLY;
-                       break;
-               case REDIRECT_OVERWRITE:
-                       mode = O_WRONLY | O_CREAT | O_TRUNC;
-                       break;
-               case REDIRECT_APPEND:
-                       mode = O_WRONLY | O_CREAT | O_APPEND;
-                       break;
-               }
-
-               openfd = open(redir->filename, mode, 0666);
-               if (openfd < 0) {
-                       /* this could get lost if stderr has been redirected, but
-                          bash and ash both lose it as well (though zsh doesn't!) */
-                       perror_msg("error opening %s", redir->filename);
-                       return 1;
-               }
-
-               if (openfd != redir->fd) {
-                       if (squirrel && redir->fd < 3) {
-                               squirrel[redir->fd] = dup(redir->fd);
-                       }
-                       dup2(openfd, redir->fd);
-                       close(openfd);
-               }
-       }
-
-       return 0;
-}
-
-static void restore_redirects(int squirrel[])
-{
-       int i, fd;
-       for (i=0; i<3; i++) {
-               fd = squirrel[i];
-               if (fd != -1) {
-                       /* No error checking.  I sure wouldn't know what
-                        * to do with an error if I found one! */
-                       dup2(fd, i);
-                       close(fd);
-               }
-       }
-}
-
-static inline void cmdedit_set_initial_prompt(void)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       PS1 = NULL;
-#else
-       PS1 = getenv("PS1");
-       if(PS1==0)
-               PS1 = "\\w \\$ ";
-#endif 
-}
-
-static inline void setup_prompt_string(char **prompt_str)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       /* Set up the prompt */
-       if (shell_context == 0) {
-               if (PS1)
-                       free(PS1);
-               PS1=xmalloc(strlen(cwd)+4);
-               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
-               *prompt_str = PS1;
-       } else {
-               *prompt_str = PS2;
-       }
-#else
-       *prompt_str = (shell_context==0)? PS1 : PS2;
-#endif 
-}
-
-static int get_command(FILE * source, char *command)
-{
-       char *prompt_str;
-
-       if (source == NULL) {
-               if (local_pending_command) {
-                       /* a command specified (-c option): return it & mark it done */
-                       strcpy(command, local_pending_command);
-                       free(local_pending_command);
-                       local_pending_command = NULL;
-                       return 0;
-               }
-               return 1;
-       }
-
-       if (source == stdin) {
-               setup_prompt_string(&prompt_str);
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-               /*
-               ** enable command line editing only while a command line
-               ** is actually being read; otherwise, we'll end up bequeathing
-               ** atexit() handlers and other unwanted stuff to our
-               ** child processes (rob@sysgo.de)
-               */
-               cmdedit_read_input(prompt_str, command);
-               return 0;
-#else
-               fputs(prompt_str, stdout);
-#endif
-       }
-
-       if (!fgets(command, BUFSIZ - 2, source)) {
-               if (source == stdin)
-                       printf("\n");
-               return 1;
-       }
-
-       return 0;
-}
-
-static char* itoa(register int i)
-{
-       static char a[7]; /* Max 7 ints */
-       register char *b = a + sizeof(a) - 1;
-       int   sign = (i < 0);
-
-       if (sign)
-               i = -i;
-       *b = 0;
-       do
-       {
-               *--b = '0' + (i % 10);
-               i /= 10;
-       }
-       while (i);
-       if (sign)
-               *--b = '-';
-       return b;
-}
-
-char * strsep_space( char *string, int * ix)
-{
-       char *token, *begin;
-
-       begin = string;
-
-       /* Short circuit the trivial case */
-       if ( !string || ! string[*ix])
-               return NULL;
-
-       /* Find the end of the token. */
-       while( string && string[*ix] && !isspace(string[*ix]) ) {
-               (*ix)++;
-       }
-
-       /* Find the end of any whitespace trailing behind 
-        * the token and let that be part of the token */
-       while( string && string[*ix] && isspace(string[*ix]) ) {
-               (*ix)++;
-       }
-
-       if (! string && *ix==0) {
-               /* Nothing useful was found */
-               return NULL;
-       }
-
-       token = xmalloc(*ix+1);
-       token[*ix] = '\0';
-       strncpy(token, string,  *ix); 
-
-       return token;
-}
-
-static int expand_arguments(char *command)
-{
-       int total_length=0, length, i, retval, ix = 0;
-       expand_t expand_result;
-       char *tmpcmd, *cmd, *cmd_copy;
-       char *src, *dst, *var;
-       const char *out_of_space = "out of space during expansion";
-       int flags = GLOB_NOCHECK
-#ifdef GLOB_BRACE
-               | GLOB_BRACE
-#endif 
-#ifdef GLOB_TILDE
-               | GLOB_TILDE
-#endif 
-               ;
-
-       /* get rid of the terminating \n */
-       chomp(command);
-
-       /* Fix up escape sequences to be the Real Thing(tm) */
-       while( command && command[ix]) {
-               if (command[ix] == '\\') {
-                       const char *tmp = command+ix+1;
-                       command[ix] = process_escape_sequence(  &tmp );
-                       memmove(command+ix + 1, tmp, strlen(tmp)+1);
-               }
-               ix++;
-       }
-       /* Use glob and then fixup environment variables and such */
-
-       /* It turns out that glob is very stupid.  We have to feed it one word at a
-        * time since it can't cope with a full string.  Here we convert command
-        * (char*) into cmd (char**, one word per string) */
-
-       /* We need a clean copy, so strsep can mess up the copy while
-        * we write stuff into the original (in a minute) */
-       cmd = cmd_copy = strdup(command);
-       *command = '\0';
-       for (ix = 0, tmpcmd = cmd; 
-                       (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
-               if (*tmpcmd == '\0')
-                       break;
-               /* we need to trim() the result for glob! */
-               trim(tmpcmd);
-               retval = glob(tmpcmd, flags, NULL, &expand_result);
-               free(tmpcmd); /* Free mem allocated by strsep_space */
-               if (retval == GLOB_NOSPACE) {
-                       /* Mem may have been allocated... */
-                       globfree (&expand_result);
-                       error_msg(out_of_space);
-                       return FALSE;
-               } else if (retval != 0) {
-                       /* Some other error.  GLOB_NOMATCH shouldn't
-                        * happen because of the GLOB_NOCHECK flag in 
-                        * the glob call. */
-                       error_msg("syntax error");
-                       return FALSE;
-               } else {
-                       /* Convert from char** (one word per string) to a simple char*,
-                        * but don't overflow command which is BUFSIZ in length */
-                       for (i=0; i < expand_result.gl_pathc; i++) {
-                               length=strlen(expand_result.gl_pathv[i]);
-                               if (total_length+length+1 >= BUFSIZ) {
-                                       error_msg(out_of_space);
-                                       return FALSE;
-                               }
-                               strcat(command+total_length, " ");
-                               total_length+=1;
-                               strcat(command+total_length, expand_result.gl_pathv[i]);
-                               total_length+=length;
-                       }
-                       globfree (&expand_result);
-               }
-       }
-       free(cmd_copy);
-       trim(command);
-
-       /* Now do the shell variable substitutions which 
-        * wordexp can't do for us, namely $? and $! */
-       src = command;
-       while((dst = strchr(src,'$')) != NULL){
-               var = NULL;
-               switch(*(dst+1)) {
-                       case '?':
-                               var = itoa(last_return_code);
-                               break;
-                       case '!':
-                               if (last_bg_pid==-1)
-                                       *(var)='\0';
-                               else
-                                       var = itoa(last_bg_pid);
-                               break;
-                               /* Everything else like $$, $#, $[0-9], etc. should all be
-                                * expanded by wordexp(), so we can in theory skip that stuff
-                                * here, but just to be on the safe side (i.e., since uClibc
-                                * wordexp doesn't do this stuff yet), lets leave it in for
-                                * now. */
-                       case '$':
-                               var = itoa(getpid());
-                               break;
-                       case '#':
-                               var = itoa(argc-1);
-                               break;
-                       case '0':case '1':case '2':case '3':case '4':
-                       case '5':case '6':case '7':case '8':case '9':
-                               {
-                                       int ixx=*(dst + 1)-48;
-                                       if (ixx >= argc) {
-                                               var='\0';
-                                       } else {
-                                               var = argv[ixx];
-                                       }
-                               }
-                               break;
-
-               }
-               if (var) {
-                       /* a single character construction was found, and 
-                        * already handled in the case statement */
-                       src=dst+2;
-               } else {
-                       /* Looks like an environment variable */
-                       char delim_hold;
-                       int num_skip_chars=0;
-                       int dstlen = strlen(dst);
-                       /* Is this a ${foo} type variable? */
-                       if (dstlen >=2 && *(dst+1) == '{') {
-                               src=strchr(dst+1, '}');
-                               num_skip_chars=1;
-                       } else {
-                               src=dst+1;
-                               while(isalnum(*src) || *src=='_') src++;
-                       }
-                       if (src == NULL) {
-                               src = dst+dstlen;
-                       }
-                       delim_hold=*src;
-                       *src='\0';  /* temporary */
-                       var = getenv(dst + 1 + num_skip_chars);
-                       *src=delim_hold;
-                       src += num_skip_chars;
-               }
-               if (var == NULL) {
-                       /* Seems we got an un-expandable variable.  So delete it. */
-                       var = "";
-               }
-               {
-                       int subst_len = strlen(var);
-                       int trail_len = strlen(src);
-                       if (dst+subst_len+trail_len >= command+BUFSIZ) {
-                               error_msg(out_of_space);
-                               return FALSE;
-                       }
-                       /* Move stuff to the end of the string to accommodate
-                        * filling the created gap with the new stuff */
-                       memmove(dst+subst_len, src, trail_len+1);
-                       /* Now copy in the new stuff */
-                       memcpy(dst, var, subst_len);
-                       src = dst+subst_len;
-               }
-       }
-
-       return TRUE;
-}
-
-/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
-   line). If a valid command is found, command_ptr is set to point to
-   the beginning of the next command (if the original command had more 
-   then one job associated with it) or NULL if no more commands are 
-   present. */
-static int parse_command(char **command_ptr, struct job *job, int *inbg)
-{
-       char *command;
-       char *return_command = NULL;
-       char *src, *buf, *chptr;
-       int argc_l = 0;
-       int done = 0;
-       int argv_alloced;
-       int i, saw_quote = 0;
-       char quote = '\0';
-       int count;
-       struct child_prog *prog;
-
-       /* skip leading white space */
-       while (**command_ptr && isspace(**command_ptr))
-               (*command_ptr)++;
-
-       /* this handles empty lines or leading '#' characters */
-       if (!**command_ptr || (**command_ptr == '#')) {
-               job->num_progs=0;
-               return 0;
-       }
-
-       *inbg = 0;
-       job->num_progs = 1;
-       job->progs = xmalloc(sizeof(*job->progs));
-
-       /* We set the argv elements to point inside of this string. The 
-          memory is freed by free_job(). Allocate twice the original
-          length in case we need to quote every single character.
-
-          Getting clean memory relieves us of the task of NULL 
-          terminating things and makes the rest of this look a bit 
-          cleaner (though it is, admittedly, a tad less efficient) */
-       job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
-       job->text = NULL;
-
-       prog = job->progs;
-       prog->num_redirects = 0;
-       prog->redirects = NULL;
-       prog->is_stopped = 0;
-       prog->family = job;
-
-       argv_alloced = 5;
-       prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
-       prog->argv[0] = job->cmdbuf;
-
-       buf = command;
-       src = *command_ptr;
-       while (*src && !done) {
-               if (quote == *src) {
-                       quote = '\0';
-               } else if (quote) {
-                       if (*src == '\\') {
-                               src++;
-                               if (!*src) {
-                                       error_msg("character expected after \\");
-                                       free_job(job);
-                                       return 1;
-                               }
-
-                               /* in shell, "\'" should yield \' */
-                               if (*src != quote) {
-                                       *buf++ = '\\';
-                                       *buf++ = '\\';
-                               }
-                       } else if (*src == '*' || *src == '?' || *src == '[' ||
-                                          *src == ']') *buf++ = '\\';
-                       *buf++ = *src;
-               } else if (isspace(*src)) {
-                       if (*prog->argv[argc_l] || saw_quote) {
-                               buf++, argc_l++;
-                               /* +1 here leaves room for the NULL which ends argv */
-                               if ((argc_l + 1) == argv_alloced) {
-                                       argv_alloced += 5;
-                                       prog->argv = xrealloc(prog->argv,
-                                                                                 sizeof(*prog->argv) *
-                                                                                 argv_alloced);
-                               }
-                               prog->argv[argc_l] = buf;
-                               saw_quote = 0;
-                       }
-               } else
-                       switch (*src) {
-                       case '"':
-                       case '\'':
-                               quote = *src;
-                               saw_quote = 1;
-                               break;
-
-                       case '#':                       /* comment */
-                               if (*(src-1)== '$')
-                                       *buf++ = *src;
-                               else
-                                       done = 1;
-                               break;
-
-                       case '>':                       /* redirects */
-                       case '<':
-                               i = prog->num_redirects++;
-                               prog->redirects = xrealloc(prog->redirects,
-                                                                                         sizeof(*prog->redirects) *
-                                                                                         (i + 1));
-
-                               prog->redirects[i].fd = -1;
-                               if (buf != prog->argv[argc_l]) {
-                                       /* the stuff before this character may be the file number 
-                                          being redirected */
-                                       prog->redirects[i].fd =
-                                               strtol(prog->argv[argc_l], &chptr, 10);
-
-                                       if (*chptr && *prog->argv[argc_l]) {
-                                               buf++, argc_l++;
-                                               prog->argv[argc_l] = buf;
-                                       }
-                               }
-
-                               if (prog->redirects[i].fd == -1) {
-                                       if (*src == '>')
-                                               prog->redirects[i].fd = 1;
-                                       else
-                                               prog->redirects[i].fd = 0;
-                               }
-
-                               if (*src++ == '>') {
-                                       if (*src == '>')
-                                               prog->redirects[i].type =
-                                                       REDIRECT_APPEND, src++;
-                                       else
-                                               prog->redirects[i].type = REDIRECT_OVERWRITE;
-                               } else {
-                                       prog->redirects[i].type = REDIRECT_INPUT;
-                               }
-
-                               /* This isn't POSIX sh compliant. Oh well. */
-                               chptr = src;
-                               while (isspace(*chptr))
-                                       chptr++;
-
-                               if (!*chptr) {
-                                       error_msg("file name expected after %c", *(src-1));
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-
-                               prog->redirects[i].filename = buf;
-                               while (*chptr && !isspace(*chptr))
-                                       *buf++ = *chptr++;
-
-                               src = chptr - 1;        /* we src++ later */
-                               prog->argv[argc_l] = ++buf;
-                               break;
-
-                       case '|':                       /* pipe */
-                               /* finish this command */
-                               if (*prog->argv[argc_l] || saw_quote)
-                                       argc_l++;
-                               if (!argc_l) {
-                                       error_msg("empty command in pipe");
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-                               prog->argv[argc_l] = NULL;
-
-                               /* and start the next */
-                               job->num_progs++;
-                               job->progs = xrealloc(job->progs,
-                                                                         sizeof(*job->progs) * job->num_progs);
-                               prog = job->progs + (job->num_progs - 1);
-                               prog->num_redirects = 0;
-                               prog->redirects = NULL;
-                               prog->is_stopped = 0;
-                               prog->family = job;
-                               argc_l = 0;
-
-                               argv_alloced = 5;
-                               prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
-                               prog->argv[0] = ++buf;
-
-                               src++;
-                               while (*src && isspace(*src))
-                                       src++;
-
-                               if (!*src) {
-                                       error_msg("empty command in pipe");
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-                               src--;                  /* we'll ++ it at the end of the loop */
-
-                               break;
-
-                       case '&':                       /* background */
-                               *inbg = 1;
-                       case ';':                       /* multiple commands */
-                               done = 1;
-                               return_command = *command_ptr + (src - *command_ptr) + 1;
-                               break;
-
-                       case '\\':
-                               src++;
-                               if (!*src) {
-                                       error_msg("character expected after \\");
-                                       free_job(job);
-                                       return 1;
-                               }
-                               if (*src == '*' || *src == '[' || *src == ']'
-                                       || *src == '?') *buf++ = '\\';
-                               /* fallthrough */
-                       default:
-                               *buf++ = *src;
-                       }
-
-               src++;
-       }
-
-       if (*prog->argv[argc_l] || saw_quote) {
-               argc_l++;
-       }
-       if (!argc_l) {
-               free_job(job);
-               return 0;
-       }
-       prog->argv[argc_l] = NULL;
-
-       if (!return_command) {
-               job->text = xmalloc(strlen(*command_ptr) + 1);
-               strcpy(job->text, *command_ptr);
-       } else {
-               /* This leaves any trailing spaces, which is a bit sloppy */
-               count = return_command - *command_ptr;
-               job->text = xmalloc(count + 1);
-               strncpy(job->text, *command_ptr, count);
-               job->text[count] = '\0';
-       }
-
-       *command_ptr = return_command;
-       
-       return 0;
-}
-
-/* Run the child_prog, no matter what kind of command it uses.
- */
-static int pseudo_exec(struct child_prog *child)
-{
-       struct built_in_command *x;
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name;
-#endif
-
-       /* Check if the command matches any of the non-forking builtins.
-        * Depending on context, this might be redundant.  But it's
-        * easier to waste a few CPU cycles than it is to figure out
-        * if this is one of those cases.
-        */
-       for (x = bltins; x->cmd; x++) {
-               if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                       exit(x->function(child));
-               }
-       }
-
-       /* Check if the command matches any of the forking builtins. */
-       for (x = bltins_forking; x->cmd; x++) {
-               if (strcmp(child->argv[0], x->cmd) == 0) {
-                       applet_name=x->cmd;
-                       exit (x->function(child));
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       /* Check if the command matches any busybox internal
-        * commands ("applets") here.  Following discussions from
-        * November 2000 on busybox@opensource.lineo.com, don't use
-        * get_last_path_component().  This way explicit (with
-        * slashes) filenames will never be interpreted as an
-        * applet, just like with builtins.  This way the user can
-        * override an applet with an explicit filename reference.
-        * The only downside to this change is that an explicit
-        * /bin/foo invocation will fork and exec /bin/foo, even if
-        * /bin/foo is a symlink to busybox.
-        */
-       name = child->argv[0];
-
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
-        * if you run /bin/cat, it will use BusyBox cat even if 
-        * /bin/cat exists on the filesystem and is _not_ busybox.
-        * Some systems want this, others do not.  Choose wisely.  :-)
-        */
-       name = get_last_path_component(name);
-#endif
-
-       {
-           char** argv_l=child->argv;
-           int argc_l;
-           for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
-           optind = 1;
-           run_applet_by_name(name, argc_l, child->argv);
-       }
-#endif
-
-       execvp(child->argv[0], child->argv);
-       perror_msg_and_die("%s", child->argv[0]);
-}
-
-static void insert_job(struct job *newjob, int inbg)
-{
-       struct job *thejob;
-       struct jobset *j_list=newjob->job_list;
-
-       /* find the ID for thejob to use */
-       newjob->jobid = 1;
-       for (thejob = j_list->head; thejob; thejob = thejob->next)
-               if (thejob->jobid >= newjob->jobid)
-                       newjob->jobid = thejob->jobid + 1;
-
-       /* add thejob to the list of running jobs */
-       if (!j_list->head) {
-               thejob = j_list->head = xmalloc(sizeof(*thejob));
-       } else {
-               for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
-               thejob->next = xmalloc(sizeof(*thejob));
-               thejob = thejob->next;
-       }
-
-       *thejob = *newjob;   /* physically copy the struct job */
-       thejob->next = NULL;
-       thejob->running_progs = thejob->num_progs;
-       thejob->stopped_progs = 0;
-
-       if (inbg) {
-               /* we don't wait for background thejobs to return -- append it 
-                  to the list of backgrounded thejobs and leave it alone */
-               printf("[%d] %d\n", thejob->jobid,
-                          newjob->progs[newjob->num_progs - 1].pid);
-               last_jobid = newjob->jobid;
-               last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
-       } else {
-               newjob->job_list->fg = thejob;
-
-               /* move the new process group into the foreground */
-               /* suppress messages when run from /linuxrc mag@sysgo.de */
-               if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
-                       perror_msg("tcsetpgrp");
-       }
-}
-
-static int run_command(struct job *newjob, int inbg, int outpipe[2])
-{
-       /* struct job *thejob; */
-       int i;
-       int nextin, nextout;
-       int pipefds[2];                         /* pipefd[0] is for reading */
-       struct built_in_command *x;
-       struct child_prog *child;
-
-       nextin = 0, nextout = 1;
-       for (i = 0; i < newjob->num_progs; i++) {
-               child = & (newjob->progs[i]);
-
-               if ((i + 1) < newjob->num_progs) {
-                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
-                       nextout = pipefds[1];
-               } else {
-                       if (outpipe[1]!=-1) {
-                               nextout = outpipe[1];
-                       } else {
-                               nextout = 1;
-                       }
-               }
-
-
-               /* Check if the command matches any non-forking builtins,
-                * but only if this is a simple command.
-                * Non-forking builtins within pipes have to fork anyway,
-                * and are handled in pseudo_exec.  "echo foo | read bar"
-                * is doomed to failure, and doesn't work on bash, either.
-                */
-               if (newjob->num_progs == 1) {
-                       for (x = bltins; x->cmd; x++) {
-                               if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                                       int squirrel[] = {-1, -1, -1};
-                                       int rcode;
-                                       setup_redirects(child, squirrel);
-                                       rcode = x->function(child);
-                                       restore_redirects(squirrel);
-                                       return rcode;
-                               }
-                       }
-               }
-
-               if (!(child->pid = fork())) {
-                       /* Set the handling for job control signals back to the default.  */
-                       signal(SIGINT, SIG_DFL);
-                       signal(SIGQUIT, SIG_DFL);
-                       signal(SIGTSTP, SIG_DFL);
-                       signal(SIGTTIN, SIG_DFL);
-                       signal(SIGTTOU, SIG_DFL);
-                       signal(SIGCHLD, SIG_DFL);
-
-                       close_all();
-
-                       if (outpipe[1]!=-1) {
-                               close(outpipe[0]);
-                       }
-                       if (nextin != 0) {
-                               dup2(nextin, 0);
-                               close(nextin);
-                       }
-
-                       if (nextout != 1) {
-                               dup2(nextout, 1);
-                               dup2(nextout, 2);  /* Really? */
-                               close(nextout);
-                               close(pipefds[0]);
-                       }
-
-                       /* explicit redirects override pipes */
-                       setup_redirects(child,NULL);
-
-                       pseudo_exec(child);
-               }
-               if (outpipe[1]!=-1) {
-                       close(outpipe[1]);
-               }
-
-               /* put our child in the process group whose leader is the
-                  first process in this pipe */
-               setpgid(child->pid, newjob->progs[0].pid);
-               if (nextin != 0)
-                       close(nextin);
-               if (nextout != 1)
-                       close(nextout);
-
-               /* If there isn't another process, nextin is garbage 
-                  but it doesn't matter */
-               nextin = pipefds[0];
-       }
-
-       newjob->pgrp = newjob->progs[0].pid;
-
-       insert_job(newjob, inbg);
-
-       return 0;
-}
-
-static int busy_loop(FILE * input)
-{
-       char *command;
-       char *next_command = NULL;
-       struct job newjob;
-       pid_t  parent_pgrp;
-       int i;
-       int inbg;
-       int status;
-       newjob.job_list = &job_list;
-       newjob.job_context = DEFAULT_CONTEXT;
-
-       /* save current owner of TTY so we can restore it on exit */
-       parent_pgrp = tcgetpgrp(shell_terminal);
-
-       command = (char *) xcalloc(BUFSIZ, sizeof(char));
-
-       while (1) {
-               if (!job_list.fg) {
-                       /* no job is in the foreground */
-
-                       /* see if any background processes have exited */
-                       checkjobs(&job_list);
-
-                       if (!next_command) {
-                               if (get_command(input, command))
-                                       break;
-                               next_command = command;
-                       }
-
-                       if (expand_arguments(next_command) == FALSE) {
-                               free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
-                               next_command = NULL;
-                               continue;
-                       }
-
-                       if (!parse_command(&next_command, &newjob, &inbg) &&
-                               newjob.num_progs) {
-                               int pipefds[2] = {-1,-1};
-                               debug_printf( "job=%p fed to run_command by busy_loop()'\n", 
-                                               &newjob);
-                               run_command(&newjob, inbg, pipefds);
-                       }
-                       else {
-                               free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
-                               next_command = NULL;
-                       }
-               } else {
-                       /* a job is running in the foreground; wait for it */
-                       i = 0;
-                       while (!job_list.fg->progs[i].pid ||
-                                  job_list.fg->progs[i].is_stopped == 1) i++;
-
-                       if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0)
-                               perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
-
-                       if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                               /* the child exited */
-                               job_list.fg->running_progs--;
-                               job_list.fg->progs[i].pid = 0;
-
-                               last_return_code=WEXITSTATUS(status);
-
-                               if (!job_list.fg->running_progs) {
-                                       /* child exited */
-                                       remove_job(&job_list, job_list.fg);
-                                       job_list.fg = NULL;
-                               }
-                       } else {
-                               /* the child was stopped */
-                               job_list.fg->stopped_progs++;
-                               job_list.fg->progs[i].is_stopped = 1;
-
-                               if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
-                                       printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
-                                                  "Stopped", job_list.fg->text);
-                                       job_list.fg = NULL;
-                               }
-                       }
-
-                       if (!job_list.fg) {
-                               /* move the shell to the foreground */
-                               /* suppress messages when run from /linuxrc mag@sysgo.de */
-                               if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp"); 
-                       }
-               }
-       }
-       free(command);
-
-       /* return controlling TTY back to parent process group before exiting */
-       if (tcsetpgrp(shell_terminal, parent_pgrp))
-               perror_msg("tcsetpgrp");
-
-       /* return exit status if called with "-c" */
-       if (input == NULL && WIFEXITED(status))
-               return WEXITSTATUS(status);
-       
-       return 0;
-}
-
-
-#ifdef BB_FEATURE_CLEAN_UP
-void free_memory(void)
-{
-       if (cwd && cwd!=unknown) {
-               free((char*)cwd);
-       }
-       if (local_pending_command)
-               free(local_pending_command);
-
-       if (job_list.fg && !job_list.fg->running_progs) {
-               remove_job(&job_list, job_list.fg);
-       }
-}
-#endif
-
-/* Make sure we have a controlling tty.  If we get started under a job
- * aware app (like bash for example), make sure we are now in charge so
- * we don't fight over who gets the foreground */
-static void setup_job_control()
-{
-       int status;
-       
-       /* Loop until we are in the foreground.  */
-       while ((status = tcgetpgrp (shell_terminal)) >= 0) {
-               if (status == (shell_pgrp = getpgrp ())) {
-                       break;
-               }
-               kill (- shell_pgrp, SIGTTIN);
-       }
-
-       /* Ignore interactive and job-control signals.  */
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGTSTP, SIG_IGN);
-       signal(SIGTTIN, SIG_IGN);
-       signal(SIGTTOU, SIG_IGN);
-       signal(SIGCHLD, SIG_IGN);
-
-       /* Put ourselves in our own process group.  */
-       setsid();
-       shell_pgrp = getpid ();
-       setpgid (shell_pgrp, shell_pgrp);
-
-       /* Grab control of the terminal.  */
-       tcsetpgrp(shell_terminal, shell_pgrp);
-}
-
-int lash_main(int argc_l, char **argv_l)
-{
-       int opt, interactive=FALSE;
-       FILE *input = stdin;
-       argc = argc_l;
-       argv = argv_l;
-
-       /* These variables need re-initializing when recursing */
-       last_jobid = 0;
-       local_pending_command = NULL;
-       close_me_head = NULL;
-       job_list.head = NULL;
-       job_list.fg = NULL;
-       last_return_code=1;
-
-       if (argv[0] && argv[0][0] == '-') {
-               FILE *prof_input;
-               prof_input = fopen("/etc/profile", "r");
-               if (prof_input) {
-                       int tmp_fd = fileno(prof_input);
-                       mark_open(tmp_fd);      
-                       /* Now run the file */
-                       busy_loop(prof_input);
-                       fclose(prof_input);
-                       mark_closed(tmp_fd);
-               }
-       }
-
-       while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               input = NULL;
-                               if (local_pending_command != 0)
-                                       error_msg_and_die("multiple -c arguments");
-                               local_pending_command = xstrdup(argv[optind]);
-                               optind++;
-                               argv = argv+optind;
-                               break;
-                       case 'i':
-                               interactive = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       /* A shell is interactive if the `-i' flag was given, or if all of
-        * the following conditions are met:
-        *        no -c command
-        *    no arguments remaining or the -s flag given
-        *    standard input is a terminal
-        *    standard output is a terminal
-        *    Refer to Posix.2, the description of the `sh' utility. */
-       if (argv[optind]==NULL && input==stdin &&
-                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
-               interactive=TRUE;
-       }
-       setup_job_control();
-       if (interactive==TRUE) {
-               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
-               /* Looks like they want an interactive shell */
-               printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
-               printf( "Enter 'help' for a list of built-in commands.\n\n");
-       } else if (local_pending_command==NULL) {
-               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
-               input = xfopen(argv[optind], "r");
-               mark_open(fileno(input));  /* be lazy, never mark this closed */
-       }
-
-       /* initialize the cwd -- this is never freed...*/
-       cwd = xgetcwd(0);
-       if (!cwd)
-               cwd = unknown;
-
-#ifdef BB_FEATURE_CLEAN_UP
-       atexit(free_memory);
-#endif
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-       cmdedit_set_initial_prompt();
-#else
-       PS1 = NULL;
-#endif
-       
-       return (busy_loop(input));
-}
diff --git a/busybox/length.c b/busybox/length.c
deleted file mode 100644 (file)
index 73becd2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "busybox.h"
-
-extern int length_main(int argc, char **argv)
-{
-       if (argc != 2 || **(argv + 1) == '-')
-               show_usage();
-       printf("%lu\n", (long)strlen(argv[1]));
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/libbb/.cvsignore b/busybox/libbb/.cvsignore
deleted file mode 100644 (file)
index 2bbe016..0000000
+++ /dev/null
@@ -1 +0,0 @@
-loop.h
diff --git a/busybox/libbb/Makefile b/busybox/libbb/Makefile
deleted file mode 100644 (file)
index a9ea769..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Silly wrapper makefile.  This Makefile is _not_ used by the build system for
-# busybox, it is just to make working on libbb more conveinient.
-#  -Erik Andersen
-
-all:
-       make -C .. libbb.a
-
-clean:
-       - rm -rf libbb.a
-       - find -name \*.o -exec rm -f {} \;
-
diff --git a/busybox/libbb/README b/busybox/libbb/README
deleted file mode 100644 (file)
index 0e36f84..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Please see the LICENSE file for copyright information.
-    
-libbb is BusyBox's utility library.  This all used to be in a single file
-(utility.c to be specific).  When I split utility.c up to create libbb, I did
-not carefully fix up the copyright and licensing information.  I'll do that for
-the next release.
-
-For now, justtrust me that a bunch of people have worked on this stuff, 
-and it is all GPL'ed.
-
-       Erik Andersen 
-       <andersen@lineo.com>
-       <andersee@debian.org>
-       <andersee@codepoet.org>
-
diff --git a/busybox/libbb/arith.c b/busybox/libbb/arith.c
deleted file mode 100644 (file)
index 04c45ec..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
-   
-   Permission is hereby granted, free of charge, to any person obtaining
-   a copy of this software and associated documentation files (the
-   "Software"), to deal in the Software without restriction, including
-   without limitation the rights to use, copy, modify, merge, publish,
-   distribute, sublicense, and/or sell copies of the Software, and to
-   permit persons to whom the Software is furnished to do so, subject to
-   the following conditions:
-   
-   The above copyright notice and this permission notice shall be
-   included in all copies or substantial portions of the Software.
-   
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/* This is my infix parser/evaluator. It is optimized for size, intended
- * as a replacement for yacc-based parsers. However, it may well be faster
- * than a comparable parser writen in yacc. The supported operators are
- * listed in #defines below. Parens, order of operations, and error handling
- * are supported. This code is threadsafe. */
-
-/* To use the routine, call it with an expression string. It returns an
- * integer result. You will also need to define an "error" function
- * that takes printf arguments and _does not return_, or modify the code
- * to use another error mechanism. */
-
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-typedef char operator;
-
-#define tok_decl(prec,id) (((id)<<5)|(prec))
-#define PREC(op) ((op)&0x1F)
-
-#define TOK_LPAREN tok_decl(0,0)
-
-#define TOK_OR tok_decl(1,0)
-
-#define TOK_AND tok_decl(2,0)
-
-#define TOK_BOR tok_decl(3,0)
-
-#define TOK_BXOR tok_decl(4,0)
-
-#define TOK_BAND tok_decl(5,0)
-
-#define TOK_EQ tok_decl(6,0)
-#define TOK_NE tok_decl(6,1)
-
-#define TOK_LT tok_decl(7,0)
-#define TOK_GT tok_decl(7,1)
-#define TOK_GE tok_decl(7,2)
-#define TOK_LE tok_decl(7,3)
-
-#define TOK_LSHIFT tok_decl(8,0)
-#define TOK_RSHIFT tok_decl(8,1)
-
-#define TOK_ADD tok_decl(9,0)
-#define TOK_SUB tok_decl(9,1)
-
-#define TOK_MUL tok_decl(10,0)
-#define TOK_DIV tok_decl(10,1)
-#define TOK_REM tok_decl(10,2)
-
-#define UNARYPREC 14
-#define TOK_BNOT tok_decl(UNARYPREC,0)
-#define TOK_NOT tok_decl(UNARYPREC,1)
-#define TOK_UMINUS tok_decl(UNARYPREC,2)
-
-#define TOK_NUM tok_decl(15,0)
-
-#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr)
-#define NUMPTR (*numstackptr)
-static short arith_apply(operator op, long *numstack, long **numstackptr)
-{
-       if (NUMPTR == numstack) goto err;
-       if (op == TOK_UMINUS)
-               NUMPTR[-1] *= -1;
-       else if (op == TOK_NOT)
-               NUMPTR[-1] = !(NUMPTR[-1]);
-       else if (op == TOK_BNOT)
-               NUMPTR[-1] = ~(NUMPTR[-1]);
-
-       /* Binary operators */
-       else {
-       if (NUMPTR-1 == numstack) goto err;
-       --NUMPTR;
-       if (op == TOK_BOR)
-               NUMPTR[-1] |= *NUMPTR;
-       else if (op == TOK_OR)
-               NUMPTR[-1] = *NUMPTR || NUMPTR[-1];
-       else if (op == TOK_BAND)
-               NUMPTR[-1] &= *NUMPTR;
-       else if (op == TOK_AND)
-               NUMPTR[-1] = NUMPTR[-1] && *NUMPTR;
-       else if (op == TOK_EQ)
-               NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR);
-       else if (op == TOK_NE)
-               NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR);
-       else if (op == TOK_GE)
-               NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR);
-       else if (op == TOK_RSHIFT)
-               NUMPTR[-1] >>= *NUMPTR;
-       else if (op == TOK_LSHIFT)
-               NUMPTR[-1] <<= *NUMPTR;
-       else if (op == TOK_GT)
-               NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR);
-       else if (op == TOK_LT)
-               NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR);
-       else if (op == TOK_LE)
-               NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR);
-       else if (op == TOK_MUL)
-               NUMPTR[-1] *= *NUMPTR;
-       else if (op == TOK_DIV) {
-               if(*NUMPTR==0)
-                       return -2;
-               NUMPTR[-1] /= *NUMPTR;
-               }
-       else if (op == TOK_REM) {
-               if(*NUMPTR==0)
-                       return -2;
-               NUMPTR[-1] %= *NUMPTR;
-               }
-       else if (op == TOK_ADD)
-               NUMPTR[-1] += *NUMPTR;
-       else if (op == TOK_SUB)
-               NUMPTR[-1] -= *NUMPTR;
-       }
-       return 0;
-err: return(-1);
-}
-
-extern long arith (const char *startbuf, int *errcode)
-{
-       register char arithval;
-       const char *expr = startbuf;
-
-       operator lasttok = TOK_MUL, op;
-       size_t datasizes = strlen(startbuf);
-       unsigned char prec;
-
-       long *numstack, *numstackptr;
-       operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack;
-
-       *errcode = 0;
-       numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack;
-
-       while ((arithval = *expr)) {
-               if (arithval == ' ' || arithval == '\n' || arithval == '\t')
-                       goto prologue;
-               if ((unsigned)arithval-'0' <= 9) /* isdigit */ {
-                       *numstackptr++ = strtol(expr, (char **) &expr, 10);
-                       lasttok = TOK_NUM;
-                       continue;
-               } if (arithval == '(') {
-                       *stackptr++ = TOK_LPAREN;
-                       lasttok = TOK_LPAREN;
-                       goto prologue;
-               } if (arithval == ')') {
-                       lasttok = TOK_NUM;
-                       while (stackptr != stack) {
-                               op = *--stackptr;
-                               if (op == TOK_LPAREN)
-                                       goto prologue;
-                               *errcode = ARITH_APPLY(op);
-                               if(*errcode) return *errcode;
-                       }
-                       goto err; /* Mismatched parens */
-               } if (arithval == '|') {
-                       if (*++expr == '|')
-                               op = TOK_OR;
-                       else {
-                               --expr;
-                               op = TOK_BOR;
-                       }
-               } else if (arithval == '&') {
-                       if (*++expr == '&')
-                               op = TOK_AND;
-                       else {
-                               --expr;
-                               op = TOK_BAND;
-                       }
-               } else if (arithval == '=') {
-                       if (*++expr != '=') goto err; /* Unknown token */
-                       op = TOK_EQ;
-               } else if (arithval == '!') {
-                       if (*++expr == '=')
-                               op = TOK_NE;
-                       else {
-                               --expr;
-                               op = TOK_NOT;
-                       }
-               } else if (arithval == '>') {
-                       switch (*++expr) {
-                               case '=':
-                                       op = TOK_GE;
-                                       break;
-                               case '>':
-                                       op = TOK_RSHIFT;
-                                       break;
-                               default:
-                                       --expr;
-                                       op = TOK_GT;
-                       }
-               } else if (arithval == '<') {
-                       switch (*++expr) {
-                               case '=':
-                                       op = TOK_LE;
-                                       break;
-                               case '<':
-                                       op = TOK_LSHIFT;
-                                       break;
-                               default:
-                                       --expr;
-                                       op = TOK_LT;
-                       }
-               } else if (arithval == '*')
-                       op = TOK_MUL;
-               else if (arithval == '/')
-                       op = TOK_DIV;
-               else if (arithval == '%')
-                       op = TOK_REM;
-               else if (arithval == '+') {
-                       if (lasttok != TOK_NUM) goto prologue; /* Unary plus */
-                       op = TOK_ADD;
-               } else if (arithval == '-')
-                       op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS;
-               else if (arithval == '~')
-                       op = TOK_BNOT;
-               else goto err; /* Unknown token */
-
-               prec = PREC(op);
-               if (prec != UNARYPREC)
-                       while (stackptr != stack && PREC(stackptr[-1]) >= prec) {
-                               *errcode = ARITH_APPLY(*--stackptr);
-                               if(*errcode) return *errcode;
-                       }
-               *stackptr++ = op;
-               lasttok = op;
-prologue: ++expr;
-       } /* yay */
-
-       while (stackptr != stack) {
-               *errcode = ARITH_APPLY(*--stackptr);
-               if(*errcode) return *errcode;
-       }
-       if (numstackptr != numstack+1) {
-err: 
-           *errcode = -1;
-           return -1;
-        /* NOTREACHED */
-       }
-
-       return *numstack;
-}
diff --git a/busybox/libbb/ask_confirmation.c b/busybox/libbb/ask_confirmation.c
deleted file mode 100644 (file)
index f292237..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include "libbb.h"
-
-
-int ask_confirmation()
-{
-       int c = '\0';
-       int ret = 0;
-
-       while (c != '\n') {
-               c = getchar();
-               if ( c != '\n' ) {
-                       ret = ((c=='y')||(c=='Y')) ? 1 : 0;
-               }
-       }
-       return ret;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/chomp.c b/busybox/libbb/chomp.c
deleted file mode 100644 (file)
index 111d4cf..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "libbb.h"
-
-
-void chomp(char *s)
-{
-       char *lc = last_char_is(s, '\n');
-       
-       if(lc)
-               *lc = 0;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/concat_path_file.c b/busybox/libbb/concat_path_file.c
deleted file mode 100644 (file)
index 86dd2fb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * busybox library eXtendet funcion
- *
- * concatenate path and file name to new allocation buffer,
- * not addition '/' if path name already have '/'
- *
-*/
-
-#include <string.h>
-#include "libbb.h"
-
-extern char *concat_path_file(const char *path, const char *filename)
-{
-       char *outbuf;
-       char *lc;
-
-       if (!path)
-           path="";
-       lc = last_char_is(path, '/');
-       while (*filename == '/')
-               filename++;
-       outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
-       sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
-
-       return outbuf;
-}
diff --git a/busybox/libbb/copy_file.c b/busybox/libbb/copy_file.c
deleted file mode 100644 (file)
index c79fbeb..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini copy_file implementation for busybox
- *
- *
- * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "libbb.h"
-
-int copy_file(const char *source, const char *dest, int flags)
-{
-       struct stat source_stat;
-       struct stat dest_stat;
-       int dest_exists = 1;
-       int status = 0;
-
-       if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                       lstat(source, &source_stat) < 0) ||
-                       (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
-                        stat(source, &source_stat) < 0)) {
-               perror_msg("%s", source);
-               return -1;
-       }
-
-       if (stat(dest, &dest_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", dest);
-                       return -1;
-               }
-               dest_exists = 0;
-       }
-
-       if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev &&
-                       source_stat.st_ino == dest_stat.st_ino) {
-               error_msg("`%s' and `%s' are the same file", source, dest);
-               return -1;
-       }
-
-       if (S_ISDIR(source_stat.st_mode)) {
-               DIR *dp;
-               struct dirent *d;
-               mode_t saved_umask = 0;
-
-               if (!(flags & FILEUTILS_RECUR)) {
-                       error_msg("%s: omitting directory", source);
-                       return -1;
-               }
-
-               /* Create DEST.  */
-               if (dest_exists) {
-                       if (!S_ISDIR(dest_stat.st_mode)) {
-                               error_msg("`%s' is not a directory", dest);
-                               return -1;
-                       }
-               } else {
-                       mode_t mode;
-                       saved_umask = umask(0);
-
-                       mode = source_stat.st_mode;
-                       if (!(flags & FILEUTILS_PRESERVE_STATUS))
-                               mode = source_stat.st_mode & ~saved_umask;
-                       mode |= S_IRWXU;
-
-                       if (mkdir(dest, mode) < 0) {
-                               umask(saved_umask);
-                               perror_msg("cannot create directory `%s'", dest);
-                               return -1;
-                       }
-
-                       umask(saved_umask);
-               }
-
-               /* Recursively copy files in SOURCE.  */
-               if ((dp = opendir(source)) == NULL) {
-                       perror_msg("unable to open directory `%s'", source);
-                       status = -1;
-                       goto end;
-               }
-
-               while ((d = readdir(dp)) != NULL) {
-                       char *new_source, *new_dest;
-
-                       if (strcmp(d->d_name, ".") == 0 ||
-                                       strcmp(d->d_name, "..") == 0)
-                               continue;
-
-                       new_source = concat_path_file(source, d->d_name);
-                       new_dest = concat_path_file(dest, d->d_name);
-                       if (copy_file(new_source, new_dest, flags) < 0)
-                               status = -1;
-                       free(new_source);
-                       free(new_dest);
-               }
-
-               /* ??? What if an error occurs in readdir?  */
-
-               if (closedir(dp) < 0) {
-                       perror_msg("unable to close directory `%s'", source);
-                       status = -1;
-               }
-
-               if (!dest_exists &&
-                               chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
-                       perror_msg("unable to change permissions of `%s'", dest);
-                       status = -1;
-               }
-       } else if (S_ISREG(source_stat.st_mode)) {
-               FILE *sfp, *dfp;
-
-               if (dest_exists) {
-                       if (flags & FILEUTILS_INTERACTIVE) {
-                               fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest);
-                               if (!ask_confirmation())
-                                       return 0;
-                       }
-
-                       if ((dfp = fopen(dest, "w")) == NULL) {
-                               if (!(flags & FILEUTILS_FORCE)) {
-                                       perror_msg("unable to open `%s'", dest);
-                                       return -1;
-                               }
-
-                               if (unlink(dest) < 0) {
-                                       perror_msg("unable to remove `%s'", dest);
-                                       return -1;
-                               }
-
-                               dest_exists = 0;
-                       }
-               }
-
-               if (!dest_exists) {
-                       int fd;
-
-                       if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
-                                       (dfp = fdopen(fd, "w")) == NULL) {
-                               if (fd >= 0)
-                                       close(fd);
-                               perror_msg("unable to open `%s'", dest);
-                               return -1;
-                       }
-               }
-
-               if ((sfp = fopen(source, "r")) == NULL) {
-                       fclose(dfp);
-                       perror_msg("unable to open `%s'", source);
-                       status = -1;
-                       goto end;
-               }
-
-               if (copy_file_chunk(sfp, dfp, -1) < 0)
-                       status = -1;
-
-               if (fclose(dfp) < 0) {
-                       perror_msg("unable to close `%s'", dest);
-                       status = -1;
-               }
-
-               if (fclose(sfp) < 0) {
-                       perror_msg("unable to close `%s'", source);
-                       status = -1;
-               }
-       } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
-                       S_ISSOCK(source_stat.st_mode)) {
-               if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
-                       perror_msg("unable to create `%s'", dest);
-                       return -1;
-               }
-       } else if (S_ISFIFO(source_stat.st_mode)) {
-               if (mkfifo(dest, source_stat.st_mode) < 0) {
-                       perror_msg("cannot create fifo `%s'", dest);
-                       return -1;
-               }
-       } else if (S_ISLNK(source_stat.st_mode)) {
-               char *lpath = xreadlink(source);
-               if (symlink(lpath, dest) < 0) {
-                       perror_msg("cannot create symlink `%s'", dest);
-                       return -1;
-               }
-               free(lpath);
-
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-               if (flags & FILEUTILS_PRESERVE_STATUS)
-                       if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
-                               perror_msg("unable to preserve ownership of `%s'", dest);
-#endif
-               return 0;
-       } else {
-               error_msg("internal error: unrecognized file type");
-               return -1;
-       }
-
-end:
-
-       if (flags & FILEUTILS_PRESERVE_STATUS) {
-               struct utimbuf times;
-
-               times.actime = source_stat.st_atime;
-               times.modtime = source_stat.st_mtime;
-               if (utime(dest, &times) < 0)
-                       perror_msg("unable to preserve times of `%s'", dest);
-               if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
-                       source_stat.st_mode &= ~(S_ISUID | S_ISGID);
-                       perror_msg("unable to preserve ownership of `%s'", dest);
-               }
-               if (chmod(dest, source_stat.st_mode) < 0)
-                       perror_msg("unable to preserve permissions of `%s'", dest);
-       }
-
-       return status;
-}
diff --git a/busybox/libbb/copy_file_chunk.c b/busybox/libbb/copy_file_chunk.c
deleted file mode 100644 (file)
index c440a61..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include "libbb.h"
-
-/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE
- * to DST_FILE.  */
-extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize)
-{
-       size_t nread, nwritten, size;
-       char buffer[BUFSIZ];
-
-       while (chunksize != 0) {
-               if (chunksize > BUFSIZ)
-                       size = BUFSIZ;
-               else
-                       size = chunksize;
-
-               nread = fread (buffer, 1, size, src_file);
-
-               if (nread != size && ferror (src_file)) {
-                       perror_msg ("read");
-                       return -1;
-               } else if (nread == 0) {
-                       if (chunksize != -1) {
-                               error_msg ("Unable to read all data");
-                               return -1;
-                       }
-
-                       return 0;
-               }
-
-               nwritten = fwrite (buffer, 1, nread, dst_file);
-
-               if (nwritten != nread) {
-                       if (ferror (dst_file))
-                               perror_msg ("write");
-                       else
-                               error_msg ("Unable to write all data");
-                       return -1;
-               }
-
-               if (chunksize != -1)
-                       chunksize -= nwritten;
-       }
-
-       return 0;
-}
diff --git a/busybox/libbb/copyfd.c b/busybox/libbb/copyfd.c
deleted file mode 100644 (file)
index aa938d1..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include "libbb.h"
-
-
-extern int copyfd(int fd1, int fd2)
-{
-       char buf[8192];
-       ssize_t nread, nwrote;
-
-       while (1) {
-               nread = safe_read(fd1, buf, sizeof(buf));
-               if (nread == 0)
-                       break;
-               if (nread == -1) {
-                       perror_msg("read");
-                       return -1;
-               }
-
-               nwrote = full_write(fd2, buf, nread);
-               if (nwrote == -1) {
-                       perror_msg("write");
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/create_icmp_socket.c b/busybox/libbb/create_icmp_socket.c
deleted file mode 100644 (file)
index d804b39..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * create raw socket for icmp protocol test permision
- * and drop root privilegies if running setuid
- *
- */
-
-#include <sys/types.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <unistd.h>
-#include "libbb.h"
-
-int create_icmp_socket(void)
-{
-       struct protoent *proto;
-       int sock;
-
-       proto = getprotobyname("icmp");
-       /* if getprotobyname failed, just silently force
-        * proto->p_proto to have the correct value for "icmp" */
-       if ((sock = socket(AF_INET, SOCK_RAW,
-                       (proto ? proto->p_proto : 1))) < 0) {        /* 1 == ICMP */
-               if (errno == EPERM)
-                       error_msg_and_die("permission denied. (are you root?)");
-               else
-                       perror_msg_and_die(can_not_create_raw_socket);
-       }
-
-       /* drop root privs if running setuid */
-       setuid(getuid());
-
-       return sock;
-}
diff --git a/busybox/libbb/device_open.c b/busybox/libbb/device_open.c
deleted file mode 100644 (file)
index 8e97ce6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include "libbb.h"
-
-
-/* try to open up the specified device */
-extern int device_open(char *device, int mode)
-{
-       int m, f, fd = -1;
-
-       m = mode | O_NONBLOCK;
-
-       /* Retry up to 5 times */
-       for (f = 0; f < 5; f++)
-               if ((fd = open(device, m, 0600)) >= 0)
-                       break;
-       if (fd < 0)
-               return fd;
-       /* Reset original flags. */
-       if (m != mode)
-               fcntl(fd, F_SETFL, mode);
-       return fd;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/dirname.c b/busybox/libbb/dirname.c
deleted file mode 100644 (file)
index df9a49d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dirname function.
- *
- * Copyright (C) 2001  Matt Kraai.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <string.h>
-#include "libbb.h"
-
-#if defined __UCLIBC__ || __GNU_LIBRARY___ < 5
-
-/* Return a string containing the path name of the parent
- * directory of PATH.  */
-
-char *dirname(char *path)
-{
-       char *s;
-
-       /* Go to the end of the string.  */
-       s = path + strlen(path) - 1;
-
-       /* Strip off trailing /s (unless it is also the leading /).  */
-       while (path < s && s[0] == '/')
-               s--;
-
-       /* Strip the last component.  */
-       while (path <= s && s[0] != '/')
-               s--;
-
-       while (path < s && s[0] == '/')
-               s--;
-
-       if (s < path)
-               return ".";
-
-       s[1] = '\0';
-       return path;
-}
-
-#endif
diff --git a/busybox/libbb/error_msg.c b/busybox/libbb/error_msg.c
deleted file mode 100644 (file)
index c7d5fdb..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void error_msg(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       verror_msg(s, p);
-       va_end(p);
-       putc('\n', stderr);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/error_msg_and_die.c b/busybox/libbb/error_msg_and_die.c
deleted file mode 100644 (file)
index b950ee0..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void error_msg_and_die(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       verror_msg(s, p);
-       va_end(p);
-       putc('\n', stderr);
-       exit(EXIT_FAILURE);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/fgets_str.c b/busybox/libbb/fgets_str.c
deleted file mode 100644 (file)
index 33d8d00..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Continue reading from file until the terminating string is encountered.
- * Return data as string.
- * e.g. fgets_str(file, "\n"); will read till end of file
- */
-
-char *fgets_str(FILE *file, const char *terminating_string)
-{
-       char *linebuf = NULL;
-       const int term_length = strlen(terminating_string);
-       int end_string_offset;
-       int linebufsz = 0;
-       int idx = 0;
-       int ch;
-
-       while (1) {
-               ch = fgetc(file);
-               if (ch == EOF) {
-                       break;
-               }
-
-               /* grow the line buffer as necessary */
-               while (idx > linebufsz - 2) {
-                       linebuf = realloc(linebuf, linebufsz += 1000); /* GROWBY */
-               }
-
-               linebuf[idx] = ch;
-               idx++;
-
-               /* Check for terminating string */
-               end_string_offset = idx - term_length;
-               if ((end_string_offset > 0) && (memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0)) {
-                       idx -= term_length;
-                       break;
-               }
-       }
-       if (idx == 0) {
-               return NULL;
-       }
-       linebuf[idx] = '\0';
-       return(linebuf);
-}
-
diff --git a/busybox/libbb/find_mount_point.c b/busybox/libbb/find_mount_point.c
deleted file mode 100644 (file)
index 2d9481a..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "libbb.h"
-
-
-#include <mntent.h>
-/*
- * Given a block device, find the mount table entry if that block device
- * is mounted.
- *
- * Given any other file (or directory), find the mount table entry for its
- * filesystem.
- */
-extern struct mntent *find_mount_point(const char *name, const char *table)
-{
-       struct stat s;
-       dev_t mountDevice;
-       FILE *mountTable;
-       struct mntent *mountEntry;
-
-       if (stat(name, &s) != 0)
-               return 0;
-
-       if ((s.st_mode & S_IFMT) == S_IFBLK)
-               mountDevice = s.st_rdev;
-       else
-               mountDevice = s.st_dev;
-
-
-       if ((mountTable = setmntent(table, "r")) == 0)
-               return 0;
-
-       while ((mountEntry = getmntent(mountTable)) != 0) {
-               if (strcmp(name, mountEntry->mnt_dir) == 0
-                       || strcmp(name, mountEntry->mnt_fsname) == 0)   /* String match. */
-                       break;
-               if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice)  /* Match the device. */
-                       break;
-               if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice)      /* Match the directory's mount point. */
-                       break;
-       }
-       endmntent(mountTable);
-       return mountEntry;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/find_pid_by_name.c b/busybox/libbb/find_pid_by_name.c
deleted file mode 100644 (file)
index 7f39dd4..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-#define READ_BUF_SIZE  50
-
-
-/* For Erik's nifty devps device driver */
-#ifdef BB_FEATURE_USE_DEVPS_PATCH
-#include <linux/devps.h> 
-
-/* find_pid_by_name()
- *  
- *  This finds the pid of the specified process,
- *  by using the /dev/ps device driver.
- *
- *  Returns a list of all matching PIDs
- */
-extern pid_t* find_pid_by_name( char* pidName)
-{
-       int fd, i, j;
-       char device[] = "/dev/ps";
-       pid_t num_pids;
-       pid_t* pid_array = NULL;
-       pid_t* pidList=NULL;
-
-       /* open device */ 
-       fd = open(device, O_RDONLY);
-       if (fd < 0)
-               perror_msg_and_die("open failed for `%s'", device);
-
-       /* Find out how many processes there are */
-       if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
-               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-       
-       /* Allocate some memory -- grab a few extras just in case 
-        * some new processes start up while we wait. The kernel will
-        * just ignore any extras if we give it too many, and will trunc.
-        * the list if we give it too few.  */
-       pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
-       pid_array[0] = num_pids+10;
-
-       /* Now grab the pid list */
-       if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
-               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-
-       /* Now search for a match */
-       for (i=1, j=0; i<pid_array[0] ; i++) {
-               char* p;
-               struct pid_info info;
-
-           info.pid = pid_array[i];
-           if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
-                       perror_msg_and_die("\nDEVPS_GET_PID_INFO");
-
-               /* Make sure we only match on the process name */
-               p=info.command_line+1;
-               while ((*p != 0) && !isspace(*(p)) && (*(p-1) != '\\')) { 
-                       (p)++;
-               }
-               if (isspace(*(p)))
-                               *p='\0';
-
-               if ((strstr(info.command_line, pidName) != NULL)
-                               && (strlen(pidName) == strlen(info.command_line))) {
-                       pidList=xrealloc( pidList, sizeof(pid_t) * (j+2));
-                       pidList[j++]=info.pid;
-               }
-       }
-       if (pidList) {
-               pidList[j]=0;
-       } else if ( strcmp(pidName, "init")==0) {
-               /* If we found nothing and they were trying to kill "init", 
-                * guess PID 1 and call it good...  Perhaps we should simply
-                * exit if /proc isn't mounted, but this will do for now. */
-               pidList=xrealloc( pidList, sizeof(pid_t));
-               pidList[0]=1;
-       } else {
-               pidList=xrealloc( pidList, sizeof(pid_t));
-               pidList[0]=-1;
-       }
-
-       /* Free memory */
-       free( pid_array);
-
-       /* close device */
-       if (close (fd) != 0) 
-               perror_msg_and_die("close failed for `%s'", device);
-
-       return pidList;
-}
-
-#else          /* BB_FEATURE_USE_DEVPS_PATCH */
-
-/* find_pid_by_name()
- *  
- *  This finds the pid of the specified process.
- *  Currently, it's implemented by rummaging through 
- *  the proc filesystem.
- *
- *  Returns a list of all matching PIDs
- */
-extern pid_t* find_pid_by_name( char* pidName)
-{
-       DIR *dir;
-       struct dirent *next;
-       pid_t* pidList=NULL;
-       int i=0;
-
-       dir = opendir("/proc");
-       if (!dir)
-               perror_msg_and_die("Cannot open /proc");
-       
-       while ((next = readdir(dir)) != NULL) {
-               FILE *status;
-               char filename[READ_BUF_SIZE];
-               char buffer[READ_BUF_SIZE];
-               char name[READ_BUF_SIZE];
-
-               /* Must skip ".." since that is outside /proc */
-               if (strcmp(next->d_name, "..") == 0)
-                       continue;
-
-               /* If it isn't a number, we don't want it */
-               if (!isdigit(*next->d_name))
-                       continue;
-
-               sprintf(filename, "/proc/%s/status", next->d_name);
-               if (! (status = fopen(filename, "r")) ) {
-                       continue;
-               }
-               if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) {
-                       fclose(status);
-                       continue;
-               }
-               fclose(status);
-
-               /* Buffer should contain a string like "Name:   binary_name" */
-               sscanf(buffer, "%*s %s", name);
-               if (strcmp(name, pidName) == 0) {
-                       pidList=xrealloc( pidList, sizeof(pid_t) * (i+2));
-                       pidList[i++]=strtol(next->d_name, NULL, 0);
-               }
-       }
-
-       if (pidList)
-               pidList[i]=0;
-       else if ( strcmp(pidName, "init")==0) {
-               /* If we found nothing and they were trying to kill "init", 
-                * guess PID 1 and call it good...  Perhaps we should simply
-                * exit if /proc isn't mounted, but this will do for now. */
-               pidList=xrealloc( pidList, sizeof(pid_t));
-               pidList[0]=1;
-       } else {
-               pidList=xrealloc( pidList, sizeof(pid_t));
-               pidList[0]=-1;
-       }
-       return pidList;
-}
-#endif                                                 /* BB_FEATURE_USE_DEVPS_PATCH */
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/find_root_device.c b/busybox/libbb/find_root_device.c
deleted file mode 100644 (file)
index f8f6846..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Copyright (C) 2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Patched by a bunch of people.  Feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-
-
-extern char *find_real_root_device_name(const char* name)
-{
-       DIR *dir;
-       struct dirent *entry;
-       struct stat statBuf, rootStat;
-       char *fileName = NULL;
-       dev_t dev;
-
-       if (stat("/", &rootStat) != 0) 
-               perror_msg("could not stat '/'");
-       else {
-               if ((dev = rootStat.st_rdev)==0) 
-                       dev=rootStat.st_dev;
-
-               dir = opendir("/dev");
-               if (!dir) 
-                       perror_msg("could not open '/dev'");
-               else {
-                       while((entry = readdir(dir)) != NULL) {
-
-                               /* Must skip ".." since that is "/", and so we 
-                                * would get a false positive on ".."  */
-                               if (strcmp(entry->d_name, "..") == 0)
-                                       continue;
-
-                               fileName = concat_path_file("/dev", entry->d_name);
-
-                               /* Some char devices have the same dev_t as block
-                                * devices, so make sure this is a block device */
-                               if (stat(fileName, &statBuf) == 0 && 
-                                               S_ISBLK(statBuf.st_mode)!=0 &&
-                                               statBuf.st_rdev == dev) 
-                                       break;
-                               free(fileName);
-                               fileName=NULL;
-                       }
-                       closedir(dir);
-               }
-       }
-       if(fileName==NULL)
-               fileName=xstrdup("/dev/root");
-       return fileName;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/full_read.c b/busybox/libbb/full_read.c
deleted file mode 100644 (file)
index e9c4bbf..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include "libbb.h"
-
-
-/*
- * Read all of the supplied buffer from a file.
- * This does multiple reads as necessary.
- * Returns the amount read, or -1 on an error.
- * A short read is returned on an end of file.
- */
-int full_read(int fd, char *buf, int len)
-{
-       int cc;
-       int total;
-
-       total = 0;
-
-       while (len > 0) {
-               cc = read(fd, buf, len);
-
-               if (cc < 0)
-                       return -1;
-
-               if (cc == 0)
-                       break;
-
-               buf += cc;
-               total += cc;
-               len -= cc;
-       }
-
-       return total;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/full_write.c b/busybox/libbb/full_write.c
deleted file mode 100644 (file)
index dc9937f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include "libbb.h"
-
-/*
- * Write all of the supplied buffer out to a file.
- * This does multiple writes as necessary.
- * Returns the amount written, or -1 on an error.
- */
-int full_write(int fd, const char *buf, int len)
-{
-       int cc;
-       int total;
-
-       total = 0;
-
-       while (len > 0) {
-               cc = write(fd, buf, len);
-
-               if (cc < 0)
-                       return -1;
-
-               buf += cc;
-               total += cc;
-               len -= cc;
-       }
-
-       return total;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/get_console.c b/busybox/libbb/get_console.c
deleted file mode 100644 (file)
index 3b36a59..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "libbb.h"
-
-
-
-
-
-/* From <linux/kd.h> */ 
-static const int KDGKBTYPE = 0x4B33;  /* get keyboard type */
-static const int KB_84 = 0x01;
-static const int KB_101 = 0x02;    /* this is what we always answer */
-
-int is_a_console(int fd)
-{
-       char arg;
-
-       arg = 0;
-       return (ioctl(fd, KDGKBTYPE, &arg) == 0
-                       && ((arg == KB_101) || (arg == KB_84)));
-}
-
-static int open_a_console(char *fnam)
-{
-       int fd;
-
-       /* try read-only */
-       fd = open(fnam, O_RDWR);
-
-       /* if failed, try read-only */
-       if (fd < 0 && errno == EACCES)
-               fd = open(fnam, O_RDONLY);
-
-       /* if failed, try write-only */
-       if (fd < 0 && errno == EACCES)
-               fd = open(fnam, O_WRONLY);
-
-       /* if failed, fail */
-       if (fd < 0)
-               return -1;
-
-       /* if not a console, fail */
-       if (!is_a_console(fd)) {
-               close(fd);
-               return -1;
-       }
-
-       /* success */
-       return fd;
-}
-
-/*
- * Get an fd for use with kbd/console ioctls.
- * We try several things because opening /dev/console will fail
- * if someone else used X (which does a chown on /dev/console).
- *
- * if tty_name is non-NULL, try this one instead.
- */
-
-int get_console_fd(char *tty_name)
-{
-       int fd;
-
-       if (tty_name) {
-               if (-1 == (fd = open_a_console(tty_name)))
-                       return -1;
-               else
-                       return fd;
-       }
-
-       fd = open_a_console(CURRENT_TTY);
-       if (fd >= 0)
-               return fd;
-
-       fd = open_a_console(CURRENT_VC);
-       if (fd >= 0)
-               return fd;
-
-       fd = open_a_console(CONSOLE_DEV);
-       if (fd >= 0)
-               return fd;
-
-       for (fd = 0; fd < 3; fd++)
-               if (is_a_console(fd))
-                       return fd;
-
-       error_msg("Couldn't get a file descriptor referring to the console");
-       return -1;                                      /* total failure */
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/get_last_path_component.c b/busybox/libbb/get_last_path_component.c
deleted file mode 100644 (file)
index f1ddfbd..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "libbb.h"
-
-
-char *get_last_path_component(char *path)
-{
-       char *s;
-       register char *ptr = path;
-       register char *prev = 0;
-
-       while (*ptr)
-               ptr++;
-       s = ptr - 1;
-
-       /* strip trailing slashes */
-       while (s != path && *s == '/') {
-               *s-- = '\0';
-       }
-
-       /* find last component */
-       ptr = path;
-       while (*ptr != '\0') {
-               if (*ptr == '/')
-                       prev = ptr;
-               ptr++;
-       }
-       s = prev;
-
-       if (s == NULL || s[1] == '\0')
-               return path;
-       else
-               return s+1;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/get_line_from_file.c b/busybox/libbb/get_line_from_file.c
deleted file mode 100644 (file)
index 7594817..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include "libbb.h"
-
-
-
-/* get_line_from_file() - This function reads an entire line from a text file
- * up to a newline. It returns a malloc'ed char * which must be stored and
- * free'ed  by the caller. */
-extern char *get_line_from_file(FILE *file)
-{
-       static const int GROWBY = 80; /* how large we will grow strings by */
-
-       int ch;
-       int idx = 0;
-       char *linebuf = NULL;
-       int linebufsz = 0;
-
-       while (1) {
-               ch = fgetc(file);
-               if (ch == EOF)
-                       break;
-               /* grow the line buffer as necessary */
-               while (idx > linebufsz-2)
-                       linebuf = xrealloc(linebuf, linebufsz += GROWBY);
-               linebuf[idx++] = (char)ch;
-               if ((char)ch == '\n')
-                       break;
-       }
-
-       if (idx == 0)
-               return NULL;
-
-       linebuf[idx] = 0;
-       return linebuf;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/gz_open.c b/busybox/libbb/gz_open.c
deleted file mode 100644 (file)
index ef30ff8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "libbb.h"
-
-extern FILE *gz_open(FILE *compressed_file, int *pid)
-{
-       int unzip_pipe[2];
-
-       if (pipe(unzip_pipe)!=0) {
-               error_msg("pipe error");
-               return(NULL);
-       }
-       if ((*pid = fork()) == -1) {
-               error_msg("fork failed");
-               return(NULL);
-       }
-       if (*pid==0) {
-               /* child process */
-               close(unzip_pipe[0]);
-               unzip(compressed_file, fdopen(unzip_pipe[1], "w"));
-               fflush(NULL);
-               fclose(compressed_file);
-               close(unzip_pipe[1]);
-               exit(EXIT_SUCCESS);
-       }
-       close(unzip_pipe[1]);
-       if (unzip_pipe[0] == -1) {
-               error_msg("gzip stream init failed");
-       }
-       return(fdopen(unzip_pipe[0], "r"));
-}
diff --git a/busybox/libbb/herror_msg.c b/busybox/libbb/herror_msg.c
deleted file mode 100644 (file)
index f4210ed..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include "libbb.h"
-
-extern void herror_msg(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       vherror_msg(s, p);
-       va_end(p);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/herror_msg_and_die.c b/busybox/libbb/herror_msg_and_die.c
deleted file mode 100644 (file)
index 0df5ed0..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include "libbb.h"
-
-extern void herror_msg_and_die(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       vherror_msg(s, p);
-       va_end(p);
-       exit(EXIT_FAILURE);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/human_readable.c b/busybox/libbb/human_readable.c
deleted file mode 100644 (file)
index 7bdad36..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * June 30, 2001                 Manuel Novoa III
- *
- * All-integer version (hey, not everyone has floating point) of
- * make_human_readable_str, modified from similar code I had written
- * for busybox several months ago.
- *
- * Notes:
- *   1) I'm using an unsigned long long to hold the product size * block_size,
- *      as df (which calls this routine) could request a representation of a
- *      partition size in bytes > max of unsigned long.  If long longs aren't
- *      available, it would be possible to do what's needed using polynomial
- *      representations (say, powers of 1024) and manipulating coefficients.
- *      The base ten "bytes" output could be handled similarly.
- *
- *   2) This routine always outputs a decimal point and a tenths digit when 
- *      display_unit != 0.  Hence, it isn't uncommon for the returned string 
- *      to have a length of 5 or 6.
- *
- *      It might be nice to add a flag to indicate no decimal digits in
- *      that case.  This could be either an additional parameter, or a
- *      special value of display_unit.  Such a flag would also be nice for du.
- *
- *      Some code to omit the decimal point and tenths digit is sketched out
- *      and "#if 0"'d below.
- */
-
-#include <stdio.h>
-#include "libbb.h"
-
-const char *make_human_readable_str(unsigned long size, 
-                                                                       unsigned long block_size,
-                                                                       unsigned long display_unit)
-{
-       /* The code will adjust for additional (appended) units. */
-       static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' };
-       static const char fmt[] = "%Lu";
-       static const char fmt_tenths[] = "%Lu.%d%c";
-
-       static char str[21];            /* Sufficient for 64 bit unsigned integers. */
-       
-       unsigned long long val;
-       int frac;
-       const char *u;
-       const char *f;
-
-       u = zero_and_units;
-       f = fmt;
-       frac = 0;
-
-       val = ((unsigned long long) size) * block_size;
-       if (val == 0) {
-               return u;
-       }
-
-       if (display_unit) {
-               val += display_unit/2;  /* Deal with rounding. */
-               val /= display_unit;    /* Don't combine with the line above!!! */
-       } else {
-               ++u;
-               while ((val >= KILOBYTE)
-                          && (u < zero_and_units + sizeof(zero_and_units) - 1)) {
-                       f = fmt_tenths;
-                       ++u;
-                       frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE;
-                       val /= KILOBYTE;
-               }
-               if (frac >= 10) {               /* We need to round up here. */
-                       ++val;
-                       frac = 0;
-               }
-#if 0
-               /* Sample code to omit decimal point and tenths digit. */
-               if ( /* no_tenths */ 1 ) {
-                       if ( frac >= 5 ) {
-                               ++val;
-                       }
-                       f = "%Lu%*c" /* fmt_no_tenths */ ;
-                       frac = 1;
-               }
-#endif
-       }
-
-       /* If f==fmt then 'frac' and 'u' are ignored. */
-       snprintf(str, sizeof(str), f, val, frac, *u);
-
-       return str;
-}
diff --git a/busybox/libbb/inode_hash.c b/busybox/libbb/inode_hash.c
deleted file mode 100644 (file)
index 790af8f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-#define HASH_SIZE      311             /* Should be prime */
-#define hash_inode(i)  ((i) % HASH_SIZE)
-
-static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
-
-/*
- * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
- * `ino_dev_hashtable', else return 0
- *
- * If NAME is a non-NULL pointer to a character pointer, and there is
- * a match, then set *NAME to the value of the name slot in that
- * bucket.
- */
-int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
-{
-       ino_dev_hashtable_bucket_t *bucket;
-
-       bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
-       while (bucket != NULL) {
-         if ((bucket->ino == statbuf->st_ino) &&
-                 (bucket->dev == statbuf->st_dev))
-         {
-               if (name) *name = bucket->name;
-               return 1;
-         }
-         bucket = bucket->next;
-       }
-       return 0;
-}
-
-/* Add statbuf to statbuf hash table */
-void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
-{
-       int i;
-       size_t s;
-       ino_dev_hashtable_bucket_t *bucket;
-    
-       i = hash_inode(statbuf->st_ino);
-       s = name ? strlen(name) : 0;
-       bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
-       bucket->ino = statbuf->st_ino;
-       bucket->dev = statbuf->st_dev;
-       if (name)
-               strcpy(bucket->name, name);
-       else
-               bucket->name[0] = '\0';
-       bucket->next = ino_dev_hashtable[i];
-       ino_dev_hashtable[i] = bucket;
-}
-
-/* Clear statbuf hash table */
-void reset_ino_dev_hashtable(void)
-{
-       int i;
-       ino_dev_hashtable_bucket_t *bucket;
-
-       for (i = 0; i < HASH_SIZE; i++) {
-               while (ino_dev_hashtable[i] != NULL) {
-                       bucket = ino_dev_hashtable[i]->next;
-                       free(ino_dev_hashtable[i]);
-                       ino_dev_hashtable[i] = bucket;
-               }
-       }
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/interface.c b/busybox/libbb/interface.c
deleted file mode 100644 (file)
index 484597c..0000000
+++ /dev/null
@@ -1,2168 +0,0 @@
-/*
- * ifconfig   This file contains an implementation of the command
- *              that either displays or sets the characteristics of
- *              one or more of the system's networking interfaces.
- *
- * Version:     $Id: interface.c,v 1.4 2001/07/19 22:28:02 andersen Exp $
- *
- * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *              and others.  Copyright 1993 MicroWalt Corporation
- *
- *              This program is free software; you can redistribute it
- *              and/or  modify it under  the terms of  the GNU General
- *              Public  License as  published  by  the  Free  Software
- *              Foundation;  either  version 2 of the License, or  (at
- *              your option) any later version.
- *
- * Patched to support 'add' and 'del' keywords for INET(4) addresses
- * by Mrs. Brisby <mrs.brisby@nimh.org>
- *
- * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *                     - gettext instead of catgets for i18n
- *          10/1998  - Andi Kleen. Use interface list primitives.       
- *         20001008 - Bernd Eckenfels, Patch from RH for setting mtu 
- *                     (default AF was wrong)
- * stolen from net-tools-1.59 and stripped down for busybox by 
- *                     Erik Andersen <andersee@debian.org>
- */
-
-/*
- * Heavily modified by Manuel Novoa III       Mar 12, 2001
- *
- * Pruned unused code using KEEP_UNUSED define.
- * Added print_bytes_scaled function to reduce code size.
- * Added some (potentially) missing defines.
- * Improved display support for -a and for a named interface.
- */
-
-/* #define KEEP_UNUSED */
-
-/* 
- * 
- * Protocol Families.
- * 
- */
-#define HAVE_AFINET 1
-#undef HAVE_AFINET6
-#undef HAVE_AFIPX
-#undef HAVE_AFATALK
-#undef HAVE_AFNETROM
-#undef HAVE_AFX25
-#undef HAVE_AFECONET
-#undef HAVE_AFASH
-
-/* 
- * 
- * Device Hardware types.
- * 
- */
-#define HAVE_HWETHER   1
-#define HAVE_HWPPP     1
-#undef HAVE_HWSLIP
-
-
-#include <features.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#if 0
-#include <arpa/nameser.h>
-#endif
-#include "libbb.h"
-
-#define _(x) x
-#define _PATH_PROCNET_DEV               "/proc/net/dev"
-#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
-#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
-
-static int procnetdev_vsn = 1;
-
-
-/* Ugh.  But libc5 doesn't provide POSIX types.  */
-#include <asm/types.h>
-
-
-#ifdef HAVE_HWSLIP
-#include <linux/if_slip.h>
-#endif
-
-#if HAVE_AFINET6
-
-#ifndef _LINUX_IN6_H
-/*
- *    This is in linux/include/net/ipv6.h.
- */
-
-struct in6_ifreq {
-    struct in6_addr ifr6_addr;
-    __u32 ifr6_prefixlen;
-    unsigned int ifr6_ifindex;
-};
-
-#endif
-
-#endif                         /* HAVE_AFINET6 */
-
-#if HAVE_AFIPX
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-#include <netipx/ipx.h>
-#else
-#include "ipx.h"
-#endif
-#endif
-#if 0
-#include "net-support.h"
-#include "pathnames.h"
-#include "version.h"
-#include "../intl.h"
-#include "interface.h"
-#include "sockets.h"
-#include "util.h"
-#endif
-
-/* Defines for glibc2.0 users. */
-#ifndef SIOCSIFTXQLEN
-#define SIOCSIFTXQLEN      0x8943
-#define SIOCGIFTXQLEN      0x8942
-#endif
-
-/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
-#ifndef ifr_qlen
-#define ifr_qlen        ifr_ifru.ifru_mtu
-#endif
-
-#ifndef HAVE_TXQUEUELEN
-#define HAVE_TXQUEUELEN 1
-#endif
-
-#ifndef IFF_DYNAMIC
-#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
-#endif
-
-/* This structure defines protocol families and their handlers. */
-struct aftype {
-    const char *name;
-    const char *title;
-    int af;
-    int alen;
-    char *(*print) (unsigned char *);
-    char *(*sprint) (struct sockaddr *, int numeric);
-    int (*input) (int type, char *bufp, struct sockaddr *);
-    void (*herror) (char *text);
-    int (*rprint) (int options);
-    int (*rinput) (int typ, int ext, char **argv);
-
-    /* may modify src */
-    int (*getmask) (char *src, struct sockaddr * mask, char *name);
-
-    int fd;
-    char *flag_file;
-};
-
-static struct aftype *aftypes[];
-
-#ifdef KEEP_UNUSED
-
-static int flag_unx;
-#ifdef HAVE_AFIPX
-static int flag_ipx;
-#endif
-#ifdef HAVE_AFX25
-static int flag_ax25;
-#endif
-#ifdef HAVE_AFATALK
-static int flag_ddp;
-#endif
-#ifdef HAVE_AFNETROM
-static int flag_netrom;
-#endif
-static int flag_inet;
-#ifdef HAVE_AFINET6
-static int flag_inet6;
-#endif
-#ifdef HAVE_AFECONET
-static int flag_econet;
-#endif
-#ifdef HAVE_AFX25
-static int flag_x25 = 0;
-#endif
-#ifdef HAVE_AFASH
-static int flag_ash;
-#endif
-
-
-static struct aftrans_t {
-    char *alias;
-    char *name;
-    int *flag;
-} aftrans[] = {
-
-#ifdef HAVE_AFX25
-    {
-       "ax25", "ax25", &flag_ax25
-    },
-#endif
-    {
-       "ip", "inet", &flag_inet
-    },
-#ifdef HAVE_AFINET6
-    {
-       "ip6", "inet6", &flag_inet6
-    },
-#endif
-#ifdef HAVE_AFIPX
-    {
-       "ipx", "ipx", &flag_ipx
-    },
-#endif
-#ifdef HAVE_AFATALK
-    {
-       "appletalk", "ddp", &flag_ddp
-    },
-#endif
-#ifdef HAVE_AFNETROM
-    {
-       "netrom", "netrom", &flag_netrom
-    },
-#endif
-    {
-       "inet", "inet", &flag_inet
-    },
-#ifdef HAVE_AFINET6
-    {
-       "inet6", "inet6", &flag_inet6
-    },
-#endif
-#ifdef HAVE_AFATALK
-    {
-       "ddp", "ddp", &flag_ddp
-    },
-#endif
-    {
-       "unix", "unix", &flag_unx
-    },
-    {
-       "tcpip", "inet", &flag_inet
-    },
-#ifdef HAVE_AFECONET
-    {
-       "econet", "ec", &flag_econet
-    },
-#endif
-#ifdef HAVE_AFX25
-    {
-       "x25", "x25", &flag_x25
-    },
-#endif
-#ifdef HAVE_AFASH
-    {
-        "ash", "ash", &flag_ash
-    },
-#endif
-    {
-       0, 0, 0
-    }
-};
-
-static char afname[256] = "";
-#endif /* KEEP_UNUSED */
-
-#if HAVE_AFUNIX
-
-/* Display a UNIX domain address. */
-static char *UNIX_print(unsigned char *ptr)
-{
-    return (ptr);
-}
-
-
-/* Display a UNIX domain address. */
-static char *UNIX_sprint(struct sockaddr *sap, int numeric)
-{
-    static char buf[64];
-
-    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
-       return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
-    return (UNIX_print(sap->sa_data));
-}
-
-
-static struct aftype unix_aftype =
-{
-    "unix", "UNIX Domain", AF_UNIX, 0,
-    UNIX_print, UNIX_sprint, NULL, NULL,
-    NULL, NULL, NULL,
-    -1,
-    "/proc/net/unix"
-};
-#endif                         /* HAVE_AFUNIX */
-
-#if HAVE_AFINET
-
-#if 0
-extern int h_errno;             /* some netdb.h versions don't export this */
-#endif
-
-/* cache */
-struct addr {
-    struct sockaddr_in addr;
-    char *name;
-    int host;
-    struct addr *next;
-};
-
-static struct addr *INET_nn = NULL;    /* addr-to-name cache           */
-
-#ifdef KEEP_UNUSED
-static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
-{
-    struct hostent *hp;
-    struct netent *np;
-
-    /* Grmpf. -FvK */
-    sin->sin_family = AF_INET;
-    sin->sin_port = 0;
-
-    /* Default is special, meaning 0.0.0.0. */
-    if (!strcmp(name, "default")) {
-       sin->sin_addr.s_addr = INADDR_ANY;
-       return (1);
-    }
-    /* Look to see if it's a dotted quad. */
-    if (inet_aton(name, &sin->sin_addr)) {
-       return 0;
-    }
-    /* If we expect this to be a hostname, try hostname database first */
-#ifdef DEBUG
-    if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
-#endif
-    if (hostfirst && 
-       (hp = gethostbyname(name)) != (struct hostent *) NULL) {
-       memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
-               sizeof(struct in_addr));
-       return 0;
-    }
-    /* Try the NETWORKS database to see if this is a known network. */
-#ifdef DEBUG
-    fprintf (stderr, "getnetbyname (%s)\n", name);
-#endif
-    if ((np = getnetbyname(name)) != (struct netent *) NULL) {
-       sin->sin_addr.s_addr = htonl(np->n_net);
-       return 1;
-    }
-    if (hostfirst) {
-       /* Don't try again */
-       errno = h_errno;
-       return -1;
-    }
-#ifdef DEBUG
-    res_init();
-    _res.options |= RES_DEBUG;
-#endif
-
-#ifdef DEBUG
-    fprintf (stderr, "gethostbyname (%s)\n", name);
-#endif
-    if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
-       errno = h_errno;
-       return -1;
-    }
-    memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
-          sizeof(struct in_addr));
-
-    return 0;
-}
-#endif /* KEEP_UNUSED */
-
-/* numeric: & 0x8000: default instead of *, 
- *         & 0x4000: host instead of net, 
- *         & 0x0fff: don't resolve
- */
-static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, 
-                        int numeric, unsigned int netmask)
-{
-    struct hostent *ent;
-    struct netent *np;
-    struct addr *pn;
-    unsigned long ad, host_ad;
-    int host = 0;
-
-    /* Grmpf. -FvK */
-    if (s_in->sin_family != AF_INET) {
-#ifdef DEBUG
-       fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family);
-#endif
-       errno = EAFNOSUPPORT;
-       return (-1);
-    }
-    ad = (unsigned long) s_in->sin_addr.s_addr;
-#ifdef DEBUG
-    fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
-#endif
-    if (ad == INADDR_ANY) {
-       if ((numeric & 0x0FFF) == 0) {
-           if (numeric & 0x8000)
-               safe_strncpy(name, "default", len);
-           else
-               safe_strncpy(name, "*", len);
-           return (0);
-       }
-    }
-    if (numeric & 0x0FFF) {
-        safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
-       return (0);
-    }
-
-    if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
-       host = 1;
-#if 0
-    INET_nn = NULL;
-#endif
-    pn = INET_nn;
-    while (pn != NULL) {
-       if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
-           safe_strncpy(name, pn->name, len);
-#ifdef DEBUG
-           fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
-#endif
-           return (0);
-       }
-       pn = pn->next;
-    }
-
-    host_ad = ntohl(ad);
-    np = NULL;
-    ent = NULL;
-    if (host) {
-#ifdef DEBUG
-       fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
-#endif
-       ent = gethostbyaddr((char *) &ad, 4, AF_INET);
-       if (ent != NULL)
-           safe_strncpy(name, ent->h_name, len);
-    } else {
-#ifdef DEBUG
-       fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
-#endif
-#if 0
-       np = getnetbyaddr(host_ad, AF_INET);
-       if (np != NULL)
-           safe_strncpy(name, np->n_name, len);
-#endif
-    }
-    if ((ent == NULL) && (np == NULL))
-       safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
-    pn = (struct addr *) xmalloc(sizeof(struct addr));
-    pn->addr = *s_in;
-    pn->next = INET_nn;
-    pn->host = host;
-    pn->name = (char *) xmalloc(strlen(name) + 1);
-    strcpy(pn->name, name);
-    INET_nn = pn;
-
-    return (0);
-}
-
-#ifdef KEEP_UNUSED
-static void INET_reserror(char *text)
-{
-    herror(text);
-}
-
-/* Display an Internet socket address. */
-static char *INET_print(unsigned char *ptr)
-{
-    return (inet_ntoa((*(struct in_addr *) ptr)));
-}
-#endif /* KEEP_UNUSED */
-
-/* Display an Internet socket address. */
-static char *INET_sprint(struct sockaddr *sap, int numeric)
-{
-    static char buff[128];
-
-    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
-       return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
-
-    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
-                     numeric, 0xffffff00) != 0)
-       return (NULL);
-
-    return (buff);
-}
-
-#ifdef KEEP_UNUSED
-static char *INET_sprintmask(struct sockaddr *sap, int numeric, 
-                     unsigned int netmask)
-{
-    static char buff[128];
-
-    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
-       return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
-    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
-                     numeric, netmask) != 0)
-       return (NULL);
-    return (buff);
-}
-
-static int INET_getsock(char *bufp, struct sockaddr *sap)
-{
-    char *sp = bufp, *bp;
-    unsigned int i;
-    unsigned val;
-    struct sockaddr_in *sin;
-
-    sin = (struct sockaddr_in *) sap;
-    sin->sin_family = AF_INET;
-    sin->sin_port = 0;
-
-    val = 0;
-    bp = (char *) &val;
-    for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
-       *sp = toupper(*sp);
-
-       if ((*sp >= 'A') && (*sp <= 'F'))
-           bp[i] |= (int) (*sp - 'A') + 10;
-       else if ((*sp >= '0') && (*sp <= '9'))
-           bp[i] |= (int) (*sp - '0');
-       else
-           return (-1);
-
-       bp[i] <<= 4;
-       sp++;
-       *sp = toupper(*sp);
-
-       if ((*sp >= 'A') && (*sp <= 'F'))
-           bp[i] |= (int) (*sp - 'A') + 10;
-       else if ((*sp >= '0') && (*sp <= '9'))
-           bp[i] |= (int) (*sp - '0');
-       else
-           return (-1);
-
-       sp++;
-    }
-    sin->sin_addr.s_addr = htonl(val);
-
-    return (sp - bufp);
-}
-
-static int INET_input(int type, char *bufp, struct sockaddr *sap)
-{
-    switch (type) {
-    case 1:
-       return (INET_getsock(bufp, sap));
-    case 256:
-       return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
-    default:
-       return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
-    }
-}
-
-static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
-{
-    struct sockaddr_in *mask = (struct sockaddr_in *) m;
-    char *slash, *end;
-    int prefix;
-
-    if ((slash = strchr(adr, '/')) == NULL)
-       return 0;
-
-    *slash++ = '\0';
-    prefix = strtoul(slash, &end, 0);
-    if (*end != '\0')
-       return -1;
-
-    if (name) {
-       sprintf(name, "/%d", prefix);
-    }
-    mask->sin_family = AF_INET;
-    mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
-    return 1;
-}
-#endif /* KEEP_UNUSED */
-
-static struct aftype inet_aftype =
-{
-    "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
-    NULL /* UNUSED INET_print */, INET_sprint,
-       NULL /* UNUSED INET_input */, NULL /* UNUSED INET_reserror */,
-    NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
-    NULL /* UNUSED INET_getnetmask */,
-    -1,
-    NULL
-};
-
-#endif                         /* HAVE_AFINET */
-
-/* Display an UNSPEC address. */
-static char *UNSPEC_print(unsigned char *ptr)
-{
-    static char buff[sizeof(struct sockaddr)*3+1];
-    char *pos;
-    unsigned int i;
-
-    pos = buff;
-    for (i = 0; i < sizeof(struct sockaddr); i++) {
-       /* careful -- not every libc's sprintf returns # bytes written */
-       sprintf(pos, "%02X-", (*ptr++ & 0377));
-       pos += 3;
-    }
-    /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
-    *--pos = '\0';
-    return (buff);
-}
-
-/* Display an UNSPEC socket address. */
-static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
-{
-    static char buf[64];
-
-    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
-       return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
-    return (UNSPEC_print(sap->sa_data));
-}
-
-static struct aftype unspec_aftype =
-{
-    "unspec", "UNSPEC", AF_UNSPEC, 0,
-    UNSPEC_print, UNSPEC_sprint, NULL, NULL,
-    NULL,
-};
-
-static struct aftype *aftypes[] =
-{
-#if HAVE_AFUNIX
-    &unix_aftype,
-#endif
-#if HAVE_AFINET
-    &inet_aftype,
-#endif
-#if HAVE_AFINET6
-    &inet6_aftype,
-#endif
-#if HAVE_AFAX25
-    &ax25_aftype,
-#endif
-#if HAVE_AFNETROM
-    &netrom_aftype,
-#endif
-#if HAVE_AFROSE
-    &rose_aftype,
-#endif
-#if HAVE_AFIPX
-    &ipx_aftype,
-#endif
-#if HAVE_AFATALK
-    &ddp_aftype,
-#endif
-#if HAVE_AFECONET
-    &ec_aftype,
-#endif
-#if HAVE_AFASH
-    &ash_aftype,
-#endif
-#if HAVE_AFX25
-    &x25_aftype,
-#endif
-    &unspec_aftype,
-    NULL
-};
-
-#ifdef KEEP_UNUSED
-static short sVafinit = 0;
-
-static void afinit()
-{
-    unspec_aftype.title = _("UNSPEC");
-#if HAVE_AFUNIX
-    unix_aftype.title = _("UNIX Domain");
-#endif
-#if HAVE_AFINET
-    inet_aftype.title = _("DARPA Internet");
-#endif
-#if HAVE_AFINET6
-    inet6_aftype.title = _("IPv6");
-#endif
-#if HAVE_AFAX25
-    ax25_aftype.title = _("AMPR AX.25");
-#endif
-#if HAVE_AFNETROM
-    netrom_aftype.title = _("AMPR NET/ROM");
-#endif
-#if HAVE_AFIPX
-    ipx_aftype.title = _("Novell IPX");
-#endif
-#if HAVE_AFATALK
-    ddp_aftype.title = _("Appletalk DDP");
-#endif
-#if HAVE_AFECONET
-    ec_aftype.title = _("Econet");
-#endif
-#if HAVE_AFX25
-    x25_aftype.title = _("CCITT X.25");
-#endif
-#if HAVE_AFROSE
-    rose_aftype.title = _("AMPR ROSE");
-#endif
-#if HAVE_AFASH
-    ash_aftype.title = _("Ash");
-#endif 
-    sVafinit = 1;
-}
-
-static int aftrans_opt(const char *arg)
-{
-    struct aftrans_t *paft;
-    char *tmp1, *tmp2;
-    char buf[256];
-
-    safe_strncpy(buf, arg, sizeof(buf));
-
-    tmp1 = buf;
-
-    while (tmp1) {
-
-       tmp2 = strchr(tmp1, ',');
-
-       if (tmp2)
-           *(tmp2++) = '\0';
-
-       paft = aftrans;
-       for (paft = aftrans; paft->alias; paft++) {
-           if (strcmp(tmp1, paft->alias))
-               continue;
-           if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
-               fprintf(stderr, _("Too much address family arguments.\n"));
-               return (0);
-           }
-           if (paft->flag)
-               (*paft->flag)++;
-           if (afname[0])
-               strcat(afname, ",");
-           strcat(afname, paft->name);
-           break;
-       }
-       if (!paft->alias) {
-           fprintf(stderr, _("Unknown address family `%s'.\n"), tmp1);
-           return (1);
-       }
-       tmp1 = tmp2;
-    }
-
-    return (0);
-}
-
-/* set the default AF list from the program name or a constant value    */
-static void aftrans_def(char *tool, char *argv0, char *dflt)
-{
-    char *tmp;
-    char *buf;
-
-    strcpy(afname, dflt);
-
-    if (!(tmp = strrchr(argv0, '/')))
-       tmp = argv0;            /* no slash?! */
-    else
-       tmp++;
-
-    if (!(buf = strdup(tmp)))
-       return;
-
-    if (strlen(tool) >= strlen(tmp)) {
-       free(buf);
-       return;
-    }
-    tmp = buf + (strlen(tmp) - strlen(tool));
-
-    if (strcmp(tmp, tool) != 0) {
-       free(buf);
-       return;
-    }
-    *tmp = '\0';
-    if ((tmp = strchr(buf, '_')))
-       *tmp = '\0';
-
-    afname[0] = '\0';
-    if (aftrans_opt(buf))
-       strcpy(afname, buf);
-
-    free(buf);
-}
-
-/* Check our protocol family table for this family. */
-static struct aftype *get_aftype(const char *name)
-{
-    struct aftype **afp;
-
-#ifdef KEEP_UNUSED
-    if (!sVafinit)
-       afinit();
-#endif /* KEEP_UNUSED */
-
-    afp = aftypes;
-    while (*afp != NULL) {
-       if (!strcmp((*afp)->name, name))
-           return (*afp);
-       afp++;
-    }
-    if (strchr(name, ','))
-       fprintf(stderr, _("Please don't supply more than one address family.\n"));
-    return (NULL);
-}
-#endif /* KEEP_UNUSED */
-
-/* Check our protocol family table for this family. */
-static struct aftype *get_afntype(int af)
-{
-    struct aftype **afp;
-
-#ifdef KEEP_UNUSED
-    if (!sVafinit)
-       afinit();
-#endif /* KEEP_UNUSED */
-
-    afp = aftypes;
-    while (*afp != NULL) {
-       if ((*afp)->af == af)
-           return (*afp);
-       afp++;
-    }
-    return (NULL);
-}
-
-/* Check our protocol family table for this family and return its socket */
-static int get_socket_for_af(int af)
-{
-    struct aftype **afp;
-
-#ifdef KEEP_UNUSED
-    if (!sVafinit)
-       afinit();
-#endif /* KEEP_UNUSED */
-
-    afp = aftypes;
-    while (*afp != NULL) {
-       if ((*afp)->af == af)
-           return (*afp)->fd;
-       afp++;
-    }
-    return -1;
-}
-
-#ifdef KEEP_UNUSED
-/* type: 0=all, 1=getroute */
-static void print_aflist(int type) {
-    int count = 0;
-    char * txt;
-    struct aftype **afp;
-
-#ifdef KEEP_UNUSED
-    if (!sVafinit)
-       afinit();
-#endif /* KEEP_UNUSED */
-
-    afp = aftypes;
-    while (*afp != NULL) {
-       if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
-               afp++; continue;
-       }
-       if ((count % 3) == 0) fprintf(stderr,count?"\n    ":"    "); 
-        txt = (*afp)->name; if (!txt) txt = "..";
-       fprintf(stderr,"%s (%s) ",txt,_((*afp)->title));
-       count++;
-       afp++;
-    }
-    fprintf(stderr,"\n");
-}
-#endif /* KEEP_UNUSED */
-
-struct user_net_device_stats {
-    unsigned long long rx_packets;     /* total packets received       */
-    unsigned long long tx_packets;     /* total packets transmitted    */
-    unsigned long long rx_bytes;       /* total bytes received         */
-    unsigned long long tx_bytes;       /* total bytes transmitted      */
-    unsigned long rx_errors;   /* bad packets received         */
-    unsigned long tx_errors;   /* packet transmit problems     */
-    unsigned long rx_dropped;  /* no space in linux buffers    */
-    unsigned long tx_dropped;  /* no space available in linux  */
-    unsigned long rx_multicast;        /* multicast packets received   */
-    unsigned long rx_compressed;
-    unsigned long tx_compressed;
-    unsigned long collisions;
-
-    /* detailed rx_errors: */
-    unsigned long rx_length_errors;
-    unsigned long rx_over_errors;      /* receiver ring buff overflow  */
-    unsigned long rx_crc_errors;       /* recved pkt with crc error    */
-    unsigned long rx_frame_errors;     /* recv'd frame alignment error */
-    unsigned long rx_fifo_errors;      /* recv'r fifo overrun          */
-    unsigned long rx_missed_errors;    /* receiver missed packet     */
-    /* detailed tx_errors */
-    unsigned long tx_aborted_errors;
-    unsigned long tx_carrier_errors;
-    unsigned long tx_fifo_errors;
-    unsigned long tx_heartbeat_errors;
-    unsigned long tx_window_errors;
-};
-
-struct interface {
-    struct interface *next, *prev; 
-    char name[IFNAMSIZ];       /* interface name        */
-    short type;                        /* if type               */
-    short flags;               /* various flags         */
-    int metric;                        /* routing metric        */
-    int mtu;                   /* MTU value             */
-    int tx_queue_len;          /* transmit queue length */
-    struct ifmap map;          /* hardware setup        */
-    struct sockaddr addr;      /* IP address            */
-    struct sockaddr dstaddr;   /* P-P IP address        */
-    struct sockaddr broadaddr; /* IP broadcast address  */
-    struct sockaddr netmask;   /* IP network mask       */
-    struct sockaddr ipxaddr_bb;        /* IPX network address   */
-    struct sockaddr ipxaddr_sn;        /* IPX network address   */
-    struct sockaddr ipxaddr_e3;        /* IPX network address   */
-    struct sockaddr ipxaddr_e2;        /* IPX network address   */
-    struct sockaddr ddpaddr;   /* Appletalk DDP address */
-    struct sockaddr ecaddr;    /* Econet address        */
-    int has_ip;
-    int has_ipx_bb;
-    int has_ipx_sn;
-    int has_ipx_e3;
-    int has_ipx_e2;
-    int has_ax25;
-    int has_ddp;
-    int has_econet;
-    char hwaddr[32];           /* HW address            */
-    int statistics_valid;
-    struct user_net_device_stats stats;                /* statistics            */
-    int keepalive;             /* keepalive value for SLIP */
-    int outfill;               /* outfill value for SLIP */
-};
-
-
-int interface_opt_a = 0;               /* show all interfaces          */
-
-#ifdef KEEP_UNUSED
-static int opt_i = 0;                  /* show the statistics          */
-static int opt_v = 0;                  /* debugging output flag        */
-
-static int addr_family = 0;            /* currently selected AF        */
-#endif /* KEEP_UNUSED */
-
-static struct interface *int_list, *int_last;
-static int skfd = -1;                  /* generic raw socket desc.     */
-
-
-static int sockets_open(int family)
-{
-    struct aftype **aft;
-    int sfd = -1;
-    static int force = -1;
-
-    if (force < 0) {
-       force = 0;
-       if (get_kernel_revision() < KRELEASE(2, 1, 0))
-           force = 1;
-       if (access("/proc/net", R_OK))
-           force = 1;
-    }
-    for (aft = aftypes; *aft; aft++) {
-       struct aftype *af = *aft;
-       int type = SOCK_DGRAM;
-       if (af->af == AF_UNSPEC)
-           continue;
-       if (family && family != af->af)
-           continue;
-       if (af->fd != -1) {
-           sfd = af->fd;
-           continue;
-       }
-       /* Check some /proc file first to not stress kmod */
-       if (!family && !force && af->flag_file) {
-           if (access(af->flag_file, R_OK))
-               continue;
-       }
-#if HAVE_AFNETROM
-       if (af->af == AF_NETROM)
-           type = SOCK_SEQPACKET;
-#endif
-#if HAVE_AFX25
-       if (af->af == AF_X25)
-           type = SOCK_SEQPACKET;
-#endif
-       af->fd = socket(af->af, type, 0);
-       if (af->fd >= 0)
-           sfd = af->fd;
-    }
-    if (sfd < 0)
-       fprintf(stderr, _("No usable address families found.\n"));
-    return sfd;
-}
-
-/* like strcmp(), but knows about numbers */
-static int nstrcmp(const char *astr, const char *b)
-{
-    const char *a = astr;
-
-    while (*a == *b) {
-       if (*a == '\0')
-           return 0;
-       a++;
-       b++;
-    }
-    if (isdigit(*a)) {
-       if (!isdigit(*b))
-           return -1;
-       while (a > astr) {
-           a--;
-           if (!isdigit(*a)) {
-               a++;
-               break;
-           }
-           if (!isdigit(*b))
-               return -1;
-           b--;
-       }
-       return atoi(a) > atoi(b) ? 1 : -1;
-    }
-    return *a - *b;
-}
-
-static struct interface *add_interface(char *name)
-{
-    struct interface *ife, **nextp, *new;
-
-    for (ife = int_last; ife; ife = ife->prev) {
-           int n = nstrcmp(ife->name, name); 
-           if (n == 0) 
-                   return ife; 
-           if (n < 0) 
-                   break; 
-    }
-    new(new); 
-    safe_strncpy(new->name, name, IFNAMSIZ); 
-    nextp = ife ? &ife->next : &int_list;
-    new->prev = ife;
-    new->next = *nextp; 
-    if (new->next) 
-           new->next->prev = new; 
-    else
-           int_last = new; 
-    *nextp = new; 
-    return new; 
-}
-
-
-static int if_readconf(void)
-{
-    int numreqs = 30;
-    struct ifconf ifc;
-    struct ifreq *ifr;
-    int n, err = -1;
-    int skfd2;
-
-    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
-       (as of 2.1.128) */ 
-    skfd2 = get_socket_for_af(AF_INET);
-    if (skfd2 < 0) {
-       fprintf(stderr, _("warning: no inet socket available: %s\n"),
-               strerror(errno));
-       /* Try to soldier on with whatever socket we can get hold of.  */
-       skfd2 = sockets_open(0);
-       if (skfd2 < 0)
-           return -1;
-    }
-
-    ifc.ifc_buf = NULL;
-    for (;;) {
-       ifc.ifc_len = sizeof(struct ifreq) * numreqs;
-       ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
-
-       if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
-           perror("SIOCGIFCONF");
-           goto out;
-       }
-       if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
-           /* assume it overflowed and try again */
-           numreqs += 10;
-           continue;
-       }
-       break;
-    }
-
-    ifr = ifc.ifc_req;
-    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
-       add_interface(ifr->ifr_name);
-       ifr++;
-    }
-    err = 0;
-
-out:
-    free(ifc.ifc_buf);
-    return err;
-}
-
-static char *get_name(char *name, char *p)
-{
-    while (isspace(*p))
-       p++;
-    while (*p) {
-       if (isspace(*p))
-           break;
-       if (*p == ':') {        /* could be an alias */
-           char *dot = p, *dotname = name;
-           *name++ = *p++;
-           while (isdigit(*p))
-               *name++ = *p++;
-           if (*p != ':') {    /* it wasn't, backup */
-               p = dot;
-               name = dotname;
-           }
-           if (*p == '\0')
-               return NULL;
-           p++;
-           break;
-       }
-       *name++ = *p++;
-    }
-    *name++ = '\0';
-    return p;
-}
-
-static int get_dev_fields(char *bp, struct interface *ife)
-{
-    switch (procnetdev_vsn) {
-    case 3:
-       sscanf(bp,
-       "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
-              &ife->stats.rx_bytes,
-              &ife->stats.rx_packets,
-              &ife->stats.rx_errors,
-              &ife->stats.rx_dropped,
-              &ife->stats.rx_fifo_errors,
-              &ife->stats.rx_frame_errors,
-              &ife->stats.rx_compressed,
-              &ife->stats.rx_multicast,
-
-              &ife->stats.tx_bytes,
-              &ife->stats.tx_packets,
-              &ife->stats.tx_errors,
-              &ife->stats.tx_dropped,
-              &ife->stats.tx_fifo_errors,
-              &ife->stats.collisions,
-              &ife->stats.tx_carrier_errors,
-              &ife->stats.tx_compressed);
-       break;
-    case 2:
-       sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
-              &ife->stats.rx_bytes,
-              &ife->stats.rx_packets,
-              &ife->stats.rx_errors,
-              &ife->stats.rx_dropped,
-              &ife->stats.rx_fifo_errors,
-              &ife->stats.rx_frame_errors,
-
-              &ife->stats.tx_bytes,
-              &ife->stats.tx_packets,
-              &ife->stats.tx_errors,
-              &ife->stats.tx_dropped,
-              &ife->stats.tx_fifo_errors,
-              &ife->stats.collisions,
-              &ife->stats.tx_carrier_errors);
-       ife->stats.rx_multicast = 0;
-       break;
-    case 1:
-       sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
-              &ife->stats.rx_packets,
-              &ife->stats.rx_errors,
-              &ife->stats.rx_dropped,
-              &ife->stats.rx_fifo_errors,
-              &ife->stats.rx_frame_errors,
-
-              &ife->stats.tx_packets,
-              &ife->stats.tx_errors,
-              &ife->stats.tx_dropped,
-              &ife->stats.tx_fifo_errors,
-              &ife->stats.collisions,
-              &ife->stats.tx_carrier_errors);
-       ife->stats.rx_bytes = 0;
-       ife->stats.tx_bytes = 0;
-       ife->stats.rx_multicast = 0;
-       break;
-    }
-    return 0;
-}
-
-static inline int procnetdev_version(char *buf)
-{
-    if (strstr(buf, "compressed"))
-       return 3;
-    if (strstr(buf, "bytes"))
-       return 2;
-    return 1;
-}
-
-static int if_readlist_proc(char *target)
-{
-    static int proc_read; 
-    FILE *fh;
-    char buf[512];
-    struct interface *ife;
-    int err;
-
-    if (proc_read) 
-           return 0; 
-    if (!target) 
-           proc_read = 1;
-
-    fh = fopen(_PATH_PROCNET_DEV, "r");
-    if (!fh) {
-               fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
-                       _PATH_PROCNET_DEV, strerror(errno)); 
-               return if_readconf();
-       }       
-    fgets(buf, sizeof buf, fh);        /* eat line */
-    fgets(buf, sizeof buf, fh);
-
-#if 0                          /* pretty, but can't cope with missing fields */
-    fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
-                      "face", "",      /* parsed separately */
-                      "bytes", "%lu",
-                      "packets", "%lu",
-                      "errs", "%lu",
-                      "drop", "%lu",
-                      "fifo", "%lu",
-                      "frame", "%lu",
-                      "compressed", "%lu",
-                      "multicast", "%lu",
-                      "bytes", "%lu",
-                      "packets", "%lu",
-                      "errs", "%lu",
-                      "drop", "%lu",
-                      "fifo", "%lu",
-                      "colls", "%lu",
-                      "carrier", "%lu",
-                      "compressed", "%lu",
-                      NULL);
-    if (!fmt)
-       return -1;
-#else
-    procnetdev_vsn = procnetdev_version(buf);
-#endif
-
-    err = 0;
-    while (fgets(buf, sizeof buf, fh)) {
-       char *s, name[IFNAMSIZ];
-       s = get_name(name, buf);    
-       ife = add_interface(name);
-       get_dev_fields(s, ife);
-       ife->statistics_valid = 1;
-       if (target && !strcmp(target,name))
-               break;
-    }
-    if (ferror(fh)) {
-       perror(_PATH_PROCNET_DEV);
-       err = -1;
-       proc_read = 0; 
-    }
-
-#if 0
-    free(fmt);
-#endif
-    fclose(fh);
-    return err;
-}
-
-static int if_readlist(void) 
-{ 
-    int err = if_readlist_proc(NULL); 
-    if (!err)
-           err = if_readconf();
-    return err;
-} 
-
-static int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
-{
-    struct interface *ife;
-
-    if (!int_list && (if_readlist() < 0))
-       return -1;
-    for (ife = int_list; ife; ife = ife->next) {
-       int err = doit(ife, cookie);
-       if (err)
-           return err;
-    }
-    return 0;
-}
-
-/* Support for fetching an IPX address */
-
-#if HAVE_AFIPX
-static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
-{
-    ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
-    return ioctl(sock, SIOCGIFADDR, ifr);
-}
-#endif
-
-
-/* Fetch the interface configuration from the kernel. */
-static int if_fetch(struct interface *ife)
-{
-    struct ifreq ifr;
-    int fd;
-    char *ifname = ife->name; 
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
-       return (-1);
-    ife->flags = ifr.ifr_flags;
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
-       memset(ife->hwaddr, 0, 32);
-    else
-       memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
-
-    ife->type = ifr.ifr_hwaddr.sa_family;
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
-       ife->metric = 0;
-    else
-       ife->metric = ifr.ifr_metric;
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
-       ife->mtu = 0;
-    else
-       ife->mtu = ifr.ifr_mtu;
-
-#ifdef HAVE_HWSLIP
-    if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
-       ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
-       ife->type == ARPHRD_ADAPT) {
-#ifdef SIOCGOUTFILL
-       strcpy(ifr.ifr_name, ifname);
-       if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
-           ife->outfill = 0;
-       else
-           ife->outfill = (unsigned int) ifr.ifr_data;
-#endif
-#ifdef SIOCGKEEPALIVE
-       strcpy(ifr.ifr_name, ifname);
-       if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
-           ife->keepalive = 0;
-       else
-           ife->keepalive = (unsigned int) ifr.ifr_data;
-#endif
-    }
-#endif
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
-       memset(&ife->map, 0, sizeof(struct ifmap));
-    else
-       memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
-
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
-       memset(&ife->map, 0, sizeof(struct ifmap));
-    else
-       ife->map = ifr.ifr_map;
-
-#ifdef HAVE_TXQUEUELEN
-    strcpy(ifr.ifr_name, ifname);
-    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
-       ife->tx_queue_len = -1; /* unknown value */
-    else
-       ife->tx_queue_len = ifr.ifr_qlen;
-#else
-    ife->tx_queue_len = -1;    /* unknown value */
-#endif
-
-#if HAVE_AFINET
-    /* IPv4 address? */
-    fd = get_socket_for_af(AF_INET);
-    if (fd >= 0) {
-       strcpy(ifr.ifr_name, ifname);
-       ifr.ifr_addr.sa_family = AF_INET;
-       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
-           ife->has_ip = 1;
-           ife->addr = ifr.ifr_addr;
-           strcpy(ifr.ifr_name, ifname);
-           if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
-               memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
-           else
-               ife->dstaddr = ifr.ifr_dstaddr;
-
-           strcpy(ifr.ifr_name, ifname);
-           if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
-               memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
-           else
-               ife->broadaddr = ifr.ifr_broadaddr;
-
-           strcpy(ifr.ifr_name, ifname);
-           if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
-               memset(&ife->netmask, 0, sizeof(struct sockaddr));
-           else
-               ife->netmask = ifr.ifr_netmask;
-       } else
-           memset(&ife->addr, 0, sizeof(struct sockaddr));
-    }
-#endif
-
-#if HAVE_AFATALK
-    /* DDP address maybe ? */
-    fd = get_socket_for_af(AF_APPLETALK);
-    if (fd >= 0) {
-       strcpy(ifr.ifr_name, ifname);
-       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
-           ife->ddpaddr = ifr.ifr_addr;
-           ife->has_ddp = 1;
-       }
-    }
-#endif
-
-#if HAVE_AFIPX
-    /* Look for IPX addresses with all framing types */
-    fd = get_socket_for_af(AF_IPX);
-    if (fd >= 0) {
-       strcpy(ifr.ifr_name, ifname);
-       if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
-           ife->has_ipx_bb = 1;
-           ife->ipxaddr_bb = ifr.ifr_addr;
-       }
-       strcpy(ifr.ifr_name, ifname);
-       if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
-           ife->has_ipx_sn = 1;
-           ife->ipxaddr_sn = ifr.ifr_addr;
-       }
-       strcpy(ifr.ifr_name, ifname);
-       if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
-           ife->has_ipx_e3 = 1;
-           ife->ipxaddr_e3 = ifr.ifr_addr;
-       }
-       strcpy(ifr.ifr_name, ifname);
-       if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
-           ife->has_ipx_e2 = 1;
-           ife->ipxaddr_e2 = ifr.ifr_addr;
-       }
-    }
-#endif
-
-#if HAVE_AFECONET
-    /* Econet address maybe? */
-    fd = get_socket_for_af(AF_ECONET);
-    if (fd >= 0) {
-       strcpy(ifr.ifr_name, ifname);
-       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
-           ife->ecaddr = ifr.ifr_addr;
-           ife->has_econet = 1;
-       }
-    }
-#endif
-
-    return 0;
-}
-
-
-static int do_if_fetch(struct interface *ife)
-{ 
-    if (if_fetch(ife) < 0) {
-       char *errmsg; 
-       if (errno == ENODEV) { 
-           /* Give better error message for this case. */ 
-           errmsg = _("Device not found"); 
-       } else { 
-           errmsg = strerror(errno); 
-       }
-       fprintf(stderr, _("%s: error fetching interface information: %s\n"),
-               ife->name, errmsg);
-       return -1;
-    }
-    return 0; 
-}
-
-/* This structure defines hardware protocols and their handlers. */
-struct hwtype {
-    const char *name;
-    const char *title;
-    int type;
-    int alen;
-    char *(*print) (unsigned char *);
-    int (*input) (char *, struct sockaddr *);
-    int (*activate) (int fd);
-    int suppress_null_addr;
-};
-
-static struct hwtype unspec_hwtype =
-{
-    "unspec", "UNSPEC", -1, 0,
-    UNSPEC_print, NULL, NULL
-};
-
-static struct hwtype loop_hwtype =
-{
-    "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
-    NULL, NULL, NULL
-};
-
-#if HAVE_HWETHER
-#include <net/if_arp.h>
-#include <linux/if_ether.h>
-
-static struct hwtype ether_hwtype;
-
-/* Display an Ethernet address in readable format. */
-static char *pr_ether(unsigned char *ptr)
-{
-    static char buff[64];
-
-    snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
-            (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
-            (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
-       );
-    return (buff);
-}
-
-#ifdef KEEP_UNUSED
-/* Input an Ethernet address and convert to binary. */
-static int in_ether(char *bufp, struct sockaddr *sap)
-{
-    unsigned char *ptr;
-    char c, *orig;
-    int i;
-    unsigned val;
-
-    sap->sa_family = ether_hwtype.type;
-    ptr = sap->sa_data;
-
-    i = 0;
-    orig = bufp;
-    while ((*bufp != '\0') && (i < ETH_ALEN)) {
-       val = 0;
-       c = *bufp++;
-       if (isdigit(c))
-           val = c - '0';
-       else if (c >= 'a' && c <= 'f')
-           val = c - 'a' + 10;
-       else if (c >= 'A' && c <= 'F')
-           val = c - 'A' + 10;
-       else {
-#ifdef DEBUG
-           fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
-#endif
-           errno = EINVAL;
-           return (-1);
-       }
-       val <<= 4;
-       c = *bufp;
-       if (isdigit(c))
-           val |= c - '0';
-       else if (c >= 'a' && c <= 'f')
-           val |= c - 'a' + 10;
-       else if (c >= 'A' && c <= 'F')
-           val |= c - 'A' + 10;
-       else if (c == ':' || c == 0)
-           val >>= 4;
-       else {
-#ifdef DEBUG
-           fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
-#endif
-           errno = EINVAL;
-           return (-1);
-       }
-       if (c != 0)
-           bufp++;
-       *ptr++ = (unsigned char) (val & 0377);
-       i++;
-
-       /* We might get a semicolon here - not required. */
-       if (*bufp == ':') {
-           if (i == ETH_ALEN) {
-#ifdef DEBUG
-               fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"),
-                       orig)
-#endif
-                   ;           /* nothing */
-           }
-           bufp++;
-       }
-    }
-
-    /* That's it.  Any trailing junk? */
-    if ((i == ETH_ALEN) && (*bufp != '\0')) {
-#ifdef DEBUG
-       fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig);
-       errno = EINVAL;
-       return (-1);
-#endif
-    }
-#ifdef DEBUG
-    fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
-#endif
-
-    return (0);
-}
-#endif /* KEEP_UNUSED */
-
-
-static struct hwtype ether_hwtype =
-{
-    "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
-    pr_ether, NULL /* UNUSED in_ether */, NULL
-};
-
-
-#endif                         /* HAVE_HWETHER */
-
-
-#if HAVE_HWPPP
-
-#include <net/if_arp.h>
-
-#ifdef KEEP_UNUSED
-/* Start the PPP encapsulation on the file descriptor. */
-static int do_ppp(int fd)
-{
-    fprintf(stderr, _("You cannot start PPP with this program.\n"));
-    return -1;
-}
-#endif /* KEEP_UNUSED */
-
-static struct hwtype ppp_hwtype =
-{
-    "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
-    NULL, NULL, NULL /* UNUSED do_ppp */, 0
-};
-
-
-#endif                         /* HAVE_PPP */
-
-static struct hwtype *hwtypes[] =
-{
-
-    &loop_hwtype,
-
-#if HAVE_HWSLIP
-    &slip_hwtype,
-    &cslip_hwtype,
-    &slip6_hwtype,
-    &cslip6_hwtype,
-    &adaptive_hwtype,
-#endif
-#if HAVE_HWSTRIP
-    &strip_hwtype,
-#endif
-#if HAVE_HWASH
-    &ash_hwtype,
-#endif
-#if HAVE_HWETHER
-    &ether_hwtype,
-#endif
-#if HAVE_HWTR
-    &tr_hwtype,
-#ifdef ARPHRD_IEEE802_TR
-    &tr_hwtype1, 
-#endif
-#endif
-#if HAVE_HWAX25
-    &ax25_hwtype,
-#endif
-#if HAVE_HWNETROM
-    &netrom_hwtype,
-#endif
-#if HAVE_HWROSE
-    &rose_hwtype,
-#endif
-#if HAVE_HWTUNNEL
-    &tunnel_hwtype,
-#endif
-#if HAVE_HWPPP
-    &ppp_hwtype,
-#endif
-#if HAVE_HWHDLCLAPB
-    &hdlc_hwtype,
-    &lapb_hwtype,
-#endif
-#if HAVE_HWARC
-    &arcnet_hwtype,
-#endif
-#if HAVE_HWFR
-    &dlci_hwtype,
-    &frad_hwtype,
-#endif
-#if HAVE_HWSIT
-    &sit_hwtype,
-#endif
-#if HAVE_HWFDDI
-    &fddi_hwtype,
-#endif
-#if HAVE_HWHIPPI
-    &hippi_hwtype,
-#endif
-#if HAVE_HWIRDA
-    &irda_hwtype,
-#endif
-#if HAVE_HWEC
-    &ec_hwtype,
-#endif
-#if HAVE_HWX25
-    &x25_hwtype,
-#endif
-    &unspec_hwtype,
-    NULL
-};
-
-#ifdef KEEP_UNUSED
-static short sVhwinit = 0;
-
-static void hwinit()
-{
-    loop_hwtype.title = _("Local Loopback");
-    unspec_hwtype.title = _("UNSPEC");
-#if HAVE_HWSLIP
-    slip_hwtype.title = _("Serial Line IP");
-    cslip_hwtype.title = _("VJ Serial Line IP");
-    slip6_hwtype.title = _("6-bit Serial Line IP");
-    cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
-    adaptive_hwtype.title = _("Adaptive Serial Line IP");
-#endif
-#if HAVE_HWETHER
-    ether_hwtype.title = _("Ethernet");
-#endif
-#if HAVE_HWASH
-    ash_hwtype.title = _("Ash");
-#endif
-#if HAVE_HWFDDI
-    fddi_hwtype.title = _("Fiber Distributed Data Interface");
-#endif
-#if HAVE_HWHIPPI
-    hippi_hwtype.title = _("HIPPI");
-#endif
-#if HAVE_HWAX25
-    ax25_hwtype.title = _("AMPR AX.25");
-#endif
-#if HAVE_HWROSE
-    rose_hwtype.title = _("AMPR ROSE");
-#endif
-#if HAVE_HWNETROM
-    netrom_hwtype.title = _("AMPR NET/ROM");
-#endif
-#if HAVE_HWX25
-    x25_hwtype.title = _("generic X.25");
-#endif
-#if HAVE_HWTUNNEL
-    tunnel_hwtype.title = _("IPIP Tunnel");
-#endif
-#if HAVE_HWPPP
-    ppp_hwtype.title = _("Point-to-Point Protocol");
-#endif
-#if HAVE_HWHDLCLAPB
-    hdlc_hwtype.title = _("(Cisco)-HDLC");
-    lapb_hwtype.title = _("LAPB");
-#endif
-#if HAVE_HWARC
-    arcnet_hwtype.title = _("ARCnet");
-#endif
-#if HAVE_HWFR
-    dlci_hwtype.title = _("Frame Relay DLCI");
-    frad_hwtype.title = _("Frame Relay Access Device");
-#endif
-#if HAVE_HWSIT
-    sit_hwtype.title = _("IPv6-in-IPv4");
-#endif
-#if HAVE_HWIRDA
-    irda_hwtype.title = _("IrLAP");
-#endif
-#if HAVE_HWTR
-    tr_hwtype.title = _("16/4 Mbps Token Ring");
-#ifdef ARPHRD_IEEE802_TR
-    tr_hwtype1.title = _("16/4 Mbps Token Ring (New)") ; 
-#endif
-#endif
-#if HAVE_HWEC
-    ec_hwtype.title = _("Econet");
-#endif
-    sVhwinit = 1;
-}
-#endif /* KEEP_UNUSED */
-
-#ifdef IFF_PORTSEL
-static const char *if_port_text[][4] =
-{
-    /* Keep in step with <linux/netdevice.h> */
-    {"unknown", NULL, NULL, NULL},
-    {"10base2", "bnc", "coax", NULL},
-    {"10baseT", "utp", "tpe", NULL},
-    {"AUI", "thick", "db15", NULL},
-    {"100baseT", NULL, NULL, NULL},
-    {"100baseTX", NULL, NULL, NULL},
-    {"100baseFX", NULL, NULL, NULL},
-    {NULL, NULL, NULL, NULL},
-};
-#endif
-
-/* Check our hardware type table for this type. */
-static struct hwtype *get_hwntype(int type)
-{
-    struct hwtype **hwp;
-
-#ifdef KEEP_UNUSED
-    if (!sVhwinit)
-       hwinit();
-#endif /* KEEP_UNUSED */
-
-    hwp = hwtypes;
-    while (*hwp != NULL) {
-       if ((*hwp)->type == type)
-           return (*hwp);
-       hwp++;
-    }
-    return (NULL);
-}
-
-/* return 1 if address is all zeros */
-static int hw_null_address(struct hwtype *hw, void *ap)
-{
-    unsigned int i;
-    unsigned char *address = (unsigned char *)ap;
-    for (i = 0; i < hw->alen; i++)
-       if (address[i])
-           return 0;
-    return 1;
-}
-
-static const char TRext[] = "\0\0k\0M";
-
-static void print_bytes_scaled(unsigned long long ull, const char *end)
-{
-       unsigned long long int_part;
-       unsigned long frac_part;
-       const char *ext;
-       int i;
-
-       frac_part = 0;
-       ext = TRext;
-       int_part = ull;
-       for (i=0 ; i<2 ; i++) {
-               if (int_part >= 1024) {
-                       frac_part = ((int_part % 1024) * 10) / 1024;
-                       int_part /= 1024;
-                       ext += 2;                       /* Kb, Mb */
-               }
-       }
-
-       printf("X bytes:%Lu (%Lu.%lu %sb)%s", ull, int_part, frac_part, ext, end);
-}
-
-static void ife_print(struct interface *ptr)
-{
-    struct aftype *ap;
-    struct hwtype *hw;
-    int hf;
-    int can_compress = 0;
-
-#if HAVE_AFIPX
-    static struct aftype *ipxtype = NULL;
-#endif
-#if HAVE_AFECONET
-    static struct aftype *ectype = NULL;
-#endif
-#if HAVE_AFATALK
-    static struct aftype *ddptype = NULL;
-#endif
-#if HAVE_AFINET6
-    FILE *f;
-    char addr6[40], devname[20];
-    struct sockaddr_in6 sap;
-    int plen, scope, dad_status, if_idx;
-    extern struct aftype inet6_aftype;
-    char addr6p[8][5];
-#endif
-
-    ap = get_afntype(ptr->addr.sa_family);
-    if (ap == NULL)
-       ap = get_afntype(0);
-
-    hf = ptr->type;
-
-    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
-       can_compress = 1;
-
-    hw = get_hwntype(hf);
-    if (hw == NULL)
-       hw = get_hwntype(-1);
-
-    printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
-    /* For some hardware types (eg Ash, ATM) we don't print the 
-       hardware address if it's null.  */
-    if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
-                                 hw->suppress_null_addr)))
-       printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
-#ifdef IFF_PORTSEL
-    if (ptr->flags & IFF_PORTSEL) {
-       printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
-       if (ptr->flags & IFF_AUTOMEDIA)
-           printf(_("(auto)"));
-    }
-#endif
-    printf("\n");
-
-#if HAVE_AFINET
-    if (ptr->has_ip) {
-       printf(_("          %s addr:%s "), ap->name,
-              ap->sprint(&ptr->addr, 1));
-       if (ptr->flags & IFF_POINTOPOINT) {
-           printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
-       }
-       if (ptr->flags & IFF_BROADCAST) {
-           printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
-       }
-       printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
-    }
-#endif
-
-#if HAVE_AFINET6
-    /* FIXME: should be integrated into interface.c.   */
-
-    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
-       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
-                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
-                 &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
-           if (!strcmp(devname, ptr->name)) {
-               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
-                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
-               inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
-               printf(_("          inet6 addr: %s/%d"),
-                inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
-               printf(_(" Scope:"));
-               switch (scope) {
-               case 0:
-                   printf(_("Global"));
-                   break;
-               case IPV6_ADDR_LINKLOCAL:
-                   printf(_("Link"));
-                   break;
-               case IPV6_ADDR_SITELOCAL:
-                   printf(_("Site"));
-                   break;
-               case IPV6_ADDR_COMPATv4:
-                   printf(_("Compat"));
-                   break;
-               case IPV6_ADDR_LOOPBACK:
-                   printf(_("Host"));
-                   break;
-               default:
-                   printf(_("Unknown"));
-               }
-               printf("\n");
-           }
-       }
-       fclose(f);
-    }
-#endif
-
-#if HAVE_AFIPX
-    if (ipxtype == NULL)
-       ipxtype = get_afntype(AF_IPX);
-
-    if (ipxtype != NULL) {
-       if (ptr->has_ipx_bb)
-           printf(_("          IPX/Ethernet II addr:%s\n"),
-                  ipxtype->sprint(&ptr->ipxaddr_bb, 1));
-       if (ptr->has_ipx_sn)
-           printf(_("          IPX/Ethernet SNAP addr:%s\n"),
-                  ipxtype->sprint(&ptr->ipxaddr_sn, 1));
-       if (ptr->has_ipx_e2)
-           printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
-                  ipxtype->sprint(&ptr->ipxaddr_e2, 1));
-       if (ptr->has_ipx_e3)
-           printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
-                  ipxtype->sprint(&ptr->ipxaddr_e3, 1));
-    }
-#endif
-
-#if HAVE_AFATALK
-    if (ddptype == NULL)
-       ddptype = get_afntype(AF_APPLETALK);
-    if (ddptype != NULL) {
-       if (ptr->has_ddp)
-           printf(_("          EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1));
-    }
-#endif
-
-#if HAVE_AFECONET
-    if (ectype == NULL)
-       ectype = get_afntype(AF_ECONET);
-    if (ectype != NULL) {
-       if (ptr->has_econet)
-           printf(_("          econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1));
-    }
-#endif
-
-    printf("          ");
-    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
-    if (ptr->flags == 0)
-       printf(_("[NO FLAGS] "));
-    if (ptr->flags & IFF_UP)
-       printf(_("UP "));
-    if (ptr->flags & IFF_BROADCAST)
-       printf(_("BROADCAST "));
-    if (ptr->flags & IFF_DEBUG)
-       printf(_("DEBUG "));
-    if (ptr->flags & IFF_LOOPBACK)
-       printf(_("LOOPBACK "));
-    if (ptr->flags & IFF_POINTOPOINT)
-       printf(_("POINTOPOINT "));
-    if (ptr->flags & IFF_NOTRAILERS)
-       printf(_("NOTRAILERS "));
-    if (ptr->flags & IFF_RUNNING)
-       printf(_("RUNNING "));
-    if (ptr->flags & IFF_NOARP)
-       printf(_("NOARP "));
-    if (ptr->flags & IFF_PROMISC)
-       printf(_("PROMISC "));
-    if (ptr->flags & IFF_ALLMULTI)
-       printf(_("ALLMULTI "));
-    if (ptr->flags & IFF_SLAVE)
-       printf(_("SLAVE "));
-    if (ptr->flags & IFF_MASTER)
-       printf(_("MASTER "));
-    if (ptr->flags & IFF_MULTICAST)
-       printf(_("MULTICAST "));
-#ifdef HAVE_DYNAMIC
-    if (ptr->flags & IFF_DYNAMIC)
-       printf(_("DYNAMIC "));
-#endif
-    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
-    printf(_(" MTU:%d  Metric:%d"),
-          ptr->mtu, ptr->metric ? ptr->metric : 1);
-#ifdef SIOCSKEEPALIVE
-    if (ptr->outfill || ptr->keepalive)
-       printf(_("  Outfill:%d  Keepalive:%d"),
-              ptr->outfill, ptr->keepalive);
-#endif
-    printf("\n");
-
-    /* If needed, display the interface statistics. */
-
-    if (ptr->statistics_valid) {
-       /* XXX: statistics are currently only printed for the primary address,
-        *      not for the aliases, although strictly speaking they're shared
-        *      by all addresses.
-        */
-       printf("          ");
-
-       printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
-              ptr->stats.rx_packets, ptr->stats.rx_errors,
-              ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
-              ptr->stats.rx_frame_errors);
-       if (can_compress)
-           printf(_("             compressed:%lu\n"), ptr->stats.rx_compressed);
-       printf("          ");
-       printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
-              ptr->stats.tx_packets, ptr->stats.tx_errors,
-              ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
-              ptr->stats.tx_carrier_errors);
-       printf(_("          collisions:%lu "), ptr->stats.collisions);
-       if (can_compress)
-           printf(_("compressed:%lu "), ptr->stats.tx_compressed);
-       if (ptr->tx_queue_len != -1)
-           printf(_("txqueuelen:%d "), ptr->tx_queue_len);
-       printf("\n          R");
-       print_bytes_scaled(ptr->stats.rx_bytes, "  T");
-       print_bytes_scaled(ptr->stats.tx_bytes, "\n");
-
-    }
-
-    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
-        ptr->map.base_addr)) {
-       printf("          ");
-       if (ptr->map.irq)
-           printf(_("Interrupt:%d "), ptr->map.irq);
-       if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for 
-                                                  I/O maps */
-           printf(_("Base address:0x%x "), ptr->map.base_addr);
-       if (ptr->map.mem_start) {
-           printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
-       }
-       if (ptr->map.dma)
-           printf(_("DMA chan:%x "), ptr->map.dma);
-       printf("\n");
-    }
-    printf("\n");
-}
-
-
-static int do_if_print(struct interface *ife, void *cookie)
-{
-    int *opt_a = (int *) cookie;
-    int res; 
-
-    res = do_if_fetch(ife); 
-    if (res >= 0) {   
-       if ((ife->flags & IFF_UP) || *opt_a)
-           ife_print(ife);
-    }
-    return res;
-}
-
-static struct interface *lookup_interface(char *name)
-{
-    struct interface *ife = NULL;
-
-    if (if_readlist_proc(name) < 0) 
-           return NULL; 
-    ife = add_interface(name); 
-    return ife;
-}
-
-/* for ipv4 add/del modes */
-static int if_print(char *ifname)
-{
-    int res;
-
-    if (!ifname) {
-       res = for_all_interfaces(do_if_print, &interface_opt_a);
-    } else {
-       struct interface *ife;
-
-       ife = lookup_interface(ifname);
-       res = do_if_fetch(ife); 
-       if (res >= 0) 
-           ife_print(ife);
-    }
-    return res; 
-}
-
-int display_interfaces(char *ifname)
-{
-    int status;
-
-    /* Create a channel to the NET kernel. */
-    if ((skfd = sockets_open(0)) < 0) {
-               perror_msg_and_die("socket");
-    }
-
-    /* Do we have to show the current setup? */
-    status = if_print(ifname);
-    close(skfd);
-    exit(status < 0);
-}
diff --git a/busybox/libbb/isdirectory.c b/busybox/libbb/isdirectory.c
deleted file mode 100644 (file)
index 65f4fee..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include "libbb.h"
-
-/*
- * Return TRUE if a fileName is a directory.
- * Nonexistant files return FALSE.
- */
-int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
-{
-       int status;
-       int didMalloc = 0;
-
-       if (statBuf == NULL) {
-           statBuf = (struct stat *)xmalloc(sizeof(struct stat));
-           ++didMalloc;
-       }
-
-       if (followLinks == TRUE)
-               status = stat(fileName, statBuf);
-       else
-               status = lstat(fileName, statBuf);
-
-       if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
-           status = FALSE;
-       }
-       else status = TRUE;
-
-       if (didMalloc) {
-           free(statBuf);
-           statBuf = NULL;
-       }
-       return status;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/kernel_version.c b/busybox/libbb/kernel_version.c
deleted file mode 100644 (file)
index 09cd582..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/utsname.h>               /* for uname(2) */
-
-#include "libbb.h"
-
-/* Returns kernel version encoded as major*65536 + minor*256 + patch,
- * so, for example,  to check if the kernel is greater than 2.2.11:
- *     if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
- */
-extern int get_kernel_revision(void)
-{
-       struct utsname name;
-       char *s;
-       int i, r;
-
-       if (uname(&name) == -1) {
-               perror_msg("cannot get system information");
-               return (0);
-       }
-
-       s = name.release;
-       r = 0;
-       for (i=0 ; i<3 ; i++) {
-               r = r * 256 + atoi(strtok(s, "."));
-               s = NULL;
-       }
-       return r;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/last_char_is.c b/busybox/libbb/last_char_is.c
deleted file mode 100644 (file)
index 4e2ee92..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * busybox library eXtended function
- *
- * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <string.h>
-#include "libbb.h"
-
-/* Find out if the last character of a string matches the one given Don't
- * underrun the buffer if the string length is 0.  Also avoids a possible
- * space-hogging inline of strlen() per usage.
- */
-char * last_char_is(const char *s, int c)
-{
-       char *sret;
-       if (!s)
-           return NULL;
-       sret  = (char *)s+strlen(s)-1;
-       if (sret>=s && *sret == c) { 
-               return sret;
-       } else {
-               return NULL;
-       }
-}
diff --git a/busybox/libbb/libbb.h b/busybox/libbb/libbb.h
deleted file mode 100644 (file)
index 30f0bb9..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Busybox main internal header file
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-#ifndef        __LIBBB_H__
-#define        __LIBBB_H__    1
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <netdb.h>
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#include <features.h>
-
-#ifndef _BB_INTERNAL_H_
-#include "../busybox.h"
-#endif
-
-#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
-/* libc5 doesn't define socklen_t */
-typedef unsigned int socklen_t;
-/* libc5 doesn't implement BSD 4.4 daemon() */
-extern int daemon (int nochdir, int noclose);
-/* libc5 doesn't implement strtok_r */
-char *strtok_r(char *s, const char *delim, char **ptrptr);
-#endif 
-
-/* Some useful definitions */
-#define FALSE   ((int) 0)
-#define TRUE    ((int) 1)
-#define SKIP   ((int) 2)
-
-/* for mtab.c */
-#define MTAB_GETMOUNTPT '1'
-#define MTAB_GETDEVICE  '2'
-
-#define BUF_SIZE        8192
-#define EXPAND_ALLOC    1024
-
-static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); }
-static inline int is_octal(int ch)   { return ((ch >= '0') && (ch <= '7')); }
-
-/* Macros for min/max.  */
-#ifndef MIN
-#define        MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-#ifndef MAX
-#define        MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-
-
-extern void show_usage(void) __attribute__ ((noreturn));
-extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
-extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
-extern void perror_msg(const char *s, ...);
-extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-extern void vherror_msg(const char *s, va_list p);
-extern void herror_msg(const char *s, ...);
-extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-
-/* These two are used internally -- you shouldn't need to use them */
-extern void verror_msg(const char *s, va_list p);
-extern void vperror_msg(const char *s, va_list p);
-
-const char *mode_string(int mode);
-const char *time_string(time_t timeVal);
-int is_directory(const char *name, int followLinks, struct stat *statBuf);
-int isDevice(const char *name);
-
-int remove_file(const char *path, int flags);
-int copy_file(const char *source, const char *dest, int flags);
-int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
-char *buildName(const char *dirName, const char *fileName);
-int makeString(int argc, const char **argv, char *buf, int bufLen);
-char *getChunk(int size);
-char *chunkstrdup(const char *str);
-void freeChunks(void);
-ssize_t safe_read(int fd, void *buf, size_t count);
-int full_write(int fd, const char *buf, int len);
-int full_read(int fd, char *buf, int len);
-int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst,
-         int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
-         int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
-         void* userData);
-
-extern int parse_mode( const char* s, mode_t* theMode);
-
-extern int get_kernel_revision(void);
-
-extern int get_console_fd(char* tty_name);
-extern struct mntent *find_mount_point(const char *name, const char *table);
-extern void write_mtab(char* blockDevice, char* directory, 
-       char* filesystemType, long flags, char* string_flags);
-extern void erase_mtab(const char * name);
-extern long atoi_w_units (const char *cp);
-extern pid_t* find_pid_by_name( char* pidName);
-extern char *find_real_root_device_name(const char* name);
-extern char *get_line_from_file(FILE *file);
-extern void print_file(FILE *file);
-extern int copyfd(int fd1, int fd2);
-extern int print_file_by_name(char *filename);
-extern char process_escape_sequence(const char **ptr);
-extern char *get_last_path_component(char *path);
-extern FILE *wfopen(const char *path, const char *mode);
-extern FILE *xfopen(const char *path, const char *mode);
-extern void chomp(char *s);
-extern void trim(char *s);
-extern struct BB_applet *find_applet_by_name(const char *name);
-void run_applet_by_name(const char *name, int argc, char **argv);
-
-#ifndef DMALLOC
-extern void *xmalloc (size_t size);
-extern void *xrealloc(void *old, size_t size);
-extern void *xcalloc(size_t nmemb, size_t size);
-extern char *xstrdup (const char *s);
-#endif
-extern char *xstrndup (const char *s, int n);
-extern char * safe_strncpy(char *dst, const char *src, size_t size);
-
-struct suffix_mult {
-       const char *suffix;
-       int mult;
-};
-
-extern unsigned long parse_number(const char *numstr,
-               const struct suffix_mult *suffixes);
-
-
-/* These parse entries in /etc/passwd and /etc/group.  This is desirable
- * for BusyBox since we want to avoid using the glibc NSS stuff, which
- * increases target size and is often not needed embedded systems.  */
-extern long my_getpwnam(const char *name);
-extern long my_getgrnam(const char *name);
-extern void my_getpwuid(char *name, long uid);
-extern void my_getgrgid(char *group, long gid);
-extern long my_getpwnamegid(const char *name);
-
-extern int device_open(char *device, int mode);
-
-extern int del_loop(const char *device);
-extern int set_loop(const char *device, const char *file, int offset, int *loopro);
-extern char *find_unused_loop_device (void);
-
-
-#if (__GLIBC__ < 2)
-extern int vdprintf(int d, const char *format, va_list ap);
-#endif
-
-int nfsmount(const char *spec, const char *node, int *flags,
-            char **extra_opts, char **mount_opts, int running_bg);
-
-void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg);
-void syslog_msg(int facility, int pri, const char *msg);
-
-/* Include our own copy of struct sysinfo to avoid binary compatability
- * problems with Linux 2.4, which changed things.  Grumble, grumble. */
-struct sysinfo {
-       long uptime;                    /* Seconds since boot */
-       unsigned long loads[3];         /* 1, 5, and 15 minute load averages */
-       unsigned long totalram;         /* Total usable main memory size */
-       unsigned long freeram;          /* Available memory size */
-       unsigned long sharedram;        /* Amount of shared memory */
-       unsigned long bufferram;        /* Memory used by buffers */
-       unsigned long totalswap;        /* Total swap space size */
-       unsigned long freeswap;         /* swap space still available */
-       unsigned short procs;           /* Number of current processes */
-       unsigned short pad;                     /* Padding needed for m68k */
-       unsigned long totalhigh;        /* Total high memory size */
-       unsigned long freehigh;         /* Available high memory size */
-       unsigned int mem_unit;          /* Memory unit size in bytes */
-       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
-};
-extern int sysinfo (struct sysinfo* info);
-
-enum {
-       KILOBYTE = 1024,
-       MEGABYTE = (KILOBYTE*1024),
-       GIGABYTE = (MEGABYTE*1024)
-};
-const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit);
-
-int ask_confirmation(void);
-int klogctl(int type, char * b, int len);
-
-char *xgetcwd(char *cwd);
-char *xreadlink(const char *path);
-char *concat_path_file(const char *path, const char *filename);
-char *last_char_is(const char *s, int c);
-
-extern long arith (const char *startbuf, int *errcode);
-
-typedef struct file_headers_s {
-       char *name;
-       char *link_name;
-       off_t size;
-       uid_t uid;
-       gid_t gid;
-       mode_t mode;
-       time_t mtime;
-       dev_t device;
-} file_header_t;
-file_header_t *get_header_ar(FILE *in_file);
-file_header_t *get_header_cpio(FILE *src_stream);
-file_header_t *get_header_tar(FILE *tar_stream);
-
-enum extract_functions_e {
-       extract_verbose_list = 1,
-       extract_list = 2,
-       extract_one_to_buffer = 4,
-       extract_to_stdout = 8,
-       extract_all_to_fs = 16,
-       extract_preserve_date = 32,
-       extract_data_tar_gz = 64,
-       extract_control_tar_gz = 128,
-       extract_unzip_only = 256,
-       extract_unconditional = 512,
-       extract_create_leading_dirs = 1024,
-       extract_quiet = 2048,
-       extract_exclude_list = 4096
-};
-char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *),
-       const int extract_function, const char *prefix, char **extract_names);
-char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function,
-       const char *prefix, const char *filename);
-int read_package_field(const char *package_buffer, char **field_name, char **field_value);
-char *fgets_str(FILE *file, const char *terminating_string);
-
-extern int unzip(FILE *l_in_file, FILE *l_out_file);
-extern void gz_close(int gunzip_pid);
-extern FILE *gz_open(FILE *compressed_file, int *pid);
-
-extern struct hostent *xgethostbyname(const char *name);
-extern int create_icmp_socket(void);
-
-char *dirname (char *path);
-
-int make_directory (char *path, long mode, int flags);
-
-const char *u_signal_names(const char *str_sig, int *signo, int startnum);
-char *simplify_path(const char *path);
-
-#define CT_AUTO        0
-#define CT_UNIX2DOS    1
-#define CT_DOS2UNIX    2
-/* extern int convert(char *fn, int ConvType); */
-
-enum {
-       FILEUTILS_PRESERVE_STATUS = 1,
-       FILEUTILS_PRESERVE_SYMLINKS = 2,
-       FILEUTILS_RECUR = 4,
-       FILEUTILS_FORCE = 8,
-       FILEUTILS_INTERACTIVE = 16
-};
-
-extern const char *applet_name;
-extern const char * const full_version;
-extern const char * const name_too_long;
-extern const char * const omitting_directory;
-extern const char * const not_a_directory;
-extern const char * const memory_exhausted;
-extern const char * const invalid_date;
-extern const char * const invalid_option;
-extern const char * const io_error;
-extern const char * const dash_dash_help;
-extern const char * const write_error;
-extern const char * const too_few_args;
-extern const char * const name_longer_than_foo;
-extern const char * const unknown;
-extern const char * const can_not_create_raw_socket;
-
-#ifdef BB_FEATURE_DEVFS
-# define CURRENT_VC "/dev/vc/0"
-# define VC_1 "/dev/vc/1"
-# define VC_2 "/dev/vc/2"
-# define VC_3 "/dev/vc/3"
-# define VC_4 "/dev/vc/4"
-# define VC_5 "/dev/vc/5"
-# define SC_0 "/dev/tts/0"
-# define SC_1 "/dev/tts/1"
-# define VC_FORMAT "/dev/vc/%d"
-# define SC_FORMAT "/dev/tts/%d"
-#else
-# define CURRENT_VC "/dev/tty0"
-# define VC_1 "/dev/tty1"
-# define VC_2 "/dev/tty2"
-# define VC_3 "/dev/tty3"
-# define VC_4 "/dev/tty4"
-# define VC_5 "/dev/tty5"
-# define SC_0 "/dev/ttyS0"
-# define SC_1 "/dev/ttyS1"
-# define VC_FORMAT "/dev/tty%d"
-# define SC_FORMAT "/dev/ttyS%d"
-#endif
-
-/* The following devices are the same on devfs and non-devfs systems.  */
-#define CURRENT_TTY "/dev/tty"
-#define CONSOLE_DEV "/dev/console"
-
-#endif /* __LIBBB_H__ */
diff --git a/busybox/libbb/libc5.c b/busybox/libbb/libc5.c
deleted file mode 100644 (file)
index 20295fd..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/* vi: set sw=4 ts=4: */
-
-
-#include <features.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <unistd.h>
-
-
-#if __GNU_LIBRARY__ < 5
-
-
-/* Copyright (C) 1991 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
-
-The GNU C 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
-
-/*
- * Modified by Manuel Novoa III     Mar 1, 2001
- *
- * Converted original strtok.c code of strtok to __strtok_r.
- * Cleaned up logic and reduced code size.
- */
-
-
-char *strtok_r(char *s, const char *delim, char **save_ptr)
-{
-       char *token;
-
-       token = 0;                                      /* Initialize to no token. */
-
-       if (s == 0) {                           /* If not first time called... */
-               s = *save_ptr;                  /* restart from where we left off. */
-       }
-       
-       if (s != 0) {                           /* If not finished... */
-               *save_ptr = 0;
-
-               s += strspn(s, delim);  /* Skip past any leading delimiters. */
-               if (*s != '\0') {               /* We have a token. */
-                       token = s;
-                       *save_ptr = strpbrk(token, delim); /* Find token's end. */
-                       if (*save_ptr != 0) {
-                               /* Terminate the token and make SAVE_PTR point past it.  */
-                               *(*save_ptr)++ = '\0';
-                       }
-               }
-       }
-
-       return token;
-}
-
-/* Basically getdelim() with the delimiter hard wired to '\n' */
-ssize_t getline(char **linebuf, size_t *n, FILE *file)
-{
-      return (getdelim (linebuf, n, '\n', file));
-}
-
-
-/*
- * daemon implementation for uClibc
- *
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Modified for uClibc by Erik Andersen 
- *        <andersee@debian.org>, <andersen@lineo.com>
- *
- * The uClibc Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- * 
- * The GNU C 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
- * Library General Public License for more details.
- * 
- * You should have received a copy of the GNU Library General Public
- * License along with the GNU C Library; see the file COPYING.LIB.  If not,
- * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA. 
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-int daemon( int nochdir, int noclose )
-{
-    int fd;
-
-    switch (fork()) {
-       case -1:
-           return(-1);
-       case 0:
-           break;
-       default:
-           _exit(0);
-    }
-
-    if (setsid() == -1)
-       return(-1);
-
-    if (!nochdir)
-       chdir("/");
-
-    if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
-       dup2(fd, STDIN_FILENO);
-       dup2(fd, STDOUT_FILENO);
-       dup2(fd, STDERR_FILENO);
-       if (fd > 2)
-           close(fd);
-    }
-    return(0);
-}
-
-
-/*-
- * Copyright (c) 1990, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
-#endif 
-
diff --git a/busybox/libbb/loop.c b/busybox/libbb/loop.c
deleted file mode 100644 (file)
index 4754b8d..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "libbb.h"
-#include "loop.h" /* Pull in loop device support */
-
-extern int del_loop(const char *device)
-{
-       int fd;
-
-       if ((fd = open(device, O_RDONLY)) < 0) {
-               perror_msg("%s", device);
-               return (FALSE);
-       }
-       if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
-               perror_msg("ioctl: LOOP_CLR_FD");
-               return (FALSE);
-       }
-       close(fd);
-       return (TRUE);
-}
-
-extern int set_loop(const char *device, const char *file, int offset,
-                                       int *loopro)
-{
-       struct loop_info loopinfo;
-       int fd, ffd, mode;
-
-       mode = *loopro ? O_RDONLY : O_RDWR;
-       if ((ffd = open(file, mode)) < 0 && !*loopro
-               && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
-               perror_msg("%s", file);
-               return 1;
-       }
-       if ((fd = open(device, mode)) < 0) {
-               close(ffd);
-               perror_msg("%s", device);
-               return 1;
-       }
-       *loopro = (mode == O_RDONLY);
-
-       memset(&loopinfo, 0, sizeof(loopinfo));
-       safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
-
-       loopinfo.lo_offset = offset;
-
-       loopinfo.lo_encrypt_key_size = 0;
-       if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
-               perror_msg("ioctl: LOOP_SET_FD");
-               close(fd);
-               close(ffd);
-               return 1;
-       }
-       if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
-               (void) ioctl(fd, LOOP_CLR_FD, 0);
-               perror_msg("ioctl: LOOP_SET_STATUS");
-               close(fd);
-               close(ffd);
-               return 1;
-       }
-       close(fd);
-       close(ffd);
-       return 0;
-}
-
-extern char *find_unused_loop_device(void)
-{
-       char dev[20];
-       int i, fd;
-       struct stat statbuf;
-       struct loop_info loopinfo;
-
-       for (i = 0; i <= 7; i++) {
-               sprintf(dev, "/dev/loop%d", i);
-               if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
-                       if ((fd = open(dev, O_RDONLY)) >= 0) {
-                               if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) {
-                                       if (errno == ENXIO) {   /* probably free */
-                                               close(fd);
-                                               return strdup(dev);
-                                       }
-                               }
-                               close(fd);
-                       }
-               }
-       }
-       return NULL;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/make_directory.c b/busybox/libbb/make_directory.c
deleted file mode 100644 (file)
index a06a410..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini make_directory implementation for busybox
- *
- * Copyright (C) 2001  Matt Kraai.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "libbb.h"
-
-/* Create the directory PATH with mode MODE, or the default if MODE is -1.
- * Also create parent directories as necessary if flags contains
- * FILEUTILS_RECUR.  */
-
-int make_directory (char *path, long mode, int flags)
-{
-       if (!(flags & FILEUTILS_RECUR)) {
-               if (mkdir (path, 0777) < 0) {
-                       perror_msg ("Cannot create directory `%s'", path);
-                       return -1;
-               }
-
-               if (mode != -1 && chmod (path, mode) < 0) {
-                       perror_msg ("Cannot set permissions of directory `%s'", path);
-                       return -1;
-               }
-       } else {
-               struct stat st;
-
-               if (stat (path, &st) < 0 && errno == ENOENT) {
-                       int status;
-                       char *buf, *parent;
-                       mode_t mask;
-
-                       mask = umask (0);
-                       umask (mask);
-
-                       buf = xstrdup (path);
-                       parent = dirname (buf);
-                       status = make_directory (parent, (0777 & ~mask) | 0300,
-                                       FILEUTILS_RECUR);
-                       free (buf);
-
-                       if (status < 0 || make_directory (path, mode, 0) < 0)
-                               return -1;
-               }
-       }
-
-       return 0;
-}
diff --git a/busybox/libbb/messages.c b/busybox/libbb/messages.c
deleted file mode 100644 (file)
index 552c3ab..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Copyright (C) 2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "libbb.h"
-
-#ifdef L_full_version
-       const char * const full_version = BB_BANNER " multi-call binary";
-#endif
-#ifdef L_name_too_long
-       const char * const name_too_long = "file name too long";
-#endif
-
-#ifdef L_omitting_directory
-       const char * const omitting_directory = "%s: omitting directory";
-#endif
-#ifdef L_not_a_directory
-       const char * const not_a_directory = "%s: not a directory";
-#endif
-#ifdef L_memory_exhausted
-       const char * const memory_exhausted = "memory exhausted";
-#endif
-#ifdef L_invalid_date
-       const char * const invalid_date = "invalid date `%s'";
-#endif
-#ifdef L_invalid_option
-       const char * const invalid_option = "invalid option -- %c";
-#endif
-#ifdef L_io_error
-       const char * const io_error = "%s: input/output error -- %s";
-#endif
-#ifdef L_dash_dash_help
-       const char * const dash_dash_help = "--help";
-#endif
-#ifdef L_write_error
-       const char * const write_error = "Write Error";
-#endif
-#ifdef L_too_few_args
-       const char * const too_few_args = "too few arguments";
-#endif
-#ifdef L_name_longer_than_foo
-       const char * const name_longer_than_foo = "Names longer than %d chars not supported.";
-#endif
-#ifdef L_unknown
-       const char * const unknown = "(unknown)";
-#endif
-
-#ifdef L_can_not_create_raw_socket
-       const char * const can_not_create_raw_socket = "can`t create raw socket";
-#endif
diff --git a/busybox/libbb/mk_loop_h.sh b/busybox/libbb/mk_loop_h.sh
deleted file mode 100755 (executable)
index 71c9873..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-#
-# Figure out (i) the type of dev_t (ii) the defines for loop stuff
-#
-# Output of this script is normally redirected to "loop.h".
-
-# Since 1.3.79 there is an include file <asm/posix_types.h>
-# that defines __kernel_dev_t.
-# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
-# If it exists, we use it, or, rather, <linux/posix_types.h> which
-# avoids namespace pollution.  Otherwise we guess that __kernel_dev_t
-# is an unsigned short (which is true on i386, but false on alpha).
-
-# BUG: This test is actually broken if your gcc is not configured to
-# search /usr/include, as may well happen with cross-compilers.
-# It would be better to ask $(CC) if these files can be found.
-
-if [ -f /usr/include/linux/posix_types.h ]; then
-   echo '#include <linux/posix_types.h>'
-   echo '#undef dev_t'
-   echo '#define dev_t __kernel_dev_t'
-else
-   echo '#undef dev_t'
-   echo '#define dev_t unsigned short'
-fi
-
-# Next we have to find the loop stuff itself.
-# First try kernel source, then a private version.
-
-if [ -f /usr/include/linux/loop.h ]; then
-   echo '#include <linux/loop.h>'
-else
-   echo '#include "real_loop.h"'
-fi
-
-echo '#undef dev_t'
-
diff --git a/busybox/libbb/mode_string.c b/busybox/libbb/mode_string.c
deleted file mode 100644 (file)
index 0a3d6e6..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include "libbb.h"
-
-
-
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
-
-/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
-static const mode_t SBIT[] = {
-       0, 0, S_ISUID,
-       0, 0, S_ISGID,
-       0, 0, S_ISVTX
-};
-
-/* The 9 mode bits to test */
-static const mode_t MBIT[] = {
-       S_IRUSR, S_IWUSR, S_IXUSR,
-       S_IRGRP, S_IWGRP, S_IXGRP,
-       S_IROTH, S_IWOTH, S_IXOTH
-};
-
-static const char MODE1[]  = "rwxrwxrwx";
-static const char MODE0[]  = "---------";
-static const char SMODE1[] = "..s..s..t";
-static const char SMODE0[] = "..S..S..T";
-
-/*
- * Return the standard ls-like mode string from a file mode.
- * This is static and so is overwritten on each call.
- */
-const char *mode_string(int mode)
-{
-       static char buf[12];
-
-       int i;
-
-       buf[0] = TYPECHAR(mode);
-       for (i = 0; i < 9; i++) {
-               if (mode & SBIT[i])
-                       buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
-               else
-                       buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
-       }
-       return buf;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/module_syscalls.c b/busybox/libbb/module_syscalls.c
deleted file mode 100644 (file)
index 8326f15..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * some system calls possibly missing from libc
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-/* Kernel headers before 2.1.mumble need this on the Alpha to get
-   _syscall* defined.  */
-#define __LIBRARY__
-#include <sys/syscall.h>
-#ifndef __UCLIBC__
-#include <asm/unistd.h>
-#endif
-#include "libbb.h"
-
-
-#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
-/* These syscalls are not included as part of libc5 */
-_syscall1(int, delete_module, const char *, name);
-_syscall1(int, get_kernel_syms, __ptr_t, ks);
-
-/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments
- * (for 2.2 and 2.4 kernels).  Use the greatest common denominator,
- * and let the kernel cope with whatever it gets.  Its good at that. */
-_syscall5(int, init_module, void *, first, void *, second, void *, third,
-               void *, fourth, void *, fifth);
-
-#ifndef __NR_query_module
-#warning This kernel does not support the query_module syscall
-#warning -> The query_module system call is being stubbed out...
-int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)
-{
-       fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
-       fprintf(stderr, "with a kernel supporting the query_module system call. -Erik\n\n");
-       errno=ENOSYS;
-       return -1;
-}
-#else
-_syscall5(int, query_module, const char *, name, int, which,
-               void *, buf, size_t, bufsize, size_t*, ret);
-#endif
-
-/* Jump through hoops to fixup error return codes */
-#define __NR___create_module  __NR_create_module
-static inline _syscall2(long, __create_module, const char *, name, size_t, size)
-unsigned long create_module(const char *name, size_t size)
-{
-       long ret = __create_module(name, size);
-
-       if (ret == -1 && errno > 125) {
-               ret = -errno;
-               errno = 0;
-       }
-       return ret;
-}
-
-#endif /* __GNU_LIBRARY__ < 5 */
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/busybox/libbb/mtab.c b/busybox/libbb/mtab.c
deleted file mode 100644 (file)
index 28c9978..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <mntent.h>
-#include "libbb.h"
-
-extern const char mtab_file[]; /* Defined in utility.c */
-static const int MS_RDONLY = 1;        /* Mount read-only.  */
-
-void erase_mtab(const char *name)
-{
-       struct mntent entries[20];
-       int count = 0;
-       FILE *mountTable = setmntent(mtab_file, "r");
-       struct mntent *m;
-
-       /* Check if reading the mtab file failed */
-       if (mountTable == 0
-                       /* Bummer.  fall back on trying the /proc filesystem */
-                       && (mountTable = setmntent("/proc/mounts", "r")) == 0) {
-               perror_msg("%s", mtab_file);
-               return;
-       }
-
-       while ((m = getmntent(mountTable)) != 0) {
-               entries[count].mnt_fsname = strdup(m->mnt_fsname);
-               entries[count].mnt_dir = strdup(m->mnt_dir);
-               entries[count].mnt_type = strdup(m->mnt_type);
-               entries[count].mnt_opts = strdup(m->mnt_opts);
-               entries[count].mnt_freq = m->mnt_freq;
-               entries[count].mnt_passno = m->mnt_passno;
-               count++;
-       }
-       endmntent(mountTable);
-       if ((mountTable = setmntent(mtab_file, "w"))) {
-               int i;
-
-               for (i = 0; i < count; i++) {
-                       int result = (strcmp(entries[i].mnt_fsname, name) == 0
-                                                 || strcmp(entries[i].mnt_dir, name) == 0);
-
-                       if (result)
-                               continue;
-                       else
-                               addmntent(mountTable, &entries[i]);
-               }
-               endmntent(mountTable);
-       } else if (errno != EROFS)
-               perror_msg("%s", mtab_file);
-}
-
-void write_mtab(char *blockDevice, char *directory,
-                               char *filesystemType, long flags, char *string_flags)
-{
-       FILE *mountTable = setmntent(mtab_file, "a+");
-       struct mntent m;
-
-       if (mountTable == 0) {
-               perror_msg("%s", mtab_file);
-               return;
-       }
-       if (mountTable) {
-               int length = strlen(directory);
-
-               if (length > 1 && directory[length - 1] == '/')
-                       directory[length - 1] = '\0';
-
-               if (filesystemType == 0) {
-                       struct mntent *p = find_mount_point(blockDevice, "/proc/mounts");
-
-                       if (p && p->mnt_type)
-                               filesystemType = p->mnt_type;
-               }
-               m.mnt_fsname = blockDevice;
-               m.mnt_dir = directory;
-               m.mnt_type = filesystemType ? filesystemType : "default";
-
-               if (*string_flags) {
-                       m.mnt_opts = string_flags;
-               } else {
-                       if ((flags | MS_RDONLY) == flags)
-                               m.mnt_opts = "ro";
-                       else
-                               m.mnt_opts = "rw";
-               }
-
-               m.mnt_freq = 0;
-               m.mnt_passno = 0;
-               addmntent(mountTable, &m);
-               endmntent(mountTable);
-       }
-}
diff --git a/busybox/libbb/mtab_file.c b/busybox/libbb/mtab_file.c
deleted file mode 100644 (file)
index 56f8e06..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include "libbb.h"
-
-
-/* Busybox mount uses either /proc/mounts or /dev/mtab to 
- * get the list of currently mounted filesystems */ 
-#if defined BB_FEATURE_MTAB_SUPPORT
-const char mtab_file[] = "/etc/mtab";
-#else
-#  if defined BB_FEATURE_USE_DEVPS_PATCH
-      const char mtab_file[] = "/dev/mtab";
-#  else
-      const char mtab_file[] = "/proc/mounts";
-#  endif
-#endif
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/my_getgrgid.c b/busybox/libbb/my_getgrgid.c
deleted file mode 100644 (file)
index fabd477..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-/* gets a groupname given a gid */
-void my_getgrgid(char *group, long gid)
-{
-       struct group *mygroup;
-
-       mygroup  = getgrgid(gid);
-       if (mygroup==NULL)
-               sprintf(group, "%-8ld ", (long)gid);
-       else
-               strcpy(group, mygroup->gr_name);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/my_getgrnam.c b/busybox/libbb/my_getgrnam.c
deleted file mode 100644 (file)
index e3226a2..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* returns a gid given a group name */
-long my_getgrnam(const char *name)
-{
-       struct group *mygroup;
-
-       mygroup  = getgrnam(name);
-       if (mygroup==NULL)
-               error_msg_and_die("unknown group name: %s", name);
-
-       return (mygroup->gr_gid);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/my_getpwnam.c b/busybox/libbb/my_getpwnam.c
deleted file mode 100644 (file)
index ae73ae7..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* returns a uid given a username */
-long my_getpwnam(const char *name)
-{
-       struct passwd *myuser;
-
-       myuser  = getpwnam(name);
-       if (myuser==NULL)
-               error_msg_and_die("unknown user name: %s", name);
-
-       return myuser->pw_uid;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/my_getpwnamegid.c b/busybox/libbb/my_getpwnamegid.c
deleted file mode 100644 (file)
index fb3d148..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* gets a gid given a user name */
-long my_getpwnamegid(const char *name)
-{
-       struct group *mygroup;
-       struct passwd *myuser;
-
-       myuser=getpwnam(name);
-       if (myuser==NULL)
-               error_msg_and_die("unknown user name: %s", name);
-
-       mygroup  = getgrgid(myuser->pw_gid);
-       if (mygroup==NULL)
-               error_msg_and_die("unknown gid %ld", (long)myuser->pw_gid);
-
-       return mygroup->gr_gid;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/my_getpwuid.c b/busybox/libbb/my_getpwuid.c
deleted file mode 100644 (file)
index 46c7a88..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* gets a username given a uid */
-void my_getpwuid(char *name, long uid)
-{
-       struct passwd *myuser;
-
-       myuser  = getpwuid(uid);
-       if (myuser==NULL)
-               sprintf(name, "%-8ld ", (long)uid);
-       else
-               strcpy(name, myuser->pw_name);
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/parse_mode.c b/busybox/libbb/parse_mode.c
deleted file mode 100644 (file)
index 30d2f21..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-
-/* This function parses the sort of string you might pass
- * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the
- * correct mode described by the string. */
-extern int parse_mode(const char *s, mode_t * theMode)
-{
-       static const mode_t group_set[] = { 
-               S_ISUID | S_IRWXU,              /* u */
-               S_ISGID | S_IRWXG,              /* g */
-               S_IRWXO,                                /* o */
-               S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
-       };
-
-       static const mode_t mode_set[] = {
-               S_IRUSR | S_IRGRP | S_IROTH, /* r */
-               S_IWUSR | S_IWGRP | S_IWOTH, /* w */
-               S_IXUSR | S_IXGRP | S_IXOTH, /* x */
-               S_ISUID | S_ISGID,              /* s */
-               S_ISVTX                                 /* t */
-       };
-
-       static const char group_chars[] = "ugoa";
-       static const char mode_chars[] = "rwxst";
-
-       const char *p;
-
-       mode_t andMode =
-               S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
-       mode_t orMode = 0;
-       mode_t mode;
-       mode_t groups;
-       char type;
-       char c;
-
-       if (s==NULL) {
-               return (FALSE);
-       }
-
-       do {
-               mode = 0;
-               groups = 0;
-       NEXT_GROUP:
-               if ((c = *s++) == '\0') {
-                       return -1;
-               }
-               for (p=group_chars ; *p ; p++) {
-                       if (*p == c) {
-                               groups |= group_set[(int)(p-group_chars)];
-                               goto NEXT_GROUP;
-                       }
-               }
-               switch (c) {
-                       case '=':
-                       case '+':
-                       case '-':
-                               type = c;
-                               if (groups == 0) { /* The default is "all" */
-                                       groups |= S_ISUID | S_ISGID | S_ISVTX
-                                                       | S_IRWXU | S_IRWXG | S_IRWXO;
-                               }
-                               break;
-                       default:
-                               if ((c < '0') || (c > '7') || (mode | groups)) {
-                                       return (FALSE);
-                               } else {
-                                       *theMode = strtol(--s, NULL, 8);
-                                       return (TRUE);
-                               }
-               }
-
-       NEXT_MODE:
-               if (((c = *s++) != '\0') && (c != ',')) {
-                       for (p=mode_chars ; *p ; p++) {
-                               if (*p == c) {
-                                       mode |= mode_set[(int)(p-mode_chars)];
-                                       goto NEXT_MODE;
-                               }
-                       }
-                       break;                          /* We're done so break out of loop.*/
-               }
-               switch (type) {
-                       case '=':
-                               andMode &= ~(groups); /* Now fall through. */
-                       case '+':
-                               orMode |= mode & groups;
-                               break;
-                       case '-':
-                               andMode &= ~(mode & groups);
-                               orMode &= ~(mode & groups);
-                               break;
-               }
-       } while (c == ',');
-
-       *theMode &= andMode;
-       *theMode |= orMode;
-
-       return TRUE;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/parse_number.c b/busybox/libbb/parse_number.c
deleted file mode 100644 (file)
index c90511d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-
-unsigned long parse_number(const char *numstr,
-               const struct suffix_mult *suffixes)
-{
-       const struct suffix_mult *sm;
-       unsigned long int ret;
-       int len;
-       char *end;
-       
-       ret = strtoul(numstr, &end, 10);
-       if (numstr == end)
-               error_msg_and_die("invalid number `%s'", numstr);
-       while (end[0] != '\0') {
-               sm = suffixes;
-               while ( sm != 0 ) {
-                       if(sm->suffix) {
-                               len = strlen(sm->suffix);
-                               if (strncmp(sm->suffix, end, len) == 0) {
-                                       ret *= sm->mult;
-                                       end += len;
-                                       break;
-                               }
-                       sm++;
-                       
-                       } else
-                               sm = 0;
-               }
-               if (sm == 0)
-                       error_msg_and_die("invalid number `%s'", numstr);
-       }
-       return ret;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/perror_msg.c b/busybox/libbb/perror_msg.c
deleted file mode 100644 (file)
index 18c71ab..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void perror_msg(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       vperror_msg(s, p);
-       va_end(p);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/perror_msg_and_die.c b/busybox/libbb/perror_msg_and_die.c
deleted file mode 100644 (file)
index 9d304a2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void perror_msg_and_die(const char *s, ...)
-{
-       va_list p;
-
-       va_start(p, s);
-       vperror_msg(s, p);
-       va_end(p);
-       exit(EXIT_FAILURE);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/print_file.c b/busybox/libbb/print_file.c
deleted file mode 100644 (file)
index bfedc5e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include "libbb.h"
-
-
-extern void print_file(FILE *file)
-{
-       fflush(stdout);
-       copyfd(fileno(file), fileno(stdout));
-       fclose(file);
-}
-
-extern int print_file_by_name(char *filename)
-{
-       struct stat statBuf;
-       int status = TRUE;
-
-       if(is_directory(filename, TRUE, &statBuf)==TRUE) {
-               error_msg("%s: Is directory", filename);
-               status = FALSE;
-       } else {
-               FILE *f = wfopen(filename, "r");
-               if(f!=NULL)
-                       print_file(f);
-               else
-                       status = FALSE;
-       }
-
-       return status;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/process_escape_sequence.c b/busybox/libbb/process_escape_sequence.c
deleted file mode 100644 (file)
index 67b0490..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) Manuel Nova III <mnovoa3@bellsouth.net>
- * and Vladimir Oleynik <vodz@usa.net> 
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 
- */
-
-#include <stdio.h>
-#include <limits.h>
-#include "libbb.h"
-
-
-
-char process_escape_sequence(const char **ptr)
-{
-       static const char charmap[] = {
-               'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
-               '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
-
-       const char *p;
-       const char *q;
-       int num_digits;
-       unsigned int n;
-       
-       n = 0;
-       q = *ptr;
-
-       for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) {
-               if ((*q < '0') || (*q > '7')) { /* not a digit? */
-                       break;
-               }
-               n = n * 8 + (*q++ - '0');
-       }
-
-       if (num_digits == 0) {  /* mnemonic escape sequence? */
-               for (p=charmap ; *p ; p++) {
-                       if (*p == *q) {
-                               q++;
-                               break;
-                       }
-               }
-               n = *(p+(sizeof(charmap)/2));
-       }
-
-          /* doesn't hurt to fall through to here from mnemonic case */
-       if (n > UCHAR_MAX) {    /* is octal code too big for a char? */
-               n /= 8;                 /* adjust value and */
-               --q;                            /* back up one char */
-       }
-
-       *ptr = q;
-       return (char) n;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/read_package_field.c b/busybox/libbb/read_package_field.c
deleted file mode 100644 (file)
index f561df8..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-/*
- * Gets the next package field from package_buffer, seperated into the field name
- * and field value, it returns the int offset to the first character of the next field
- */
-int read_package_field(const char *package_buffer, char **field_name, char **field_value)
-{
-       int offset_name_start = 0;
-       int offset_name_end = 0;
-       int offset_value_start = 0;
-       int offset_value_end = 0;
-       int offset = 0;
-       int next_offset;
-       int name_length;
-       int value_length;
-       int exit_flag = FALSE;
-
-       if (package_buffer == NULL) {
-               *field_name = NULL;
-               *field_value = NULL;
-               return(-1);
-       }
-       while (1) {
-               next_offset = offset + 1;
-               switch (package_buffer[offset]) {
-                       case('\0'):
-                               exit_flag = TRUE;
-                               break;
-                       case(':'):
-                               if (offset_name_end == 0) {
-                                       offset_name_end = offset;
-                                       offset_value_start = next_offset;
-                               }
-                               /* TODO: Name might still have trailing spaces if ':' isnt
-                                * immediately after name */
-                               break;
-                       case('\n'):
-                               /* TODO: The char next_offset may be out of bounds */
-                               if (package_buffer[next_offset] != ' ') {
-                                       exit_flag = TRUE;
-                                       break;
-                               }
-                       case('\t'):
-                       case(' '):
-                               /* increment the value start point if its a just filler */
-                               if (offset_name_start == offset) {
-                                       offset_name_start++;
-                               }
-                               if (offset_value_start == offset) {
-                                       offset_value_start++;
-                               }
-                               break;
-               }
-               if (exit_flag == TRUE) {
-                       /* Check that the names are valid */
-                       offset_value_end = offset;
-                       name_length = offset_name_end - offset_name_start;
-                       value_length = offset_value_end - offset_value_start;
-                       if (name_length == 0) {
-                               break;
-                       }
-                       if ((name_length > 0) && (value_length > 0)) {
-                               break;
-                       }
-
-                       /* If not valid, start fresh with next field */
-                       exit_flag = FALSE;
-                       offset_name_start = offset + 1;
-                       offset_name_end = 0;
-                       offset_value_start = offset + 1;
-                       offset_value_end = offset + 1;
-                       offset++;
-               }
-               offset++;
-       }
-       if (name_length == 0) {
-               *field_name = NULL;
-       } else {
-               *field_name = xstrndup(&package_buffer[offset_name_start], name_length);
-       }
-       if (value_length > 0) {
-               *field_value = xstrndup(&package_buffer[offset_value_start], value_length);
-       } else {
-               *field_value = NULL;
-       }
-       return(next_offset);
-}
-
diff --git a/busybox/libbb/real_loop.h b/busybox/libbb/real_loop.h
deleted file mode 100644 (file)
index 1bd7fa8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * include/linux/loop.h
- *
- * Written by Theodore Ts'o, 3/29/93.
- *
- * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
- * permitted under the GNU Public License.
- */
-
-#define LO_NAME_SIZE   64
-#define LO_KEY_SIZE    32
-       
-struct loop_info {
-       int             lo_number;      /* ioctl r/o */
-       dev_t           lo_device;      /* ioctl r/o */
-       unsigned long   lo_inode;       /* ioctl r/o */
-       dev_t           lo_rdevice;     /* ioctl r/o */
-       int             lo_offset;
-       int             lo_encrypt_type;
-       int             lo_encrypt_key_size;    /* ioctl w/o */
-       int             lo_flags;       /* ioctl r/o */
-       char            lo_name[LO_NAME_SIZE];
-       unsigned char   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
-       unsigned long   lo_init[2];
-       char            reserved[4];
-};
-
-#define LO_CRYPT_NONE  0
-#define LO_CRYPT_XOR   1
-#define LO_CRYPT_DES   2
-#define LO_CRYPT_IDEA  3
-#define MAX_LO_CRYPT   4
-
-#define LOOP_SET_FD    0x4C00
-#define LOOP_CLR_FD    0x4C01
-#define LOOP_SET_STATUS        0x4C02
-#define LOOP_GET_STATUS        0x4C03
diff --git a/busybox/libbb/recursive_action.c b/busybox/libbb/recursive_action.c
deleted file mode 100644 (file)
index 6672db1..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <stdlib.h>    /* free() */
-#include "libbb.h"
-
-#undef DEBUG_RECURS_ACTION
-
-
-/*
- * Walk down all the directories under the specified 
- * location, and do something (something specified
- * by the fileAction and dirAction function pointers).
- *
- * Unfortunately, while nftw(3) could replace this and reduce 
- * code size a bit, nftw() wasn't supported before GNU libc 2.1, 
- * and so isn't sufficiently portable to take over since glibc2.1
- * is so stinking huge.
- */
-int recursive_action(const char *fileName,
-                                       int recurse, int followLinks, int depthFirst,
-                                       int (*fileAction) (const char *fileName,
-                                                                          struct stat * statbuf,
-                                                                          void* userData),
-                                       int (*dirAction) (const char *fileName,
-                                                                         struct stat * statbuf,
-                                                                         void* userData),
-                                       void* userData)
-{
-       int status;
-       struct stat statbuf;
-       struct dirent *next;
-
-       if (followLinks == TRUE)
-               status = stat(fileName, &statbuf);
-       else
-               status = lstat(fileName, &statbuf);
-
-       if (status < 0) {
-#ifdef DEBUG_RECURS_ACTION
-               fprintf(stderr,
-                               "status=%d followLinks=%d TRUE=%d\n",
-                               status, followLinks, TRUE);
-#endif
-               perror_msg("%s", fileName);
-               return FALSE;
-       }
-
-       if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
-               if (fileAction == NULL)
-                       return TRUE;
-               else
-                       return fileAction(fileName, &statbuf, userData);
-       }
-
-       if (recurse == FALSE) {
-               if (S_ISDIR(statbuf.st_mode)) {
-                       if (dirAction != NULL)
-                               return (dirAction(fileName, &statbuf, userData));
-                       else
-                               return TRUE;
-               }
-       }
-
-       if (S_ISDIR(statbuf.st_mode)) {
-               DIR *dir;
-
-               if (dirAction != NULL && depthFirst == FALSE) {
-                       status = dirAction(fileName, &statbuf, userData);
-                       if (status == FALSE) {
-                               perror_msg("%s", fileName);
-                               return FALSE;
-                       } else if (status == SKIP)
-                               return TRUE;
-               }
-               dir = opendir(fileName);
-               if (!dir) {
-                       perror_msg("%s", fileName);
-                       return FALSE;
-               }
-               status = TRUE;
-               while ((next = readdir(dir)) != NULL) {
-                       char *nextFile;
-
-                       if ((strcmp(next->d_name, "..") == 0)
-                                       || (strcmp(next->d_name, ".") == 0)) {
-                               continue;
-                       }
-                       nextFile = concat_path_file(fileName, next->d_name);
-                       if (recursive_action(nextFile, TRUE, followLinks, depthFirst,
-                                               fileAction, dirAction, userData) == FALSE) {
-                               status = FALSE;
-                       }
-                       free(nextFile);
-               }
-               closedir(dir);
-               if (dirAction != NULL && depthFirst == TRUE) {
-                       if (dirAction(fileName, &statbuf, userData) == FALSE) {
-                               perror_msg("%s", fileName);
-                               return FALSE;
-                       }
-               }
-               if (status == FALSE)
-                       return FALSE;
-       } else {
-               if (fileAction == NULL)
-                       return TRUE;
-               else
-                       return fileAction(fileName, &statbuf, userData);
-       }
-       return TRUE;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/remove_file.c b/busybox/libbb/remove_file.c
deleted file mode 100644 (file)
index 3b84680..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini remove_file implementation for busybox
- *
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <utime.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include "libbb.h"
-
-extern int remove_file(const char *path, int flags)
-{
-       struct stat path_stat;
-       int path_exists = 1;
-
-       if (lstat(path, &path_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", path);
-                       return -1;
-               }
-
-               path_exists = 0;
-       }
-
-       if (!path_exists) {
-               if (!(flags & FILEUTILS_FORCE)) {
-                       perror_msg("cannot remove `%s'", path);
-                       return -1;
-               }
-               return 0;
-       }
-
-       if (S_ISDIR(path_stat.st_mode)) {
-               DIR *dp;
-               struct dirent *d;
-               int status = 0;
-
-               if (!(flags & FILEUTILS_RECUR)) {
-                       error_msg("%s: is a directory", path);
-                       return -1;
-               }
-
-               if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
-                                       isatty(0)) ||
-                               (flags & FILEUTILS_INTERACTIVE)) {
-                       fprintf(stderr, "%s: descend into directory `%s'? ", applet_name,
-                                       path);
-                       if (!ask_confirmation())
-                               return 0;
-               }
-
-               if ((dp = opendir(path)) == NULL) {
-                       perror_msg("unable to open `%s'", path);
-                       return -1;
-               }
-
-               while ((d = readdir(dp)) != NULL) {
-                       char *new_path;
-
-                       if (strcmp(d->d_name, ".") == 0 ||
-                                       strcmp(d->d_name, "..") == 0)
-                               continue;
-
-                       new_path = concat_path_file(path, d->d_name);
-                       if (remove_file(new_path, flags) < 0)
-                               status = -1;
-                       free(new_path);
-               }
-
-               if (closedir(dp) < 0) {
-                       perror_msg("unable to close `%s'", path);
-                       return -1;
-               }
-
-               if (flags & FILEUTILS_INTERACTIVE) {
-                       fprintf(stderr, "%s: remove directory `%s'? ", applet_name, path);
-                       if (!ask_confirmation())
-                               return status;
-               }
-
-               if (rmdir(path) < 0) {
-                       perror_msg("unable to remove `%s'", path);
-                       return -1;
-               }
-
-               return status;
-       } else {
-               if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
-                                       !S_ISLNK(path_stat.st_mode) &&
-                                       isatty(0)) ||
-                               (flags & FILEUTILS_INTERACTIVE)) {
-                       fprintf(stderr, "%s: remove `%s'? ", applet_name, path);
-                       if (!ask_confirmation())
-                               return 0;
-               }
-
-               if (unlink(path) < 0) {
-                       perror_msg("unable to remove `%s'", path);
-                       return -1;
-               }
-
-               return 0;
-       }
-}
diff --git a/busybox/libbb/safe_read.c b/busybox/libbb/safe_read.c
deleted file mode 100644 (file)
index dbf4aa7..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include "libbb.h"
-
-
-
-ssize_t safe_read(int fd, void *buf, size_t count)
-{
-       ssize_t n;
-
-       do {
-               n = read(fd, buf, count);
-       } while (n < 0 && errno == EINTR);
-
-       return n;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/safe_strncpy.c b/busybox/libbb/safe_strncpy.c
deleted file mode 100644 (file)
index 55ec798..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <string.h>
-#include "libbb.h"
-
-
-
-/* Like strncpy but make sure the resulting string is always 0 terminated. */  
-extern char * safe_strncpy(char *dst, const char *src, size_t size)
-{   
-       dst[size-1] = '\0';
-       return strncpy(dst, src, size-1);   
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/simplify_path.c b/busybox/libbb/simplify_path.c
deleted file mode 100644 (file)
index cf5b838..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * simplify_path implementation for busybox
- *
- *
- * Copyright (C) 2001  Manuel Novoa III  <mjn3@opensource.lineo.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-
-#include "libbb.h"
-
-char *simplify_path(const char *path)
-{
-       char *s, *start, *p;
-
-       if (path[0] == '/')
-               start = xstrdup(path);
-       else {
-               s = xgetcwd(NULL);
-               start = concat_path_file(s, path);
-               free(s);
-       }
-       p = s = start;
-
-       do {
-               if (*p == '/') {
-                       if (*s == '/') {        /* skip duplicate (or initial) slash */
-                               continue;
-                       } else if (*s == '.') {
-                               if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
-                                       continue;
-                               } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
-                                       ++s;
-                                       if (p > start) {
-                                               while (*--p != '/');    /* omit previous dir */
-                                       }
-                                       continue;
-                               }
-                       }
-               }
-               *++p = *s;
-       } while (*++s);
-
-       if ((p == start) || (*p != '/')) {      /* not a trailing slash */
-               ++p;                                    /* so keep last character */
-       }
-       *p = 0;
-
-       return start;
-}
diff --git a/busybox/libbb/syscalls.c b/busybox/libbb/syscalls.c
deleted file mode 100644 (file)
index 426a14a..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * some system calls possibly missing from libc
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-/* Kernel headers before 2.1.mumble need this on the Alpha to get
-   _syscall* defined.  */
-#define __LIBRARY__
-
-
-#include <sys/syscall.h>
-#ifndef __UCLIBC__
-#include <asm/unistd.h>
-#endif
-#include "libbb.h"
-
-#if defined(__ia64__)
-int sysfs( int option, unsigned int fs_index, char * buf)
-{
-       return(syscall(__NR_sysfs, option, fs_index, buf));
-}
-#else
-_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf);
-#endif
-
-#ifndef __NR_pivot_root
-#warning This kernel does not support the pivot_root syscall
-#warning -> The pivot_root system call is being stubbed out...
-int pivot_root(const char * new_root,const char * put_old)
-{
-       /* BusyBox was compiled against a kernel that did not support
-        *  the pivot_root system call.  To make this application work,
-        *  you will need to recompile with a kernel supporting the
-        *  pivot_root system call.
-        */
-       fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
-       fprintf(stderr, "with a kernel supporting the pivot_root system call. -Erik\n\n");
-       errno=ENOSYS;
-       return -1;
-}
-#else
-#  if defined(__ia64__)
-       int pivot_root(const char * new_root,const char * put_old)
-       {
-               return(syscall(__NR_pivot_root, new_root, put_old));
-       }
-#  else
-    _syscall2(int,pivot_root,const char *,new_root,const char *,put_old);
-#  endif
-#endif
-
-
-
-
-#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
-/* These syscalls are not included as part of libc5 */
-_syscall2(int, bdflush, int, func, int, data);
-
-#ifndef __alpha__
-# define __NR_klogctl __NR_syslog
-  _syscall3(int, klogctl, int, type, char *, b, int, len);
-#endif
-
-#ifndef __NR_umount2
-# warning This kernel does not support the umount2 syscall
-# warning -> The umount2 system call is being stubbed out...
-int umount2(const char * special_file, int flags)
-{
-       /* BusyBox was compiled against a kernel that did not support
-        *  the umount2 system call.  To make this application work,
-        *  you will need to recompile with a kernel supporting the
-        *  umount2 system call.
-        */
-       fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
-       fprintf(stderr, "with a kernel supporting the umount2 system call. -Erik\n\n");
-       errno=ENOSYS;
-       return -1;
-}
-# else
-_syscall2(int, umount2, const char *, special_file, int, flags);
-#endif
-
-
-#endif /* __GNU_LIBRARY__ < 5 */
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/syslog_msg_with_name.c b/busybox/libbb/syslog_msg_with_name.c
deleted file mode 100644 (file)
index 5dadcc4..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <sys/syslog.h>
-#include "libbb.h"
-
-void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg)
-{
-       openlog(name, 0, facility);
-       syslog(pri, "%s", msg);
-       closelog();
-}
-
-void syslog_msg(int facility, int pri, const char *msg)
-{
-       syslog_msg_with_name(applet_name, facility, pri, msg);
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/time_string.c b/busybox/libbb/time_string.c
deleted file mode 100644 (file)
index 0765290..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <utime.h>
-#include "libbb.h"
-
-
-/*
- * Return the standard ls-like time string from a time_t
- * This is static and so is overwritten on each call.
- */
-const char *time_string(time_t timeVal)
-{
-       time_t now;
-       char *str;
-       static char buf[26];
-
-       time(&now);
-
-       str = ctime(&timeVal);
-
-       strcpy(buf, &str[4]);
-       buf[12] = '\0';
-
-       if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
-               strcpy(&buf[7], &str[20]);
-               buf[11] = '\0';
-       }
-
-       return buf;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/trim.c b/busybox/libbb/trim.c
deleted file mode 100644 (file)
index 76b87ca..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include "libbb.h"
-
-
-void trim(char *s)
-{
-       int len = strlen(s);
-
-       /* trim trailing whitespace */
-       while ( len > 0 && isspace(s[len-1]))
-               s[--len]='\0';
-
-       /* trim leading whitespace */
-       memmove(s, &s[strspn(s, " \n\r\t\v")], len);
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/u_signal_names.c b/busybox/libbb/u_signal_names.c
deleted file mode 100644 (file)
index 623b103..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct signal_name {
-       const char *name;
-       int number;
-};
-
-static const struct signal_name signames[] = {
-       /* POSIX signals */
-       { "EXIT",       0 },            /* 0 */
-       { "HUP",        SIGHUP },       /* 1 */
-       { "INT",        SIGINT },       /* 2 */
-       { "QUIT",       SIGQUIT },      /* 3 */
-       { "ILL",        SIGILL },       /* 4 */
-       { "ABRT",       SIGABRT },      /* 6 */
-       { "FPE",        SIGFPE },       /* 8 */
-       { "KILL",       SIGKILL },      /* 9 */
-       { "SEGV",       SIGSEGV },      /* 11 */
-       { "PIPE",       SIGPIPE },      /* 13 */
-       { "ALRM",       SIGALRM },      /* 14 */
-       { "TERM",       SIGTERM },      /* 15 */
-       { "USR1",       SIGUSR1 },      /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
-       { "USR2",       SIGUSR2 },      /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
-       { "CHLD",       SIGCHLD },      /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
-       { "CONT",       SIGCONT },      /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
-       { "STOP",       SIGSTOP },      /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
-       { "TSTP",       SIGTSTP },      /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
-       { "TTIN",       SIGTTIN },      /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
-       { "TTOU",       SIGTTOU },      /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
-       /* Miscellaneous other signals */
-#ifdef SIGTRAP
-       { "TRAP",       SIGTRAP },      /* 5 */
-#endif
-#ifdef SIGIOT
-       { "IOT",        SIGIOT },       /* 6, same as SIGABRT */
-#endif
-#ifdef SIGEMT
-       { "EMT",        SIGEMT },       /* 7 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGBUS
-       { "BUS",        SIGBUS },       /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSYS
-       { "SYS",        SIGSYS },       /* 12 (mips,alpha,sparc*) */
-#endif
-#ifdef SIGSTKFLT
-       { "STKFLT",     SIGSTKFLT },    /* 16 (arm,i386,m68k,ppc) */
-#endif
-#ifdef SIGURG
-       { "URG",        SIGURG },       /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
-#endif
-#ifdef SIGIO
-       { "IO",         SIGIO },        /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
-#endif
-#ifdef SIGPOLL
-       { "POLL",       SIGPOLL },      /* same as SIGIO */
-#endif
-#ifdef SIGCLD
-       { "CLD",        SIGCLD },       /* same as SIGCHLD (mips) */
-#endif
-#ifdef SIGXCPU
-       { "XCPU",       SIGXCPU },      /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
-#endif
-#ifdef SIGXFSZ
-       { "XFSZ",       SIGXFSZ },      /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
-#endif
-#ifdef SIGVTALRM
-       { "VTALRM",     SIGVTALRM },    /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
-#endif
-#ifdef SIGPROF
-       { "PROF",       SIGPROF },      /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
-#endif
-#ifdef SIGPWR
-       { "PWR",        SIGPWR },       /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
-#endif
-#ifdef SIGINFO
-       { "INFO",       SIGINFO },      /* 29 (alpha) */
-#endif
-#ifdef SIGLOST
-       { "LOST",       SIGLOST },      /* 29 (arm,i386,m68k,ppc,sparc*) */
-#endif
-#ifdef SIGWINCH
-       { "WINCH",      SIGWINCH },     /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
-#endif
-#ifdef SIGUNUSED
-       { "UNUSED",     SIGUNUSED },    /* 31 (arm,i386,m68k,ppc) */
-#endif
-       {0, 0}
-};
-
-/*
-       if str_sig == NULL returned signal name [*signo],
-       if str_sig != NULL - set *signo from signal_name,
-               findings with digit number or with or without SIG-prefix name
-
-       if startnum=0 flag for support finding zero signal,
-               but str_sig="0" always found, (hmm - standart or realize?)
-       if startnum<0 returned reverse signal_number  <-> signal_name
-       if found error - returned NULL
-
-*/
-
-const char *
-u_signal_names(const char *str_sig, int *signo, int startnum)
-{
-       static char retstr[16];
-       const struct signal_name *s = signames;
-       static const char prefix[] = "SIG";
-       const char *sptr;
-
-       if(startnum)
-               s++;
-       if(str_sig==NULL) {
-               while (s->name != 0) {
-                       if(s->number == *signo)
-                               break;
-                       s++;
-               }
-       } else {
-               if (isdigit(((unsigned char)*str_sig))) {
-                       char *endp;
-                       long int sn = strtol(str_sig, &endp, 10);
-                       /* test correct and overflow */
-                       if(*endp == 0 && sn >= 0 && sn < NSIG) {
-                               *signo = (int)sn;
-                               /* test for unnamed */
-                               sptr = u_signal_names(0, signo, 0);
-                               if(sptr==NULL)
-                                       return NULL;
-                               if(sn!=0)
-                                       sptr += 3;
-                               return sptr;
-                       }
-               } else {
-                       sptr = str_sig;
-                       while (s->name != 0) {
-                               if (strcasecmp(s->name, sptr) == 0) {
-                                       *signo = s->number;
-                                       if(startnum<0) {
-                                               sprintf(retstr, "%d", *signo);
-                                               return retstr;
-                                       }
-                                       break;
-                               }
-                               if(s!=signames && sptr == str_sig &&
-                                               strncasecmp(sptr, prefix, 3) == 0) {
-                                       sptr += 3;      /* strlen(prefix) */
-                                       continue;
-                               }
-                               sptr = str_sig;
-                               s++;
-                       }
-               }
-       }
-       if(s->name==0)
-               return NULL;
-       if(s!=signames)
-               strcpy(retstr, prefix);
-        else
-               retstr[0] = 0;
-       return strcat(retstr, s->name);
-}
diff --git a/busybox/libbb/unarchive.c b/busybox/libbb/unarchive.c
deleted file mode 100644 (file)
index 4d47eff..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- *  Copyright (C) 2000 by Glenn McGrath
- *  Copyright (C) 2001 by Laurence Anderson
- *     
- *  Based on previous work by busybox developers and others.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <utime.h>
-#include "libbb.h"
-
-extern void seek_sub_file(FILE *src_stream, const int count);
-extern char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
- const int function, const char *prefix);
-
-
-#ifdef L_archive_offset
-off_t archive_offset;
-#else
-extern off_t archive_offset;
-#endif 
-
-#ifdef L_seek_sub_file
-void seek_sub_file(FILE *src_stream, const int count)
-{
-       int i;
-       /* Try to fseek as faster */
-       archive_offset += count;
-       if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) {
-       for (i = 0; i < count; i++) {
-               fgetc(src_stream);
-               }
-       }
-       return;
-}
-#endif 
-
-
-
-#ifdef L_extract_archive
-/* Extract the data postioned at src_stream to either filesystem, stdout or 
- * buffer depending on the value of 'function' which is defined in libbb.h 
- *
- * prefix doesnt have to be just a directory, it may prefix the filename as well.
- *
- * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath 
- * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have 
- * 'dpkg.' as their prefix
- *
- * For this reason if prefix does point to a dir then it must end with a
- * trailing '/' or else the last dir will be assumed to be the file prefix 
- */
-char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
- const int function, const char *prefix)
-{
-       FILE *dst_stream = NULL;
-       char *full_name = NULL;
-       char *buffer = NULL;
-       struct utimbuf t;
-
-       /* prefix doesnt have to be a proper path it may prepend 
-        * the filename as well */
-       if (prefix != NULL) {
-               /* strip leading '/' in filename to extract as prefix may not be dir */
-               /* Cant use concat_path_file here as prefix might not be a directory */
-               char *path = file_entry->name;
-               if (strncmp("./", path, 2) == 0) {
-                       path += 2;
-                       if (strlen(path) == 0) {
-                               return(NULL);
-                       }
-               }
-               full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
-               strcpy(full_name, prefix);
-               strcat(full_name, path);
-       } else {
-               full_name = file_entry->name;
-       }
-       if (function & extract_to_stdout) {
-               if (S_ISREG(file_entry->mode)) {
-                       copy_file_chunk(src_stream, out_stream, file_entry->size);                      
-                       archive_offset += file_entry->size;
-               }
-       }
-       else if (function & extract_one_to_buffer) { 
-               if (S_ISREG(file_entry->mode)) {
-                       buffer = (char *) xmalloc(file_entry->size + 1);
-                       fread(buffer, 1, file_entry->size, src_stream);
-                       buffer[file_entry->size] = '\0';
-                       archive_offset += file_entry->size;
-                       return(buffer);
-               }
-       }
-       else if (function & extract_all_to_fs) {
-               struct stat oldfile;
-               int stat_res;
-               stat_res = lstat (full_name, &oldfile);
-               if (stat_res == 0) { /* The file already exists */
-                       if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
-                               if (!S_ISDIR(oldfile.st_mode)) {
-                                       unlink(full_name); /* Directories might not be empty etc */
-                               }
-                       } else {
-                               if ((function & extract_quiet) != extract_quiet) {
-                                       error_msg("%s not created: newer or same age file exists", file_entry->name);
-                               }
-                               seek_sub_file(src_stream, file_entry->size);
-                               return (NULL);
-                       }
-               }
-               if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */
-                       char *buf, *parent;
-                       buf = xstrdup(full_name);
-                       parent = dirname(buf);
-                       if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) {
-                               if ((function & extract_quiet) != extract_quiet) {
-                                       error_msg("couldn't create leading directories");
-                               }
-                       }
-                       free (buf);
-               }
-               switch(file_entry->mode & S_IFMT) {
-                       case S_IFREG:
-                               if (file_entry->link_name) { /* Found a cpio hard link */
-                                       if (link(file_entry->link_name, full_name) != 0) {
-                                               if ((function & extract_quiet) != extract_quiet) {
-                                                       perror_msg("Cannot link from %s to '%s'",
-                                                               file_entry->name, file_entry->link_name);
-                                               }
-                                       }
-                               } else {
-                                       if ((dst_stream = wfopen(full_name, "w")) == NULL) {
-                                               seek_sub_file(src_stream, file_entry->size);
-                                               return NULL;
-                                       }
-                                       archive_offset += file_entry->size;
-                                       copy_file_chunk(src_stream, dst_stream, file_entry->size);                      
-                                       fclose(dst_stream);
-                               }
-                               break;
-                       case S_IFDIR:
-                               if (stat_res != 0) {
-                                       if (mkdir(full_name, file_entry->mode) < 0) {
-                                               if ((function & extract_quiet) != extract_quiet) {
-                                                       perror_msg("extract_archive: %s", full_name);
-                                               }
-                                       }
-                               }
-                               break;
-                       case S_IFLNK:
-                               if (symlink(file_entry->link_name, full_name) < 0) {
-                                       if ((function & extract_quiet) != extract_quiet) {
-                                               perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name);
-                                       }
-                                       return NULL;
-                               }
-                               break;
-                       case S_IFSOCK:
-                       case S_IFBLK:
-                       case S_IFCHR:
-                       case S_IFIFO:
-                               if (mknod(full_name, file_entry->mode, file_entry->device) == -1) {
-                                       if ((function & extract_quiet) != extract_quiet) {
-                                               perror_msg("Cannot create node %s", file_entry->name);
-                                       }
-                                       return NULL;
-                               }
-                               break;
-               }
-
-               /* Changing a symlink's properties normally changes the properties of the 
-                * file pointed to, so dont try and change the date or mode, lchown does
-                * does the right thing, but isnt available in older versions of libc */
-               if (S_ISLNK(file_entry->mode)) {
-#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1)
-                       lchown(full_name, file_entry->uid, file_entry->gid);
-#endif
-               } else {
-                       if (function & extract_preserve_date) {
-                               t.actime = file_entry->mtime;
-                               t.modtime = file_entry->mtime;
-                               utime(full_name, &t);
-                       }
-                       chmod(full_name, file_entry->mode);
-                       chown(full_name, file_entry->uid, file_entry->gid);
-               }
-       } else {
-               /* If we arent extracting data we have to skip it, 
-                * if data size is 0 then then just do it anyway
-                * (saves testing for it) */
-               seek_sub_file(src_stream, file_entry->size);
-       }
-
-       /* extract_list and extract_verbose_list can be used in conjunction
-        * with one of the above four extraction functions, so do this seperately */
-       if (function & extract_verbose_list) {
-               fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), 
-                       file_entry->uid, file_entry->gid,
-                       (int) file_entry->size, time_string(file_entry->mtime));
-       }
-       if ((function & extract_list) || (function & extract_verbose_list)){
-               /* fputs doesnt add a trailing \n, so use fprintf */
-               fprintf(out_stream, "%s\n", file_entry->name);
-       }
-
-       free(full_name);
-
-       return(NULL); /* Maybe we should say if failed */
-}
-#endif
-
-#ifdef L_unarchive
-char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *),
-       const int extract_function, const char *prefix, char **extract_names)
-{
-       file_header_t *file_entry;
-       int extract_flag;
-       int i;
-       char *buffer = NULL;
-
-       archive_offset = 0;
-       while ((file_entry = get_headers(src_stream)) != NULL) {
-               extract_flag = TRUE;
-               if (extract_names != NULL) {
-                       int found_flag = FALSE;
-                       for(i = 0; extract_names[i] != 0; i++) {
-                               if (strcmp(extract_names[i], file_entry->name) == 0) {
-                                       found_flag = TRUE;
-                                       break;
-                               }
-                       }
-                       if (extract_function & extract_exclude_list) {
-                               if (found_flag == TRUE) {
-                                       extract_flag = FALSE;
-                               }
-                       } else {
-                               /* If its not found in the include list dont extract it */
-                               if (found_flag == FALSE) {
-                                       extract_flag = FALSE;
-                               }
-                       }
-
-               }
-
-               if (extract_flag == TRUE) {
-                       buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix);
-               } else {
-                       /* seek past the data entry */
-                       seek_sub_file(src_stream, file_entry->size);
-               }
-               free(file_entry->name); /* may be null, but doesn't matter */
-               free(file_entry->link_name);
-               free(file_entry);
-       }
-       return(buffer);
-}
-#endif
-
-#ifdef L_get_header_ar
-file_header_t *get_header_ar(FILE *src_stream)
-{
-       file_header_t *typed;
-       union {
-               char raw[60];
-               struct {
-                       char name[16];
-                       char date[12];
-                       char uid[6];
-                       char gid[6];
-                       char mode[8];
-                       char size[10];
-                       char magic[2];
-               } formated;
-       } ar;
-       static char *ar_long_names;
-
-       if (fread(ar.raw, 1, 60, src_stream) != 60) {
-               return(NULL);
-       }
-       archive_offset += 60;
-       /* align the headers based on the header magic */
-       if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
-               /* some version of ar, have an extra '\n' after each data entry,
-                * this puts the next header out by 1 */
-               if (ar.formated.magic[1] != '`') {
-                       error_msg("Invalid magic");
-                       return(NULL);
-               }
-               /* read the next char out of what would be the data section,
-                * if its a '\n' then it is a valid header offset by 1*/
-               archive_offset++;
-               if (fgetc(src_stream) != '\n') {
-                       error_msg("Invalid magic");
-                       return(NULL);
-               }
-               /* fix up the header, we started reading 1 byte too early */
-               /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
-               memmove(ar.raw, &ar.raw[1], 59);
-       }
-               
-       typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
-
-       typed->size = (size_t) atoi(ar.formated.size);
-       /* long filenames have '/' as the first character */
-       if (ar.formated.name[0] == '/') {
-               if (ar.formated.name[1] == '/') {
-                       /* If the second char is a '/' then this entries data section
-                        * stores long filename for multiple entries, they are stored
-                        * in static variable long_names for use in future entries */
-                       ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
-                       fread(ar_long_names, 1, typed->size, src_stream);
-                       archive_offset += typed->size;
-                       /* This ar entries data section only contained filenames for other records
-                        * they are stored in the static ar_long_names for future reference */
-                       return (get_header_ar(src_stream)); /* Return next header */
-               } else if (ar.formated.name[1] == ' ') {
-                       /* This is the index of symbols in the file for compilers */
-                       seek_sub_file(src_stream, typed->size);
-                       return (get_header_ar(src_stream)); /* Return next header */
-               } else {
-                       /* The number after the '/' indicates the offset in the ar data section
-                       (saved in variable long_name) that conatains the real filename */
-                       if (!ar_long_names) {
-                               error_msg("Cannot resolve long file name");
-                               return (NULL);
-                       }
-                       typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
-               }
-       } else {
-               /* short filenames */
-               typed->name = xcalloc(1, 16);
-               strncpy(typed->name, ar.formated.name, 16);
-       }
-       typed->name[strcspn(typed->name, " /")]='\0';
-
-       /* convert the rest of the now valid char header to its typed struct */ 
-       parse_mode(ar.formated.mode, &typed->mode);
-       typed->mtime = atoi(ar.formated.date);
-       typed->uid = atoi(ar.formated.uid);
-       typed->gid = atoi(ar.formated.gid);
-
-       return(typed);
-}
-#endif
-
-#ifdef L_get_header_cpio
-struct hardlinks {
-       file_header_t *entry;
-       int inode;
-       struct hardlinks *next;
-};
-
-file_header_t *get_header_cpio(FILE *src_stream)
-{
-       file_header_t *cpio_entry = NULL;
-       char cpio_header[110];
-       int namesize;
-       char dummy[16];
-       int major, minor, nlink, inode;
-       static struct hardlinks *saved_hardlinks = NULL;
-       static int pending_hardlinks = 0;
-
-       if (pending_hardlinks) { /* Deal with any pending hardlinks */
-               struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
-               while (tmp) {
-                       if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
-                               cpio_entry = tmp->entry;
-                               if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */
-                               else saved_hardlinks = tmp->next;
-                               free(tmp);
-                               return (cpio_entry);
-                       }
-                       oldtmp = tmp;
-                       tmp = tmp->next;
-               }
-               pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
-       }
-  
-       /* There can be padding before archive header */
-       seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
-       if (fread(cpio_header, 1, 110, src_stream) == 110) {
-               archive_offset += 110;
-               if (strncmp(cpio_header, "07070", 5) != 0) {
-                       error_msg("Unsupported format or invalid magic");
-                       return(NULL);
-               }
-               switch (cpio_header[5]) {
-                       case '2': /* "crc" header format */
-                               /* Doesnt do the crc check yet */
-                       case '1': /* "newc" header format */
-                               cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t));
-                               sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
-                                       dummy, &inode, (unsigned int*)&cpio_entry->mode, 
-                                       (unsigned int*)&cpio_entry->uid, (unsigned int*)&cpio_entry->gid,
-                                       &nlink, &cpio_entry->mtime, &cpio_entry->size,
-                                       dummy, &major, &minor, &namesize, dummy);
-
-                               cpio_entry->name = (char *) xcalloc(1, namesize);
-                               fread(cpio_entry->name, 1, namesize, src_stream); /* Read in filename */
-                               archive_offset += namesize;
-                               /* Skip padding before file contents */
-                               seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
-                               if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) {
-                                       printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */
-                                       if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
-                                               struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
-                                               while (tmp) {
-                                                       error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
-                                                       oldtmp = tmp;
-                                                       tmp = tmp->next;
-                                                       free (oldtmp->entry->name);
-                                                       free (oldtmp->entry);
-                                                       free (oldtmp);
-                                               }
-                                               saved_hardlinks = NULL;
-                                               pending_hardlinks = 0;
-                                       }
-                                       return(NULL);
-                               }
-
-                               if (S_ISLNK(cpio_entry->mode)) {
-                                       cpio_entry->link_name = (char *) xcalloc(1, cpio_entry->size + 1);
-                                       fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream);
-                                       archive_offset += cpio_entry->size;
-                                       cpio_entry->size = 0; /* Stop possiable seeks in future */
-                               }
-                               if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) {
-                                       if (cpio_entry->size == 0) { /* Put file on a linked list for later */
-                                               struct hardlinks *new = xmalloc(sizeof(struct hardlinks));
-                                               new->next = saved_hardlinks;
-                                               new->inode = inode;
-                                               new->entry = cpio_entry;
-                                               saved_hardlinks = new;
-                                       return(get_header_cpio(src_stream)); /* Recurse to next file */
-                                       } else { /* Found the file with data in */
-                                               struct hardlinks *tmp = saved_hardlinks;
-                                               pending_hardlinks = 1;
-                                               while (tmp) {
-                                                       if (tmp->inode == inode) {
-                                                               tmp->entry->link_name = xstrdup(cpio_entry->name);
-                                                               nlink--;
-                                                       }
-                                                       tmp = tmp->next;
-                                               }
-                                               if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
-                                       }
-                               }
-                               cpio_entry->device = (major << 8) | minor;
-                               break;
-                       default:
-                               error_msg("Unsupported format");
-                               return(NULL);
-               }
-               if (ferror(src_stream) || feof(src_stream)) {
-                       perror_msg("Stream error");
-                       return(NULL);
-               }
-       }
-       return(cpio_entry);
-}
-#endif
-
-#ifdef L_get_header_tar
-file_header_t *get_header_tar(FILE *tar_stream)
-{
-       union {
-               unsigned char raw[512];
-               struct {
-                       char name[100];         /*   0-99 */
-                       char mode[8];           /* 100-107 */
-                       char uid[8];            /* 108-115 */
-                       char gid[8];            /* 116-123 */
-                       char size[12];          /* 124-135 */
-                       char mtime[12];         /* 136-147 */
-                       char chksum[8];         /* 148-155 */
-                       char typeflag;          /* 156-156 */
-                       char linkname[100];     /* 157-256 */
-                       char magic[6];          /* 257-262 */
-                       char version[2];        /* 263-264 */
-                       char uname[32];         /* 265-296 */
-                       char gname[32];         /* 297-328 */
-                       char devmajor[8];       /* 329-336 */
-                       char devminor[8];       /* 337-344 */
-                       char prefix[155];       /* 345-499 */
-                       char padding[12];       /* 500-512 */
-               } formated;
-       } tar;
-       file_header_t *tar_entry = NULL;
-       long i;
-       long sum = 0;
-
-       if (archive_offset % 512 != 0) {
-               seek_sub_file(tar_stream, 512 - (archive_offset % 512));
-       }
-
-       if (fread(tar.raw, 1, 512, tar_stream) != 512) {
-               /* Unfortunatly its common for tar files to have all sorts of
-                * trailing garbage, fail silently */
-//             error_msg("Couldnt read header");
-               return(NULL);
-       }
-       archive_offset += 512;
-
-       /* Check header has valid magic, unfortunately some tar files
-        * have empty (0'ed) tar entries at the end, which will
-        * cause this to fail, so fail silently for now
-        */
-       if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
-               return(NULL);
-       }
-
-       /* Do checksum on headers */
-       for (i =  0; i < 148 ; i++) {
-               sum += tar.raw[i];
-       }
-       sum += ' ' * 8;
-       for (i =  156; i < 512 ; i++) {
-               sum += tar.raw[i];
-       }
-       if (sum != strtol(tar.formated.chksum, NULL, 8)) {
-               error_msg("Invalid tar header checksum");
-               return(NULL);
-       }
-
-       /* convert to type'ed variables */
-       tar_entry = xcalloc(1, sizeof(file_header_t));
-       tar_entry->name = xstrdup(tar.formated.name);
-
-       parse_mode(tar.formated.mode, &tar_entry->mode);
-       tar_entry->uid   = strtol(tar.formated.uid, NULL, 8);
-       tar_entry->gid   = strtol(tar.formated.gid, NULL, 8);
-       tar_entry->size  = strtol(tar.formated.size, NULL, 8);
-       tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
-       tar_entry->link_name  = strlen(tar.formated.linkname) ? 
-           xstrdup(tar.formated.linkname) : NULL;
-       tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
-               strtol(tar.formated.devminor, NULL, 8);
-
-       return(tar_entry);
-}
-#endif
-
-#ifdef L_deb_extract
-char *deb_extract(const char *package_filename, FILE *out_stream, 
-       const int extract_function, const char *prefix, const char *filename)
-{
-       FILE *deb_stream;
-       FILE *uncompressed_stream = NULL;
-       file_header_t *ar_header = NULL;
-       char **file_list = NULL;
-       char *output_buffer = NULL;
-       char *ared_file = NULL;
-       char ar_magic[8];
-       int gunzip_pid;
-
-       if (filename != NULL) {
-               file_list = xmalloc(sizeof(char *) * 2);
-               file_list[0] = xstrdup(filename);
-               file_list[1] = NULL;
-       }
-       
-       if (extract_function & extract_control_tar_gz) {
-               ared_file = xstrdup("control.tar.gz");
-       }
-       else if (extract_function & extract_data_tar_gz) {              
-               ared_file = xstrdup("data.tar.gz");
-       }
-
-       /* open the debian package to be worked on */
-       deb_stream = wfopen(package_filename, "r");
-       if (deb_stream == NULL) {
-               return(NULL);
-       }
-       /* set the buffer size */
-       setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
-
-       /* check ar magic */
-       fread(ar_magic, 1, 8, deb_stream);
-       if (strncmp(ar_magic,"!<arch>",7) != 0) {
-               error_msg_and_die("invalid magic");
-       }
-       archive_offset = 8;
-
-       while ((ar_header = get_header_ar(deb_stream)) != NULL) {
-               if (strcmp(ared_file, ar_header->name) == 0) {
-                       /* open a stream of decompressed data */
-                       uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
-                       archive_offset = 0;
-                       output_buffer = unarchive(uncompressed_stream, out_stream, get_header_tar, extract_function, prefix, file_list);
-               }
-               seek_sub_file(deb_stream, ar_header->size);
-       }
-       gz_close(gunzip_pid);
-       fclose(deb_stream);
-       fclose(uncompressed_stream);
-       free(ared_file);
-       return(output_buffer);
-}
-#endif
diff --git a/busybox/libbb/unzip.c b/busybox/libbb/unzip.c
deleted file mode 100644 (file)
index ee74621..0000000
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * gunzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#if 0
-static char *license_msg[] = {
-       "   Copyright (C) 1992-1993 Jean-loup Gailly",
-       "   This program is free software; you can redistribute it and/or modify",
-       "   it under the terms of the GNU General Public License as published by",
-       "   the Free Software Foundation; either version 2, or (at your option)",
-       "   any later version.",
-       "",
-       "   This program is distributed in the hope that it will be useful,",
-       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
-       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
-       "   GNU General Public License for more details.",
-       "",
-       "   You should have received a copy of the GNU General Public License",
-       "   along with this program; if not, write to the Free Software",
-       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
-       0
-};
-#endif
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-static FILE *in_file, *out_file;
-
-/* these are freed by gz_close */
-static unsigned char *window;
-static unsigned long *crc_table;
-
-static unsigned long crc = 0xffffffffL;        /* shift register contents */
-
-/* Return codes from gzip */
-static const int ERROR = 1;
-
-/*
- * window size--must be a power of two, and
- *  at least 32K for zip's deflate method 
- */
-static const int WSIZE = 0x8000;
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-static const int BMAX = 16;            /* maximum bit length of any code (16 for explode) */
-static const int N_MAX = 288;          /* maximum number of codes in any set */
-
-static long bytes_out;         /* number of output bytes */
-static unsigned long outcnt;   /* bytes in output buffer */
-
-static unsigned hufts;         /* track memory usage */
-static unsigned long bb;                       /* bit buffer */
-static unsigned bk;            /* bits in bit buffer */
-
-typedef struct huft_s {
-       unsigned char e;                /* number of extra bits or operation */
-       unsigned char b;                /* number of bits in this code or subcode */
-       union {
-               unsigned short n;               /* literal, length base, or distance base */
-               struct huft_s *t;       /* pointer to next level of table */
-       } v;
-} huft_t;
-
-static const unsigned short mask_bits[] = {
-       0x0000,
-       0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-       0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-//static int error_number = 0;
-/* ========================================================================
- * Signal and error handler.
- */
-static void abort_gzip()
-{
-       error_msg("gzip aborted\n");
-       exit(ERROR);
-}
-
-static void make_crc_table()
-{
-       unsigned long table_entry;      /* crc shift register */
-       unsigned long poly = 0;      /* polynomial exclusive-or pattern */
-       int i;                /* counter for all possible eight bit values */
-       int k;                /* byte being shifted into crc apparatus */
-
-       /* terms of polynomial defining this crc (except x^32): */
-       static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-       crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long));
-
-       /* Make exclusive-or pattern from polynomial (0xedb88320) */
-       for (i = 0; i < sizeof(p)/sizeof(int); i++)
-               poly |= 1L << (31 - p[i]);
-
-       /* Compute and print table of CRC's, five per line */
-       for (i = 0; i < 256; i++) {
-               table_entry = i;
-          /* The idea to initialize the register with the byte instead of
-            * zero was stolen from Haruhiko Okumura's ar002
-            */
-               for (k = 8; k; k--) {
-                       table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
-               }
-               crc_table[i]=table_entry;
-       }
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-       int n;
-
-       if (outcnt == 0)
-               return;
-
-       for (n = 0; n < outcnt; n++) {
-               crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
-       }
-
-       if (fwrite(window, 1, outcnt, out_file) != outcnt) {
-               error_msg_and_die("Couldnt write");
-       }
-       bytes_out += (unsigned long) outcnt;
-       outcnt = 0;
-}
-
-/*
- * Free the malloc'ed tables built by huft_build(), which makes a linked
- * list of the tables it made, with the links in a dummy first entry of
- * each table. 
- * t: table to free
- */
-static int huft_free(huft_t *t)
-{
-       huft_t *p, *q;
-
-       /* Go through linked list, freeing from the malloced (t[-1]) address. */
-       p = t;
-       while (p != (huft_t *) NULL) {
-               q = (--p)->v.t;
-               free((char *) p);
-               p = q;
-       }
-       return 0;
-}
-
-/* Given a list of code lengths and a maximum table size, make a set of
- * tables to decode that set of codes.  Return zero on success, one if
- * the given code set is incomplete (the tables are still built in this
- * case), two if the input is invalid (all zero length codes or an
- * oversubscribed set of lengths), and three if not enough memory.
- *
- * b:  code lengths in bits (all assumed <= BMAX)
- * n:  number of codes (assumed <= N_MAX)
- * s:  number of simple-valued codes (0..s-1)
- * d:  list of base values for non-simple codes
- * e:  list of extra bits for non-simple codes
- * t:  result: starting table
- * m:  maximum lookup bits, returns actual
- */
-static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, 
-       const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
-{
-       unsigned a;             /* counter for codes of length k */
-       unsigned c[BMAX + 1];   /* bit length count table */
-       unsigned f;             /* i repeats in table every f entries */
-       int g;                  /* maximum code length */
-       int h;                  /* table level */
-       register unsigned i;    /* counter, current code */
-       register unsigned j;    /* counter */
-       register int k;         /* number of bits in current code */
-       int l;                  /* bits per table (returned in m) */
-       register unsigned *p;           /* pointer into c[], b[], or v[] */
-       register huft_t *q;     /* points to current table */
-       huft_t r;               /* table entry for structure assignment */
-       huft_t *u[BMAX];        /* table stack */
-       unsigned v[N_MAX];      /* values in order of bit length */
-       register int w;         /* bits before this table == (l * h) */
-       unsigned x[BMAX + 1];   /* bit offsets, then code stack */
-       unsigned *xp;           /* pointer into x */
-       int y;                  /* number of dummy codes added */
-       unsigned z;             /* number of entries in current table */
-
-       /* Generate counts for each bit length */
-       memset ((void *)(c), 0, sizeof(c));
-       p = b;
-       i = n;
-       do {
-               c[*p]++;        /* assume all entries <= BMAX */
-               p++;            /* Can't combine with above line (Solaris bug) */
-       } while (--i);
-       if (c[0] == n) {        /* null input--all zero length codes */
-               *t = (huft_t *) NULL;
-               *m = 0;
-               return 0;
-       }
-
-       /* Find minimum and maximum length, bound *m by those */
-       l = *m;
-       for (j = 1; j <= BMAX; j++)
-               if (c[j])
-                       break;
-       k = j;                          /* minimum code length */
-       if ((unsigned) l < j)
-               l = j;
-       for (i = BMAX; i; i--)
-               if (c[i])
-                       break;
-       g = i;                          /* maximum code length */
-       if ((unsigned) l > i)
-               l = i;
-       *m = l;
-
-       /* Adjust last length count to fill out codes, if needed */
-       for (y = 1 << j; j < i; j++, y <<= 1)
-               if ((y -= c[j]) < 0)
-                       return 2;       /* bad input: more codes than bits */
-       if ((y -= c[i]) < 0)
-               return 2;
-       c[i] += y;
-
-       /* Generate starting offsets into the value table for each length */
-       x[1] = j = 0;
-       p = c + 1;
-       xp = x + 2;
-       while (--i) {                   /* note that i == g from above */
-               *xp++ = (j += *p++);
-       }
-
-       /* Make a table of values in order of bit lengths */
-       p = b;
-       i = 0;
-       do {
-               if ((j = *p++) != 0)
-                       v[x[j]++] = i;
-       } while (++i < n);
-
-       /* Generate the Huffman codes and for each, make the table entries */
-       x[0] = i = 0;                   /* first Huffman code is zero */
-       p = v;                          /* grab values in bit order */
-       h = -1;                         /* no tables yet--level -1 */
-       w = -l;                         /* bits decoded == (l * h) */
-       u[0] = (huft_t *) NULL; /* just to keep compilers happy */
-       q = (huft_t *) NULL;    /* ditto */
-       z = 0;                          /* ditto */
-
-       /* go through the bit lengths (k already is bits in shortest code) */
-       for (; k <= g; k++) {
-               a = c[k];
-               while (a--) {
-                       /* here i is the Huffman code of length k bits for value *p */
-                       /* make tables up to required level */
-                       while (k > w + l) {
-                               h++;
-                               w += l;         /* previous table always l bits */
-
-                               /* compute minimum size table less than or equal to l bits */
-                               z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
-                               if ((f = 1 << (j = k - w)) > a + 1) {   /* try a k-w bit table *//* too few codes for k-w bit table */
-                                       f -= a + 1;     /* deduct codes from patterns left */
-                                       xp = c + k;
-                                       while (++j < z) {       /* try smaller tables up to z bits */
-                                               if ((f <<= 1) <= *++xp)
-                                                       break;  /* enough codes to use up j bits */
-                                               f -= *xp;       /* else deduct codes from patterns */
-                                       }
-                               }
-                               z = 1 << j;             /* table entries for j-bit table */
-
-                               /* allocate and link in new table */
-                               if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
-                                       if (h) {
-                                               huft_free(u[0]);
-                                       }
-                                       return 3;       /* not enough memory */
-                               }
-                               hufts += z + 1; /* track memory usage */
-                               *t = q + 1;             /* link to list for huft_free() */
-                               *(t = &(q->v.t)) = NULL;
-                               u[h] = ++q;             /* table starts after link */
-
-                               /* connect to last table, if there is one */
-                               if (h) {
-                                       x[h] = i;       /* save pattern for backing up */
-                                       r.b = (unsigned char) l;        /* bits to dump before this table */
-                                       r.e = (unsigned char) (16 + j); /* bits in this table */
-                                       r.v.t = q;      /* pointer to this table */
-                                       j = i >> (w - l);       /* (get around Turbo C bug) */
-                                       u[h - 1][j] = r;        /* connect to last table */
-                               }
-                       }
-
-                       /* set up table entry in r */
-                       r.b = (unsigned char) (k - w);
-                       if (p >= v + n)
-                               r.e = 99;               /* out of values--invalid code */
-                       else if (*p < s) {
-                               r.e = (unsigned char) (*p < 256 ? 16 : 15);     /* 256 is end-of-block code */
-                               r.v.n = (unsigned short) (*p);  /* simple code is just the value */
-                               p++;                    /* one compiler does not like *p++ */
-                       } else {
-                               r.e = (unsigned char) e[*p - s];        /* non-simple--look up in lists */
-                               r.v.n = d[*p++ - s];
-                       }
-
-                       /* fill code-like entries with r */
-                       f = 1 << (k - w);
-                       for (j = i >> w; j < z; j += f)
-                               q[j] = r;
-
-                       /* backwards increment the k-bit code i */
-                       for (j = 1 << (k - 1); i & j; j >>= 1)
-                               i ^= j;
-                       i ^= j;
-
-                       /* backup over finished tables */
-                       while ((i & ((1 << w) - 1)) != x[h]) {
-                               h--;                    /* don't need to update q */
-                               w -= l;
-                       }
-               }
-       }
-       /* Return true (1) if we were given an incomplete table */
-       return y != 0 && g != 1;
-}
-
-/*
- * inflate (decompress) the codes in a deflated (compressed) block.
- * Return an error code or zero if it all goes ok.
- *
- * tl, td: literal/length and distance decoder tables
- * bl, bd: number of bits decoded by tl[] and td[]
- */
-static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
-{
-       register unsigned long e;               /* table entry flag/number of extra bits */
-       unsigned long n, d;                             /* length and index for copy */
-       unsigned long w;                                /* current window position */
-       huft_t *t;                              /* pointer to table entry */
-       unsigned ml, md;                        /* masks for bl and bd bits */
-       register unsigned long b;                               /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-
-       /* make local copies of globals */
-       b = bb;                                 /* initialize bit buffer */
-       k = bk;
-       w = outcnt;                             /* initialize window position */
-
-       /* inflate the coded data */
-       ml = mask_bits[bl];                     /* precompute masks for speed */
-       md = mask_bits[bd];
-       for (;;) {                              /* do until end of block */
-               while (k < (unsigned) bl) {
-                       b |= ((unsigned long)fgetc(in_file)) << k;
-                       k += 8;
-               }
-               if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
-               do {
-                       if (e == 99) {
-                               return 1;
-                       }
-                       b >>= t->b;
-                       k -= t->b;
-                       e -= 16;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-               b >>= t->b;
-               k -= t->b;
-               if (e == 16) {          /* then it's a literal */
-                       window[w++] = (unsigned char) t->v.n;
-                       if (w == WSIZE) {
-                               outcnt=(w),
-                               flush_window();
-                               w = 0;
-                       }
-               } else {                                /* it's an EOB or a length */
-
-                       /* exit if end of block */
-                       if (e == 15) {
-                               break;
-                       }
-
-                       /* get length of block to copy */
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       n = t->v.n + ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* decode distance of block to copy */
-                       while (k < (unsigned) bd) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-
-                       if ((e = (t = td + ((unsigned) b & md))->e) > 16)
-                               do {
-                                       if (e == 99)
-                                               return 1;
-                                       b >>= t->b;
-                                       k -= t->b;
-                                       e -= 16;
-                                       while (k < e) {
-                                               b |= ((unsigned long)fgetc(in_file)) << k;
-                                               k += 8;
-                                       }
-                               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
-                       b >>= t->b;
-                       k -= t->b;
-                       while (k < e) {
-                               b |= ((unsigned long)fgetc(in_file)) << k;
-                               k += 8;
-                       }
-                       d = w - t->v.n - ((unsigned) b & mask_bits[e]);
-                       b >>= e;
-                       k -= e;
-
-                       /* do the copy */
-                       do {
-                               n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
-                               if (w - d >= e) {       /* (this test assumes unsigned comparison) */
-                                       memcpy(window + w, window + d, e);
-                                       w += e;
-                                       d += e;
-                               } else                  /* do it slow to avoid memcpy() overlap */
-#endif                                                 /* !NOMEMCPY */
-                                       do {
-                                               window[w++] = window[d++];
-                                       } while (--e);
-                               if (w == WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                       } while (n);
-               }
-       }
-
-       /* restore the globals from the locals */
-       outcnt = w;                     /* restore global window pointer */
-       bb = b;                         /* restore global bit buffer */
-       bk = k;
-
-       /* done */
-       return 0;
-}
-
-/*
- * decompress an inflated block
- * e: last block flag
- *
- * GLOBAL VARIABLES: bb, kk,
- */
-static int inflate_block(int *e)
-{
-       unsigned t;                     /* block type */
-       register unsigned long b;                       /* bit buffer */
-       register unsigned k;            /* number of bits in bit buffer */
-       static unsigned short cplens[] = {              /* Copy lengths for literal codes 257..285 */
-               3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-               35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
-       };
-       /* note: see note #13 above about the 258 in this list. */
-       static unsigned short cplext[] = {              /* Extra bits for literal codes 257..285 */
-               0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-               3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
-       };                              /* 99==invalid */
-       static unsigned short cpdist[] = {              /* Copy offsets for distance codes 0..29 */
-               1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-               257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-               8193, 12289, 16385, 24577
-       };
-       static unsigned short cpdext[] = {              /* Extra bits for distance codes */
-               0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-               7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-               12, 12, 13, 13
-       };
-
-       /* make local bit buffer */
-       b = bb;
-       k = bk;
-
-       /* read in last block bit */
-       while (k < 1) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       *e = (int) b & 1;
-       b >>= 1;
-       k -= 1;
-
-       /* read in block type */
-       while (k < 2) {
-               b |= ((unsigned long)fgetc(in_file)) << k;
-               k += 8;
-       }
-       t = (unsigned) b & 3;
-       b >>= 2;
-       k -= 2;
-
-       /* restore the global bit buffer */
-       bb = b;
-       bk = k;
-
-       /* inflate that block type */
-       switch (t) {
-       case 0: /* Inflate stored */
-               {
-                       unsigned long n;                        /* number of bytes in block */
-                       unsigned long w;                        /* current window position */
-                       register unsigned long b_stored;                        /* bit buffer */
-                       register unsigned long k_stored;                /* number of bits in bit buffer */
-
-                       /* make local copies of globals */
-                       b_stored = bb;                          /* initialize bit buffer */
-                       k_stored = bk;
-                       w = outcnt;                     /* initialize window position */
-
-                       /* go to byte boundary */
-                       n = k_stored & 7;
-                       b_stored >>= n;
-                       k_stored -= n;
-
-                       /* get the length and its complement */
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       n = ((unsigned) b_stored & 0xffff);
-                       b_stored >>= 16;
-                       k_stored -= 16;
-                       while (k_stored < 16) {
-                               b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                               k_stored += 8;
-                       }
-                       if (n != (unsigned) ((~b_stored) & 0xffff)) {
-                               return 1;               /* error in compressed data */
-                       }
-                       b_stored >>= 16;
-                       k_stored -= 16;
-
-                       /* read and output the compressed data */
-                       while (n--) {
-                               while (k_stored < 8) {
-                                       b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
-                                       k_stored += 8;
-                               }
-                               window[w++] = (unsigned char) b_stored;
-                               if (w == (unsigned long)WSIZE) {
-                                       outcnt=(w),
-                                       flush_window();
-                                       w = 0;
-                               }
-                               b_stored >>= 8;
-                               k_stored -= 8;
-                       }
-
-                       /* restore the globals from the locals */
-                       outcnt = w;                     /* restore global window pointer */
-                       bb = b_stored;                          /* restore global bit buffer */
-                       bk = k_stored;
-                       return 0;
-               }
-       case 1: /* Inflate fixed 
-                        * decompress an inflated type 1 (fixed Huffman codes) block.  We should
-                        * either replace this with a custom decoder, or at least precompute the
-                        * Huffman tables.
-                        */
-               {
-                       int i;                                  /* temporary variable */
-                       huft_t *tl;                             /* literal/length code table */
-                       huft_t *td;                             /* distance code table */
-                       int bl;                                 /* lookup bits for tl */
-                       int bd;                                 /* lookup bits for td */
-                       unsigned int l[288];    /* length list for huft_build */
-
-                       /* set up literal table */
-                       for (i = 0; i < 144; i++) {
-                               l[i] = 8;
-                       }
-                       for (; i < 256; i++) {
-                               l[i] = 9;
-                       }
-                       for (; i < 280; i++) {
-                               l[i] = 7;
-                       }
-                       for (; i < 288; i++) {  /* make a complete, but wrong code set */
-                               l[i] = 8;
-                       }
-                       bl = 7;
-                       if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               return i;
-                       }
-
-                       /* set up distance table */
-                       for (i = 0; i < 30; i++) {      /* make an incomplete code set */
-                               l[i] = 5;
-                       }
-                       bd = 5;
-                       if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
-                               huft_free(tl);
-                               return i;
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       case 2: /* Inflate dynamic */
-               {
-                       /* Tables for deflate from PKZIP's appnote.txt. */
-                       static unsigned border[] = {    /* Order of the bit length code lengths */
-                               16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
-                       };
-                       int dbits = 6;                                  /* bits in base distance lookup table */
-                       int lbits = 9;                                  /* bits in base literal/length lookup table */
-
-                       int i;                                          /* temporary variables */
-                       unsigned j;
-                       unsigned l;                                     /* last length */
-                       unsigned m;                                     /* mask for bit lengths table */
-                       unsigned n;                                     /* number of lengths to get */
-                       huft_t *tl;                     /* literal/length code table */
-                       huft_t *td;                     /* distance code table */
-                       int bl;                                         /* lookup bits for tl */
-                       int bd;                                         /* lookup bits for td */
-                       unsigned nb;                            /* number of bit length codes */
-                       unsigned nl;                            /* number of literal/length codes */
-                       unsigned nd;                            /* number of distance codes */
-
-                       unsigned ll[286 + 30];          /* literal/length and distance code lengths */
-                       register unsigned long b_dynamic;       /* bit buffer */
-                       register unsigned k_dynamic;            /* number of bits in bit buffer */
-
-                       /* make local bit buffer */
-                       b_dynamic = bb;
-                       k_dynamic = bk;
-
-                       /* read in table lengths */
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nl = 257 + ((unsigned) b_dynamic & 0x1f);       /* number of literal/length codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 5) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
-                       b_dynamic >>= 5;
-                       k_dynamic -= 5;
-                       while (k_dynamic < 4) {
-                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                               k_dynamic += 8;
-                       }
-                       nb = 4 + ((unsigned) b_dynamic & 0xf);  /* number of bit length codes */
-                       b_dynamic >>= 4;
-                       k_dynamic -= 4;
-                       if (nl > 286 || nd > 30) {
-                               return 1;       /* bad lengths */
-                       }
-
-                       /* read in bit-length-code lengths */
-                       for (j = 0; j < nb; j++) {
-                               while (k_dynamic < 3) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               ll[border[j]] = (unsigned) b_dynamic & 7;
-                               b_dynamic >>= 3;
-                               k_dynamic -= 3;
-                       }
-                       for (; j < 19; j++) {
-                               ll[border[j]] = 0;
-                       }
-
-                       /* build decoding table for trees--single level, 7 bit lookup */
-                       bl = 7;
-                       if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* read in literal and distance code lengths */
-                       n = nl + nd;
-                       m = mask_bits[bl];
-                       i = l = 0;
-                       while ((unsigned) i < n) {
-                               while (k_dynamic < (unsigned) bl) {
-                                       b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                       k_dynamic += 8;
-                               }
-                               j = (td = tl + ((unsigned) b_dynamic & m))->b;
-                               b_dynamic >>= j;
-                               k_dynamic -= j;
-                               j = td->v.n;
-                               if (j < 16) {                   /* length of code in bits (0..15) */
-                                       ll[i++] = l = j;        /* save last length in l */
-                               }
-                               else if (j == 16) {             /* repeat last length 3 to 6 times */
-                                       while (k_dynamic < 2) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 3);
-                                       b_dynamic >>= 2;
-                                       k_dynamic -= 2;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = l;
-                                       }
-                               } else if (j == 17) {   /* 3 to 10 zero length codes */
-                                       while (k_dynamic < 3) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 3 + ((unsigned) b_dynamic & 7);
-                                       b_dynamic >>= 3;
-                                       k_dynamic -= 3;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               } else {                /* j == 18: 11 to 138 zero length codes */
-                                       while (k_dynamic < 7) {
-                                               b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
-                                               k_dynamic += 8;
-                                       }
-                                       j = 11 + ((unsigned) b_dynamic & 0x7f);
-                                       b_dynamic >>= 7;
-                                       k_dynamic -= 7;
-                                       if ((unsigned) i + j > n) {
-                                               return 1;
-                                       }
-                                       while (j--) {
-                                               ll[i++] = 0;
-                                       }
-                                       l = 0;
-                               }
-                       }
-
-                       /* free decoding table for trees */
-                       huft_free(tl);
-
-                       /* restore the global bit buffer */
-                       bb = b_dynamic;
-                       bk = k_dynamic;
-
-                       /* build the decoding tables for literal/length and distance codes */
-                       bl = lbits;
-                       if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
-                               if (i == 1) {
-                                       error_msg("Incomplete literal tree");
-                                       huft_free(tl);
-                               }
-                               return i;                       /* incomplete code set */
-                       }
-                       bd = dbits;
-                       if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
-                               if (i == 1) {
-                                       error_msg("incomplete distance tree");
-                                       huft_free(td);
-                               }
-                               huft_free(tl);
-                               return i;                       /* incomplete code set */
-                       }
-
-                       /* decompress until an end-of-block code */
-                       if (inflate_codes(tl, td, bl, bd))
-                               return 1;
-
-                       /* free the decoding tables, return */
-                       huft_free(tl);
-                       huft_free(td);
-                       return 0;
-               }
-       default:
-               /* bad block type */
-               return 2;
-       }
-}
-
-/*
- * decompress an inflated entry
- *
- * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
- */
-static int inflate()
-{
-       int e;                          /* last block flag */
-       int r;                          /* result code */
-       unsigned h = 0;         /* maximum struct huft's malloc'ed */
-
-       /* initialize window, bit buffer */
-       outcnt = 0;
-       bk = 0;
-       bb = 0;
-
-       /* decompress until the last block */
-       do {
-               hufts = 0;
-               if ((r = inflate_block(&e)) != 0) {
-                       return r;
-               }
-               if (hufts > h) {
-                       h = hufts;
-               }
-       } while (!e);
-
-       /* flush out window */
-       flush_window();
-
-       /* return success */
-       return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- *   the compressed data, from offsets inptr to insize-1 included.
- *   The magic header has already been checked. The output buffer is cleared.
- * in, out: input and output file descriptors
- */
-extern int unzip(FILE *l_in_file, FILE *l_out_file)
-{
-       const int extra_field = 0x04;   /* bit 2 set: extra field present */
-       const int orig_name = 0x08;     /* bit 3 set: original file name present */
-       const int comment = 0x10;       /* bit 4 set: file comment present */
-       unsigned char buf[8];   /* extended local header */
-       unsigned char flags;    /* compression flags */
-       char magic[2];                  /* magic header */
-       int method;
-       typedef void (*sig_type) (int);
-       int exit_code=0;        /* program exit code */
-       int i;
-
-       in_file = l_in_file;
-       out_file = l_out_file;
-
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGINT, (sig_type) abort_gzip);
-       }
-#ifdef SIGTERM
-//     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-//             (void) signal(SIGTERM, (sig_type) abort_gzip);
-//     }
-#endif
-#ifdef SIGHUP
-       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-               (void) signal(SIGHUP, (sig_type) abort_gzip);
-       }
-#endif
-
-       /* Allocate all global buffers (for DYN_ALLOC option) */
-       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
-       outcnt = 0;
-       bytes_out = 0L;
-
-       magic[0] = fgetc(in_file);
-       magic[1] = fgetc(in_file);
-
-       /* Magic header for gzip files, 1F 8B = \037\213 */
-       if (memcmp(magic, "\037\213", 2) != 0) {
-               error_msg("Invalid gzip magic");
-               return EXIT_FAILURE;
-       }
-
-       method = (int) fgetc(in_file);
-       if (method != 8) {
-               error_msg("unknown method %d -- get newer version of gzip", method);
-               exit_code = 1;
-               return -1;
-       }
-
-       flags = (unsigned char) fgetc(in_file);
-
-       /* Ignore time stamp(4), extra flags(1), OS type(1) */
-       for (i = 0; i < 6; i++)
-               fgetc(in_file);
-
-       if ((flags & extra_field) != 0) {
-               size_t extra;
-               extra = fgetc(in_file);
-               extra += fgetc(in_file) << 8;
-
-               for (i = 0; i < extra; i++)
-                       fgetc(in_file);
-       }
-
-       /* Discard original name if any */
-       if ((flags & orig_name) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       /* Discard file comment if any */
-       if ((flags & comment) != 0) {
-               while (fgetc(in_file) != 0);    /* null */
-       }
-
-       if (method < 0) {
-               printf("it failed\n");
-               return(exit_code);              /* error message already emitted */
-       }
-
-       make_crc_table();
-
-       /* Decompress */
-       if (method == 8) {
-
-               int res = inflate();
-
-               if (res == 3) {
-                       error_msg(memory_exhausted);
-               } else if (res != 0) {
-                       error_msg("invalid compressed data--format violated");
-               }
-
-       } else {
-               error_msg("internal error, invalid method");
-       }
-
-       /* Get the crc and original length
-        * crc32  (see algorithm.doc)
-        * uncompressed input size modulo 2^32
-        */
-       fread(buf, 1, 8, in_file);
-
-       /* Validate decompression - crc */
-       if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
-               error_msg("invalid compressed data--crc error");
-       }
-       /* Validate decompression - size */
-       if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
-               error_msg("invalid compressed data--length error");
-       }
-
-       free(window);
-       free(crc_table);
-
-       return 0;
-}
-
-/*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
- */
-extern void gz_close(int gunzip_pid)
-{
-       if (kill(gunzip_pid, SIGTERM) == -1) {
-               error_msg_and_die("***  Couldnt kill old gunzip process *** aborting");
-       }
-
-       if (waitpid(gunzip_pid, NULL, 0) == -1) {
-               printf("Couldnt wait ?");
-       }
-               free(window);
-               free(crc_table);
-}
diff --git a/busybox/libbb/vdprintf.c b/busybox/libbb/vdprintf.c
deleted file mode 100644 (file)
index 8c3e32a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include "libbb.h"
-
-
-
-#if (__GLIBC__ < 2)
-extern int vdprintf(int d, const char *format, va_list ap)
-{
-       char buf[BUF_SIZE];
-       int len;
-
-       len = vsprintf(buf, format, ap);
-       return write(d, buf, len);
-}
-#endif
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/verror_msg.c b/busybox/libbb/verror_msg.c
deleted file mode 100644 (file)
index b348215..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void verror_msg(const char *s, va_list p)
-{
-       fflush(stdout);
-       fprintf(stderr, "%s: ", applet_name);
-       vfprintf(stderr, s, p);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/vherror_msg.c b/busybox/libbb/vherror_msg.c
deleted file mode 100644 (file)
index ee0bb50..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdarg.h>
-#include <netdb.h>
-extern int h_errno;
-
-#include <stdio.h>
-
-#include "libbb.h"
-
-extern void vherror_msg(const char *s, va_list p)
-{
-       if(s == 0)
-               s = "";
-       verror_msg(s, p);
-       if (*s)
-               fputs(": ", stderr);
-       herror("");
-}
diff --git a/busybox/libbb/vperror_msg.c b/busybox/libbb/vperror_msg.c
deleted file mode 100644 (file)
index ca9361e..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void vperror_msg(const char *s, va_list p)
-{
-       int err=errno;
-       if(s == 0) s = "";
-       verror_msg(s, p);
-       if (*s) s = ": ";
-       fprintf(stderr, "%s%s\n", s, strerror(err));
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/wfopen.c b/busybox/libbb/wfopen.c
deleted file mode 100644 (file)
index 8b074d2..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include "libbb.h"
-
-FILE *wfopen(const char *path, const char *mode)
-{
-       FILE *fp;
-       if ((fp = fopen(path, mode)) == NULL) {
-               perror_msg("%s", path);
-               errno = 0;
-       }
-       return fp;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/xfuncs.c b/busybox/libbb/xfuncs.c
deleted file mode 100644 (file)
index eb93bf1..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "libbb.h"
-
-
-#ifndef DMALLOC
-extern void *xmalloc(size_t size)
-{
-       void *ptr = malloc(size);
-
-       if (!ptr)
-               error_msg_and_die(memory_exhausted);
-       return ptr;
-}
-
-extern void *xrealloc(void *old, size_t size)
-{
-       void *ptr;
-
-       /* SuS2 says "If size is 0 and ptr is not a null pointer, the
-        * object pointed to is freed."  Do that here, in case realloc
-        * returns a NULL, since we don't want to choke in that case. */
-       if (size==0 && old) {
-               free(old);
-               return NULL;
-       }
-
-       ptr = realloc(old, size);
-       if (!ptr)
-               error_msg_and_die(memory_exhausted);
-       return ptr;
-}
-
-extern void *xcalloc(size_t nmemb, size_t size)
-{
-       void *ptr = calloc(nmemb, size);
-       if (!ptr)
-               error_msg_and_die(memory_exhausted);
-       return ptr;
-}
-
-extern char * xstrdup (const char *s) {
-       char *t;
-
-       if (s == NULL)
-               return NULL;
-
-       t = strdup (s);
-
-       if (t == NULL)
-               error_msg_and_die(memory_exhausted);
-
-       return t;
-}
-#endif
-
-extern char * xstrndup (const char *s, int n) {
-       char *t;
-
-       if (s == NULL)
-               error_msg_and_die("xstrndup bug");
-
-       t = xmalloc(++n);
-       
-       return safe_strncpy(t,s,n);
-}
-
-FILE *xfopen(const char *path, const char *mode)
-{
-       FILE *fp;
-       if ((fp = fopen(path, mode)) == NULL)
-               perror_msg_and_die("%s", path);
-       return fp;
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/libbb/xgetcwd.c b/busybox/libbb/xgetcwd.c
deleted file mode 100644 (file)
index 4f77481..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * xgetcwd.c -- return current directory with unlimited length
- * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
- * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
- *
- * Special function for busybox written by Vladimir Oleynik <vodz@usa.net>
-*/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/param.h>
-#include "libbb.h"
-
-/* Amount to increase buffer size by in each try. */
-#define PATH_INCR 32
-
-/* Return the current directory, newly allocated, arbitrarily long.
-   Return NULL and set errno on error.
-   If argument is not NULL (previous usage allocate memory), call free()
-*/
-
-char *
-xgetcwd (char *cwd)
-{
-  char *ret;
-  unsigned path_max;
-
-  errno = 0;
-  path_max = (unsigned) PATH_MAX;
-  path_max += 2;                /* The getcwd docs say to do this. */
-
-  if(cwd==0)
-       cwd = xmalloc (path_max);
-
-  errno = 0;
-  while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
-      path_max += PATH_INCR;
-      cwd = xrealloc (cwd, path_max);
-      errno = 0;
-  }
-
-  if (ret == NULL) {
-      int save_errno = errno;
-      free (cwd);
-      errno = save_errno;
-      perror_msg("getcwd()");
-      return NULL;
-  }
-
-  return cwd;
-}
diff --git a/busybox/libbb/xgethostbyname.c b/busybox/libbb/xgethostbyname.c
deleted file mode 100644 (file)
index 2585103..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini xgethostbyname implementation.
- *
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <netdb.h>
-extern int h_errno;
-
-#include "libbb.h"
-
-struct hostent *xgethostbyname(const char *name)
-{
-       struct hostent *retval;
-
-       if ((retval = gethostbyname(name)) == NULL)
-               herror_msg_and_die("%s", name);
-
-       return retval;
-}
diff --git a/busybox/libbb/xreadlink.c b/busybox/libbb/xreadlink.c
deleted file mode 100644 (file)
index 932e487..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  xreadlink.c - safe implementation of readlink.
- *  Returns a NULL on failure...
- */
-
-#include <stdio.h>
-
-/*
- * NOTE: This function returns a malloced char* that you will have to free
- * yourself. You have been warned.
- */
-
-#include <unistd.h>
-#include "libbb.h"
-
-extern char *xreadlink(const char *path)
-{                       
-       static const int GROWBY = 80; /* how large we will grow strings by */
-
-       char *buf = NULL;   
-       int bufsize = 0, readsize = 0;
-
-       do {
-               buf = xrealloc(buf, bufsize += GROWBY);
-               readsize = readlink(path, buf, bufsize); /* 1st try */
-               if (readsize == -1) {
-                   perror_msg("%s:%s", applet_name, path);
-                   return NULL;
-               }
-       }           
-       while (bufsize < readsize + 1);
-
-       buf[readsize] = '\0';
-
-       return buf;
-}       
-
diff --git a/busybox/libbb/xregcomp.c b/busybox/libbb/xregcomp.c
deleted file mode 100644 (file)
index 6f5e2f0..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks.  Tracking down who wrote what
- * isn't something I'm going to worry about...  If you wrote something
- * here, please feel free to acknowledge your work.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
- * Permission has been granted to redistribute this code under the GPL.
- *
- */
-
-#include <stdio.h>
-#include "libbb.h"
-#include <regex.h>
-
-
-
-void xregcomp(regex_t *preg, const char *regex, int cflags)
-{
-       int ret;
-       if ((ret = regcomp(preg, regex, cflags)) != 0) {
-               int errmsgsz = regerror(ret, preg, NULL, 0);
-               char *errmsg = xmalloc(errmsgsz);
-               regerror(ret, preg, errmsg, errmsgsz);
-               error_msg_and_die("xregcomp: %s", errmsg);
-       }
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/ln.c b/busybox/ln.c
deleted file mode 100644 (file)
index 7412a86..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ln implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-static const int LN_SYMLINK = 1;
-static const int LN_FORCE = 2;
-static const int LN_NODEREFERENCE = 4;
-
-/*
- * linkDestName is where the link points to,
- * linkSrcName is the name of the link to be created.
- */
-static int fs_link(const char *link_destname, const char *link_srcname, 
-               const int flag)
-{
-       int status;
-       int src_is_dir;
-       char *src_name;
-
-       if (link_destname==NULL)
-               return(FALSE);
-
-       src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1);
-
-       if (link_srcname==NULL)
-               strcpy(src_name, link_destname);
-       else
-               strcpy(src_name, link_srcname);
-
-       if (flag&LN_NODEREFERENCE)
-               src_is_dir = is_directory(src_name, TRUE, NULL);
-       else
-               src_is_dir = is_directory(src_name, FALSE, NULL);       
-       
-       if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) {
-               char* srcdir_name;
-
-               srcdir_name = xstrdup(link_destname);
-               strcat(src_name, "/");
-               strcat(src_name, get_last_path_component(srcdir_name));
-               free(srcdir_name);
-       }
-       
-       if (flag&LN_FORCE)
-               unlink(src_name);
-               
-       if (flag&LN_SYMLINK)
-               status = symlink(link_destname, src_name);
-       else
-               status = link(link_destname, src_name);
-
-       if (status != 0) {
-               perror_msg(src_name);
-               return(FALSE);
-       }
-       return(TRUE);
-}
-
-extern int ln_main(int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int flag = 0;
-       int opt;
-       
-       /* Parse any options */
-       while ((opt=getopt(argc, argv, "sfn")) != -1) {
-               switch(opt) {
-                       case 's':
-                               flag |= LN_SYMLINK;
-                               break;
-                       case 'f':
-                               flag |= LN_FORCE;
-                               break;
-                       case 'n':
-                               flag |= LN_NODEREFERENCE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       if (optind > (argc-1)) {
-               show_usage();
-       } 
-       if (optind == (argc-1)) {
-               if (fs_link(argv[optind], 
-                                       get_last_path_component(argv[optind]), flag)==FALSE)
-                       status = EXIT_FAILURE;
-       }
-       while(optind<(argc-1)) {
-               if (fs_link(argv[optind], argv[argc-1], flag)==FALSE)
-                       status = EXIT_FAILURE;
-               optind++;
-       }
-       exit(status);
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/loadacm.c b/busybox/loadacm.c
deleted file mode 100644 (file)
index 3fb4e76..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Derived from
- * mapscrn.c - version 0.92
- *
- * Was taken from console-tools and adapted by 
- * Peter Novodvorsky <petya@logic.ru>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/kd.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-typedef unsigned short unicode;
-
-static long int ctoi(unsigned char *s, int *is_unicode);
-static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]);
-static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode);
-static unicode utf8_to_ucs2(char *buf);
-static int screen_map_load(int fd, FILE * fp);
-
-int loadacm_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc>=2 && *argv[1]=='-') {
-               show_usage();
-       }
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0) {
-               perror_msg_and_die("Error opening " CURRENT_VC);
-       }
-
-       if (screen_map_load(fd, stdin)) {
-               perror_msg_and_die("Error loading acm");
-       }
-
-       write(fd, "\033(K", 3);
-
-       return EXIT_SUCCESS;
-}
-
-static int screen_map_load(int fd, FILE * fp)
-{
-       struct stat stbuf;
-       unicode wbuf[E_TABSZ];
-       unsigned char buf[E_TABSZ];
-       int parse_failed = 0;
-       int is_unicode;
-
-       if (fstat(fileno(fp), &stbuf))
-               perror_msg_and_die("Cannot stat map file");
-
-       /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */
-       if (!
-               (parse_failed =
-                (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode)))
-|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) {       /* test for binary UTF map by size */
-               if (parse_failed) {
-                       if (-1 == fseek(fp, 0, SEEK_SET)) {
-                               if (errno == ESPIPE)
-                                       error_msg_and_die("16bit screen-map MUST be a regular file.");
-                               else
-                                       perror_msg_and_die("fseek failed reading binary 16bit screen-map");
-                       }
-
-                       if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1)
-                               perror_msg_and_die("Cannot read [new] map from file");
-#if 0
-                       else
-                               error_msg("Input screen-map is binary.");
-#endif
-               }
-
-               /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */
-               /* same if it was binary, ie. if parse_failed */
-               if (parse_failed || is_unicode) {
-                       if (ioctl(fd, PIO_UNISCRNMAP, wbuf))
-                               perror_msg_and_die("PIO_UNISCRNMAP ioctl");
-                       else
-                               return 0;
-               }
-       }
-
-       /* rewind... */
-       if (-1 == fseek(fp, 0, SEEK_SET)) {
-               if (errno == ESPIPE)
-                       error_msg("Assuming 8bit screen-map - MUST be a regular file."),
-                               exit(1);
-               else
-                       perror_msg_and_die("fseek failed assuming 8bit screen-map");
-       }
-
-       /* ... and try an old 8-bit screen-map */
-       if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) ||
-               (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) {       /* test for binary old 8-bit map by size */
-               if (parse_failed) {
-                       if (-1 == fseek(fp, 0, SEEK_SET)) {
-                               if (errno == ESPIPE)
-                                       /* should not - it succedeed above */
-                                       error_msg_and_die("fseek() returned ESPIPE !");
-                               else
-                                       perror_msg_and_die("fseek for binary 8bit screen-map");
-                       }
-
-                       if (fread(buf, E_TABSZ, 1, fp) != 1)
-                               perror_msg_and_die("Cannot read [old] map from file");
-#if 0
-                       else
-                               error_msg("Input screen-map is binary.");
-#endif
-               }
-
-               if (ioctl(fd, PIO_SCRNMAP, buf))
-                       perror_msg_and_die("PIO_SCRNMAP ioctl");
-               else
-                       return 0;
-       }
-       error_msg("Error parsing symbolic map");
-       return(1);
-}
-
-
-/*
- * - reads `fp' as a 16-bit ASCII SFM file.
- * - returns -1 on error.
- * - returns it in `unicode' in an E_TABSZ-elements array.
- * - sets `*is_unicode' flagiff there were any non-8-bit
- *   (ie. real 16-bit) mapping.
- *
- * FIXME: ignores everything after second word
- */
-static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode)
-{
-       char buffer[256];                       /* line buffer reading file */
-       char *p, *q;                            /* 1st + 2nd words in line */
-       int in, on;                                     /* the same, as numbers */
-       int tmp_is_unicode;                     /* tmp for is_unicode calculation */
-       int i;                                          /* loop index - result holder */
-       int ret_code = 0;                       /* return code */
-       sigset_t acmsigset, old_sigset;
-
-       assert(is_unicode);
-
-       *is_unicode = 0;
-
-       /* first 128 codes defaults to ASCII */
-       for (i = 0; i < 128; i++)
-               buf[i] = i;
-       /* remaining defaults to replacement char (usually E_TABSZ = 256) */
-       for (; i < E_TABSZ; i++)
-               buf[i] = 0xfffd;
-
-       /* block SIGCHLD */
-       sigemptyset(&acmsigset);
-       sigaddset(&acmsigset, SIGCHLD);
-       sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset);
-
-       do {
-               if (NULL == fgets(buffer, sizeof(buffer), fp)) {
-                       if (feof(fp))
-                               break;
-                       else
-                               perror_msg_and_die("uni_screen_map_read_ascii() can't read line");
-               }
-
-               /* get "charset-relative charcode", stripping leading spaces */
-               p = strtok(buffer, " \t\n");
-
-               /* skip empty lines and comments */
-               if (!p || *p == '#')
-                       continue;
-
-               /* get unicode mapping */
-               q = strtok(NULL, " \t\n");
-               if (q) {
-                       in = ctoi(p, NULL);
-                       if (in < 0 || in > 255) {
-                               ret_code = -1;
-                               break;
-                       }
-
-                       on = ctoi(q, &tmp_is_unicode);
-                       if (in < 0 && on > 65535) {
-                               ret_code = -1;
-                               break;
-                       }
-
-                       *is_unicode |= tmp_is_unicode;
-                       buf[in] = on;
-               } else {
-                       ret_code = -1;
-                       break;
-               }
-       }
-       while (1);                                      /* terminated by break on feof() */
-
-       /* restore sig mask */
-       sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-       return ret_code;
-}
-
-
-static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[])
-{
-       char buffer[256];
-       int in, on;
-       char *p, *q;
-
-       for (in = 0; in < 256; in++)
-               buf[in] = in;
-
-       while (fgets(buffer, sizeof(buffer) - 1, fp)) {
-               p = strtok(buffer, " \t\n");
-
-               if (!p || *p == '#')
-                       continue;
-
-               q = strtok(NULL, " \t\n#");
-               if (q) {
-                       in = ctoi(p, NULL);
-                       if (in < 0 || in > 255)
-                               return -1;
-
-                       on = ctoi(q, NULL);
-                       if (in < 0 && on > 255)
-                               return -1;
-
-                       buf[in] = on;
-               } else
-                       return -1;
-       }
-
-       return (0);
-}
-
-
-/*
- * - converts a string into an int.
- * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars.
- * - returns the converted value
- * - if `is_unicode != NULL', use it to tell whether it was unicode
- *
- * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones.
- */
-static long int ctoi(unsigned char *s, int *is_unicode)
-{
-       int i;
-       size_t ls;
-
-       ls = strlen(s);
-       if (is_unicode)
-               *is_unicode = 0;
-
-       /* hex-specified UCS2 */
-       if ((strncmp(s, "U+", 2) == 0) &&
-               (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) {
-               sscanf(s + 2, "%x", &i);
-               if (is_unicode)
-                       *is_unicode = 1;
-       }
-
-       /* hex-specified byte */
-       else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) &&
-                        (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2))
-               sscanf(s + 2, "%x", &i);
-
-       /* oct-specified number (byte) */
-       else if ((*s == '0') && (strspn(s, "01234567") == ls))
-               sscanf(s, "%o", &i);
-
-       /* dec-specified number (byte) */
-       else if (strspn(s, "0123456789") == ls)
-               sscanf(s, "%d", &i);
-
-       /* single-byte quoted char */
-       else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
-               i = s[1];
-
-       /* multi-byte UTF8 quoted char */
-       else if ((s[0] == '\'') && (s[ls - 1] == '\'')) {
-               s[ls - 1] = 0;                  /* ensure we'll not "parse UTF too far" */
-               i = utf8_to_ucs2(s + 1);
-               if (is_unicode)
-                       *is_unicode = 1;
-       } else
-               return (-1);
-
-       return (i);
-}
-
-
-static unicode utf8_to_ucs2(char *buf)
-{
-       int utf_count = 0;
-       long utf_char = 0;
-       unicode tc = 0;
-       unsigned char c;
-
-       do {
-               c = *buf;
-               buf++;
-
-               /* if byte should be part of multi-byte sequence */
-               if (c & 0x80) {
-                       /* if we have already started to parse a UTF8 sequence */
-                       if (utf_count > 0 && (c & 0xc0) == 0x80) {
-                               utf_char = (utf_char << 6) | (c & 0x3f);
-                               utf_count--;
-                               if (utf_count == 0)
-                                       tc = utf_char;
-                               else
-                                       continue;
-                       } else {                        /* Possibly 1st char of a UTF8 sequence */
-
-                               if ((c & 0xe0) == 0xc0) {
-                                       utf_count = 1;
-                                       utf_char = (c & 0x1f);
-                               } else if ((c & 0xf0) == 0xe0) {
-                                       utf_count = 2;
-                                       utf_char = (c & 0x0f);
-                               } else if ((c & 0xf8) == 0xf0) {
-                                       utf_count = 3;
-                                       utf_char = (c & 0x07);
-                               } else if ((c & 0xfc) == 0xf8) {
-                                       utf_count = 4;
-                                       utf_char = (c & 0x03);
-                               } else if ((c & 0xfe) == 0xfc) {
-                                       utf_count = 5;
-                                       utf_char = (c & 0x01);
-                               } else
-                                       utf_count = 0;
-                               continue;
-                       }
-               } else {                                /* not part of multi-byte sequence - treat as ASCII
-                                                                  * this makes incomplete sequences to be ignored
-                                                                */
-                       tc = c;
-                       utf_count = 0;
-               }
-       }
-       while (utf_count);
-
-       return tc;
-}
diff --git a/busybox/loadfont.c b/busybox/loadfont.c
deleted file mode 100644 (file)
index d665001..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * loadfont.c - Eugene Crosser & Andries Brouwer
- *
- * Version 0.96bb
- *
- * Loads the console font, and possibly the corresponding screen map(s).
- * (Adapted for busybox by Matej Vela.)
- */
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <memory.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/kd.h>
-#include <endian.h>
-#include "busybox.h"
-
-static const int PSF_MAGIC1 = 0x36;
-static const int PSF_MAGIC2 = 0x04;
-
-static const int PSF_MODE512 = 0x01;
-static const int PSF_MODEHASTAB = 0x02;
-static const int PSF_MAXMODE = 0x03;
-static const int PSF_SEPARATOR = 0xFFFF;
-
-struct psf_header {
-       unsigned char magic1, magic2;   /* Magic number */
-       unsigned char mode;                     /* PSF font mode */
-       unsigned char charsize;         /* Character size */
-};
-
-#define PSF_MAGIC_OK(x)        ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
-
-static void loadnewfont(int fd);
-
-extern int loadfont_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc != 1)
-               show_usage();
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0)
-               perror_msg_and_die("Error opening " CURRENT_VC);
-       loadnewfont(fd);
-
-       return EXIT_SUCCESS;
-}
-
-static void do_loadfont(int fd, char *inbuf, int unit, int fontsize)
-{
-       char buf[16384];
-       int i;
-
-       memset(buf, 0, sizeof(buf));
-
-       if (unit < 1 || unit > 32)
-               error_msg_and_die("Bad character size %d", unit);
-
-       for (i = 0; i < fontsize; i++)
-               memcpy(buf + (32 * i), inbuf + (unit * i), unit);
-
-#if defined( PIO_FONTX ) && !defined( __sparc__ )
-       {
-               struct consolefontdesc cfd;
-
-               cfd.charcount = fontsize;
-               cfd.charheight = unit;
-               cfd.chardata = buf;
-
-               if (ioctl(fd, PIO_FONTX, &cfd) == 0)
-                       return;                         /* success */
-               perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)");
-       }
-#endif
-       if (ioctl(fd, PIO_FONT, buf))
-               perror_msg_and_die("PIO_FONT ioctl error");
-}
-
-static void
-do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
-{
-       struct unimapinit advice;
-       struct unimapdesc ud;
-       struct unipair *up;
-       int ct = 0, maxct;
-       int glyph;
-       u_short unicode;
-
-       maxct = tailsz;                         /* more than enough */
-       up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair));
-
-       for (glyph = 0; glyph < fontsize; glyph++) {
-               while (tailsz >= 2) {
-                       unicode = (((u_short) inbuf[1]) << 8) + inbuf[0];
-                       tailsz -= 2;
-                       inbuf += 2;
-                       if (unicode == PSF_SEPARATOR)
-                               break;
-                       up[ct].unicode = unicode;
-                       up[ct].fontpos = glyph;
-                       ct++;
-               }
-       }
-
-       /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
-          this printf did not work on many kernels */
-
-       advice.advised_hashsize = 0;
-       advice.advised_hashstep = 0;
-       advice.advised_hashlevel = 0;
-       if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
-#ifdef ENOIOCTLCMD
-               if (errno == ENOIOCTLCMD) {
-                       error_msg("It seems this kernel is older than 1.1.92");
-                       error_msg_and_die("No Unicode mapping table loaded.");
-               } else
-#endif
-                       perror_msg_and_die("PIO_UNIMAPCLR");
-       }
-       ud.entry_ct = ct;
-       ud.entries = up;
-       if (ioctl(fd, PIO_UNIMAP, &ud)) {
-#if 0
-               if (errno == ENOMEM) {
-                       /* change advice parameters */
-               }
-#endif
-               perror_msg_and_die("PIO_UNIMAP");
-       }
-}
-
-static void loadnewfont(int fd)
-{
-       int unit;
-       char inbuf[32768];                      /* primitive */
-       unsigned int inputlth, offset;
-
-       /*
-        * We used to look at the length of the input file
-        * with stat(); now that we accept compressed files,
-        * just read the entire file.
-        */
-       inputlth = fread(inbuf, 1, sizeof(inbuf), stdin);
-       if (ferror(stdin))
-               perror_msg_and_die("Error reading input font");
-       /* use malloc/realloc in case of giant files;
-          maybe these do not occur: 16kB for the font,
-          and 16kB for the map leaves 32 unicode values
-          for each font position */
-       if (!feof(stdin))
-               perror_msg_and_die("Font too large");
-
-       /* test for psf first */
-       {
-               struct psf_header psfhdr;
-               int fontsize;
-               int hastable;
-               unsigned int head0, head;
-
-               if (inputlth < sizeof(struct psf_header))
-                       goto no_psf;
-
-               psfhdr = *(struct psf_header *) &inbuf[0];
-
-               if (!PSF_MAGIC_OK(psfhdr))
-                       goto no_psf;
-
-               if (psfhdr.mode > PSF_MAXMODE)
-                       error_msg_and_die("Unsupported psf file mode");
-               fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
-#if !defined( PIO_FONTX ) || defined( __sparc__ )
-               if (fontsize != 256)
-                       error_msg_and_die("Only fontsize 256 supported");
-#endif
-               hastable = (psfhdr.mode & PSF_MODEHASTAB);
-               unit = psfhdr.charsize;
-               head0 = sizeof(struct psf_header);
-
-               head = head0 + fontsize * unit;
-               if (head > inputlth || (!hastable && head != inputlth))
-                       error_msg_and_die("Input file: bad length");
-               do_loadfont(fd, inbuf + head0, unit, fontsize);
-               if (hastable)
-                       do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
-               return;
-       }
-  no_psf:
-
-       /* file with three code pages? */
-       if (inputlth == 9780) {
-               offset = 40;
-               unit = 16;
-       } else {
-               /* bare font */
-               if (inputlth & 0377)
-                       error_msg_and_die("Bad input file size");
-               offset = 0;
-               unit = inputlth / 256;
-       }
-       do_loadfont(fd, inbuf + offset, unit, 256);
-}
diff --git a/busybox/loadkmap.c b/busybox/loadkmap.c
deleted file mode 100644 (file)
index 4f217d6..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini loadkmap implementation for busybox
- *
- * Copyright (C) 1998 Enrique Zanardi <ezanardi@ull.es>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#define BINARY_KEYMAP_MAGIC "bkeymap"
-
-/* From <linux/kd.h> */
-struct kbentry {
-       unsigned char kb_table;
-       unsigned char kb_index;
-       unsigned short kb_value;
-};
-static const int KDSKBENT = 0x4B47;  /* sets one entry in translation table */
-
-/* From <linux/keyboard.h> */
-static const int NR_KEYS = 128;
-static const int MAX_NR_KEYMAPS = 256;
-
-int loadkmap_main(int argc, char **argv)
-{
-       struct kbentry ke;
-       u_short *ibuff;
-       int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short);
-       char flags[MAX_NR_KEYMAPS], buff[7];
-
-       if (argc != 1)
-               show_usage();
-
-       fd = open(CURRENT_VC, O_RDWR);
-       if (fd < 0)
-               perror_msg_and_die("Error opening " CURRENT_VC);
-
-       read(0, buff, 7);
-       if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7))
-               error_msg_and_die("This is not a valid binary keymap.");
-
-       if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS))
-               perror_msg_and_die("Error reading keymap flags");
-
-       ibuff = (u_short *) xmalloc(ibuffsz);
-
-       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
-               if (flags[i] == 1) {
-                       pos = 0;
-                       while (pos < ibuffsz) {
-                               if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0)
-                                       perror_msg_and_die("Error reading keymap");
-                               pos += readsz;
-                       }
-                       for (j = 0; j < NR_KEYS; j++) {
-                               ke.kb_index = j;
-                               ke.kb_table = i;
-                               ke.kb_value = ibuff[j];
-                               ioctl(fd, KDSKBENT, &ke);
-                       }
-               }
-       }
-       /* Don't bother to close files.  Exit does that 
-        * automagically, so we can save a few bytes */
-       /* close(fd); */
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/logger.c b/busybox/logger.c
deleted file mode 100644 (file)
index 9f73091..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini logger implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-#if !defined BB_SYSLOGD
-
-#define SYSLOG_NAMES
-#include <sys/syslog.h>
-
-#else
-#include <sys/syslog.h>
-#  ifndef __dietlibc__
-       /* We have to do this since the header file defines static
-        * structures.  Argh.... bad libc, bad, bad...
-        */
-       typedef struct _code {
-               char *c_name;
-               int c_val;
-       } CODE;
-       extern CODE prioritynames[];
-       extern CODE facilitynames[];
-#  endif
-#endif
-
-/* Decode a symbolic name to a numeric value 
- * this function is based on code
- * Copyright (c) 1983, 1993
- * The Regents of the University of California.  All rights reserved.
- *  
- * Original copyright notice is retained at the end of this file.
- */
-static int decode(char *name, CODE * codetab)
-{
-       CODE *c;
-
-       if (isdigit(*name))
-               return (atoi(name));
-       for (c = codetab; c->c_name; c++) {
-               if (!strcasecmp(name, c->c_name)) {
-                       return (c->c_val);
-               }
-       }
-
-       return (-1);
-}
-
-/* Decode a symbolic name to a numeric value 
- * this function is based on code
- * Copyright (c) 1983, 1993
- * The Regents of the University of California.  All rights reserved.
- *
- * Original copyright notice is retained at the end of this file.
- */
-static int pencode(char *s)
-{
-       char *save;
-       int lev, fac = LOG_USER;
-
-       for (save = s; *s && *s != '.'; ++s);
-       if (*s) {
-               *s = '\0';
-               fac = decode(save, facilitynames);
-               if (fac < 0)
-                       error_msg_and_die("unknown facility name: %s", save);
-               *s++ = '.';
-       } else {
-               s = save;
-       }
-       lev = decode(s, prioritynames);
-       if (lev < 0)
-               error_msg_and_die("unknown priority name: %s", save);
-       return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
-}
-
-
-extern int logger_main(int argc, char **argv)
-{
-       int pri = LOG_USER | LOG_NOTICE;
-       int option = 0;
-       int c, i, len, opt;
-       char *message=NULL, buf[1024], name[128];
-
-       /* Fill out the name string early (may be overwritten later) */
-       my_getpwuid(name, geteuid());
-
-       /* Parse any options */
-       while ((opt = getopt(argc, argv, "p:st:")) > 0) {
-               switch (opt) {
-                       case 's':
-                               option |= LOG_PERROR;
-                               break;
-                       case 'p':
-                               pri = pencode(optarg);
-                               break;
-                       case 't':
-                               strncpy(name, optarg, sizeof(name));
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       openlog(name, option, (pri | LOG_FACMASK));
-       if (optind == argc) {
-               do {
-                       /* read from stdin */
-                       i = 0;
-                       while ((c = getc(stdin)) != EOF && c != '\n' && 
-                                       i < (sizeof(buf)-1)) {
-                               buf[i++] = c;
-                       }
-                       if (i > 0) {
-                               buf[i++] = '\0';
-                               syslog(pri, "%s", buf);
-                       }
-               } while (c != EOF);
-       } else {
-               len = 1; /* for the '\0' */
-               message=xcalloc(1, 1);
-               for (i = optind; i < argc; i++) {
-                       len += strlen(argv[i]);
-                       len += 1;  /* for the space between the args */
-                       message = xrealloc(message, len);
-                       strcat(message, argv[i]);
-                       strcat(message, " ");
-               }
-               message[strlen(message)-1] = '\0';
-               syslog(pri, "%s", message);
-       }
-
-       closelog();
-       return EXIT_SUCCESS;
-}
-
-
-/*-
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This is the original license statement for the decode and pencode functions.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
-
diff --git a/busybox/logname.c b/busybox/logname.c
deleted file mode 100644 (file)
index 0924b24..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini logname implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int logname_main(int argc, char **argv)
-{
-       char user[9];
-
-       if (argc > 1)
-               show_usage();
-
-       my_getpwuid(user, geteuid());
-       if (*user) {
-               puts(user);
-               return EXIT_SUCCESS;
-       }
-       error_msg_and_die("no login name");
-}
diff --git a/busybox/logread.c b/busybox/logread.c
deleted file mode 100644 (file)
index d334962..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * circular buffer syslog implementation for busybox
- *
- * Copyright (C) 2000 by Gennady Feldman <gfeldman@cachier.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ipc.h>
-#include <sys/types.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
-#include <signal.h>
-#include <setjmp.h>
-#include "busybox.h"
-
-#if __GNU_LIBRARY__ < 5
-#error Sorry.  Looks like you are using libc5.  
-#error libc5 shm support isnt good enough.
-#error Please disable BB_FEATURE_IPC_SYSLOG 
-#endif 
-
-
-static const long KEY_ID = 0x414e4547; /*"GENA"*/
-
-static struct shbuf_ds {
-       int size;               // size of data written
-       int head;               // start of message list
-       int tail;               // end of message list
-       char data[1];           // data/messages
-} *buf = NULL;                 // shared memory pointer
-
-
-// Semaphore operation structures
-static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup
-static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn
-
-static int     log_shmid = -1; // ipc shared memory id
-static int     log_semid = -1; // ipc semaphore id
-static jmp_buf jmp_env;
-
-static void error_exit(const char *str);
-static void interrupted(int sig);
-
-/*
- * sem_up - up()'s a semaphore.
- */
-static inline void sem_up(int semid)
-{
-       if ( semop(semid, SMrup, 1) == -1 ) 
-               error_exit("semop[SMrup]");
-}
-
-/*
- * sem_down - down()'s a semaphore
- */                            
-static inline void sem_down(int semid)
-{
-       if ( semop(semid, SMrdn, 2) == -1 )
-               error_exit("semop[SMrdn]");
-}
-
-extern int logread_main(int argc, char **argv)
-{
-       int i;
-       
-       /* no options, no getopt */
-       if (argc > 1)
-               show_usage();
-       
-       // handle intrrupt signal
-       if (setjmp(jmp_env)) goto output_end;
-       
-       // attempt to redefine ^C signal
-       signal(SIGINT, interrupted);
-       
-       if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1)
-               error_exit("Can't find circular buffer");
-       
-       // Attach shared memory to our char*
-       if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL)
-               error_exit("Can't get access to circular buffer from syslogd");
-
-       if ( (log_semid = semget(KEY_ID, 0, 0)) == -1)
-               error_exit("Can't get access to semaphone(s) for circular buffer from syslogd");
-
-       sem_down(log_semid);    
-       // Read Memory 
-       i=buf->head;
-
-       //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size);
-       if (buf->head == buf->tail) {
-               printf("<empty syslog>\n");
-       }
-       
-       while ( i != buf->tail) {
-               printf("%s", buf->data+i);
-               i+= strlen(buf->data+i) + 1;
-               if (i >= buf->size )
-                       i=0;
-       }
-       sem_up(log_semid);
-
-output_end:
-       if (log_shmid != -1) 
-               shmdt(buf);
-               
-       return EXIT_SUCCESS;            
-}
-
-static void interrupted(int sig){
-       signal(SIGINT, SIG_IGN);
-       longjmp(jmp_env, 1);
-}
-
-static void error_exit(const char *str){
-       perror(str);
-       //release all acquired resources
-       if (log_shmid != -1) 
-               shmdt(buf);
-
-       exit(1);
-}
diff --git a/busybox/ls.c b/busybox/ls.c
deleted file mode 100644 (file)
index 8d0282d..0000000
+++ /dev/null
@@ -1,937 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * tiny-ls.c version 0.1.0: A minimalist 'ls'
- * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * To achieve a small memory footprint, this version of 'ls' doesn't do any
- * file sorting, and only has the most essential command line switches
- * (i.e., the ones I couldn't live without :-) All features which involve
- * linking in substantial chunks of libc can be disabled.
- *
- * Although I don't really want to add new features to this program to
- * keep it small, I *am* interested to receive bug fixes and ways to make
- * it more portable.
- *
- * KNOWN BUGS:
- * 1. ls -l of a directory doesn't give "total <blocks>" header
- * 2. ls of a symlink to a directory doesn't list directory contents
- * 3. hidden files can make column width too large
- *
- * NON-OPTIMAL BEHAVIOUR:
- * 1. autowidth reads directories twice
- * 2. if you do a short directory listing without filetype characters
- *    appended, there's no need to stat each one
- * PORTABILITY:
- * 1. requires lstat (BSD) - how do you do it without?
- */
-
-enum {
-       TERMINAL_WIDTH = 80,            /* use 79 if terminal has linefold bug */
-       COLUMN_WIDTH = 14,                      /* default if AUTOWIDTH not defined */
-       COLUMN_GAP = 2,                         /* includes the file type char */
-};
-
-
-/************************************************************************/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-#include <time.h>
-#endif
-
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
-/* what is the overall style of the listing */
-enum {
-STYLE_AUTO = 0,
-STYLE_LONG = 1,                /* one record per line, extended info */
-STYLE_SINGLE = 2,              /* one record per line */
-STYLE_COLUMNS = 3              /* fill columns */
-};
-
-/* 51306 lrwxrwxrwx  1 root     root         2 May 11 01:43 /bin/view -> vi* */
-/* what file information will be listed */
-#define LIST_INO               (1<<0)
-#define LIST_BLOCKS            (1<<1)
-#define LIST_MODEBITS  (1<<2)
-#define LIST_NLINKS            (1<<3)
-#define LIST_ID_NAME   (1<<4)
-#define LIST_ID_NUMERIC        (1<<5)
-#define LIST_SIZE              (1<<6)
-#define LIST_DEV               (1<<7)
-#define LIST_DATE_TIME (1<<8)
-#define LIST_FULLTIME  (1<<9)
-#define LIST_FILENAME  (1<<10)
-#define LIST_SYMLINK   (1<<11)
-#define LIST_FILETYPE  (1<<12)
-#define LIST_EXEC              (1<<13)
-
-/* what files will be displayed */
-#define DISP_NORMAL            (0)             /* show normal filenames */
-#define DISP_DIRNAME   (1<<0)  /* 2 or more items? label directories */
-#define DISP_HIDDEN            (1<<1)  /* show filenames starting with .  */
-#define DISP_DOT               (1<<2)  /* show . and .. */
-#define DISP_NOLIST            (1<<3)  /* show directory as itself, not contents */
-#define DISP_RECURSIVE (1<<4)  /* show directory and everything below it */
-#define DISP_ROWS              (1<<5)  /* print across rows */
-
-#ifdef BB_FEATURE_LS_SORTFILES
-/* how will the files be sorted */
-static const int SORT_FORWARD = 0;             /* sort in reverse order */
-static const int SORT_REVERSE = 1;             /* sort in reverse order */
-static const int SORT_NAME = 2;                /* sort by file name */
-static const int SORT_SIZE = 3;                /* sort by file size */
-static const int SORT_ATIME = 4;               /* sort by last access time */
-static const int SORT_CTIME = 5;               /* sort by last change time */
-static const int SORT_MTIME = 6;               /* sort by last modification time */
-static const int SORT_VERSION = 7;             /* sort by version */
-static const int SORT_EXT = 8;         /* sort by file name extension */
-static const int SORT_DIR = 9;         /* sort by file or directory */
-#endif
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-/* which of the three times will be used */
-static const int TIME_MOD = 0;
-static const int TIME_CHANGE = 1;
-static const int TIME_ACCESS = 2;
-#endif
-
-#define LIST_SHORT             (LIST_FILENAME)
-#define LIST_ISHORT            (LIST_INO | LIST_FILENAME)
-#define LIST_LONG              (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | \
-                                               LIST_SIZE | LIST_DATE_TIME | LIST_FILENAME | \
-                                               LIST_SYMLINK)
-#define LIST_ILONG             (LIST_INO | LIST_LONG)
-
-static const int SPLIT_DIR = 0;
-static const int SPLIT_FILE = 1;
-static const int SPLIT_SUBDIR = 2;
-
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
-#ifdef BB_FEATURE_LS_FILETYPES
-#define APPCHAR(mode)   ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
-#endif
-
-/*
- * a directory entry and its stat info are stored here
- */
-struct dnode {                         /* the basic node */
-    char *name;                                /* the dir entry name */
-    char *fullname;                    /* the dir entry name */
-    struct stat dstat;         /* the file stat info */
-    struct dnode *next;                /* point at the next node */
-};
-typedef struct dnode dnode_t;
-
-static struct dnode **list_dir(char *);
-static struct dnode **dnalloc(int);
-static int list_single(struct dnode *);
-
-static unsigned int disp_opts;
-static unsigned int style_fmt;
-static unsigned int list_fmt;
-#ifdef BB_FEATURE_LS_SORTFILES
-static unsigned int sort_opts;
-static unsigned int sort_order;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-static unsigned int time_fmt;
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-static unsigned int follow_links=FALSE;
-#endif
-
-static unsigned short column = 0;
-#ifdef BB_FEATURE_AUTOWIDTH
-static unsigned short terminal_width = TERMINAL_WIDTH;
-static unsigned short column_width = COLUMN_WIDTH;
-static unsigned short tabstops = COLUMN_GAP;
-#else
-static unsigned short column_width = COLUMN_WIDTH;
-#endif
-
-static int status = EXIT_SUCCESS;
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-static unsigned long ls_disp_hr = 0;
-#endif
-
-static int my_stat(struct dnode *cur)
-{
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-       if (follow_links == TRUE) {
-               if (stat(cur->fullname, &cur->dstat)) {
-                       perror_msg("%s", cur->fullname);
-                       status = EXIT_FAILURE;
-                       free(cur->fullname);
-                       free(cur);
-                       return -1;
-               }
-       } else
-#endif
-       if (lstat(cur->fullname, &cur->dstat)) {
-               perror_msg("%s", cur->fullname);
-               status = EXIT_FAILURE;
-               free(cur->fullname);
-               free(cur);
-               return -1;
-       }
-       return 0;
-}
-
-static void newline(void)
-{
-    if (column > 0) {
-        putchar('\n');
-        column = 0;
-    }
-}
-
-/*----------------------------------------------------------------------*/
-#ifdef BB_FEATURE_LS_FILETYPES
-static char append_char(mode_t mode)
-{
-       if ( !(list_fmt & LIST_FILETYPE))
-               return '\0';
-       if ((list_fmt & LIST_EXEC) && S_ISREG(mode)
-           && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
-               return APPCHAR(mode);
-}
-#endif
-
-/*----------------------------------------------------------------------*/
-static void nexttabstop( void )
-{
-       static short nexttab= 0;
-       int n=0;
-
-       if (column > 0) {
-               n= nexttab - column;
-               if (n < 1) n= 1;
-               while (n--) {
-                       putchar(' ');
-                       column++;
-               }
-       }
-       nexttab= column + column_width + COLUMN_GAP; 
-}
-
-/*----------------------------------------------------------------------*/
-static int is_subdir(struct dnode *dn)
-{
-       return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 &&
-                       strcmp(dn->name, "..") != 0);
-}
-
-static int countdirs(struct dnode **dn, int nfiles)
-{
-       int i, dirs;
-
-       if (dn==NULL || nfiles < 1) return(0);
-       dirs= 0;
-       for (i=0; i<nfiles; i++) {
-               if (S_ISDIR(dn[i]->dstat.st_mode)) dirs++;
-       }
-       return(dirs);
-}
-
-static int countsubdirs(struct dnode **dn, int nfiles)
-{
-       int i, subdirs;
-
-       if (dn == NULL || nfiles < 1) return 0;
-       subdirs = 0;
-       for (i = 0; i < nfiles; i++)
-               if (is_subdir(dn[i]))
-                       subdirs++;
-       return subdirs;
-}
-
-static int countfiles(struct dnode **dnp)
-{
-       int nfiles;
-       struct dnode *cur;
-
-       if (dnp == NULL) return(0);
-       nfiles= 0;
-       for (cur= dnp[0];  cur->next != NULL ; cur= cur->next) nfiles++;
-       nfiles++;
-       return(nfiles);
-}
-
-/* get memory to hold an array of pointers */
-static struct dnode **dnalloc(int num)
-{
-       struct dnode **p;
-
-       if (num < 1) return(NULL);
-
-       p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *)));
-       return(p);
-}
-
-#ifdef BB_FEATURE_LS_RECURSIVE
-static void dfree(struct dnode **dnp)
-{
-       struct dnode *cur, *next;
-
-       if(dnp == NULL) return;
-
-       cur=dnp[0];
-       while (cur != NULL) {
-               if (cur->fullname != NULL) free(cur->fullname); /* free the filename */
-               next= cur->next;
-               free(cur);                              /* free the dnode */
-               cur= next;
-       }
-       free(dnp);      /* free the array holding the dnode pointers */
-}
-#endif
-
-static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
-{
-       int dncnt, i, d;
-       struct dnode **dnp;
-
-       if (dn==NULL || nfiles < 1) return(NULL);
-
-       /* count how many dirs and regular files there are */
-       if (which == SPLIT_SUBDIR)
-               dncnt = countsubdirs(dn, nfiles);
-       else {
-               dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */
-               if (which == SPLIT_FILE)
-                       dncnt= nfiles - dncnt;  /* looking for files */
-       }
-
-       /* allocate a file array and a dir array */
-       dnp= dnalloc(dncnt);
-
-       /* copy the entrys into the file or dir array */
-       for (d= i=0; i<nfiles; i++) {
-               if (which == SPLIT_DIR) {
-                       if (S_ISDIR(dn[i]->dstat.st_mode)) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the file */
-               } else if (which == SPLIT_SUBDIR) {
-                       if (is_subdir(dn[i])) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the file or dir */
-               } else {
-                       if (!(S_ISDIR(dn[i]->dstat.st_mode))) {
-                               dnp[d++]= dn[i];
-                       }  /* else skip the dir */
-               }
-       }
-       return(dnp);
-}
-
-/*----------------------------------------------------------------------*/
-#ifdef BB_FEATURE_LS_SORTFILES
-static int sortcmp(struct dnode *d1, struct dnode *d2)
-{
-       int cmp, dif;
-
-       cmp= 0;
-       if (sort_opts == SORT_SIZE) {
-               dif= (int)(d1->dstat.st_size - d2->dstat.st_size);
-       } else if (sort_opts == SORT_ATIME) {
-               dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime);
-       } else if (sort_opts == SORT_CTIME) {
-               dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime);
-       } else if (sort_opts == SORT_MTIME) {
-               dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime);
-       } else if (sort_opts == SORT_DIR) {
-               dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode);
-       /* } else if (sort_opts == SORT_VERSION) { */
-       /* } else if (sort_opts == SORT_EXT) { */
-       } else {    /* assume SORT_NAME */
-               dif= 0;
-       }
-
-       if (dif > 0) cmp= -1;
-       if (dif < 0) cmp=  1;
-       if (dif == 0) {
-               /* sort by name- may be a tie_breaker for time or size cmp */
-               dif= strcmp(d1->name, d2->name);
-               if (dif > 0) cmp=  1;
-               if (dif < 0) cmp= -1;
-       }
-
-       if (sort_order == SORT_REVERSE) {
-               cmp=  -1 * cmp;
-       }
-       return(cmp);
-}
-
-/*----------------------------------------------------------------------*/
-static void shellsort(struct dnode **dn, int size)
-{
-       struct dnode *temp;
-       int gap, i, j;
-
-       /* shell short the array */
-       if(dn==NULL || size < 2) return;
-
-       for (gap= size/2; gap>0; gap /=2) {
-               for (i=gap; i<size; i++) {
-                       for (j= i-gap; j>=0; j-=gap) {
-                               if (sortcmp(dn[j], dn[j+gap]) <= 0)
-                                       break;
-                               /* they are out of order, swap them */
-                               temp= dn[j];
-                               dn[j]= dn[j+gap];
-                               dn[j+gap]= temp;
-                       }
-               }
-       }
-}
-#endif
-
-/*----------------------------------------------------------------------*/
-static void showfiles(struct dnode **dn, int nfiles)
-{
-       int i, ncols, nrows, row, nc;
-#ifdef BB_FEATURE_AUTOWIDTH
-       int len;
-#endif
-
-       if(dn==NULL || nfiles < 1) return;
-
-#ifdef BB_FEATURE_AUTOWIDTH
-       /* find the longest file name-  use that as the column width */
-       column_width= 0;
-       for (i=0; i<nfiles; i++) {
-               len= strlen(dn[i]->name) +
-                       ((list_fmt & LIST_INO) ? 8 : 0) +
-                       ((list_fmt & LIST_BLOCKS) ? 5 : 0)
-                       ;
-               if (column_width < len) 
-                       column_width= len;
-       }
-       if (column_width >= 6)
-               ncols = (int)(terminal_width / (column_width + COLUMN_GAP));
-       else {
-               ncols = 1;
-               column_width = COLUMN_WIDTH;
-       }
-#else
-       ncols= TERMINAL_WIDTH;
-#endif
-       switch (style_fmt) {
-               case STYLE_LONG:        /* one record per line, extended info */
-               case STYLE_SINGLE:      /* one record per line */
-                       ncols= 1;
-                       break;
-       }
-
-       if (ncols > 1) {
-               nrows = nfiles / ncols;
-       } else {
-               nrows = nfiles;
-               ncols = 1;
-       }
-       if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */
-
-       if (nrows > nfiles) nrows= nfiles;
-       for (row=0; row<nrows; row++) {
-               for (nc=0; nc<ncols; nc++) {
-                       /* reach into the array based on the column and row */
-                       i= (nc * nrows) + row;          /* assume display by column */
-                       if (disp_opts & DISP_ROWS)
-                               i= (row * ncols) + nc;  /* display across row */
-                       if (i < nfiles) {
-                               nexttabstop();
-                               list_single(dn[i]);
-                       }
-               }
-               newline();
-       }
-}
-
-/*----------------------------------------------------------------------*/
-static void showdirs(struct dnode **dn, int ndirs)
-{
-       int i, nfiles;
-       struct dnode **subdnp;
-#ifdef BB_FEATURE_LS_RECURSIVE
-       int dndirs;
-       struct dnode **dnd;
-#endif
-
-       if (dn==NULL || ndirs < 1) return;
-
-       for (i=0; i<ndirs; i++) {
-               if (disp_opts & (DISP_DIRNAME | DISP_RECURSIVE)) {
-                       printf("\n%s:\n", dn[i]->fullname);
-               }
-               subdnp= list_dir(dn[i]->fullname);
-               nfiles= countfiles(subdnp);
-               if (nfiles > 0) {
-                       /* list all files at this level */
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(subdnp, nfiles);
-#endif
-                       showfiles(subdnp, nfiles);
-#ifdef BB_FEATURE_LS_RECURSIVE
-                       if (disp_opts & DISP_RECURSIVE) {
-                               /* recursive- list the sub-dirs */
-                               dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
-                               dndirs= countsubdirs(subdnp, nfiles);
-                               if (dndirs > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                                       shellsort(dnd, dndirs);
-#endif
-                                       showdirs(dnd, dndirs);
-                                       free(dnd);  /* free the array of dnode pointers to the dirs */
-                               }
-                       }
-                       dfree(subdnp);  /* free the dnodes and the fullname mem */
-#endif
-               }
-       }
-}
-
-/*----------------------------------------------------------------------*/
-static struct dnode **list_dir(char *path)
-{
-       struct dnode *dn, *cur, **dnp;
-       struct dirent *entry;
-       DIR *dir;
-       int i, nfiles;
-
-       if (path==NULL) return(NULL);
-
-       dn= NULL;
-       nfiles= 0;
-       dir = opendir(path);
-       if (dir == NULL) {
-               perror_msg("%s", path);
-               status = EXIT_FAILURE;
-               return(NULL);   /* could not open the dir */
-       }
-       while ((entry = readdir(dir)) != NULL) {
-               /* are we going to list the file- it may be . or .. or a hidden file */
-               if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT))
-                       continue;
-               if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT))
-                       continue;
-               if ((entry->d_name[0] ==  '.') && !(disp_opts & DISP_HIDDEN))
-                       continue;
-               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
-               cur->fullname = concat_path_file(path, entry->d_name);
-               cur->name = cur->fullname +
-                               (strlen(cur->fullname) - strlen(entry->d_name));
-               if (my_stat(cur))
-                       continue;
-               cur->next= dn;
-               dn= cur;
-               nfiles++;
-       }
-       closedir(dir);
-
-       /* now that we know how many files there are
-       ** allocate memory for an array to hold dnode pointers
-       */
-       if (nfiles < 1) return(NULL);
-       dnp= dnalloc(nfiles);
-       for (i=0, cur=dn; i<nfiles; i++) {
-               dnp[i]= cur;   /* save pointer to node in array */
-               cur= cur->next;
-       }
-
-       return(dnp);
-}
-
-/*----------------------------------------------------------------------*/
-static int list_single(struct dnode *dn)
-{
-       int i;
-       char scratch[BUFSIZ + 1];
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       char *filetime;
-       time_t ttime, age;
-#endif
-#if defined (BB_FEATURE_LS_FILETYPES)
-       struct stat info;
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-       char append;
-#endif
-
-       if (dn==NULL || dn->fullname==NULL) return(0);
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       ttime= dn->dstat.st_mtime;      /* the default time */
-       if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime;
-       if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime;
-       filetime= ctime(&ttime);
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-       append = append_char(dn->dstat.st_mode);
-#endif
-
-       for (i=0; i<=31; i++) {
-               switch (list_fmt & (1<<i)) {
-                       case LIST_INO:
-                               printf("%7ld ", (long int)dn->dstat.st_ino);
-                               column += 8;
-                               break;
-                       case LIST_BLOCKS:
-#ifdef BB_FEATURE_HUMAN_READABLE
-                               fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, 
-                                                       KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE));
-#else
-#if _FILE_OFFSET_BITS == 64
-                               printf("%4lld ", dn->dstat.st_blocks>>1);
-#else
-                               printf("%4ld ", dn->dstat.st_blocks>>1);
-#endif
-#endif
-                               column += 5;
-                               break;
-                       case LIST_MODEBITS:
-                               printf("%-10s ", (char *)mode_string(dn->dstat.st_mode));
-                               column += 10;
-                               break;
-                       case LIST_NLINKS:
-                               printf("%4ld ", (long)dn->dstat.st_nlink);
-                               column += 10;
-                               break;
-                       case LIST_ID_NAME:
-#ifdef BB_FEATURE_LS_USERNAME
-                               my_getpwuid(scratch, dn->dstat.st_uid);
-                               printf("%-8.8s ", scratch);
-                               my_getgrgid(scratch, dn->dstat.st_gid);
-                               printf("%-8.8s", scratch);
-                               column += 17;
-                               break;
-#endif
-                       case LIST_ID_NUMERIC:
-                               printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid);
-                               column += 17;
-                               break;
-                       case LIST_SIZE:
-                       case LIST_DEV:
-                               if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
-                                       printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev));
-                               } else {
-#ifdef BB_FEATURE_HUMAN_READABLE
-                                       if (ls_disp_hr==TRUE) {
-                                               fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0));
-                                       } else 
-#endif 
-                                       {
-#if _FILE_OFFSET_BITS == 64
-                                               printf("%9lld ", (long long)dn->dstat.st_size);
-#else
-                                               printf("%9ld ", dn->dstat.st_size);
-#endif
-                                       }
-                               }
-                               column += 10;
-                               break;
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-                       case LIST_FULLTIME:
-                       case LIST_DATE_TIME:
-                               if (list_fmt & LIST_FULLTIME) {
-                                       printf("%24.24s ", filetime);
-                                       column += 25;
-                                       break;
-                               }
-                               age = time(NULL) - ttime;
-                               printf("%6.6s ", filetime+4);
-                               if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
-                                       /* hh:mm if less than 6 months old */
-                                       printf("%5.5s ", filetime+11);
-                               } else {
-                                       printf(" %4.4s ", filetime+20);
-                               }
-                               column += 13;
-                               break;
-#endif
-                       case LIST_FILENAME:
-                               printf("%s", dn->name);
-                               column += strlen(dn->name);
-                               break;
-                       case LIST_SYMLINK:
-                               if (S_ISLNK(dn->dstat.st_mode)) {
-                                       char *lpath = xreadlink(dn->fullname);
-                                       if (lpath) {
-                                               printf(" -> %s", lpath);
-#ifdef BB_FEATURE_LS_FILETYPES
-                                               if (!stat(dn->fullname, &info)) {
-                                                       append = append_char(info.st_mode);
-                                               }
-#endif
-                                               column += strlen(lpath) + 4;
-                                               free(lpath);
-                                       }
-                               }
-                               break;
-#ifdef BB_FEATURE_LS_FILETYPES
-                       case LIST_FILETYPE:
-                               if (append != '\0') {
-                                       printf("%1c", append);
-                                       column++;
-                               }
-                               break;
-#endif
-               }
-       }
-
-       return(0);
-}
-
-/*----------------------------------------------------------------------*/
-extern int ls_main(int argc, char **argv)
-{
-       struct dnode **dnf, **dnd;
-       int dnfiles, dndirs;
-       struct dnode *dn, *cur, **dnp;
-       int i, nfiles;
-       int opt;
-       int oi, ac;
-       char **av;
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-#endif
-
-       disp_opts= DISP_NORMAL;
-       style_fmt= STYLE_AUTO;
-       list_fmt=  LIST_SHORT;
-#ifdef BB_FEATURE_LS_SORTFILES
-       sort_opts= SORT_NAME;
-       sort_order=     SORT_FORWARD;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-       time_fmt= TIME_MOD;
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-       ioctl(fileno(stdout), TIOCGWINSZ, &win);
-       if (win.ws_row > 4)
-               column_width = win.ws_row - 2;
-       if (win.ws_col > 0)
-               terminal_width = win.ws_col - 1;
-#endif
-       nfiles=0;
-
-       /* process options */
-       while ((opt = getopt(argc, argv, "1AaCdgilnsx"
-#ifdef BB_FEATURE_AUTOWIDTH
-"T:w:"
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-"Fp"
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-"R"
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-"rSvX"
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-"cetu"
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-"L"
-#endif
-#ifdef BB_FEATURE_HUMAN_READABLE
-"h"
-#endif
-"k")) > 0) {
-               switch (opt) {
-                       case '1': style_fmt = STYLE_SINGLE; break;
-                       case 'A': disp_opts |= DISP_HIDDEN; break;
-                       case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break;
-                       case 'C': style_fmt = STYLE_COLUMNS; break;
-                       case 'd': disp_opts |= DISP_NOLIST; break;
-                       case 'g': /* ignore -- for ftp servers */ break;
-                       case 'i': list_fmt |= LIST_INO; break;
-                       case 'l':
-                               style_fmt = STYLE_LONG;
-                               list_fmt |= LIST_LONG;
-#ifdef BB_FEATURE_HUMAN_READABLE
-                               ls_disp_hr = FALSE;
-#endif
-                       break;
-                       case 'n': list_fmt |= LIST_ID_NUMERIC; break;
-                       case 's': list_fmt |= LIST_BLOCKS; break;
-                       case 'x': disp_opts = DISP_ROWS; break;
-#ifdef BB_FEATURE_LS_FILETYPES
-                       case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break;
-                       case 'p': list_fmt |= LIST_FILETYPE; break;
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-                       case 'R': disp_opts |= DISP_RECURSIVE; break;
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-                       case 'r': sort_order |= SORT_REVERSE; break;
-                       case 'S': sort_opts= SORT_SIZE; break;
-                       case 'v': sort_opts= SORT_VERSION; break;
-                       case 'X': sort_opts= SORT_EXT; break;
-#endif
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-                       case 'e': list_fmt |= LIST_FULLTIME; break;
-                       case 'c':
-                               time_fmt = TIME_CHANGE;
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_CTIME;
-#endif
-                               break;
-                       case 'u':
-                               time_fmt = TIME_ACCESS;
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_ATIME;
-#endif
-                               break;
-                       case 't':
-#ifdef BB_FEATURE_LS_SORTFILES
-                               sort_opts= SORT_MTIME;
-#endif
-                               break;
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-                       case 'L': follow_links= TRUE; break;
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-                       case 'T': tabstops= atoi(optarg); break;
-                       case 'w': terminal_width= atoi(optarg); break;
-#endif
-#ifdef BB_FEATURE_HUMAN_READABLE
-                       case 'h': ls_disp_hr = TRUE; break;
-#endif
-                       case 'k': break;
-                       default:
-                               goto print_usage_message;
-               }
-       }
-
-       /* sort out which command line options take precedence */
-#ifdef BB_FEATURE_LS_RECURSIVE
-       if (disp_opts & DISP_NOLIST)
-               disp_opts &= ~DISP_RECURSIVE;   /* no recurse if listing only dir */
-#endif
-#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES)
-       if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME;
-       if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME;
-#endif
-       if (style_fmt != STYLE_LONG)
-                       list_fmt &= ~LIST_ID_NUMERIC;  /* numeric uid only for long list */
-#ifdef BB_FEATURE_LS_USERNAME
-       if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC))
-                       list_fmt &= ~LIST_ID_NAME;  /* don't list names if numeric uid */
-#endif
-
-       /* choose a display format */
-       if (style_fmt == STYLE_AUTO)
-               style_fmt = isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE;
-
-       /*
-        * when there are no cmd line args we have to supply a default "." arg.
-        * we will create a second argv array, "av" that will hold either
-        * our created "." arg, or the real cmd line args.  The av array
-        * just holds the pointers- we don't move the date the pointers
-        * point to.
-        */
-       ac= argc - optind;   /* how many cmd line args are left */
-       if (ac < 1) {
-               av= (char **)xcalloc((size_t)1, (size_t)(sizeof(char *)));
-               av[0]= xstrdup(".");
-               ac=1;
-       } else {
-               av= (char **)xcalloc((size_t)ac, (size_t)(sizeof(char *)));
-               for (oi=0 ; oi < ac; oi++) {
-                       av[oi]= argv[optind++];  /* copy pointer to real cmd line arg */
-               }
-       }
-
-       /* now, everything is in the av array */
-       if (ac > 1)
-               disp_opts |= DISP_DIRNAME;   /* 2 or more items? label directories */
-
-       /* stuff the command line file names into an dnode array */
-       dn=NULL;
-       for (oi=0 ; oi < ac; oi++) {
-               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
-               cur->fullname= xstrdup(av[oi]);
-               cur->name= cur->fullname;
-               if (my_stat(cur))
-                       continue;
-               cur->next= dn;
-               dn= cur;
-               nfiles++;
-       }
-
-       /* now that we know how many files there are
-       ** allocate memory for an array to hold dnode pointers
-       */
-       dnp= dnalloc(nfiles);
-       for (i=0, cur=dn; i<nfiles; i++) {
-               dnp[i]= cur;   /* save pointer to node in array */
-               cur= cur->next;
-       }
-
-
-       if (disp_opts & DISP_NOLIST) {
-#ifdef BB_FEATURE_LS_SORTFILES
-               shellsort(dnp, nfiles);
-#endif
-               if (nfiles > 0) showfiles(dnp, nfiles);
-       } else {
-               dnd= splitdnarray(dnp, nfiles, SPLIT_DIR);
-               dnf= splitdnarray(dnp, nfiles, SPLIT_FILE);
-               dndirs= countdirs(dnp, nfiles);
-               dnfiles= nfiles - dndirs;
-               if (dnfiles > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(dnf, dnfiles);
-#endif
-                       showfiles(dnf, dnfiles);
-               }
-               if (dndirs > 0) {
-#ifdef BB_FEATURE_LS_SORTFILES
-                       shellsort(dnd, dndirs);
-#endif
-                       showdirs(dnd, dndirs);
-               }
-       }
-       return(status);
-
-  print_usage_message:
-       show_usage();
-}
diff --git a/busybox/lsmod.c b/busybox/lsmod.c
deleted file mode 100644 (file)
index 76ed2fd..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini lsmod implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
- * (which lack the query_module() interface).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <assert.h>
-#include <getopt.h>
-#include <sys/utsname.h>
-#include <sys/file.h>
-#include "busybox.h"
-
-
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-
-struct module_info
-{
-       unsigned long addr;
-       unsigned long size;
-       unsigned long flags;
-       long usecount;
-};
-
-
-int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
-
-/* Values for query_module's which.  */
-static const int QM_MODULES = 1;
-static const int QM_DEPS = 2;
-static const int QM_REFS = 3;
-static const int QM_SYMBOLS = 4;
-static const int QM_INFO = 5;
-
-/* Bits of module.flags.  */
-static const int NEW_MOD_RUNNING = 1;
-static const int NEW_MOD_DELETED = 2;
-static const int NEW_MOD_AUTOCLEAN = 4;
-static const int NEW_MOD_VISITED = 8;
-static const int NEW_MOD_USED_ONCE = 16;
-static const int NEW_MOD_INITIALIZING = 64;
-
-static int my_query_module(const char *name, int which, void **buf,
-               size_t *bufsize, size_t *ret)
-{
-       int my_ret;
-
-       my_ret = query_module(name, which, *buf, *bufsize, ret);
-
-       if (my_ret == -1 && errno == ENOSPC) {
-               *buf = xrealloc(*buf, *ret);
-               *bufsize = *ret;
-
-               my_ret = query_module(name, which, *buf, *bufsize, ret);
-       }
-
-       return my_ret;
-}
-
-extern int lsmod_main(int argc, char **argv)
-{
-       struct module_info info;
-       char *module_names, *mn, *deps, *dn;
-       size_t bufsize, depsize, nmod, count, i, j;
-
-       module_names = xmalloc(bufsize = 256);
-       if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize,
-                               &nmod)) {
-               perror_msg_and_die("QM_MODULES");
-       }
-
-       deps = xmalloc(depsize = 256);
-       printf("Module                  Size  Used by\n");
-       for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
-               if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
-                       if (errno == ENOENT) {
-                               /* The module was removed out from underneath us. */
-                               continue;
-                       }
-                       /* else choke */
-                       perror_msg_and_die("module %s: QM_INFO", mn);
-               }
-               if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) {
-                       if (errno == ENOENT) {
-                               /* The module was removed out from underneath us. */
-                               continue;
-                       }
-                       perror_msg_and_die("module %s: QM_REFS", mn);
-               }
-               printf("%-20s%8lu%4ld ", mn, info.size, info.usecount);
-               if (info.flags & NEW_MOD_DELETED)
-                       printf("(deleted)");
-               else if (info.flags & NEW_MOD_INITIALIZING)
-                       printf("(initializing)");
-               else if (!(info.flags & NEW_MOD_RUNNING))
-                       printf("(uninitialized)");
-               else {
-                       if (info.flags & NEW_MOD_AUTOCLEAN)
-                               printf("(autoclean) ");
-                       if (!(info.flags & NEW_MOD_USED_ONCE))
-                               printf("(unused)");
-               }
-               if (count) printf("[");
-               for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
-                       printf("%s%s", dn, (j==count-1)? "":" ");
-               }
-               if (count) printf("] ");
-
-               printf("\n");
-       }
-
-
-       return( 0);
-}
-
-#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/
-
-extern int lsmod_main(int argc, char **argv)
-{
-       int fd, i;
-       char line[128];
-
-       puts("Module                  Size  Used by");
-       fflush(stdout);
-
-       if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
-               while ((i = read(fd, line, sizeof(line))) > 0) {
-                       write(fileno(stdout), line, i);
-               }
-               close(fd);
-               return 0;
-       }
-       perror_msg_and_die("/proc/modules");
-       return 1;
-}
-
-#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/
diff --git a/busybox/makedevs.c b/busybox/makedevs.c
deleted file mode 100644 (file)
index b8c6dd1..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- * 
- * makedevs
- * Make ranges of device files quickly. 
- * known bugs: can't deal with alpha ranges
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-int makedevs_main(int argc, char **argv)
-{
-
-       const char *basedev = argv[1];
-       const char *type = argv[2];
-       int major = atoi(argv[3]);
-       int Sminor = atoi(argv[4]);
-       int S = atoi(argv[5]);
-       int E = atoi(argv[6]);
-       int sbase = argc == 8 ? 1 : 0;
-
-       mode_t mode = 0;
-       dev_t dev = 0;
-       char devname[255];
-       char buf[255];
-
-       if (argc < 7 || *argv[1]=='-')
-               show_usage();
-
-       switch (type[0]) {
-       case 'c':
-               mode = S_IFCHR;
-               break;
-       case 'b':
-               mode = S_IFBLK;
-               break;
-       case 'f':
-               mode = S_IFIFO;
-               break;
-       default:
-               show_usage();
-       }
-       mode |= 0660;
-
-       while (S <= E) {
-
-               if (type[0] != 'f')
-                       dev = (major << 8) | Sminor;
-               strcpy(devname, basedev);
-
-               if (sbase == 0) {
-                       sprintf(buf, "%d", S);
-                       strcat(devname, buf);
-               } else {
-                       sbase = 0;
-               }
-
-               if (mknod(devname, mode, dev))
-                       printf("Failed to create: %s\n", devname);
-
-               S++;
-               Sminor++;
-       }
-
-       return 0;
-}
-
-/*
-And this is what this program replaces. The shell is too slow!
-
-makedev () {
-local basedev=$1; local S=$2; local E=$3
-local major=$4; local Sminor=$5; local type=$6
-local sbase=$7
-
-       if [ ! "$sbase" = "" ]; then
-               mknod "$basedev" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       fi
-
-       while [ $S -le $E ]; do
-               mknod "$basedev$S" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       done
-}
-*/
diff --git a/busybox/md5sum.c b/busybox/md5sum.c
deleted file mode 100644 (file)
index bb4d115..0000000
+++ /dev/null
@@ -1,1074 +0,0 @@
-/* md5sum.c - Compute MD5 checksum of files or strings according to the
- *            definition of MD5 in RFC 1321 from April 1992.
- * Copyright (C) 1995-1999 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
-/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
-
-/*
- * June 29, 2001        Manuel Novoa III
- *
- * Added MD5SUM_SIZE_VS_SPEED configuration option.
- *
- * Current valid values, with data from my system for comparison, are:
- *   (using uClibc and running on linux-2.4.4.tar.bz2)
- *                     user times (sec)  text size (386)
- *     0 (fastest)         1.1                6144
- *     1                   1.4                5392
- *     2                   3.0                5088
- *     3 (smallest)        5.1                4912
- */
-
-#define MD5SUM_SIZE_VS_SPEED 2
-
-/**********************************************************************/
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <endian.h>
-#include <sys/types.h>
-#if defined HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include "busybox.h"
-
-/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
-#undef TRUE
-#undef FALSE
-#define FALSE   ((int) 1)
-#define TRUE    ((int) 0)
-
-//----------------------------------------------------------------------------
-//--------md5.c
-//----------------------------------------------------------------------------
-
-/* md5.c - Functions to compute MD5 message digest of files or memory blocks
- *         according to the definition of MD5 in RFC 1321 from April 1992.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
-
-//----------------------------------------------------------------------------
-//--------md5.h
-//----------------------------------------------------------------------------
-
-/* md5.h - Declaration of functions and data types used for MD5 sum
-   computing library functions. */
-
-typedef u_int32_t md5_uint32;
-
-/* Structure to save state of computation between the single steps.  */
-struct md5_ctx
-{
-  md5_uint32 A;
-  md5_uint32 B;
-  md5_uint32 C;
-  md5_uint32 D;
-
-  md5_uint32 total[2];
-  md5_uint32 buflen;
-  char buffer[128];
-};
-
-/*
- * The following three functions are build up the low level used in
- * the functions `md5_stream' and `md5_buffer'.
- */
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-static void md5_init_ctx __P ((struct md5_ctx *ctx));
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is necessary that LEN is a multiple of 64!!! */
-static void md5_process_block __P ((const void *buffer, size_t len,
-                                   struct md5_ctx *ctx));
-
-/* Starting with the result of former calls of this function (or the
-   initialization function update the context for the next LEN bytes
-   starting at BUFFER.
-   It is NOT required that LEN is a multiple of 64.  */
-static void md5_process_bytes __P ((const void *buffer, size_t len,
-                                   struct md5_ctx *ctx));
-
-/* Process the remaining bytes in the buffer and put result from CTX
-   in first 16 bytes following RESBUF.  The result is always in little
-   endian byte order, so that a byte-wise output yields to the wanted
-   ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-static void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
-
-
-
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-static int md5_stream __P ((FILE *stream, void *resblock));
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-static void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
-
-//----------------------------------------------------------------------------
-//--------end of md5.h
-//----------------------------------------------------------------------------
-
-/* Handle endian-ness */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-       #define SWAP(n) (n)
-#else
-       #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
-#endif
-
-
-
-#if MD5SUM_SIZE_VS_SPEED == 0
-/* This array contains the bytes used to pad the buffer to the next
-   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
-static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */  };
-#endif
-
-/* Initialize structure containing state of computation.
-   (RFC 1321, 3.3: Step 3)  */
-void md5_init_ctx(struct md5_ctx *ctx)
-{
-  ctx->A = 0x67452301;
-  ctx->B = 0xefcdab89;
-  ctx->C = 0x98badcfe;
-  ctx->D = 0x10325476;
-
-  ctx->total[0] = ctx->total[1] = 0;
-  ctx->buflen = 0;
-}
-
-/* Process the remaining bytes in the internal buffer and the usual
-   prolog according to the standard and write the result to RESBUF.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
-{
-  /* Take yet unprocessed bytes into account.  */
-  md5_uint32 bytes = ctx->buflen;
-  size_t pad;
-
-  /* Now count remaining bytes.  */
-  ctx->total[0] += bytes;
-  if (ctx->total[0] < bytes)
-    ++ctx->total[1];
-
-  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
-#if MD5SUM_SIZE_VS_SPEED > 0
-  memset(&ctx->buffer[bytes], 0, pad);
-  ctx->buffer[bytes] = 0x80;
-#else
-  memcpy(&ctx->buffer[bytes], fillbuf, pad);
-#endif
-
-  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
-  *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
-  *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
-    SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
-
-  /* Process last bytes.  */
-  md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
-
-/* Put result from CTX in first 16 bytes following RESBUF.  The result is
-   always in little endian byte order, so that a byte-wise output yields
-   to the wanted ASCII representation of the message digest.
-
-   IMPORTANT: On some systems it is required that RESBUF is correctly
-   aligned for a 32 bits value.  */
-  ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
-  ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
-  ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
-  ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
-
-  return resbuf;
-}
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-static int md5_stream(FILE *stream, void *resblock)
-{
-  /* Important: BLOCKSIZE must be a multiple of 64.  */
-static const int BLOCKSIZE = 4096;
-  struct md5_ctx ctx;
-  char buffer[BLOCKSIZE + 72];
-  size_t sum;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx(&ctx);
-
-  /* Iterate over full file contents.  */
-  while (1) {
-    /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-       computation function processes the whole buffer so that with the
-       next round of the loop another block can be read.  */
-    size_t n;
-    sum = 0;
-
-    /* Read block.  Take care for partial reads.  */
-    do {
-      n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-      sum += n;
-    }
-    while (sum < BLOCKSIZE && n != 0);
-    if (n == 0 && ferror(stream))
-      return 1;
-
-    /* If end of file is reached, end the loop.  */
-    if (n == 0)
-      break;
-
-    /* Process buffer with BLOCKSIZE bytes.  Note that
-       BLOCKSIZE % 64 == 0
-    */
-    md5_process_block(buffer, BLOCKSIZE, &ctx);
-  }
-
-  /* Add the last bytes if necessary.  */
-  if (sum > 0)
-    md5_process_bytes(buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  md5_finish_ctx(&ctx, resblock);
-  return 0;
-}
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
-   result is always in little endian byte order, so that a byte-wise
-   output yields to the wanted ASCII representation of the message
-   digest.  */
-static void *md5_buffer(const char *buffer, size_t len, void *resblock)
-{
-  struct md5_ctx ctx;
-
-  /* Initialize the computation context.  */
-  md5_init_ctx(&ctx);
-
-  /* Process whole buffer but last len % 64 bytes.  */
-  md5_process_bytes(buffer, len, &ctx);
-
-  /* Put result in desired memory area.  */
-  return md5_finish_ctx(&ctx, resblock);
-}
-
-static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
-{
-  /* When we already have some bits in our internal buffer concatenate
-     both inputs first.  */
-  if (ctx->buflen != 0) {
-    size_t left_over = ctx->buflen;
-    size_t add = 128 - left_over > len ? len : 128 - left_over;
-
-    memcpy(&ctx->buffer[left_over], buffer, add);
-    ctx->buflen += add;
-
-    if (left_over + add > 64) {
-      md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
-      /* The regions in the following copy operation cannot overlap.  */
-      memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
-            (left_over + add) & 63);
-      ctx->buflen = (left_over + add) & 63;
-    }
-
-    buffer = (const char *) buffer + add;
-    len -= add;
-  }
-
-  /* Process available complete blocks.  */
-  if (len > 64) {
-    md5_process_block(buffer, len & ~63, ctx);
-    buffer = (const char *) buffer + (len & ~63);
-    len &= 63;
-  }
-
-  /* Move remaining bytes in internal buffer.  */
-  if (len > 0) {
-    memcpy(ctx->buffer, buffer, len);
-    ctx->buflen = len;
-  }
-}
-
-/* These are the four functions used in the four steps of the MD5 algorithm
-   and defined in the RFC 1321.  The first function is a little bit optimized
-   (as found in Colin Plumbs public domain implementation).  */
-/* #define FF(b, c, d) ((b & c) | (~b & d)) */
-#define FF(b, c, d) (d ^ (b & (c ^ d)))
-#define FG(b, c, d) FF (d, b, c)
-#define FH(b, c, d) (b ^ c ^ d)
-#define FI(b, c, d) (c ^ (b | ~d))
-
-/* Process LEN bytes of BUFFER, accumulating context into CTX.
-   It is assumed that LEN % 64 == 0.  */
-static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
-{
-  md5_uint32 correct_words[16];
-  const md5_uint32 *words = buffer;
-  size_t nwords = len / sizeof(md5_uint32);
-  const md5_uint32 *endp = words + nwords;
-#if MD5SUM_SIZE_VS_SPEED > 0
-  static const md5_uint32 C_array[] = {
-      /* round 1 */
-      0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
-      0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
-      0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
-      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
-      /* round 2 */
-      0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
-      0xd62f105d, 0x2441453,  0xd8a1e681, 0xe7d3fbc8,
-      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
-      0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
-      /* round 3 */
-      0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
-      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
-      0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
-      0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
-      /* round 4 */
-      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
-      0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
-      0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
-      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
-  };
-
-  static const char P_array[] = {
-#if MD5SUM_SIZE_VS_SPEED > 1
-      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
-#endif
-      1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
-      5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
-      0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
-  };
-
-#if MD5SUM_SIZE_VS_SPEED > 1
-  static const char S_array[] = {
-      7, 12, 17, 22,
-      5, 9, 14, 20,
-      4, 11, 16, 23,
-      6, 10, 15, 21
-  };
-#endif
-#endif
-
-  md5_uint32 A = ctx->A;
-  md5_uint32 B = ctx->B;
-  md5_uint32 C = ctx->C;
-  md5_uint32 D = ctx->D;
-
-  /* First increment the byte count.  RFC 1321 specifies the possible
-     length of the file up to 2^64 bits.  Here we only compute the
-     number of bytes.  Do a double word increment.  */
-  ctx->total[0] += len;
-  if (ctx->total[0] < len)
-    ++ctx->total[1];
-
-  /* Process all bytes in the buffer with 64 bytes in each round of
-     the loop.  */
-  while (words < endp) {
-    md5_uint32 *cwp = correct_words;
-    md5_uint32 A_save = A;
-    md5_uint32 B_save = B;
-    md5_uint32 C_save = C;
-    md5_uint32 D_save = D;
-
-#if MD5SUM_SIZE_VS_SPEED > 1
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
-    const md5_uint32 *pc;
-    const char *pp;
-    const char *ps;
-    int i;
-    md5_uint32 temp;
-
-    for ( i=0 ; i < 16 ; i++ ) {
-       cwp[i] = SWAP(words[i]);
-    }
-    words += 16;
-
-#if MD5SUM_SIZE_VS_SPEED > 2
-    pc = C_array; pp = P_array; ps = S_array - 4;
-
-    for ( i = 0 ; i < 64 ; i++ ) {
-       if ((i&0x0f) == 0) ps += 4;
-       temp = A;
-       switch (i>>4) {
-           case 0:
-               temp += FF(B,C,D);
-               break;
-           case 1:
-               temp += FG(B,C,D);
-               break;
-           case 2:
-               temp += FH(B,C,D);
-               break;
-           case 3:
-               temp += FI(B,C,D);
-       }
-       temp += cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-#else
-    pc = C_array; pp = P_array; ps = S_array;
-
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-    ps += 4;
-    for ( i = 0 ; i < 16 ; i++ ) {
-       temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
-       temp = CYCLIC (temp, ps[i&3]);
-       temp += B;
-       A = D; D = C; C = B; B = temp;
-    }
-
-#endif
-#else
-    /* First round: using the given function, the context and a constant
-       the next context is computed.  Because the algorithms processing
-       unit is a 32-bit word and it is determined to work on words in
-       little endian byte order we perhaps have to change the byte order
-       before the computation.  To reduce the work for the next steps
-       we store the swapped words in the array CORRECT_WORDS.  */
-
-#define OP(a, b, c, d, s, T)                                           \
-      do                                                               \
-        {                                                              \
-         a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;             \
-         ++words;                                                      \
-         CYCLIC (a, s);                                                \
-         a += b;                                                       \
-        }                                                              \
-      while (0)
-
-    /* It is unfortunate that C does not provide an operator for
-       cyclic rotation.  Hope the C compiler is smart enough.  */
-    /* gcc 2.95.4 seems to be --aaronl */
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
-    /* Before we start, one word to the strange constants.
-       They are defined in RFC 1321 as
-
-       T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
-    */
-
-#if MD5SUM_SIZE_VS_SPEED == 1
-    const md5_uint32 *pc;
-    const char *pp;
-    int i;
-#endif
-
-    /* Round 1.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    pc = C_array;
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(A, B, C, D, 7, *pc++);
-       OP(D, A, B, C, 12, *pc++);
-       OP(C, D, A, B, 17, *pc++);
-       OP(B, C, D, A, 22, *pc++);
-    }
-#else
-    OP(A, B, C, D, 7, 0xd76aa478);
-    OP(D, A, B, C, 12, 0xe8c7b756);
-    OP(C, D, A, B, 17, 0x242070db);
-    OP(B, C, D, A, 22, 0xc1bdceee);
-    OP(A, B, C, D, 7, 0xf57c0faf);
-    OP(D, A, B, C, 12, 0x4787c62a);
-    OP(C, D, A, B, 17, 0xa8304613);
-    OP(B, C, D, A, 22, 0xfd469501);
-    OP(A, B, C, D, 7, 0x698098d8);
-    OP(D, A, B, C, 12, 0x8b44f7af);
-    OP(C, D, A, B, 17, 0xffff5bb1);
-    OP(B, C, D, A, 22, 0x895cd7be);
-    OP(A, B, C, D, 7, 0x6b901122);
-    OP(D, A, B, C, 12, 0xfd987193);
-    OP(C, D, A, B, 17, 0xa679438e);
-    OP(B, C, D, A, 22, 0x49b40821);
-#endif
-
-    /* For the second to fourth round we have the possibly swapped words
-       in CORRECT_WORDS.  Redefine the macro to take an additional first
-       argument specifying the function to use.  */
-#undef OP
-#define OP(f, a, b, c, d, k, s, T)                                     \
-      do                                                               \
-       {                                                               \
-         a += f (b, c, d) + correct_words[k] + T;                      \
-         CYCLIC (a, s);                                                \
-         a += b;                                                       \
-       }                                                               \
-      while (0)
-
-    /* Round 2.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    pp = P_array;
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
-       OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
-       OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
-       OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
-    }
-#else
-    OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
-    OP(FG, D, A, B, C, 6, 9, 0xc040b340);
-    OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
-    OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
-    OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
-    OP(FG, D, A, B, C, 10, 9, 0x02441453);
-    OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
-    OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
-    OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
-    OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
-    OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
-    OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
-    OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
-    OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
-    OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
-    OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
-#endif
-
-    /* Round 3.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
-       OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
-       OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
-       OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
-    }
-#else
-    OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
-    OP(FH, D, A, B, C, 8, 11, 0x8771f681);
-    OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
-    OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
-    OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
-    OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
-    OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
-    OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
-    OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
-    OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
-    OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
-    OP(FH, B, C, D, A, 6, 23, 0x04881d05);
-    OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
-    OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
-    OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
-    OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
-#endif
-
-    /* Round 4.  */
-#if MD5SUM_SIZE_VS_SPEED == 1
-    for ( i=0 ; i < 4 ; i++ ) {
-       OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
-       OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
-       OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
-       OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
-    }
-#else
-    OP(FI, A, B, C, D, 0, 6, 0xf4292244);
-    OP(FI, D, A, B, C, 7, 10, 0x432aff97);
-    OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
-    OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
-    OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
-    OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
-    OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
-    OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
-    OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
-    OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
-    OP(FI, C, D, A, B, 6, 15, 0xa3014314);
-    OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
-    OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
-    OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
-    OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
-    OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
-#endif
-#endif
-
-    /* Add the starting values of the context.  */
-    A += A_save;
-    B += B_save;
-    C += C_save;
-    D += D_save;
-  }
-
-  /* Put checksum in context given as argument.  */
-  ctx->A = A;
-  ctx->B = B;
-  ctx->C = C;
-  ctx->D = D;
-}
-
-//----------------------------------------------------------------------------
-//--------end of md5.c
-//----------------------------------------------------------------------------
-
-#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
-#define ISXDIGIT(c) (isxdigit (c))
-
-/* The minimum length of a valid digest line in a file produced
-   by `md5sum FILE' and read by `md5sum -c'.  This length does
-   not include any newline character at the end of a line.  */
-static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
-                                      2 - blank and binary indicator
-                                      1 - minimum filename length */
-
-static int have_read_stdin; /* Nonzero if any of the files read were
-                               the standard input. */
-
-static int status_only = 0; /* With -c, don't generate any output.
-                               The exit code indicates success or failure */
-static int warn = 0; /* With -w, print a message to standard error warning
-                        about each improperly formatted MD5 checksum line */
-
-static int split_3(char *s,
-                   size_t s_len,
-                   unsigned char **u,
-                   char **w)
-{
-  size_t i = 0;
-  int escaped_filename = 0;
-
-  while (ISWHITE(s[i]))
-    ++i;
-
-  /* The line must have at least 35 (36 if the first is a backslash)
-     more characters to contain correct message digest information.
-     Ignore this line if it is too short.  */
-  if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
-        || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
-    return FALSE;
-
-  if (s[i] == '\\') {
-    ++i;
-    escaped_filename = 1;
-  }
-  *u = (unsigned char *) &s[i];
-
-  /* The first field has to be the 32-character hexadecimal
-     representation of the message digest.  If it is not followed
-     immediately by a white space it's an error.  */
-  i += 32;
-  if (!ISWHITE(s[i]))
-    return FALSE;
-
-  s[i++] = '\0';
-
-  if (s[i] != ' ' && s[i++] != '*')
-    return FALSE;
-
-  /* All characters between the type indicator and end of line are
-     significant -- that includes leading and trailing white space.  */
-  *w = &s[i];
-
-  if (escaped_filename) {
-    /* Translate each `\n' string in the file name to a NEWLINE,
-       and each `\\' string to a backslash.  */
-
-    char *dst = &s[i];
-
-    while (i < s_len) {
-      switch (s[i]) {
-       case '\\':
-        if (i == s_len - 1) {
-          /* A valid line does not end with a backslash.  */
-          return FALSE;
-        }
-        ++i;
-        switch (s[i++]) {
-         case 'n':
-          *dst++ = '\n';
-          break;
-         case '\\':
-          *dst++ = '\\';
-          break;
-         default:
-          /* Only `\' or `n' may follow a backslash.  */
-          return FALSE;
-        }
-        break;
-
-       case '\0':
-        /* The file name may not contain a NUL.  */
-        return FALSE;
-        break;
-
-       default:
-        *dst++ = s[i++];
-        break;
-      }
-    }
-    *dst = '\0';
-  }
-  return TRUE;
-}
-
-static inline int hex_digits(unsigned char const *s)
-{
-  while (*s) {
-    if (!ISXDIGIT(*s))
-      return TRUE;
-    ++s;
-  }
-  return FALSE;
-}
-
-/* An interface to md5_stream.  Operate on FILENAME (it may be "-") and
-   put the result in *MD5_RESULT.  Return non-zero upon failure, zero
-   to indicate success.  */
-static int md5_file(const char *filename,
-                    unsigned char *md5_result)
-{
-  FILE *fp;
-
-  if (filename[0] == '-' && filename[1] == '\0') {
-    have_read_stdin = 1;
-    fp = stdin;
-  } else {
-    fp = wfopen(filename, "r");
-    if (fp == NULL)
-      return FALSE;
-    }
-
-  if (md5_stream(fp, md5_result)) {
-    perror_msg("%s", filename);
-
-    if (fp != stdin)
-      fclose(fp);
-    return FALSE;
-  }
-
-  if (fp != stdin && fclose(fp) == EOF) {
-    perror_msg("%s", filename);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static int md5_check(const char *checkfile_name)
-{
-  FILE *checkfile_stream;
-  int n_properly_formated_lines = 0;
-  int n_mismatched_checksums = 0;
-  int n_open_or_read_failures = 0;
-  unsigned char md5buffer[16];
-  size_t line_number;
-  char line[BUFSIZ];
-
-  if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
-    have_read_stdin = 1;
-    checkfile_stream = stdin;
-  } else {
-    checkfile_stream = wfopen(checkfile_name, "r");
-    if (checkfile_stream == NULL)
-      return FALSE;
-    }
-
-  line_number = 0;
-
-  do {
-    char *filename;
-    unsigned char *md5num;
-    int line_length;
-
-    ++line_number;
-
-    fgets(line, BUFSIZ-1, checkfile_stream);
-    line_length = strlen(line);
-
-    if (line_length <= 0 || line==NULL)
-      break;
-
-    /* Ignore comment lines, which begin with a '#' character.  */
-    if (line[0] == '#')
-      continue;
-
-    /* Remove any trailing newline.  */
-    if (line[line_length - 1] == '\n')
-      line[--line_length] = '\0';
-
-    if (split_3(line, line_length, &md5num, &filename)
-        || !hex_digits(md5num)) {
-      if (warn) {
-        error_msg("%s: %lu: improperly formatted MD5 checksum line",
-                 checkfile_name, (unsigned long) line_number);
-      }
-    } else {
-      static const char bin2hex[] = {
-        '0', '1', '2', '3',
-        '4', '5', '6', '7',
-        '8', '9', 'a', 'b',
-        'c', 'd', 'e', 'f'
-      };
-
-      ++n_properly_formated_lines;
-
-      if (md5_file(filename, md5buffer)) {
-        ++n_open_or_read_failures;
-        if (!status_only) {
-          printf("%s: FAILED open or read\n", filename);
-          fflush(stdout);
-        }
-      } else {
-        size_t cnt;
-        /* Compare generated binary number with text representation
-           in check file.  Ignore case of hex digits.  */
-        for (cnt = 0; cnt < 16; ++cnt) {
-          if (tolower(md5num[2 * cnt])
-              != bin2hex[md5buffer[cnt] >> 4]
-              || (tolower(md5num[2 * cnt + 1])
-                  != (bin2hex[md5buffer[cnt] & 0xf])))
-            break;
-        }
-        if (cnt != 16)
-          ++n_mismatched_checksums;
-
-        if (!status_only) {
-          printf("%s: %s\n", filename,
-                 (cnt != 16 ? "FAILED" : "OK"));
-          fflush(stdout);
-        }
-      }
-    }
-  }
-
-  while (!feof(checkfile_stream) && !ferror(checkfile_stream));
-
-  if (ferror(checkfile_stream)) {
-    error_msg("%s: read error", checkfile_name);
-    return FALSE;
-  }
-
-  if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
-    perror_msg("md5sum: %s", checkfile_name);
-    return FALSE;
-  }
-
-  if (n_properly_formated_lines == 0) {
-    /* Warn if no tests are found.  */
-    error_msg("%s: no properly formatted MD5 checksum lines found",
-             checkfile_name);
-    return FALSE;
-  } else {
-    if (!status_only) {
-      int n_computed_checkums = (n_properly_formated_lines
-                                 - n_open_or_read_failures);
-
-      if (n_open_or_read_failures > 0) {
-        error_msg("WARNING: %d of %d listed files could not be read",
-                 n_open_or_read_failures, n_properly_formated_lines);
-        return FALSE;
-      }
-
-      if (n_mismatched_checksums > 0) {
-        error_msg("WARNING: %d of %d computed checksums did NOT match",
-                 n_mismatched_checksums, n_computed_checkums);
-        return FALSE;
-      }
-    }
-  }
-
-  return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
-           && n_open_or_read_failures == 0) ? 0 : 1);
-}
-
-int md5sum_main(int argc,
-                char **argv)
-{
-  unsigned char md5buffer[16];
-  int do_check = 0;
-  int opt;
-  char **string = NULL;
-  size_t n_strings = 0;
-  size_t err = 0;
-  char file_type_specified = 0;
-  char binary = 0;
-
-  while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
-    switch (opt) {
-     case 'g': { /* read a string */
-       if (string == NULL)
-         string = (char **) xmalloc ((argc - 1) * sizeof (char *));
-
-       string[n_strings++] = optarg;
-       break;
-     }
-
-     case 'b': /* read files in binary mode */
-      file_type_specified = 1;
-      binary = 1;
-      break;
-
-     case 'c': /* check MD5 sums against given list */
-      do_check = 1;
-      break;
-
-     case 's':  /* don't output anything, status code shows success */
-      status_only = 1;
-      warn = 0;
-      break;
-
-     case 't': /* read files in text mode (default) */
-      file_type_specified = 1;
-      binary = 0;
-      break;
-
-     case 'w': /* warn about improperly formated MD5 checksum lines */
-      status_only = 0;
-      warn = 1;
-      break;
-
-     default:
-      show_usage();
-    }
-  }
-
-  if (file_type_specified && do_check) {
-    error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
-  }
-
-  if (n_strings > 0 && do_check) {
-    error_msg_and_die("the -g and -c options are mutually exclusive");
-  }
-
-  if (status_only && !do_check) {
-    error_msg_and_die("the -s option is meaningful only when verifying checksums");
-  }
-
-  if (warn && !do_check) {
-    error_msg_and_die("the -w option is meaningful only when verifying checksums");
-  }
-
-  if (n_strings > 0) {
-    size_t i;
-
-    if (optind < argc) {
-      error_msg_and_die("no files may be specified when using -g");
-    }
-    for (i = 0; i < n_strings; ++i) {
-      size_t cnt;
-      md5_buffer (string[i], strlen (string[i]), md5buffer);
-
-      for (cnt = 0; cnt < 16; ++cnt)
-        printf ("%02x", md5buffer[cnt]);
-
-      printf ("  \"%s\"\n", string[i]);
-    }
-  } else if (do_check) {
-    if (optind + 1 < argc) {
-      error_msg("only one argument may be specified when using -c");
-    }
-
-    err = md5_check ((optind == argc) ? "-" : argv[optind]);
-  } else {
-    if (optind == argc)
-      argv[argc++] = "-";
-
-    for (; optind < argc; ++optind) {
-      int fail;
-      char *file = argv[optind];
-
-      fail = md5_file (file, md5buffer);
-      err |= fail;
-      if (!fail && file[0]=='-' && file[1] == '\0') {
-         size_t i;
-         for (i = 0; i < 16; ++i)
-             printf ("%02x", md5buffer[i]);
-         putchar ('\n');
-      } else if (!fail) {
-        size_t i;
-        /* Output a leading backslash if the file name contains
-           a newline or backslash.  */
-        if (strchr (file, '\n') || strchr (file, '\\'))
-          putchar ('\\');
-
-        for (i = 0; i < 16; ++i)
-          printf ("%02x", md5buffer[i]);
-
-        putchar (' ');
-        if (binary)
-          putchar ('*');
-        else
-          putchar (' ');
-
-        /* Translate each NEWLINE byte to the string, "\\n",
-           and each backslash to "\\\\".  */
-        for (i = 0; i < strlen (file); ++i) {
-          switch (file[i]) {
-           case '\n':
-            fputs ("\\n", stdout);
-            break;
-
-           case '\\':
-            fputs ("\\\\", stdout);
-            break;
-
-           default:
-            putchar (file[i]);
-            break;
-          }
-        }
-        putchar ('\n');
-      }
-    }
-  }
-
-  if (fclose (stdout) == EOF) {
-    error_msg_and_die("write error");
-  }
-
-  if (have_read_stdin && fclose (stdin) == EOF) {
-    error_msg_and_die("standard input");
-  }
-
-  if (err == 0)
-         return EXIT_SUCCESS;
-  else
-         return EXIT_FAILURE;
-}
diff --git a/busybox/miscutils/adjtimex.c b/busybox/miscutils/adjtimex.c
deleted file mode 100644 (file)
index e3c160d..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables.
- *
- * Originally written: October 1997
- * Last hack: March 2001
- * Copyright 1997, 2000, 2001 Larry Doolittle <LRDoolittle@lbl.gov>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License (Version 2,
- *  June 1991) as published by the Free Software Foundation.  At the
- *  time of writing, that license was published by the FSF with the URL
- *  http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
- *  reference.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- * This adjtimex(1) is very similar in intent to adjtimex(8) by Steven
- * Dick <ssd@nevets.oau.org> and Jim Van Zandt <jrv@vanzandt.mv.com>
- * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*).
- * That version predates this one, and is _much_ bigger and more
- * featureful.  My independently written version was very similar to
- * Steven's from the start, because they both follow the kernel timex
- * structure.  I further tweaked this version to be equivalent to Steven's
- * where possible, but I don't like getopt_long, so the actual usage
- * syntax is incompatible.
- *
- * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes)
- * don't actually give a prototype for adjtimex(2), so building
- * this code (with -Wall) gives a warning.  Later versions of
- * glibc fix this issue.
- *
- * This program is too simple for a Makefile, just build with:
- *  gcc -Wall -O adjtimex.c -o adjtimex
- *
- * busyboxed 20 March 2001, Larry Doolittle <ldoolitt@recycle.lbl.gov>
- * It will autosense if it is built in a busybox environment, based
- * on the BB_VER preprocessor macro.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#if __GNU_LIBRARY__ < 5
-#include <sys/timex.h>
-extern int adjtimex(struct timex *buf);
-#else
-#include <sys/timex.h>
-#endif
-
-#ifdef BB_VER
-#include "busybox.h"
-#endif
-
-static struct {int bit; char *name;} statlist[] = {
-       { STA_PLL,       "PLL"       },
-       { STA_PPSFREQ,   "PPSFREQ"   },
-       { STA_PPSTIME,   "PPSTIME"   },
-       { STA_FLL,       "FFL"       },
-       { STA_INS,       "INS"       },
-       { STA_DEL,       "DEL"       },
-       { STA_UNSYNC,    "UNSYNC"    },
-       { STA_FREQHOLD,  "FREQHOLD"  },
-       { STA_PPSSIGNAL, "PPSSIGNAL" },
-       { STA_PPSJITTER, "PPSJITTER" },
-       { STA_PPSWANDER, "PPSWANDER" },
-       { STA_PPSERROR,  "PPSERROR"  },
-       { STA_CLOCKERR,  "CLOCKERR"  },
-       { 0, NULL } };
-
-static char *ret_code_descript[] = {
-       "clock synchronized",
-       "insert leap second",
-       "delete leap second",
-       "leap second in progress",
-       "leap second has occurred",
-       "clock not synchronized" };
-
-#ifdef BB_VER
-#define main adjtimex_main
-#else
-void usage(char *prog)
-{
-       fprintf(stderr, 
-               "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n",
-               prog);
-}
-#define show_usage() usage(argv[0])
-#endif
-
-int main(int argc, char ** argv)
-{
-       struct timex txc;
-       int quiet=0;
-       int c, i, ret, sep;
-       char *descript;
-       txc.modes=0;
-       for (;;) {
-               c = getopt( argc, argv, "qo:f:p:t:");
-               if (c == EOF) break;
-               switch (c) {
-                       case 'q':
-                               quiet=1;
-                               break;
-                       case 'o':
-                               txc.offset = atoi(optarg);
-                               txc.modes |= ADJ_OFFSET_SINGLESHOT;
-                               break;
-                       case 'f':
-                               txc.freq = atoi(optarg);
-                               txc.modes |= ADJ_FREQUENCY;
-                               break;
-                       case 'p':
-                               txc.constant = atoi(optarg);
-                               txc.modes |= ADJ_TIMECONST;
-                               break;
-                       case 't':
-                               txc.tick = atoi(optarg);
-                               txc.modes |= ADJ_TICK;
-                               break;
-                       default:
-                               show_usage();
-                               exit(1);
-               }
-       }
-       if (argc != optind) { /* no valid non-option parameters */
-               show_usage();
-               exit(1);
-       }
-
-       ret = adjtimex(&txc);
-
-       if (ret < 0) perror("adjtimex");
-       
-       if (!quiet && ret>=0) {
-               printf(
-                       "    mode:         %d\n"
-                       "-o  offset:       %ld\n"
-                       "-f  frequency:    %ld\n"
-                       "    maxerror:     %ld\n"
-                       "    esterror:     %ld\n"
-                       "    status:       %d ( ",
-               txc.modes, txc.offset, txc.freq, txc.maxerror,
-               txc.esterror, txc.status);
-
-               /* representative output of next code fragment:
-                  "PLL | PPSTIME" */
-               sep=0;
-               for (i=0; statlist[i].name; i++) {
-                       if (txc.status & statlist[i].bit) {
-                               if (sep) fputs(" | ",stdout);
-                               fputs(statlist[i].name,stdout);
-                               sep=1;
-                       }
-               }
-
-               descript = "error";
-               if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret];
-               printf(" )\n"
-                       "-p  timeconstant: %ld\n"
-                       "    precision:    %ld\n"
-                       "    tolerance:    %ld\n"
-                       "-t  tick:         %ld\n"
-                       "    time.tv_sec:  %ld\n"
-                       "    time.tv_usec: %ld\n"
-                       "    return value: %d (%s)\n",
-               txc.constant,
-               txc.precision, txc.tolerance, txc.tick,
-               (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript);
-       }
-       return (ret<0);
-}
diff --git a/busybox/miscutils/dc.c b/busybox/miscutils/dc.c
deleted file mode 100644 (file)
index 8d7a92a..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <math.h>
-#include "busybox.h"
-
-/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
-
-static double stack[100];
-static unsigned int pointer;
-
-static void push(double a)
-{
-       if (pointer >= (sizeof(stack) / sizeof(*stack)))
-               error_msg_and_die("stack overflow");
-       stack[pointer++] = a;
-}
-
-static double pop()
-{
-       if (pointer == 0)
-               error_msg_and_die("stack underflow");
-       return stack[--pointer];
-}
-
-static void add()
-{
-       push(pop() + pop());
-}
-
-static void sub()
-{
-       double subtrahend = pop();
-
-       push(pop() - subtrahend);
-}
-
-static void mul()
-{
-       push(pop() * pop());
-}
-
-static void divide()
-{
-       double divisor = pop();
-
-       push(pop() / divisor);
-}
-
-static void and()
-{
-       push((unsigned int) pop() & (unsigned int) pop());
-}
-
-static void or()
-{
-       push((unsigned int) pop() | (unsigned int) pop());
-}
-
-static void eor()
-{
-       push((unsigned int) pop() ^ (unsigned int) pop());
-}
-
-static void not()
-{
-       push(~(unsigned int) pop());
-}
-
-static void print()
-{
-       printf("%g\n", pop());
-}
-
-struct op {
-       const char *name;
-       void (*function) ();
-};
-
-static const struct op operators[] = {
-       {"+",   add},
-       {"add", add},
-       {"-",   sub},
-       {"sub", sub},
-       {"*",   mul},
-       {"mul", mul},
-       {"/",   divide},
-       {"div", divide},
-       {"and", and},
-       {"or",  or},
-       {"not", not},
-       {"eor", eor},
-       {0,     0}
-};
-
-static void stack_machine(const char *argument)
-{
-       char *endPointer = 0;
-       double d;
-       const struct op *o = operators;
-
-       if (argument == 0) {
-               print();
-               return;
-       }
-
-       d = strtod(argument, &endPointer);
-
-       if (endPointer != argument) {
-               push(d);
-               return;
-       }
-
-       while (o->name != 0) {
-               if (strcmp(o->name, argument) == 0) {
-                       (*(o->function)) ();
-                       return;
-               }
-               o++;
-       }
-       error_msg_and_die("%s: syntax error.", argument);
-}
-
-/* return pointer to next token in buffer and set *buffer to one char
- * past the end of the above mentioned token 
- */
-static char *get_token(char **buffer)
-{
-       char *start   = NULL;
-       char *current = *buffer;
-
-       while (isspace(*current)) { current++; }
-       if (*current != 0) {
-               start = current;
-               while (!isspace(*current) && current != 0) { current++; }
-               *buffer = current;
-       }
-       return start;
-}
-
-/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
-static int number_of_tokens(char *buffer)
-{
-       int   i = 0;
-       char *b = buffer;
-       while (get_token(&b)) { i++; }
-       return i;
-}
-
-int dc_main(int argc, char **argv)
-{
-       /* take stuff from stdin if no args are given */
-       if (argc <= 1) {
-               int i, len;
-               char *line   = NULL;
-               char *cursor = NULL;
-               char *token  = NULL;
-               while ((line = get_line_from_file(stdin))) {
-                       cursor = line;
-                       len = number_of_tokens(line);
-                       for (i = 0; i < len; i++) {
-                               token = get_token(&cursor);
-                               *cursor++ = 0;
-                               stack_machine(token);
-                       }
-                       free(line);
-               }
-       } else {
-               if (*argv[1]=='-')
-                       show_usage();
-               while (argc >= 2) {
-                       stack_machine(argv[1]);
-                       argv++;
-                       argc--;
-               }
-       }
-       stack_machine(0);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/miscutils/dutmp.c b/busybox/miscutils/dutmp.c
deleted file mode 100644 (file)
index df7f64d..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- * 
- * dutmp
- * Takes utmp formated file on stdin and dumps it's contents 
- * out in colon delimited fields. Easy to 'cut' for shell based 
- * versions of 'who', 'last', etc. IP Addr is output in hex, 
- * little endian on x86.
- * 
- * Modified to support all sorts of libcs by 
- * Erik Andersen <andersen@lineo.com>
- */
-
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <errno.h>
-#include <utmp.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int dutmp_main(int argc, char **argv)
-{
-
-       int file;
-       struct utmp ut;
-
-       if (argc<2) {
-               file = fileno(stdin);
-       } else if (*argv[1] == '-' ) {
-               show_usage();
-       } else  {
-               file = open(argv[1], O_RDONLY);
-               if (file < 0) {
-                       perror_msg_and_die(io_error, argv[1]);
-               }
-       }
-
-/* Kludge around the fact that the binary format for utmp has changed. */
-#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__
-       /* Linux libc5 */
-       while (read(file, (void*)&ut, sizeof(struct utmp))) {
-               printf("%d|%d|%s|%s|%s|%s|%s|%lx\n",
-                               ut.ut_type, ut.ut_pid, ut.ut_line,
-                               ut.ut_id, ut.ut_user, ut.ut_host,
-                               ctime(&(ut.ut_time)), 
-                               (long)ut.ut_addr);
-       }
-#else
-       /* Glibc, uClibc, etc. */
-       while (read(file, (void*)&ut, sizeof(struct utmp))) {
-               printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
-               ut.ut_type, ut.ut_pid, ut.ut_line,
-               ut.ut_id, ut.ut_user,   ut.ut_host,
-               ut.ut_exit.e_termination, ut.ut_exit.e_exit,
-               ut.ut_session,
-               ut.ut_tv.tv_sec, ut.ut_tv.tv_usec,
-               ut.ut_addr);
-       }
-#endif
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/miscutils/makedevs.c b/busybox/miscutils/makedevs.c
deleted file mode 100644 (file)
index b8c6dd1..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- * 
- * makedevs
- * Make ranges of device files quickly. 
- * known bugs: can't deal with alpha ranges
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-int makedevs_main(int argc, char **argv)
-{
-
-       const char *basedev = argv[1];
-       const char *type = argv[2];
-       int major = atoi(argv[3]);
-       int Sminor = atoi(argv[4]);
-       int S = atoi(argv[5]);
-       int E = atoi(argv[6]);
-       int sbase = argc == 8 ? 1 : 0;
-
-       mode_t mode = 0;
-       dev_t dev = 0;
-       char devname[255];
-       char buf[255];
-
-       if (argc < 7 || *argv[1]=='-')
-               show_usage();
-
-       switch (type[0]) {
-       case 'c':
-               mode = S_IFCHR;
-               break;
-       case 'b':
-               mode = S_IFBLK;
-               break;
-       case 'f':
-               mode = S_IFIFO;
-               break;
-       default:
-               show_usage();
-       }
-       mode |= 0660;
-
-       while (S <= E) {
-
-               if (type[0] != 'f')
-                       dev = (major << 8) | Sminor;
-               strcpy(devname, basedev);
-
-               if (sbase == 0) {
-                       sprintf(buf, "%d", S);
-                       strcat(devname, buf);
-               } else {
-                       sbase = 0;
-               }
-
-               if (mknod(devname, mode, dev))
-                       printf("Failed to create: %s\n", devname);
-
-               S++;
-               Sminor++;
-       }
-
-       return 0;
-}
-
-/*
-And this is what this program replaces. The shell is too slow!
-
-makedev () {
-local basedev=$1; local S=$2; local E=$3
-local major=$4; local Sminor=$5; local type=$6
-local sbase=$7
-
-       if [ ! "$sbase" = "" ]; then
-               mknod "$basedev" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       fi
-
-       while [ $S -le $E ]; do
-               mknod "$basedev$S" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       done
-}
-*/
diff --git a/busybox/miscutils/mktemp.c b/busybox/miscutils/mktemp.c
deleted file mode 100644 (file)
index bc47d0a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mktemp implementation for busybox
- *
- *
- * Copyright (C) 2000 by Daniel Jacobowitz
- * Written by Daniel Jacobowitz <dan@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int mktemp_main(int argc, char **argv)
-{
-       if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q")))
-               show_usage();
-       if(mkstemp(argv[argc-1]) < 0)
-               return EXIT_FAILURE;
-       (void) puts(argv[argc-1]);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/miscutils/mt.c b/busybox/miscutils/mt.c
deleted file mode 100644 (file)
index 49dc70a..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mtio.h>
-#include <sys/fcntl.h>
-#include "busybox.h"
-
-struct mt_opcodes {
-       char *name;
-       short value;
-};
-
-/* missing: eod/seod, stoptions, stwrthreshold, densities */
-static const struct mt_opcodes opcodes[] = {
-       {"bsf", MTBSF},
-       {"bsfm", MTBSFM},
-       {"bsr", MTBSR},
-       {"bss", MTBSS},
-       {"datacompression", MTCOMPRESSION},
-       {"eom", MTEOM},
-       {"erase", MTERASE},
-       {"fsf", MTFSF},
-       {"fsfm", MTFSFM},
-       {"fsr", MTFSR},
-       {"fss", MTFSS},
-       {"load", MTLOAD},
-       {"lock", MTLOCK},
-       {"mkpart", MTMKPART},
-       {"nop", MTNOP},
-       {"offline", MTOFFL},
-       {"rewoffline", MTOFFL},
-       {"ras1", MTRAS1},
-       {"ras2", MTRAS2},
-       {"ras3", MTRAS3},
-       {"reset", MTRESET},
-       {"retension", MTRETEN},
-       {"rewind", MTREW},
-       {"seek", MTSEEK},
-       {"setblk", MTSETBLK},
-       {"setdensity", MTSETDENSITY},
-       {"drvbuffer", MTSETDRVBUFFER},
-       {"setpart", MTSETPART},
-       {"tell", MTTELL},
-       {"wset", MTWSM},
-       {"unload", MTUNLOAD},
-       {"unlock", MTUNLOCK},
-       {"eof", MTWEOF},
-       {"weof", MTWEOF},
-       {0, 0}
-};
-
-extern int mt_main(int argc, char **argv)
-{
-       const char *file = "/dev/tape";
-       const struct mt_opcodes *code = opcodes;
-       struct mtop op;
-       struct mtpos position;
-       int fd, mode;
-       
-       if (argc < 2) {
-               show_usage();
-       }
-
-       if (strcmp(argv[1], "-f") == 0) {
-               if (argc < 4) {
-                       show_usage();
-               }
-               file = argv[2];
-               argv += 2;
-               argc -= 2;
-       }
-
-       while (code->name != 0) {
-               if (strcmp(code->name, argv[1]) == 0)
-                       break;
-               code++;
-       }
-
-       if (code->name == 0) {
-               error_msg("unrecognized opcode %s.", argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       op.mt_op = code->value;
-       if (argc >= 3)
-               op.mt_count = atoi(argv[2]);
-       else
-               op.mt_count = 1;                /* One, not zero, right? */
-
-       switch (code->value) {
-               case MTWEOF:
-               case MTERASE:
-               case MTWSM:
-               case MTSETDRVBUFFER:
-                       mode = O_WRONLY;
-                       break;
-
-               default:
-                       mode = O_RDONLY;
-                       break;
-       }
-
-       if ((fd = open(file, mode, 0)) < 0)
-               perror_msg_and_die("%s", file);
-
-       switch (code->value) {
-               case MTTELL:
-                       if (ioctl(fd, MTIOCPOS, &position) < 0)
-                               perror_msg_and_die("%s", file);
-                       printf ("At block %d.\n", (int) position.mt_blkno);
-                       break;
-
-               default:
-                       if (ioctl(fd, MTIOCTOP, &op) != 0)
-                               perror_msg_and_die("%s", file);
-                       break;
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/miscutils/readlink.c b/busybox/miscutils/readlink.c
deleted file mode 100644 (file)
index c46ebd1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini readlink implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-int readlink_main(int argc, char **argv)
-{
-       char *buf = NULL;
-
-       /* no options, no getopt */
-
-       if (argc != 2)
-               show_usage();
-
-       buf = xreadlink(argv[1]);
-       if (!buf)
-               return EXIT_FAILURE;
-       puts(buf);
-#ifdef BB_FEATURE_CLEAN_UP
-       free(buf);
-#endif
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/miscutils/update.c b/busybox/miscutils/update.c
deleted file mode 100644 (file)
index 27a04dd..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini update implementation for busybox; much pasted from update-2.11
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
- * Copyright (c) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/*
- * Note: This program is only necessary if you are running a 2.0.x (or
- * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically.
- */
-
-#include <sys/param.h>
-#include <sys/syslog.h>
-#include <unistd.h> /* for getopt() */
-#include <stdlib.h>
-
-#if __GNU_LIBRARY__ > 5
-       #include <sys/kdaemon.h>
-#else
-       extern int bdflush (int func, long int data);
-#endif
-
-#include "busybox.h"
-
-static unsigned int sync_duration = 30;
-static unsigned int flush_duration = 5;
-static int use_sync = 0;
-
-extern int update_main(int argc, char **argv)
-{
-       int pid;
-       int opt;
-
-       while ((opt = getopt(argc, argv, "Ss:f:")) > 0) {
-               switch (opt) {
-                       case 'S':
-                               use_sync = 1;
-                               break;
-                       case 's':
-                               sync_duration = atoi(optarg);
-                               break;
-                       case 'f':
-                               flush_duration = atoi(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       
-       if (daemon(0, 1) < 0)
-               perror_msg_and_die("daemon");
-
-#ifdef OPEN_MAX
-       for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
-#else
-       /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */
-       for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid);
-#endif
-
-       /* This is no longer necessary since 1.3.5x, but it will harmlessly
-        * exit if that is the case.
-        */
-
-       /* set the program name that will show up in a 'ps' listing */
-       argv[0] = "bdflush (update)";
-       argv[1] = NULL;
-       argv[2] = NULL;
-       for (;;) {
-               if (use_sync) {
-                       sleep(sync_duration);
-                       sync();
-               } else {
-                       sleep(flush_duration);
-                       if (bdflush(1, 0) < 0) {
-                               openlog("update", LOG_CONS, LOG_DAEMON);
-                               syslog(LOG_INFO,
-                                               "This kernel does not need update(8). Exiting.");
-                               closelog();
-                               return EXIT_SUCCESS;
-                       }
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/miscutils/watchdog.c b/busybox/miscutils/watchdog.c
deleted file mode 100644 (file)
index f0b0ebd..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini watchdog implementation for busybox
- *
- * Copyright (C) 2000  spoon <spoon@ix.netcom.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int watchdog_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc != 2) {
-               show_usage();
-       }
-
-       if ((fd=open(argv[1], O_WRONLY)) == -1) {
-               perror_msg_and_die(argv[1]);
-       }
-
-       while (1) {
-               sleep(30);
-               write(fd, "\0", 1);
-       }
-
-       return EXIT_FAILURE;
-}
diff --git a/busybox/mk_loop_h.sh b/busybox/mk_loop_h.sh
deleted file mode 100755 (executable)
index 71c9873..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-#
-# Figure out (i) the type of dev_t (ii) the defines for loop stuff
-#
-# Output of this script is normally redirected to "loop.h".
-
-# Since 1.3.79 there is an include file <asm/posix_types.h>
-# that defines __kernel_dev_t.
-# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
-# If it exists, we use it, or, rather, <linux/posix_types.h> which
-# avoids namespace pollution.  Otherwise we guess that __kernel_dev_t
-# is an unsigned short (which is true on i386, but false on alpha).
-
-# BUG: This test is actually broken if your gcc is not configured to
-# search /usr/include, as may well happen with cross-compilers.
-# It would be better to ask $(CC) if these files can be found.
-
-if [ -f /usr/include/linux/posix_types.h ]; then
-   echo '#include <linux/posix_types.h>'
-   echo '#undef dev_t'
-   echo '#define dev_t __kernel_dev_t'
-else
-   echo '#undef dev_t'
-   echo '#define dev_t unsigned short'
-fi
-
-# Next we have to find the loop stuff itself.
-# First try kernel source, then a private version.
-
-if [ -f /usr/include/linux/loop.h ]; then
-   echo '#include <linux/loop.h>'
-else
-   echo '#include "real_loop.h"'
-fi
-
-echo '#undef dev_t'
-
diff --git a/busybox/mkdir.c b/busybox/mkdir.c
deleted file mode 100644 (file)
index 03c49f0..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mkdir implementation for busybox
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "busybox.h"
-
-extern int mkdir_main (int argc, char **argv)
-{
-       mode_t mode = -1;
-       int flags = 0;
-       int status = 0;
-       int i, opt;
-
-       while ((opt = getopt (argc, argv, "m:p")) != -1) {
-               switch (opt) {
-               case 'm':
-                       mode = 0777;
-                       if (!parse_mode (optarg, &mode))
-                               error_msg_and_die ("invalid mode `%s'", optarg);
-                       break;
-               case 'p':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               default:
-                       show_usage ();
-               }
-       }
-
-       if (optind == argc)
-               show_usage ();
-
-       for (i = optind; i < argc; i++)
-               if (make_directory (argv[i], mode, flags) < 0)
-                       status = 1;
-
-       return status;
-}
diff --git a/busybox/mkfifo.c b/busybox/mkfifo.c
deleted file mode 100644 (file)
index ca217fa..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mkfifo implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int mkfifo_main(int argc, char **argv)
-{
-       char *thisarg;
-       mode_t mode = 0666;
-
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (argc > 1) {
-               if (**argv != '-')
-                       show_usage();
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'm':
-                       argc--;
-                       argv++;
-                       parse_mode(*argv, &mode);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc < 1 || *argv[0] == '-')
-               show_usage();
-       if (mkfifo(*argv, mode) < 0)
-               perror_msg_and_die("mkfifo");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/mkfs_minix.c b/busybox/mkfs_minix.c
deleted file mode 100644 (file)
index ccc0e85..0000000
+++ /dev/null
@@ -1,847 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * mkfs.c - make a linux (minix) file-system.
- *
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
- */
-
-/*
- * DD.MM.YY
- *
- * 24.11.91  - Time began. Used the fsck sources to get started.
- *
- * 25.11.91  - Corrected some bugs. Added support for ".badblocks"
- *             The algorithm for ".badblocks" is a bit weird, but
- *             it should work. Oh, well.
- *
- * 25.01.92  - Added the -l option for getting the list of bad blocks
- *             out of a named file. (Dave Rivers, rivers@ponds.uucp)
- *
- * 28.02.92  - Added %-information when using -c.
- *
- * 28.02.93  - Added support for other namelengths than the original
- *             14 characters so that I can test the new kernel routines..
- *
- * 09.10.93  - Make exit status conform to that required by fsutil
- *             (Rik Faith, faith@cs.unc.edu)
- *
- * 31.10.93  - Added inode request feature, for backup floppies: use
- *             32 inodes, for a news partition use more.
- *             (Scott Heavner, sdh@po.cwru.edu)
- *
- * 03.01.94  - Added support for file system valid flag.
- *             (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
- *
- * 30.10.94 - added support for v2 filesystem
- *           (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
- * 
- * 09.11.94  - Added test to prevent overwrite of mounted fs adapted
- *             from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
- *             program.  (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 03.20.95  - Clear first 512 bytes of filesystem to make certain that
- *             the filesystem is not misidentified as a MS-DOS FAT filesystem.
- *             (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 02.07.96  -  Added small patch from Russell King to make the program a
- *             good deal more portable (janl@math.uio.no)
- *
- * Usage:  mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
- *
- *     -c for readablility checking (SLOW!)
- *      -l for getting a list of bad blocks from a file.
- *     -n for namelength (currently the kernel only uses 14 or 30)
- *     -i for number of inodes
- *     -v for v2 filesystem
- *
- * The device may be a block device or a image of one, but this isn't
- * enforced (but it's not much fun on a character device :-). 
- *
- * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
- *     removed getopt based parser and added a hand rolled one.
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <mntent.h>
-#include "busybox.h"
-
-#define MINIX_ROOT_INO 1
-#define MINIX_LINK_MAX 250
-#define MINIX2_LINK_MAX        65530
-
-#define MINIX_I_MAP_SLOTS      8
-#define MINIX_Z_MAP_SLOTS      64
-#define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
-#define MINIX2_SUPER_MAGIC     0x2468          /* minix V2 fs */
-#define MINIX2_SUPER_MAGIC2    0x2478          /* minix V2 fs, 30 char names */
-#define MINIX_VALID_FS         0x0001          /* Clean fs. */
-#define MINIX_ERROR_FS         0x0002          /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-
-#define MINIX_V1               0x0001          /* original minix fs */
-#define MINIX_V2               0x0002          /* minix V2 fs */
-
-#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
-       u_int16_t i_mode;
-       u_int16_t i_uid;
-       u_int32_t i_size;
-       u_int32_t i_time;
-       u_int8_t  i_gid;
-       u_int8_t  i_nlinks;
-       u_int16_t i_zone[9];
-};
-
-/*
- * The new minix inode has all the time entries, as well as
- * long block numbers and a third indirect block (7+1+1+1
- * instead of 7+1+1). Also, some previously 8-bit values are
- * now 16-bit. The inode is now 64 bytes instead of 32.
- */
-struct minix2_inode {
-       u_int16_t i_mode;
-       u_int16_t i_nlinks;
-       u_int16_t i_uid;
-       u_int16_t i_gid;
-       u_int32_t i_size;
-       u_int32_t i_atime;
-       u_int32_t i_mtime;
-       u_int32_t i_ctime;
-       u_int32_t i_zone[10];
-};
-
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
-       u_int16_t s_ninodes;
-       u_int16_t s_nzones;
-       u_int16_t s_imap_blocks;
-       u_int16_t s_zmap_blocks;
-       u_int16_t s_firstdatazone;
-       u_int16_t s_log_zone_size;
-       u_int32_t s_max_size;
-       u_int16_t s_magic;
-       u_int16_t s_state;
-       u_int32_t s_zones;
-};
-
-struct minix_dir_entry {
-       u_int16_t inode;
-       char name[0];
-};
-
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-#define NAME_MAX         255   /* # chars in a file name */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-
-#define MINIX_VALID_FS               0x0001          /* Clean fs. */
-#define MINIX_ERROR_FS               0x0002          /* fs has errors. */
-
-#define MINIX_SUPER_MAGIC    0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2   0x138F          /* minix fs, 30 char names */
-
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96)    /* return device size */
-#endif
-
-
-#ifndef __linux__
-#define volatile
-#endif
-
-#define MINIX_ROOT_INO 1
-#define MINIX_BAD_INO 2
-
-#define TEST_BUFFER_BLOCKS 16
-#define MAX_GOOD_BLOCKS 512
-
-#define UPPER(size,n) (((size)+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef BB_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
-                                   : MINIX_INODES_PER_BLOCK))
-#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
-#endif
-#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
-
-#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long BLOCKS = 0;
-static int check = 0;
-static int badblocks = 0;
-static int namelen = 30;               /* default (changed to 30, per Linus's
-
-                                                                  suggestion, Sun Nov 21 08:05:07 1993) */
-static int dirsize = 32;
-static int magic = MINIX_SUPER_MAGIC2;
-static int version2 = 0;
-
-static char root_block[BLOCK_SIZE] = "\0";
-
-static char *inode_buffer = NULL;
-
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#ifdef BB_FEATURE_MINIX2
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-#endif
-static char super_block_buffer[BLOCK_SIZE];
-static char boot_block_buffer[512];
-
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef BB_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
-#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
-static int used_good_blocks = 0;
-static unsigned long req_nr_inodes = 0;
-
-static inline int bit(char * a,unsigned int i)
-{
-         return (a[i >> 3] & (1<<(i & 7))) != 0;
-}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-
-#define mark_inode(x) (setbit(inode_map,(x)))
-#define unmark_inode(x) (clrbit(inode_map,(x)))
-
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
-
-/*
- * Check to make certain that our new filesystem won't be created on
- * an already mounted partition.  Code adapted from mke2fs, Copyright
- * (C) 1994 Theodore Ts'o.  Also licensed under GPL.
- */
-static void check_mount(void)
-{
-       FILE *f;
-       struct mntent *mnt;
-
-       if ((f = setmntent(MOUNTED, "r")) == NULL)
-               return;
-       while ((mnt = getmntent(f)) != NULL)
-               if (strcmp(device_name, mnt->mnt_fsname) == 0)
-                       break;
-       endmntent(f);
-       if (!mnt)
-               return;
-
-       error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
-}
-
-static long valid_offset(int fd, int offset)
-{
-       char ch;
-
-       if (lseek(fd, offset, 0) < 0)
-               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;
-
-       if ((fd = open(file, O_RDWR)) < 0)
-               perror_msg_and_die("%s", file);
-       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
-               close(fd);
-               return (size * 512);
-       }
-
-       size = count_blocks(fd);
-       close(fd);
-       return size;
-}
-
-static void write_tables(void)
-{
-       /* Mark the super block valid. */
-       Super.s_state |= MINIX_VALID_FS;
-       Super.s_state &= ~MINIX_ERROR_FS;
-
-       if (lseek(DEV, 0, SEEK_SET))
-               error_msg_and_die("seek to boot block failed in write_tables");
-       if (512 != write(DEV, boot_block_buffer, 512))
-               error_msg_and_die("unable to clear boot sector");
-       if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
-               error_msg_and_die("seek failed in write_tables");
-       if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
-               error_msg_and_die("unable to write super-block");
-       if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
-               error_msg_and_die("unable to write inode map");
-       if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
-               error_msg_and_die("unable to write zone map");
-       if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
-               error_msg_and_die("unable to write inodes");
-
-}
-
-static void write_block(int blk, char *buffer)
-{
-       if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
-               error_msg_and_die("seek failed in write_block");
-       if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
-               error_msg_and_die("write failed in write_block");
-}
-
-static int get_free_block(void)
-{
-       int blk;
-
-       if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
-               error_msg_and_die("too many bad blocks");
-       if (used_good_blocks)
-               blk = good_blocks_table[used_good_blocks - 1] + 1;
-       else
-               blk = FIRSTZONE;
-       while (blk < ZONES && zone_in_use(blk))
-               blk++;
-       if (blk >= ZONES)
-               error_msg_and_die("not enough good blocks");
-       good_blocks_table[used_good_blocks] = blk;
-       used_good_blocks++;
-       return blk;
-}
-
-static void mark_good_blocks(void)
-{
-       int blk;
-
-       for (blk = 0; blk < used_good_blocks; blk++)
-               mark_zone(good_blocks_table[blk]);
-}
-
-static int next(int zone)
-{
-       if (!zone)
-               zone = FIRSTZONE - 1;
-       while (++zone < ZONES)
-               if (zone_in_use(zone))
-                       return zone;
-       return 0;
-}
-
-static void make_bad_inode(void)
-{
-       struct minix_inode *inode = &Inode[MINIX_BAD_INO];
-       int i, j, zone;
-       int ind = 0, dind = 0;
-       unsigned short ind_block[BLOCK_SIZE >> 1];
-       unsigned short dind_block[BLOCK_SIZE >> 1];
-
-#define NEXT_BAD (zone = next(zone))
-
-       if (!badblocks)
-               return;
-       mark_inode(MINIX_BAD_INO);
-       inode->i_nlinks = 1;
-       inode->i_time = time(NULL);
-       inode->i_mode = S_IFREG + 0000;
-       inode->i_size = 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;
-               }
-       }
-       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);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void make_bad_inode2(void)
-{
-       struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
-       int i, j, zone;
-       int ind = 0, dind = 0;
-       unsigned long ind_block[BLOCK_SIZE >> 2];
-       unsigned long dind_block[BLOCK_SIZE >> 2];
-
-       if (!badblocks)
-               return;
-       mark_inode(MINIX_BAD_INO);
-       inode->i_nlinks = 1;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
-       inode->i_mode = S_IFREG + 0000;
-       inode->i_size = 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 */
-       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);
-}
-#endif
-
-static void make_root_inode(void)
-{
-       struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
-
-       mark_inode(MINIX_ROOT_INO);
-       inode->i_zone[0] = get_free_block();
-       inode->i_nlinks = 2;
-       inode->i_time = time(NULL);
-       if (badblocks)
-               inode->i_size = 3 * dirsize;
-       else {
-               root_block[2 * dirsize] = '\0';
-               root_block[2 * dirsize + 1] = '\0';
-               inode->i_size = 2 * 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], root_block);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void make_root_inode2(void)
-{
-       struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
-
-       mark_inode(MINIX_ROOT_INO);
-       inode->i_zone[0] = get_free_block();
-       inode->i_nlinks = 2;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
-       if (badblocks)
-               inode->i_size = 3 * dirsize;
-       else {
-               root_block[2 * dirsize] = '\0';
-               root_block[2 * dirsize + 1] = '\0';
-               inode->i_size = 2 * 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], root_block);
-}
-#endif
-
-static void setup_tables(void)
-{
-       int i;
-       unsigned long inodes;
-
-       memset(super_block_buffer, 0, BLOCK_SIZE);
-       memset(boot_block_buffer, 0, 512);
-       MAGIC = magic;
-       ZONESIZE = 0;
-       MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
-       ZONES = BLOCKS;
-/* some magic nrs: 1 inode / 3 blocks */
-       if (req_nr_inodes == 0)
-               inodes = BLOCKS / 3;
-       else
-               inodes = req_nr_inodes;
-       /* Round up inode count to fill block size */
-#ifdef BB_FEATURE_MINIX2
-       if (version2)
-               inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
-                                 ~(MINIX2_INODES_PER_BLOCK - 1));
-       else
-#endif
-               inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
-                                 ~(MINIX_INODES_PER_BLOCK - 1));
-       if (inodes > 65535)
-               inodes = 65535;
-       INODES = inodes;
-       IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
-       ZMAPS = 0;
-       i = 0;
-       while (ZMAPS !=
-                  UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
-                                BITS_PER_BLOCK) && i < 1000) {
-               ZMAPS =
-                       UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
-                                 BITS_PER_BLOCK);
-               i++;
-       }
-       /* Real bad hack but overwise mkfs.minix can be thrown
-        * in infinite loop...
-        * try:
-        * dd if=/dev/zero of=test.fs count=10 bs=1024
-        * /sbin/mkfs.minix -i 200 test.fs
-        * */
-       if (i >= 999) {
-               error_msg_and_die("unable to allocate buffers for maps");
-       }
-       FIRSTZONE = NORM_FIRSTZONE;
-       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
-       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
-       memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
-       memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
-       for (i = FIRSTZONE; i < ZONES; i++)
-               unmark_zone(i);
-       for (i = MINIX_ROOT_INO; i <= INODES; i++)
-               unmark_inode(i);
-       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
-       memset(inode_buffer, 0, INODE_BUFFER_SIZE);
-       printf("%ld inodes\n", INODES);
-       printf("%ld blocks\n", ZONES);
-       printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
-       printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
-       printf("Maxsize=%ld\n\n", MAXSIZE);
-}
-
-/*
- * Perform a test of a block; return the number of
- * blocks readable/writeable.
- */
-static long do_check(char *buffer, int try, unsigned int current_block)
-{
-       long got;
-
-       /* Seek to the correct loc. */
-       if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
-               current_block * BLOCK_SIZE) {
-               error_msg_and_die("seek failed during testing of blocks");
-       }
-
-
-       /* Try the read */
-       got = read(DEV, buffer, try * BLOCK_SIZE);
-       if (got < 0)
-               got = 0;
-       if (got & (BLOCK_SIZE - 1)) {
-               printf("Weird values in do_check: probably bugs\n");
-       }
-       got /= BLOCK_SIZE;
-       return got;
-}
-
-static unsigned int currently_testing = 0;
-
-static void alarm_intr(int alnum)
-{
-       if (currently_testing >= ZONES)
-               return;
-       signal(SIGALRM, alarm_intr);
-       alarm(5);
-       if (!currently_testing)
-               return;
-       printf("%d ...", currently_testing);
-       fflush(stdout);
-}
-
-static void check_blocks(void)
-{
-       int try, got;
-       static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
-
-       currently_testing = 0;
-       signal(SIGALRM, alarm_intr);
-       alarm(5);
-       while (currently_testing < ZONES) {
-               if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
-                       currently_testing * BLOCK_SIZE)
-                       error_msg_and_die("seek failed in check_blocks");
-               try = TEST_BUFFER_BLOCKS;
-               if (currently_testing + try > ZONES)
-                       try = ZONES - currently_testing;
-               got = do_check(buffer, try, currently_testing);
-               currently_testing += got;
-               if (got == try)
-                       continue;
-               if (currently_testing < FIRSTZONE)
-                       error_msg_and_die("bad blocks before data-area: cannot make fs");
-               mark_zone(currently_testing);
-               badblocks++;
-               currently_testing++;
-       }
-       if (badblocks > 1)
-               printf("%d bad blocks\n", badblocks);
-       else if (badblocks == 1)
-               printf("one bad block\n");
-}
-
-static void get_list_blocks(filename)
-char *filename;
-
-{
-       FILE *listfile;
-       unsigned long blockno;
-
-       listfile = xfopen(filename, "r");
-       while (!feof(listfile)) {
-               fscanf(listfile, "%ld\n", &blockno);
-               mark_zone(blockno);
-               badblocks++;
-       }
-       if (badblocks > 1)
-               printf("%d bad blocks\n", badblocks);
-       else if (badblocks == 1)
-               printf("one bad block\n");
-}
-
-extern int mkfs_minix_main(int argc, char **argv)
-{
-       int i=1;
-       char *tmp;
-       struct stat statbuf;
-       char *listfile = NULL;
-       int stopIt=FALSE;
-
-       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
-               error_msg_and_die("bad inode size");
-#ifdef BB_FEATURE_MINIX2
-       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
-               error_msg_and_die("bad inode size");
-#endif
-       
-       /* Parse options */
-       argv++;
-       while (--argc >= 0 && *argv && **argv) {
-               if (**argv == '-') {
-                       stopIt=FALSE;
-                       while (i > 0 && *++(*argv) && stopIt==FALSE) {
-                               switch (**argv) {
-                                       case 'c':
-                                               check = 1;
-                                               break;
-                                       case 'i':
-                                               {
-                                                       char *cp=NULL;
-                                                       if (*(*argv+1) != 0) {
-                                                               cp = ++(*argv);
-                                                       } else {
-                                                               if (--argc == 0) {
-                                                                       goto goodbye;
-                                                               }
-                                                               cp = *(++argv);
-                                                       }
-                                                       req_nr_inodes = strtoul(cp, &tmp, 0);
-                                                       if (*tmp)
-                                                               show_usage();
-                                                       stopIt=TRUE;
-                                                       break;
-                                               }
-                                       case 'l':
-                                               if (--argc == 0) {
-                                                       goto goodbye;
-                                               }
-                                               listfile = *(++argv);
-                                               break;
-                                       case 'n':
-                                               {
-                                                       char *cp=NULL;
-
-                                                       if (*(*argv+1) != 0) {
-                                                               cp = ++(*argv);
-                                                       } else {
-                                                               if (--argc == 0) {
-                                                                       goto goodbye;
-                                                               }
-                                                               cp = *(++argv);
-                                                       }
-                                                       i = strtoul(cp, &tmp, 0);
-                                                       if (*tmp)
-                                                               show_usage();
-                                                       if (i == 14)
-                                                               magic = MINIX_SUPER_MAGIC;
-                                                       else if (i == 30)
-                                                               magic = MINIX_SUPER_MAGIC2;
-                                                       else 
-                                                               show_usage();
-                                                       namelen = i;
-                                                       dirsize = i + 2;
-                                                       stopIt=TRUE;
-                                                       break;
-                                               }
-                                       case 'v':
-#ifdef BB_FEATURE_MINIX2
-                                               version2 = 1;
-#else
-                                               error_msg("%s: not compiled with minix v2 support",
-                                                               device_name);
-                                               exit(-1);
-#endif
-                                               break;
-                                       case '-':
-                                       case 'h':
-                                       default:
-goodbye:
-                                               show_usage();
-                               }
-                       }
-               } else {
-                       if (device_name == NULL)
-                               device_name = *argv;
-                       else if (BLOCKS == 0)
-                               BLOCKS = strtol(*argv, &tmp, 0);
-                       else {
-                               goto goodbye;
-                       }
-               }
-               argv++;
-       }
-
-       if (device_name && !BLOCKS)
-               BLOCKS = get_size(device_name) / 1024;
-       if (!device_name || BLOCKS < 10) {
-               show_usage();
-       }
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               if (namelen == 14)
-                       magic = MINIX2_SUPER_MAGIC;
-               else
-                       magic = MINIX2_SUPER_MAGIC2;
-       } else
-#endif
-       if (BLOCKS > 65535)
-               BLOCKS = 65535;
-       check_mount();                          /* is it already mounted? */
-       tmp = root_block;
-       *(short *) tmp = 1;
-       strcpy(tmp + 2, ".");
-       tmp += dirsize;
-       *(short *) tmp = 1;
-       strcpy(tmp + 2, "..");
-       tmp += dirsize;
-       *(short *) tmp = 2;
-       strcpy(tmp + 2, ".badblocks");
-       DEV = open(device_name, O_RDWR);
-       if (DEV < 0)
-               error_msg_and_die("unable to open %s", device_name);
-       if (fstat(DEV, &statbuf) < 0)
-               error_msg_and_die("unable to stat %s", device_name);
-       if (!S_ISBLK(statbuf.st_mode))
-               check = 0;
-       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
-               error_msg_and_die("will not try to make filesystem on '%s'", device_name);
-       setup_tables();
-       if (check)
-               check_blocks();
-       else if (listfile)
-               get_list_blocks(listfile);
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               make_root_inode2();
-               make_bad_inode2();
-       } else
-#endif
-       {
-               make_root_inode();
-               make_bad_inode();
-       }
-       mark_good_blocks();
-       write_tables();
-       return( 0);
-
-}
diff --git a/busybox/mknod.c b/busybox/mknod.c
deleted file mode 100644 (file)
index b4d4b82..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mknod implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-int mknod_main(int argc, char **argv)
-{
-       char *thisarg;
-       mode_t mode = 0;
-       mode_t perm = 0666;
-       dev_t dev = 0;
-
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (argc > 1) {
-               if (**argv != '-')
-                       break;
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'm':
-                       argc--;
-                       argv++;
-                       parse_mode(*argv, &perm);
-                       umask(0);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc != 4 && argc != 2) {
-               show_usage();
-       }
-       switch (argv[1][0]) {
-       case 'c':
-       case 'u':
-               mode = S_IFCHR;
-               break;
-       case 'b':
-               mode = S_IFBLK;
-               break;
-       case 'p':
-               mode = S_IFIFO;
-               if (argc!=2) {
-                       show_usage();
-               }
-               break;
-       default:
-               show_usage();
-       }
-
-       if (mode == S_IFCHR || mode == S_IFBLK) {
-               dev = (atoi(argv[2]) << 8) | atoi(argv[3]);
-       }
-
-       mode |= perm;
-
-       if (mknod(argv[0], mode, dev) != 0)
-               perror_msg_and_die("%s", argv[0]);
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/mkswap.c b/busybox/mkswap.c
deleted file mode 100644 (file)
index f72c700..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * mkswap.c - set up a linux swap device
- *
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
- */
-
-/*
- * 20.12.91  - time began. Got VM working yesterday by doing this by hand.
- *
- * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
- *
- *     -c   for readability checking. (Use it unless you are SURE!)
- *     -vN  for swap areas version N. (Only N=0,1 known today.)
- *      -f   for forcing swap creation even if it would smash partition table.
- *
- * The device may be a block device or an image of one, but this isn't
- * enforced (but it's not much fun on a character device :-).
- *
- * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
- * size-in-blocks parameter optional added Wed Feb  8 10:33:43 1995.
- *
- * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
- *
- * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
- * V1_MAX_PAGES fixes, jj, 990325.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- *  from util-linux -- adapted for busybox by
- *  Erik Andersen <andersee@debian.org>. I ripped out Native Language
- *  Support, made some stuff smaller, and fitted for life in busybox.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>                 /* for _IO */
-#include <sys/utsname.h>
-#include <asm/page.h>                  /* for PAGE_SIZE and PAGE_SHIFT */
-                               /* we also get PAGE_SIZE via getpagesize() */
-#include "busybox.h"
-
-#ifndef _IO
-/* pre-1.3.45 */
-static const int BLKGETSIZE = 0x1260;
-#else
-/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
-#define BLKGETSIZE _IO(0x12,96)
-#endif
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long PAGES = 0;
-static int check = 0;
-static int badpages = 0;
-static int version = -1;
-
-#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
-
-/*
- * The definition of the union swap_header uses the constant PAGE_SIZE.
- * Unfortunately, on some architectures this depends on the hardware model,
- * and can only be found at run time -- we use getpagesize().
- */
-
-static int pagesize;
-static int *signature_page;
-
-static struct swap_header_v1 {
-       char bootbits[1024];            /* Space for disklabel etc. */
-       unsigned int version;
-       unsigned int last_page;
-       unsigned int nr_badpages;
-       unsigned int padding[125];
-       unsigned int badpages[1];
-} *p;
-
-static void init_signature_page()
-{
-       pagesize = getpagesize();
-
-#ifdef PAGE_SIZE
-       if (pagesize != PAGE_SIZE)
-               error_msg("Assuming pages of size %d", pagesize);
-#endif
-       signature_page = (int *) xmalloc(pagesize);
-       memset(signature_page, 0, pagesize);
-       p = (struct swap_header_v1 *) signature_page;
-}
-
-static void write_signature(char *sig)
-{
-       char *sp = (char *) signature_page;
-
-       strncpy(sp + pagesize - 10, sig, 10);
-}
-
-#define V0_MAX_PAGES   (8 * (pagesize - 10))
-/* Before 2.2.0pre9 */
-#define V1_OLD_MAX_PAGES       ((0x7fffffff / pagesize) - 1)
-/* Since 2.2.0pre9:
-   error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
-   with variations on
-       #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
-       #define SWP_OFFSET(entry) ((entry) >> 8)
-   on the various architectures. Below the result - yuk.
-
-   Machine     pagesize        SWP_ENTRY       SWP_OFFSET      bound+1 oldbound+2
-   i386                2^12            o<<8            e>>8            1<<24   1<<19
-   mips                2^12            o<<15           e>>15           1<<17   1<<19
-   alpha       2^13            o<<40           e>>40           1<<24   1<<18
-   m68k                2^12            o<<12           e>>12           1<<20   1<<19
-   sparc       2^{12,13}       (o&0x3ffff)<<9  (e>>9)&0x3ffff  1<<18   1<<{19,18}
-   sparc64     2^13            o<<13           e>>13           1<<51   1<<18
-   ppc         2^12            o<<8            e>>8            1<<24   1<<19
-   armo                2^{13,14,15}    o<<8            e>>8            1<<24   1<<{18,17,16}
-   armv                2^12            o<<9            e>>9            1<<23   1<<19
-
-   assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
-
-   The bad part is that we need to know this since the kernel will
-   refuse a swap space if it is too large.
-*/
-/* patch from jj - why does this differ from the above? */
-#if defined(__alpha__)
-#define V1_MAX_PAGES           ((1 << 24) - 1)
-#elif defined(__mips__)
-#define V1_MAX_PAGES           ((1 << 17) - 1)
-#elif defined(__sparc_v9__)
-#define V1_MAX_PAGES           ((3 << 29) - 1)
-#elif defined(__sparc__)
-#define V1_MAX_PAGES           (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
-#else
-#define V1_MAX_PAGES           V1_OLD_MAX_PAGES
-#endif
-/* man page now says:
-The maximum useful size of a swap area now depends on the architecture.
-It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
-128GB on alpha and 3TB on sparc64.
-*/
-
-#define MAX_BADPAGES   ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
-
-static void bit_set(unsigned int *addr, unsigned int nr)
-{
-       unsigned int r, m;
-
-       addr += nr / (8 * sizeof(int));
-
-       r = *addr;
-       m = 1 << (nr & (8 * sizeof(int) - 1));
-
-       *addr = r | m;
-}
-
-static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
-{
-       unsigned int r, m;
-
-       addr += nr / (8 * sizeof(int));
-
-       r = *addr;
-       m = 1 << (nr & (8 * sizeof(int) - 1));
-
-       *addr = r & ~m;
-       return (r & m) != 0;
-}
-
-
-static void page_ok(int page)
-{
-       if (version == 0)
-               bit_set(signature_page, page);
-}
-
-static void page_bad(int page)
-{
-       if (version == 0)
-               bit_test_and_clear(signature_page, page);
-       else {
-               if (badpages == MAX_BADPAGES)
-                       error_msg_and_die("too many bad pages");
-               p->badpages[badpages] = page;
-       }
-       badpages++;
-}
-
-static void check_blocks(void)
-{
-       unsigned int current_page;
-       int do_seek = 1;
-       char *buffer;
-
-       buffer = xmalloc(pagesize);
-       current_page = 0;
-       while (current_page < PAGES) {
-               if (!check) {
-                       page_ok(current_page++);
-                       continue;
-               }
-               if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
-                       current_page * pagesize)
-                       error_msg_and_die("seek failed in check_blocks");
-               if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
-                       page_bad(current_page++);
-                       continue;
-               }
-               page_ok(current_page++);
-       }
-       if (badpages == 1)
-               printf("one bad page\n");
-       else if (badpages > 1)
-               printf("%d bad pages\n", badpages);
-}
-
-static long valid_offset(int fd, int offset)
-{
-       char ch;
-
-       if (lseek(fd, offset, 0) < 0)
-               return 0;
-       if (read(fd, &ch, 1) < 1)
-               return 0;
-       return 1;
-}
-
-static int find_size(int fd)
-{
-       unsigned int high, low;
-
-       low = 0;
-       for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
-               low = high;
-       while (low < high - 1) {
-               const int mid = (low + high) / 2;
-
-               if (valid_offset(fd, mid))
-                       low = mid;
-               else
-                       high = mid;
-       }
-       return (low + 1);
-}
-
-/* return size in pages, to avoid integer overflow */
-static long get_size(const char *file)
-{
-       int fd;
-       long size;
-
-       if ((fd = open(file, O_RDONLY)) < 0)
-               perror_msg_and_die("%s", file);
-       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
-               int sectors_per_page = pagesize / 512;
-
-               size /= sectors_per_page;
-       } else {
-               size = find_size(fd) / pagesize;
-       }
-       close(fd);
-       return size;
-}
-
-int mkswap_main(int argc, char **argv)
-{
-       char *tmp;
-       struct stat statbuf;
-       int sz;
-       int maxpages;
-       int goodpages;
-       int offset;
-       int force = 0;
-
-       init_signature_page();          /* get pagesize */
-
-       while (argc-- > 1) {
-               argv++;
-               if (argv[0][0] != '-') {
-                       if (device_name) {
-                               int blocks_per_page = pagesize / 1024;
-
-                               PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
-                               if (*tmp)
-                                       show_usage();
-                       } else
-                               device_name = argv[0];
-               } else {
-                       switch (argv[0][1]) {
-                       case 'c':
-                               check = 1;
-                               break;
-                       case 'f':
-                               force = 1;
-                               break;
-                       case 'v':
-                               version = atoi(argv[0] + 2);
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-       if (!device_name) {
-               error_msg("error: Nowhere to set up swap on?");
-               show_usage();
-       }
-       sz = get_size(device_name);
-       if (!PAGES) {
-               PAGES = sz;
-       } else if (PAGES > sz && !force) {
-               error_msg("error: size %ld is larger than device size %d",
-                               PAGES * (pagesize / 1024), sz * (pagesize / 1024));
-               return EXIT_FAILURE;
-       }
-
-       if (version == -1) {
-               if (PAGES <= V0_MAX_PAGES)
-                       version = 0;
-               else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
-                       version = 0;
-               else if (pagesize < 2048)
-                       version = 0;
-               else
-                       version = 1;
-       }
-       if (version != 0 && version != 1) {
-               error_msg("error: unknown version %d", version);
-               show_usage();
-       }
-       if (PAGES < 10) {
-               error_msg("error: swap area needs to be at least %ldkB",
-                               (long) (10 * pagesize / 1024));
-               show_usage();
-       }
-#if 0
-       maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
-#else
-       if (!version)
-               maxpages = V0_MAX_PAGES;
-       else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
-               maxpages = V1_MAX_PAGES;
-       else {
-               maxpages = V1_OLD_MAX_PAGES;
-               if (maxpages > V1_MAX_PAGES)
-                       maxpages = V1_MAX_PAGES;
-       }
-#endif
-       if (PAGES > maxpages) {
-               PAGES = maxpages;
-               error_msg("warning: truncating swap area to %ldkB",
-                               PAGES * pagesize / 1024);
-       }
-
-       DEV = open(device_name, O_RDWR);
-       if (DEV < 0 || fstat(DEV, &statbuf) < 0)
-               perror_msg_and_die("%s", device_name);
-       if (!S_ISBLK(statbuf.st_mode))
-               check = 0;
-       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
-               error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
-
-#ifdef __sparc__
-       if (!force && version == 0) {
-               /* Don't overwrite partition table unless forced */
-               unsigned char *buffer = (unsigned char *) signature_page;
-               unsigned short *q, sum;
-
-               if (read(DEV, buffer, 512) != 512)
-                       error_msg_and_die("fatal: first page unreadable");
-               if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
-                       q = (unsigned short *) (buffer + 510);
-                       for (sum = 0; q >= (unsigned short *) buffer;)
-                               sum ^= *q--;
-                       if (!sum) {
-                               error_msg("Device '%s' contains a valid Sun disklabel.\n"
-"This probably means creating v0 swap would destroy your partition table\n"
-"No swap created. If you really want to create swap v0 on that device, use\n"
-"the -f option to force it.", device_name);
-                               return EXIT_FAILURE;
-                       }
-               }
-       }
-#endif
-
-       if (version == 0 || check)
-               check_blocks();
-       if (version == 0 && !bit_test_and_clear(signature_page, 0))
-               error_msg_and_die("fatal: first page unreadable");
-       if (version == 1) {
-               p->version = version;
-               p->last_page = PAGES - 1;
-               p->nr_badpages = badpages;
-       }
-
-       goodpages = PAGES - badpages - 1;
-       if (goodpages <= 0)
-               error_msg_and_die("Unable to set up swap-space: unreadable");
-       printf("Setting up swapspace version %d, size = %ld bytes\n",
-                  version, (long) (goodpages * pagesize));
-       write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
-
-       offset = ((version == 0) ? 0 : 1024);
-       if (lseek(DEV, offset, SEEK_SET) != offset)
-               error_msg_and_die("unable to rewind swap-device");
-       if (write(DEV, (char *) signature_page + offset, pagesize - offset)
-               != pagesize - offset)
-               error_msg_and_die("unable to write signature page");
-
-       /*
-        * A subsequent swapon() will fail if the signature
-        * is not actually on disk. (This is a kernel bug.)
-        */
-       if (fsync(DEV))
-               error_msg_and_die("fsync failed");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/mktemp.c b/busybox/mktemp.c
deleted file mode 100644 (file)
index bc47d0a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mktemp implementation for busybox
- *
- *
- * Copyright (C) 2000 by Daniel Jacobowitz
- * Written by Daniel Jacobowitz <dan@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int mktemp_main(int argc, char **argv)
-{
-       if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q")))
-               show_usage();
-       if(mkstemp(argv[argc-1]) < 0)
-               return EXIT_FAILURE;
-       (void) puts(argv[argc-1]);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/modprobe.c b/busybox/modprobe.c
deleted file mode 100644 (file)
index 05b40c5..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * really dumb modprobe implementation for busybox
- * Copyright (C) 2001 Lineo, davidm@lineo.com
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include "busybox.h"
-
-static char cmd[128];
-
-extern int modprobe_main(int argc, char** argv)
-{
-       int     ch, rc = 0;
-       int     loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0;
-       int     show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0;
-       char    *load_type = NULL, *config = NULL;
-
-       while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1)
-               switch(ch) {
-               case 'a':
-                       loadall++;
-                       break;
-               case 'c':
-                       showconfig++;
-                       break;
-               case 'd':
-                       debug++;
-                       break;
-               case 'k':
-                       autoclean++;
-                       break;
-               case 'l':
-                       list++;
-                       break;
-               case 'n':
-                       show_only++;
-                       break;
-               case 'q':
-                       quiet++;
-                       break;
-               case 'r':
-                       remove_opt++;
-                       break;
-               case 's':
-                       do_syslog++;
-                       break;
-               case 't':
-                       load_type = optarg;
-                       break;
-               case 'v':
-                       verbose++;
-                       break;
-               case 'C':
-                       config = optarg;
-                       break;
-               case 'V':
-               default:
-                       show_usage();
-                       break;
-               }
-
-       if (load_type || config) {
-               fprintf(stderr, "-t and -C not supported\n");
-               exit(EXIT_FAILURE);
-       }
-
-       if (showconfig)
-               exit(EXIT_SUCCESS);
-       
-       if (list)
-               exit(EXIT_SUCCESS);
-       
-       if (remove_opt) {
-               do {
-                       sprintf(cmd, "rmmod %s %s %s",
-                                       optind >= argc ? "-a" : "",
-                                       do_syslog ? "-s" : "",
-                                       optind < argc ? argv[optind] : "");
-                       if (do_syslog)
-                               syslog(LOG_INFO, "%s", cmd);
-                       if (show_only || verbose)
-                               printf("%s\n", cmd);
-                       if (!show_only)
-                               rc = system(cmd);
-               } while (++optind < argc);
-               exit(EXIT_SUCCESS);
-       }
-
-       if (optind >= argc) {
-               fprintf(stderr, "No module or pattern provided\n");
-               exit(EXIT_FAILURE);
-       }
-
-       sprintf(cmd, "insmod %s %s %s",
-                       do_syslog ? "-s" : "",
-                       quiet ? "-q" : "",
-                       autoclean ? "-k" : "");
-       while (optind < argc) {
-               strcat(cmd, argv[optind]);
-               strcat(cmd, " ");
-               optind++;
-       }
-       if (do_syslog)
-               syslog(LOG_INFO, "%s", cmd);
-       if (show_only || verbose)
-               printf("%s\n", cmd);
-       if (!show_only)
-               rc = system(cmd);
-       else
-               rc = 0;
-
-       exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
-}
-
-
diff --git a/busybox/modutils/insmod.c b/busybox/modutils/insmod.c
deleted file mode 100644 (file)
index 413af5c..0000000
+++ /dev/null
@@ -1,3481 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini insmod implementation for busybox
- *
- * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 
- * and MIPS.
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>
- * and Ron Alder <alder@lineo.com>
- *
- * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
- * and (theoretically) SH3. I have only tested SH4 in little endian mode.
- *
- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI.  Only
- * very minor changes required to also work with StrongArm and presumably
- * all ARM based systems.
- *
- * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
- *   PowerPC specific code stolen from modutils-2.3.16, 
- *   written by Paul Mackerras, Copyright 1996, 1997 Linux International.
- *   I've only tested the code on mpc8xx platforms in big-endian mode.
- *   Did some cleanup and added BB_USE_xxx_ENTRIES...
- *
- * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
- *   based on modutils-2.4.2
- *   MIPS specific support for Elf loading and relocation.
- *   Copyright 1996, 1997 Linux International.
- *   Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
- *
- * Based almost entirely on the Linux modutils-2.3.11 implementation.
- *   Copyright 1996, 1997 Linux International.
- *   New implementation contributed by Richard Henderson <rth@tamu.edu>
- *   Based on original work by Bjorn Ekwall <bj0rn@blox.se>
- *   Restructured (and partly rewritten) by:
- *   Björn Ekwall <bj0rn@blox.se> February 1999
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <assert.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/utsname.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-# undef BB_FEATURE_OLD_MODULE_INTERFACE
-# define new_sys_init_module   init_module
-#else
-# define old_sys_init_module   init_module
-#endif
-
-#ifdef BB_FEATURE_INSMOD_LOADINKMEM
-#define LOADBITS 0     
-#else
-#define LOADBITS 1
-#endif
-
-#if defined(__powerpc__)
-#define BB_USE_PLT_ENTRIES
-#define BB_PLT_ENTRY_SIZE 16
-#endif
-
-#if defined(__arm__)
-#define BB_USE_PLT_ENTRIES
-#define BB_PLT_ENTRY_SIZE 8
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 8
-#endif
-
-#if defined(__sh__)
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 4
-#endif
-
-#if defined(__i386__)
-#define BB_USE_GOT_ENTRIES
-#define BB_GOT_ENTRY_SIZE 4
-#endif
-
-#if defined(__mips__)
-// neither used
-#endif
-
-//----------------------------------------------------------------------------
-//--------modutils module.h, lines 45-242
-//----------------------------------------------------------------------------
-
-/* Definitions for the Linux module syscall interface.
-   Copyright 1996, 1997 Linux International.
-
-   Contributed by Richard Henderson <rth@tamu.edu>
-
-   This file is part of the Linux modutils.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2 of the License, or (at your
-   option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-
-#ifndef MODUTILS_MODULE_H
-static const int MODUTILS_MODULE_H = 1;
-
-/* This file contains the structures used by the 2.0 and 2.1 kernels.
-   We do not use the kernel headers directly because we do not wish
-   to be dependant on a particular kernel version to compile insmod.  */
-
-
-/*======================================================================*/
-/* The structures used by Linux 2.0.  */
-
-/* The symbol format used by get_kernel_syms(2).  */
-struct old_kernel_sym
-{
-  unsigned long value;
-  char name[60];
-};
-
-struct old_module_ref
-{
-  unsigned long module;                /* kernel addresses */
-  unsigned long next;
-};
-
-struct old_module_symbol
-{
-  unsigned long addr;
-  unsigned long name;
-};
-
-struct old_symbol_table
-{
-  int size;                    /* total, including string table!!! */
-  int n_symbols;
-  int n_refs;
-  struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
-  struct old_module_ref ref[0];        /* actual size defined by n_refs */
-};
-
-struct old_mod_routines
-{
-  unsigned long init;
-  unsigned long cleanup;
-};
-
-struct old_module
-{
-  unsigned long next;
-  unsigned long ref;           /* the list of modules that refer to me */
-  unsigned long symtab;
-  unsigned long name;
-  int size;                    /* size of module in pages */
-  unsigned long addr;          /* address of module */
-  int state;
-  unsigned long cleanup;       /* cleanup routine */
-};
-
-/* Sent to init_module(2) or'ed into the code size parameter.  */
-static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */
-
-int get_kernel_syms(struct old_kernel_sym *);
-int old_sys_init_module(const char *name, char *code, unsigned codesize,
-                       struct old_mod_routines *, struct old_symbol_table *);
-
-/*======================================================================*/
-/* For sizeof() which are related to the module platform and not to the
-   environment isnmod is running in, use sizeof_xx instead of sizeof(xx).  */
-
-#define tgt_sizeof_char                sizeof(char)
-#define tgt_sizeof_short       sizeof(short)
-#define tgt_sizeof_int         sizeof(int)
-#define tgt_sizeof_long                sizeof(long)
-#define tgt_sizeof_char_p      sizeof(char *)
-#define tgt_sizeof_void_p      sizeof(void *)
-#define tgt_long               long
-
-#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
-#undef tgt_sizeof_long
-#undef tgt_sizeof_char_p
-#undef tgt_sizeof_void_p
-#undef tgt_long
-static const int tgt_sizeof_long = 8;
-static const int tgt_sizeof_char_p = 8;
-static const int tgt_sizeof_void_p = 8;
-#define tgt_long               long long
-#endif
-
-/*======================================================================*/
-/* The structures used in Linux 2.1.  */
-
-/* Note: new_module_symbol does not use tgt_long intentionally */
-struct new_module_symbol
-{
-  unsigned long value;
-  unsigned long name;
-};
-
-struct new_module_persist;
-
-struct new_module_ref
-{
-  unsigned tgt_long dep;               /* kernel addresses */
-  unsigned tgt_long ref;
-  unsigned tgt_long next_ref;
-};
-
-struct new_module
-{
-  unsigned tgt_long size_of_struct;    /* == sizeof(module) */
-  unsigned tgt_long next;
-  unsigned tgt_long name;
-  unsigned tgt_long size;
-
-  tgt_long usecount;
-  unsigned tgt_long flags;             /* AUTOCLEAN et al */
-
-  unsigned nsyms;
-  unsigned ndeps;
-
-  unsigned tgt_long syms;
-  unsigned tgt_long deps;
-  unsigned tgt_long refs;
-  unsigned tgt_long init;
-  unsigned tgt_long cleanup;
-  unsigned tgt_long ex_table_start;
-  unsigned tgt_long ex_table_end;
-#ifdef __alpha__
-  unsigned tgt_long gp;
-#endif
-  /* Everything after here is extension.  */
-  unsigned tgt_long persist_start;
-  unsigned tgt_long persist_end;
-  unsigned tgt_long can_unload;
-  unsigned tgt_long runsize;
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-  const char *kallsyms_start;     /* All symbols for kernel debugging */
-  const char *kallsyms_end;
-  const char *archdata_start;     /* arch specific data for module */
-  const char *archdata_end;
-  const char *kernel_data;        /* Reserved for kernel internal use */
-#endif
-};
-
-#define ARCHDATA_SEC_NAME "__archdata"
-#define KALLSYMS_SEC_NAME "__kallsyms"
-
-
-struct new_module_info
-{
-  unsigned long addr;
-  unsigned long size;
-  unsigned long flags;
-          long usecount;
-};
-
-/* Bits of module.flags.  */
-static const int NEW_MOD_RUNNING = 1;
-static const int NEW_MOD_DELETED = 2;
-static const int NEW_MOD_AUTOCLEAN = 4;
-static const int NEW_MOD_VISITED = 8;
-static const int NEW_MOD_USED_ONCE = 16;
-
-int new_sys_init_module(const char *name, const struct new_module *);
-int query_module(const char *name, int which, void *buf, size_t bufsize,
-                size_t *ret);
-
-/* Values for query_module's which.  */
-
-static const int QM_MODULES = 1;
-static const int QM_DEPS = 2;
-static const int QM_REFS = 3;
-static const int QM_SYMBOLS = 4;
-static const int QM_INFO = 5;
-
-/*======================================================================*/
-/* The system calls unchanged between 2.0 and 2.1.  */
-
-unsigned long create_module(const char *, size_t);
-int delete_module(const char *);
-
-
-#endif /* module.h */
-
-//----------------------------------------------------------------------------
-//--------end of modutils module.h
-//----------------------------------------------------------------------------
-
-
-
-//----------------------------------------------------------------------------
-//--------modutils obj.h, lines 253-462
-//----------------------------------------------------------------------------
-
-/* Elf object file loading and relocation routines.
-   Copyright 1996, 1997 Linux International.
-
-   Contributed by Richard Henderson <rth@tamu.edu>
-
-   This file is part of the Linux modutils.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2 of the License, or (at your
-   option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-
-#ifndef MODUTILS_OBJ_H
-static const int MODUTILS_OBJ_H = 1;
-
-/* The relocatable object is manipulated using elfin types.  */
-
-#include <stdio.h>
-#include <elf.h>
-
-
-/* Machine-specific elf macros for i386 et al.  */
-
-/* the SH changes have only been tested on the SH4 in =little endian= mode */
-/* I'm not sure about big endian, so let's warn: */
-
-#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
-#error insmod.c may require changes for use on big endian SH4/SH3
-#endif
-
-/* it may or may not work on the SH1/SH2... So let's error on those
-   also */
-#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
-#error insmod.c may require changes for non-SH3/SH4 use
-#endif
-
-#define ELFCLASSM      ELFCLASS32
-
-#if (defined(__mc68000__))                                     
-#define ELFDATAM       ELFDATA2MSB
-#endif
-
-
-
-#if defined(__sh__)
-
-#define MATCH_MACHINE(x) (x == EM_SH)
-#define SHT_RELM       SHT_RELA
-#define Elf32_RelM     Elf32_Rela
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__arm__)
-
-#define MATCH_MACHINE(x) (x == EM_ARM)
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__powerpc__)
-
-#define MATCH_MACHINE(x) (x == EM_PPC)
-#define SHT_RELM       SHT_RELA
-#define Elf32_RelM     Elf32_Rela
-#define ELFDATAM    ELFDATA2MSB
-
-#elif defined(__mips__)
-
-/* Account for ELF spec changes.  */
-#ifndef EM_MIPS_RS3_LE
-#ifdef EM_MIPS_RS4_BE
-#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
-#else
-#define EM_MIPS_RS3_LE 10
-#endif
-#endif /* !EM_MIPS_RS3_LE */
-
-#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#ifdef __MIPSEB__
-#define ELFDATAM        ELFDATA2MSB
-#endif
-#ifdef __MIPSEL__
-#define ELFDATAM        ELFDATA2LSB
-#endif
-
-#elif defined(__i386__)
-
-/* presumably we can use these for anything but the SH and ARM*/
-/* this is the previous behavior, but it does result in
-   insmod.c being broken on anything except i386 */
-#ifndef EM_486
-#define MATCH_MACHINE(x)  (x == EM_386)
-#else
-#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
-#endif
-
-#define SHT_RELM       SHT_REL
-#define Elf32_RelM     Elf32_Rel
-#define ELFDATAM       ELFDATA2LSB
-
-#elif defined(__mc68000__) 
-
-#define MATCH_MACHINE(x)       (x == EM_68K)
-#define SHT_RELM                       SHT_RELA
-#define Elf32_RelM                     Elf32_Rela
-
-#else
-#error Sorry, but insmod.c does not yet support this architecture...
-#endif
-
-#ifndef ElfW
-# if ELFCLASSM == ELFCLASS32
-#  define ElfW(x)  Elf32_ ## x
-#  define ELFW(x)  ELF32_ ## x
-# else
-#  define ElfW(x)  Elf64_ ## x
-#  define ELFW(x)  ELF64_ ## x
-# endif
-#endif
-
-/* For some reason this is missing from libc5.  */
-#ifndef ELF32_ST_INFO
-# define ELF32_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
-#endif
-
-#ifndef ELF64_ST_INFO
-# define ELF64_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
-#endif
-
-struct obj_string_patch;
-struct obj_symbol_patch;
-
-struct obj_section
-{
-  ElfW(Shdr) header;
-  const char *name;
-  char *contents;
-  struct obj_section *load_next;
-  int idx;
-};
-
-struct obj_symbol
-{
-  struct obj_symbol *next;     /* hash table link */
-  const char *name;
-  unsigned long value;
-  unsigned long size;
-  int secidx;                  /* the defining section index/module */
-  int info;
-  int ksymidx;                 /* for export to the kernel symtab */
-  int referenced;              /* actually used in the link */
-};
-
-/* Hardcode the hash table size.  We shouldn't be needing so many
-   symbols that we begin to degrade performance, and we get a big win
-   by giving the compiler a constant divisor.  */
-
-#define HASH_BUCKETS  521
-
-struct obj_file
-{
-  ElfW(Ehdr) header;
-  ElfW(Addr) baseaddr;
-  struct obj_section **sections;
-  struct obj_section *load_order;
-  struct obj_section **load_order_search_start;
-  struct obj_string_patch *string_patches;
-  struct obj_symbol_patch *symbol_patches;
-  int (*symbol_cmp)(const char *, const char *);
-  unsigned long (*symbol_hash)(const char *);
-  unsigned long local_symtab_size;
-  struct obj_symbol **local_symtab;
-  struct obj_symbol *symtab[HASH_BUCKETS];
-};
-
-enum obj_reloc
-{
-  obj_reloc_ok,
-  obj_reloc_overflow,
-  obj_reloc_dangerous,
-  obj_reloc_unhandled
-};
-
-struct obj_string_patch
-{
-  struct obj_string_patch *next;
-  int reloc_secidx;
-  ElfW(Addr) reloc_offset;
-  ElfW(Addr) string_offset;
-};
-
-struct obj_symbol_patch
-{
-  struct obj_symbol_patch *next;
-  int reloc_secidx;
-  ElfW(Addr) reloc_offset;
-  struct obj_symbol *sym;
-};
-
-
-/* Generic object manipulation routines.  */
-
-static unsigned long obj_elf_hash(const char *);
-
-static unsigned long obj_elf_hash_n(const char *, unsigned long len);
-
-static struct obj_symbol *obj_find_symbol (struct obj_file *f,
-                                        const char *name);
-
-static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
-                                 struct obj_symbol *sym);
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static void obj_set_symbol_compare(struct obj_file *f,
-                           int (*cmp)(const char *, const char *),
-                           unsigned long (*hash)(const char *));
-#endif
-
-static struct obj_section *obj_find_section (struct obj_file *f,
-                                          const char *name);
-
-static void obj_insert_section_load_order (struct obj_file *f,
-                                   struct obj_section *sec);
-
-static struct obj_section *obj_create_alloced_section (struct obj_file *f,
-                                               const char *name,
-                                               unsigned long align,
-                                               unsigned long size);
-
-static struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
-                                                     const char *name,
-                                                     unsigned long align,
-                                                     unsigned long size);
-
-static void *obj_extend_section (struct obj_section *sec, unsigned long more);
-
-static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                    const char *string);
-
-static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                    struct obj_symbol *sym);
-
-static int obj_check_undefineds(struct obj_file *f);
-
-static void obj_allocate_commons(struct obj_file *f);
-
-static unsigned long obj_load_size (struct obj_file *f);
-
-static int obj_relocate (struct obj_file *f, ElfW(Addr) base);
-
-static struct obj_file *obj_load(FILE *f, int loadprogbits);
-
-static int obj_create_image (struct obj_file *f, char *image);
-
-/* Architecture specific manipulation routines.  */
-
-static struct obj_file *arch_new_file (void);
-
-static struct obj_section *arch_new_section (void);
-
-static struct obj_symbol *arch_new_symbol (void);
-
-static enum obj_reloc arch_apply_relocation (struct obj_file *f,
-                                     struct obj_section *targsec,
-                                     struct obj_section *symsec,
-                                     struct obj_symbol *sym,
-                                     ElfW(RelM) *rel, ElfW(Addr) value);
-
-static int arch_create_got (struct obj_file *f);
-
-static int arch_init_module (struct obj_file *f, struct new_module *);
-
-#endif /* obj.h */
-//----------------------------------------------------------------------------
-//--------end of modutils obj.h
-//----------------------------------------------------------------------------
-
-
-
-
-
-#define _PATH_MODULES  "/lib/modules"
-static const int STRVERSIONLEN = 32;
-
-/*======================================================================*/
-
-static int flag_force_load = 0;
-static int flag_autoclean = 0;
-static int flag_verbose = 0;
-static int flag_export = 1;
-
-
-/*======================================================================*/
-
-/* previously, these were named i386_* but since we could be
-   compiling for the sh, I've renamed them to the more general
-   arch_* These structures are the same between the x86 and SH, 
-   and we can't support anything else right now anyway. In the
-   future maybe they should be #if defined'd */
-
-/* Done ;-) */
-
-
-
-#if defined(BB_USE_PLT_ENTRIES)
-struct arch_plt_entry
-{
-  int offset;
-  int allocated:1;
-  int inited:1;                /* has been set up */
-};
-#endif
-
-#if defined(BB_USE_GOT_ENTRIES)
-struct arch_got_entry {
-       int offset;
-       unsigned offset_done:1;
-       unsigned reloc_done:1;
-};
-#endif
-
-#if defined(__mips__)
-struct mips_hi16
-{
-  struct mips_hi16 *next;
-  Elf32_Addr *addr;
-  Elf32_Addr value;
-};
-#endif
-
-struct arch_file {
-       struct obj_file root;
-#if defined(BB_USE_PLT_ENTRIES)
-       struct obj_section *plt;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       struct obj_section *got;
-#endif
-#if defined(__mips__)
-       struct mips_hi16 *mips_hi16_list;
-#endif
-};
-
-struct arch_symbol {
-       struct obj_symbol root;
-#if defined(BB_USE_PLT_ENTRIES)
-       struct arch_plt_entry pltent;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       struct arch_got_entry gotent;
-#endif
-};
-
-
-struct external_module {
-       const char *name;
-       ElfW(Addr) addr;
-       int used;
-       size_t nsyms;
-       struct new_module_symbol *syms;
-};
-
-static struct new_module_symbol *ksyms;
-static size_t nksyms;
-
-static struct external_module *ext_modules;
-static int n_ext_modules;
-static int n_ext_modules_used;
-extern int delete_module(const char *);
-
-static char m_filename[FILENAME_MAX + 1];
-static char m_fullName[FILENAME_MAX + 1];
-
-
-
-/*======================================================================*/
-
-
-static int check_module_name_match(const char *filename, struct stat *statbuf,
-                                                  void *userdata)
-{
-       char *fullname = (char *) userdata;
-
-       if (fullname[0] == '\0')
-               return (FALSE);
-       else {
-               char *tmp, *tmp1 = strdup(filename);
-               tmp = get_last_path_component(tmp1);
-               if (strcmp(tmp, fullname) == 0) {
-                       free(tmp1);
-                       /* Stop searching if we find a match */
-                       safe_strncpy(m_filename, filename, sizeof(m_filename));
-                       return (TRUE);
-               }
-               free(tmp1);
-       }
-       return (FALSE);
-}
-
-
-/*======================================================================*/
-
-static struct obj_file *arch_new_file(void)
-{
-       struct arch_file *f;
-       f = xmalloc(sizeof(*f));
-
-#if defined(BB_USE_PLT_ENTRIES)
-       f->plt = NULL;
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       f->got = NULL;
-#endif
-#if defined(__mips__)
-       f->mips_hi16_list = NULL;
-#endif
-
-       return &f->root;
-}
-
-static struct obj_section *arch_new_section(void)
-{
-       return xmalloc(sizeof(struct obj_section));
-}
-
-static struct obj_symbol *arch_new_symbol(void)
-{
-       struct arch_symbol *sym;
-       sym = xmalloc(sizeof(*sym));
-
-#if defined(BB_USE_PLT_ENTRIES)
-       memset(&sym->pltent, 0, sizeof(sym->pltent));
-#endif
-#if defined(BB_USE_GOT_ENTRIES)
-       memset(&sym->gotent, 0, sizeof(sym->gotent));
-#endif
-
-       return &sym->root;
-}
-
-static enum obj_reloc
-arch_apply_relocation(struct obj_file *f,
-                                         struct obj_section *targsec,
-                                         struct obj_section *symsec,
-                                         struct obj_symbol *sym,
-                                     ElfW(RelM) *rel, ElfW(Addr) v)
-{
-       struct arch_file *ifile = (struct arch_file *) f;
-#if !(defined(__mips__))
-       struct arch_symbol *isym = (struct arch_symbol *) sym;
-#endif
-
-       ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
-       ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
-#if defined(BB_USE_GOT_ENTRIES)
-       ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-       ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
-       struct arch_plt_entry *pe;
-       unsigned long *ip;
-#endif
-       enum obj_reloc ret = obj_reloc_ok;
-
-       switch (ELF32_R_TYPE(rel->r_info)) {
-
-/* even though these constants seem to be the same for
-   the i386 and the sh, we "#if define" them for clarity
-   and in case that ever changes */
-#if defined(__sh__)
-       case R_SH_NONE:
-#elif defined(__arm__)
-       case R_ARM_NONE:
-#elif defined(__i386__)
-       case R_386_NONE:
-#elif defined(__mc68000__) 
-       case R_68K_NONE:
-#elif defined(__powerpc__)
-       case R_PPC_NONE:
-#elif defined(__mips__)
-       case R_MIPS_NONE:
-#endif
-               break;
-
-#if defined(__sh__)
-       case R_SH_DIR32:
-#elif defined(__arm__)
-       case R_ARM_ABS32:
-#elif defined(__i386__)
-       case R_386_32:  
-#elif defined(__mc68000__) 
-       case R_68K_32:
-#elif defined(__powerpc__)
-       case R_PPC_ADDR32:
-#elif defined(__mips__)
-       case R_MIPS_32:
-#endif
-               *loc += v;
-               break;
-#if defined(__mc68000__)
-    case R_68K_8:
-               if (v > 0xff)
-               ret = obj_reloc_overflow;
-               *(char *)loc = v;
-               break;
-    case R_68K_16:
-               if (v > 0xffff)
-               ret = obj_reloc_overflow;
-               *(short *)loc = v;
-               break;
-#endif /* __mc68000__   */
-
-#if defined(__powerpc__)
-       case R_PPC_ADDR16_HA:
-               *(unsigned short *)loc = (v + 0x8000) >> 16;
-               break;
-
-       case R_PPC_ADDR16_HI:
-               *(unsigned short *)loc = v >> 16;
-               break;
-
-       case R_PPC_ADDR16_LO:
-               *(unsigned short *)loc = v;
-               break;
-#endif
-
-#if defined(__mips__)
-       case R_MIPS_26:
-               if (v % 4)
-                       ret = obj_reloc_dangerous;
-               if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
-                       ret = obj_reloc_overflow;
-               *loc =
-                   (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
-                                           0x03ffffff);
-               break;
-
-       case R_MIPS_HI16:
-               {
-                       struct mips_hi16 *n;
-
-                       /* We cannot relocate this one now because we don't know the value
-                          of the carry we need to add.  Save the information, and let LO16
-                          do the actual relocation.  */
-                       n = (struct mips_hi16 *) xmalloc(sizeof *n);
-                       n->addr = loc;
-                       n->value = v;
-                       n->next = ifile->mips_hi16_list;
-                       ifile->mips_hi16_list = n;
-                       break;
-               }
-
-       case R_MIPS_LO16:
-               {
-                       unsigned long insnlo = *loc;
-                       Elf32_Addr val, vallo;
-
-                       /* Sign extend the addend we extract from the lo insn.  */
-                       vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
-
-                       if (ifile->mips_hi16_list != NULL) {
-                               struct mips_hi16 *l;
-
-                               l = ifile->mips_hi16_list;
-                               while (l != NULL) {
-                                       struct mips_hi16 *next;
-                                       unsigned long insn;
-
-                                       /* The value for the HI16 had best be the same. */
-                                       assert(v == l->value);
-
-                                       /* Do the HI16 relocation.  Note that we actually don't
-                                          need to know anything about the LO16 itself, except where
-                                          to find the low 16 bits of the addend needed by the LO16.  */
-                                       insn = *l->addr;
-                                       val =
-                                           ((insn & 0xffff) << 16) +
-                                           vallo;
-                                       val += v;
-
-                                       /* Account for the sign extension that will happen in the
-                                          low bits.  */
-                                       val =
-                                           ((val >> 16) +
-                                            ((val & 0x8000) !=
-                                             0)) & 0xffff;
-
-                                       insn = (insn & ~0xffff) | val;
-                                       *l->addr = insn;
-
-                                       next = l->next;
-                                       free(l);
-                                       l = next;
-                               }
-
-                               ifile->mips_hi16_list = NULL;
-                       }
-
-                       /* Ok, we're done with the HI16 relocs.  Now deal with the LO16.  */
-                       val = v + vallo;
-                       insnlo = (insnlo & ~0xffff) | (val & 0xffff);
-                       *loc = insnlo;
-                       break;
-               }
-#endif
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_REL32:
-               *loc += v - dot;
-               break;
-#elif defined(__i386__)
-       case R_386_PLT32:
-       case R_386_PC32:
-               *loc += v - dot;
-               break;
-#elif defined(__mc68000__)
-    case R_68K_PC8:
-               v -= dot;
-               if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80)
-               ret = obj_reloc_overflow;
-               *(char *)loc = v;
-    break;
-               case R_68K_PC16:
-               v -= dot;
-               if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000)
-               ret = obj_reloc_overflow;
-               *(short *)loc = v;
-               break;
-    case R_68K_PC32:
-               *(int *)loc = v - dot;
-               break;
-#elif defined(__powerpc__)
-       case R_PPC_REL32:
-               *loc = v - dot;
-               break;
-#endif
-
-#if defined(__sh__)
-        case R_SH_PLT32:
-                *loc = v - dot;
-                break;
-#elif defined(__i386__)
-#endif
-
-#if defined(BB_USE_PLT_ENTRIES)
-
-#if defined(__arm__)
-    case R_ARM_PC24:
-    case R_ARM_PLT32:
-#endif
-#if defined(__powerpc__)
-       case R_PPC_REL24:
-#endif
-      /* find the plt entry and initialize it if necessary */
-      assert(isym != NULL);
-
-      pe = (struct arch_plt_entry*) &isym->pltent;
-
-      if (! pe->inited) {
-               ip = (unsigned long *) (ifile->plt->contents + pe->offset);
-
-               /* generate some machine code */
-
-#if defined(__arm__)
-               ip[0] = 0xe51ff004;                     /* ldr pc,[pc,#-4] */
-               ip[1] = v;                              /* sym@ */
-#endif
-#if defined(__powerpc__)
-         ip[0] = 0x3d600000 + ((v + 0x8000) >> 16);  /* lis r11,sym@ha */
-         ip[1] = 0x396b0000 + (v & 0xffff);          /* addi r11,r11,sym@l */
-         ip[2] = 0x7d6903a6;                         /* mtctr r11 */
-         ip[3] = 0x4e800420;                         /* bctr */
-#endif
-               pe->inited = 1;
-         }
-
-      /* relative distance to target */
-      v -= dot;
-      /* if the target is too far away.... */
-      if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
-           /* go via the plt */
-           v = plt + pe->offset - dot;
-         }
-      if (v & 3)
-           ret = obj_reloc_dangerous;
-
-      /* merge the offset into the instruction. */
-#if defined(__arm__)
-      /* Convert to words. */
-      v >>= 2;
-
-      *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
-#endif
-#if defined(__powerpc__)
-      *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
-#endif
-      break;
-#endif /* BB_USE_PLT_ENTRIES */
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_GLOB_DAT:
-        case R_SH_JMP_SLOT:
-                       *loc = v;
-                break;
-#elif defined(__i386__)
-       case R_386_GLOB_DAT:
-       case R_386_JMP_SLOT:
-               *loc = v;
-               break;
-#elif defined(__mc68000__)
-       case R_68K_GLOB_DAT:
-       case R_68K_JMP_SLOT:
-               *loc = v;
-               break;
-#endif
-
-#if defined(__arm__)
-#elif defined(__sh__)
-        case R_SH_RELATIVE:
-               *loc += f->baseaddr + rel->r_addend;
-                break;
-#elif defined(__i386__)
-        case R_386_RELATIVE:
-               *loc += f->baseaddr;
-               break;
-#elif defined(__mc68000__)
-    case R_68K_RELATIVE:
-       *(int *)loc += f->baseaddr;
-       break;
-#endif
-
-#if defined(BB_USE_GOT_ENTRIES)
-
-#if !defined(__68k__)
-#if defined(__sh__)
-        case R_SH_GOTPC:
-#elif defined(__arm__)
-    case R_ARM_GOTPC:
-#elif defined(__i386__)
-       case R_386_GOTPC:
-#endif
-               assert(got != 0);
-#if defined(__sh__)
-               *loc += got - dot + rel->r_addend;;
-#elif defined(__i386__) || defined(__arm__) || defined(__m68k_)
-               *loc += got - dot;
-#endif
-               break;
-#endif // __68k__
-
-#if defined(__sh__)
-       case R_SH_GOT32:
-#elif defined(__arm__)
-       case R_ARM_GOT32:
-#elif defined(__i386__)
-       case R_386_GOT32:
-#elif defined(__mc68000__)
-       case R_68K_GOT32:
-#endif
-               assert(isym != NULL);
-        /* needs an entry in the .got: set it, once */
-               if (!isym->gotent.reloc_done) {
-                       isym->gotent.reloc_done = 1;
-                       *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
-               }
-        /* make the reloc with_respect_to_.got */
-#if defined(__sh__)
-               *loc += isym->gotent.offset + rel->r_addend;
-#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
-               *loc += isym->gotent.offset;
-#endif
-               break;
-
-    /* address relative to the got */
-#if !defined(__mc68000__)
-#if defined(__sh__)
-       case R_SH_GOTOFF:
-#elif defined(__arm__)
-       case R_ARM_GOTOFF:
-#elif defined(__i386__)
-       case R_386_GOTOFF:
-#elif defined(__mc68000__)
-       case R_68K_GOTOFF:
-#endif
-               assert(got != 0);
-               *loc += v - got;
-               break;
-#endif // __mc68000__
-
-#endif /* BB_USE_GOT_ENTRIES */
-
-       default:
-        printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
-               ret = obj_reloc_unhandled;
-               break;
-       }
-
-       return ret;
-}
-
-static int arch_create_got(struct obj_file *f)
-{
-#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
-       struct arch_file *ifile = (struct arch_file *) f;
-       int i;
-#if defined(BB_USE_GOT_ENTRIES)
-       int got_offset = 0, gotneeded = 0;
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-       int plt_offset = 0, pltneeded = 0;
-#endif
-    struct obj_section *relsec, *symsec, *strsec;
-       ElfW(RelM) *rel, *relend;
-       ElfW(Sym) *symtab, *extsym;
-       const char *strtab, *name;
-       struct arch_symbol *intsym;
-
-       for (i = 0; i < f->header.e_shnum; ++i) {
-               relsec = f->sections[i];
-               if (relsec->header.sh_type != SHT_RELM)
-                       continue;
-
-               symsec = f->sections[relsec->header.sh_link];
-               strsec = f->sections[symsec->header.sh_link];
-
-               rel = (ElfW(RelM) *) relsec->contents;
-               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
-               symtab = (ElfW(Sym) *) symsec->contents;
-               strtab = (const char *) strsec->contents;
-
-               for (; rel < relend; ++rel) {
-                       extsym = &symtab[ELF32_R_SYM(rel->r_info)];
-
-                       switch (ELF32_R_TYPE(rel->r_info)) {
-#if defined(__arm__)
-                       case R_ARM_GOT32:
-                               break;
-#elif defined(__sh__)
-                       case R_SH_GOT32:
-                               break;
-#elif defined(__i386__)
-                       case R_386_GOT32:
-                               break;
-#elif defined(__mc68000__)
-                       case R_68K_GOT32:
-                               break;
-#endif
-
-#if defined(__powerpc__)
-                       case R_PPC_REL24:
-                               pltneeded = 1;
-                               break;
-#endif
-
-#if defined(__arm__)
-                       case R_ARM_PC24:
-                       case R_ARM_PLT32:
-                               pltneeded = 1;
-                               break;
-
-                       case R_ARM_GOTPC:
-                       case R_ARM_GOTOFF:
-                               gotneeded = 1;
-                               if (got_offset == 0)
-                                       got_offset = 4;
-#elif defined(__sh__)
-                       case R_SH_GOTPC:
-                       case R_SH_GOTOFF:
-                               gotneeded = 1;
-#elif defined(__i386__)
-                       case R_386_GOTPC:
-                       case R_386_GOTOFF:
-                               gotneeded = 1;
-#endif
-
-                       default:
-                               continue;
-                       }
-
-                       if (extsym->st_name != 0) {
-                               name = strtab + extsym->st_name;
-                       } else {
-                               name = f->sections[extsym->st_shndx]->name;
-                       }
-                       intsym = (struct arch_symbol *) obj_find_symbol(f, name);
-#if defined(BB_USE_GOT_ENTRIES)
-                       if (!intsym->gotent.offset_done) {
-                               intsym->gotent.offset_done = 1;
-                               intsym->gotent.offset = got_offset;
-                               got_offset += BB_GOT_ENTRY_SIZE;
-                       }
-#endif
-#if defined(BB_USE_PLT_ENTRIES)
-                       if (pltneeded && intsym->pltent.allocated == 0) {
-                               intsym->pltent.allocated = 1;
-                               intsym->pltent.offset = plt_offset;
-                               plt_offset += BB_PLT_ENTRY_SIZE;
-                               intsym->pltent.inited = 0;
-                               pltneeded = 0;
-                       }
-#endif
-                       }
-               }
-
-#if defined(BB_USE_GOT_ENTRIES)
-       if (got_offset) {
-               struct obj_section* myrelsec = obj_find_section(f, ".got");
-
-               if (myrelsec) {
-                       obj_extend_section(myrelsec, got_offset);
-               } else {
-                       myrelsec = obj_create_alloced_section(f, ".got", 
-                                                           BB_GOT_ENTRY_SIZE,
-                                                           got_offset);
-                       assert(myrelsec);
-               }
-
-               ifile->got = myrelsec;
-       }
-#endif
-
-#if defined(BB_USE_PLT_ENTRIES)
-       if (plt_offset)
-               ifile->plt = obj_create_alloced_section(f, ".plt", 
-                                                       BB_PLT_ENTRY_SIZE, 
-                                                       plt_offset);
-#endif
-#endif
-       return 1;
-}
-
-static int arch_init_module(struct obj_file *f, struct new_module *mod)
-{
-       return 1;
-}
-
-
-/*======================================================================*/
-
-/* Standard ELF hash function.  */
-static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n)
-{
-       unsigned long h = 0;
-       unsigned long g;
-       unsigned char ch;
-
-       while (n > 0) {
-               ch = *name++;
-               h = (h << 4) + ch;
-               if ((g = (h & 0xf0000000)) != 0) {
-                       h ^= g >> 24;
-                       h &= ~g;
-               }
-               n--;
-       }
-       return h;
-}
-
-static unsigned long obj_elf_hash(const char *name)
-{
-       return obj_elf_hash_n(name, strlen(name));
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-/* String comparison for non-co-versioned kernel and module.  */
-
-static int ncv_strcmp(const char *a, const char *b)
-{
-       size_t alen = strlen(a), blen = strlen(b);
-
-       if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
-               return strncmp(a, b, alen);
-       else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
-               return strncmp(a, b, blen);
-       else
-               return strcmp(a, b);
-}
-
-/* String hashing for non-co-versioned kernel and module.  Here
-   we are simply forced to drop the crc from the hash.  */
-
-static unsigned long ncv_symbol_hash(const char *str)
-{
-       size_t len = strlen(str);
-       if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
-               len -= 10;
-       return obj_elf_hash_n(str, len);
-}
-
-static void
-obj_set_symbol_compare(struct obj_file *f,
-                                          int (*cmp) (const char *, const char *),
-                                          unsigned long (*hash) (const char *))
-{
-       if (cmp)
-               f->symbol_cmp = cmp;
-       if (hash) {
-               struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
-               int i;
-
-               f->symbol_hash = hash;
-
-               memcpy(tmptab, f->symtab, sizeof(tmptab));
-               memset(f->symtab, 0, sizeof(f->symtab));
-
-               for (i = 0; i < HASH_BUCKETS; ++i)
-                       for (sym = tmptab[i]; sym; sym = next) {
-                               unsigned long h = hash(sym->name) % HASH_BUCKETS;
-                               next = sym->next;
-                               sym->next = f->symtab[h];
-                               f->symtab[h] = sym;
-                       }
-       }
-}
-
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-static struct obj_symbol *
-obj_add_symbol(struct obj_file *f, const char *name,
-                                                                 unsigned long symidx, int info,
-                                                                 int secidx, ElfW(Addr) value,
-                                                                 unsigned long size)
-{
-       struct obj_symbol *sym;
-       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
-       int n_type = ELFW(ST_TYPE) (info);
-       int n_binding = ELFW(ST_BIND) (info);
-
-       for (sym = f->symtab[hash]; sym; sym = sym->next)
-               if (f->symbol_cmp(sym->name, name) == 0) {
-                       int o_secidx = sym->secidx;
-                       int o_info = sym->info;
-                       int o_type = ELFW(ST_TYPE) (o_info);
-                       int o_binding = ELFW(ST_BIND) (o_info);
-
-                       /* A redefinition!  Is it legal?  */
-
-                       if (secidx == SHN_UNDEF)
-                               return sym;
-                       else if (o_secidx == SHN_UNDEF)
-                               goto found;
-                       else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
-                               /* Cope with local and global symbols of the same name
-                                  in the same object file, as might have been created
-                                  by ld -r.  The only reason locals are now seen at this
-                                  level at all is so that we can do semi-sensible things
-                                  with parameters.  */
-
-                               struct obj_symbol *nsym, **p;
-
-                               nsym = arch_new_symbol();
-                               nsym->next = sym->next;
-                               nsym->ksymidx = -1;
-
-                               /* Excise the old (local) symbol from the hash chain.  */
-                               for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
-                                       continue;
-                               *p = sym = nsym;
-                               goto found;
-                       } else if (n_binding == STB_LOCAL) {
-                               /* Another symbol of the same name has already been defined.
-                                  Just add this to the local table.  */
-                               sym = arch_new_symbol();
-                               sym->next = NULL;
-                               sym->ksymidx = -1;
-                               f->local_symtab[symidx] = sym;
-                               goto found;
-                       } else if (n_binding == STB_WEAK)
-                               return sym;
-                       else if (o_binding == STB_WEAK)
-                               goto found;
-                       /* Don't unify COMMON symbols with object types the programmer
-                          doesn't expect.  */
-                       else if (secidx == SHN_COMMON
-                                        && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
-                               return sym;
-                       else if (o_secidx == SHN_COMMON
-                                        && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
-                               goto found;
-                       else {
-                               /* Don't report an error if the symbol is coming from
-                                  the kernel or some external module.  */
-                               if (secidx <= SHN_HIRESERVE)
-                                       error_msg("%s multiply defined", name);
-                               return sym;
-                       }
-               }
-
-       /* Completely new symbol.  */
-       sym = arch_new_symbol();
-       sym->next = f->symtab[hash];
-       f->symtab[hash] = sym;
-       sym->ksymidx = -1;
-
-       if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
-               if (symidx >= f->local_symtab_size)
-                       error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
-                                       name, (long) symidx, (long) f->local_symtab_size);
-               else
-                       f->local_symtab[symidx] = sym;
-       }
-
-  found:
-       sym->name = name;
-       sym->value = value;
-       sym->size = size;
-       sym->secidx = secidx;
-       sym->info = info;
-
-       return sym;
-}
-
-static struct obj_symbol *
-obj_find_symbol(struct obj_file *f, const char *name)
-{
-       struct obj_symbol *sym;
-       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
-
-       for (sym = f->symtab[hash]; sym; sym = sym->next)
-               if (f->symbol_cmp(sym->name, name) == 0)
-                       return sym;
-
-       return NULL;
-}
-
-static ElfW(Addr)
-       obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
-{
-       if (sym) {
-               if (sym->secidx >= SHN_LORESERVE)
-                       return sym->value;
-
-               return sym->value + f->sections[sym->secidx]->header.sh_addr;
-       } else {
-               /* As a special case, a NULL sym has value zero.  */
-               return 0;
-       }
-}
-
-static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
-{
-       int i, n = f->header.e_shnum;
-
-       for (i = 0; i < n; ++i)
-               if (strcmp(f->sections[i]->name, name) == 0)
-                       return f->sections[i];
-
-       return NULL;
-}
-
-static int obj_load_order_prio(struct obj_section *a)
-{
-       unsigned long af, ac;
-
-       af = a->header.sh_flags;
-
-       ac = 0;
-       if (a->name[0] != '.' || strlen(a->name) != 10 ||
-               strcmp(a->name + 5, ".init"))
-               ac |= 32;
-       if (af & SHF_ALLOC)
-               ac |= 16;
-       if (!(af & SHF_WRITE))
-               ac |= 8;
-       if (af & SHF_EXECINSTR)
-               ac |= 4;
-       if (a->header.sh_type != SHT_NOBITS)
-               ac |= 2;
-
-       return ac;
-}
-
-static void
-obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
-{
-       struct obj_section **p;
-       int prio = obj_load_order_prio(sec);
-       for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
-               if (obj_load_order_prio(*p) < prio)
-                       break;
-       sec->load_next = *p;
-       *p = sec;
-}
-
-static struct obj_section *obj_create_alloced_section(struct obj_file *f,
-                                                                                          const char *name,
-                                                                                          unsigned long align,
-                                                                                          unsigned long size)
-{
-       int newidx = f->header.e_shnum++;
-       struct obj_section *sec;
-
-       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
-       f->sections[newidx] = sec = arch_new_section();
-
-       memset(sec, 0, sizeof(*sec));
-       sec->header.sh_type = SHT_PROGBITS;
-       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-       sec->header.sh_size = size;
-       sec->header.sh_addralign = align;
-       sec->name = name;
-       sec->idx = newidx;
-       if (size)
-               sec->contents = xmalloc(size);
-
-       obj_insert_section_load_order(f, sec);
-
-       return sec;
-}
-
-static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
-                                                                                                        const char *name,
-                                                                                                        unsigned long align,
-                                                                                                        unsigned long size)
-{
-       int newidx = f->header.e_shnum++;
-       struct obj_section *sec;
-
-       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
-       f->sections[newidx] = sec = arch_new_section();
-
-       memset(sec, 0, sizeof(*sec));
-       sec->header.sh_type = SHT_PROGBITS;
-       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-       sec->header.sh_size = size;
-       sec->header.sh_addralign = align;
-       sec->name = name;
-       sec->idx = newidx;
-       if (size)
-               sec->contents = xmalloc(size);
-
-       sec->load_next = f->load_order;
-       f->load_order = sec;
-       if (f->load_order_search_start == &f->load_order)
-               f->load_order_search_start = &sec->load_next;
-
-       return sec;
-}
-
-static void *obj_extend_section(struct obj_section *sec, unsigned long more)
-{
-       unsigned long oldsize = sec->header.sh_size;
-       if (more) { 
-               sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
-       }
-       return sec->contents + oldsize;
-}
-
-
-/* Conditionally add the symbols from the given symbol set to the
-   new module.  */
-
-static int
-add_symbols_from(
-                                struct obj_file *f,
-                                int idx, struct new_module_symbol *syms, size_t nsyms)
-{
-       struct new_module_symbol *s;
-       size_t i;
-       int used = 0;
-
-       for (i = 0, s = syms; i < nsyms; ++i, ++s) {
-
-               /* Only add symbols that are already marked external.  If we
-                  override locals we may cause problems for argument initialization.
-                  We will also create a false dependency on the module.  */
-               struct obj_symbol *sym;
-
-               sym = obj_find_symbol(f, (char *) s->name);
-               if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
-                       sym = obj_add_symbol(f, (char *) s->name, -1,
-                                                                ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
-                                                                idx, s->value, 0);
-                       /* Did our symbol just get installed?  If so, mark the
-                          module as "used".  */
-                       if (sym->secidx == idx)
-                               used = 1;
-               }
-       }
-
-       return used;
-}
-
-static void add_kernel_symbols(struct obj_file *f)
-{
-       struct external_module *m;
-       int i, nused = 0;
-
-       /* Add module symbols first.  */
-
-       for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m)
-               if (m->nsyms
-                       && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms,
-                                                               m->nsyms)) m->used = 1, ++nused;
-
-       n_ext_modules_used = nused;
-
-       /* And finally the symbols from the kernel proper.  */
-
-       if (nksyms)
-               add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
-}
-
-static char *get_modinfo_value(struct obj_file *f, const char *key)
-{
-       struct obj_section *sec;
-       char *p, *v, *n, *ep;
-       size_t klen = strlen(key);
-
-       sec = obj_find_section(f, ".modinfo");
-       if (sec == NULL)
-               return NULL;
-       p = sec->contents;
-       ep = p + sec->header.sh_size;
-       while (p < ep) {
-               v = strchr(p, '=');
-               n = strchr(p, '\0');
-               if (v) {
-                       if (p + klen == v && strncmp(p, key, klen) == 0)
-                               return v + 1;
-               } else {
-                       if (p + klen == n && strcmp(p, key) == 0)
-                               return n;
-               }
-               p = n + 1;
-       }
-
-       return NULL;
-}
-
-
-/*======================================================================*/
-/* Functions relating to module loading in pre 2.1 kernels.  */
-
-static int
-old_process_module_arguments(struct obj_file *f, int argc, char **argv)
-{
-       while (argc > 0) {
-               char *p, *q;
-               struct obj_symbol *sym;
-               int *loc;
-
-               p = *argv;
-               if ((q = strchr(p, '=')) == NULL) {
-                       argc--;
-                       continue;
-                }
-               *q++ = '\0';
-
-               sym = obj_find_symbol(f, p);
-
-               /* Also check that the parameter was not resolved from the kernel.  */
-               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
-                       error_msg("symbol for parameter %s not found", p);
-                       return 0;
-               }
-
-               loc = (int *) (f->sections[sym->secidx]->contents + sym->value);
-
-               /* Do C quoting if we begin with a ".  */
-               if (*q == '"') {
-                       char *r, *str;
-
-                       str = alloca(strlen(q));
-                       for (r = str, q++; *q != '"'; ++q, ++r) {
-                               if (*q == '\0') {
-                                       error_msg("improperly terminated string argument for %s", p);
-                                       return 0;
-                               } else if (*q == '\\')
-                                       switch (*++q) {
-                                       case 'a':
-                                               *r = '\a';
-                                               break;
-                                       case 'b':
-                                               *r = '\b';
-                                               break;
-                                       case 'e':
-                                               *r = '\033';
-                                               break;
-                                       case 'f':
-                                               *r = '\f';
-                                               break;
-                                       case 'n':
-                                               *r = '\n';
-                                               break;
-                                       case 'r':
-                                               *r = '\r';
-                                               break;
-                                       case 't':
-                                               *r = '\t';
-                                               break;
-
-                                       case '0':
-                                       case '1':
-                                       case '2':
-                                       case '3':
-                                       case '4':
-                                       case '5':
-                                       case '6':
-                                       case '7':
-                                               {
-                                                       int c = *q - '0';
-                                                       if (q[1] >= '0' && q[1] <= '7') {
-                                                               c = (c * 8) + *++q - '0';
-                                                               if (q[1] >= '0' && q[1] <= '7')
-                                                                       c = (c * 8) + *++q - '0';
-                                                       }
-                                                       *r = c;
-                                               }
-                                               break;
-
-                                       default:
-                                               *r = *q;
-                                               break;
-                               } else
-                                       *r = *q;
-                       }
-                       *r = '\0';
-                       obj_string_patch(f, sym->secidx, sym->value, str);
-               } else if (*q >= '0' && *q <= '9') {
-                       do
-                               *loc++ = strtoul(q, &q, 0);
-                       while (*q++ == ',');
-               } else {
-                       char *contents = f->sections[sym->secidx]->contents;
-                       char *myloc = contents + sym->value;
-                       char *r;                        /* To search for commas */
-
-                       /* Break the string with comas */
-                       while ((r = strchr(q, ',')) != (char *) NULL) {
-                               *r++ = '\0';
-                               obj_string_patch(f, sym->secidx, myloc - contents, q);
-                               myloc += sizeof(char *);
-                               q = r;
-                       }
-
-                       /* last part */
-                       obj_string_patch(f, sym->secidx, myloc - contents, q);
-               }
-
-               argc--, argv++;
-       }
-
-       return 1;
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static int old_is_module_checksummed(struct obj_file *f)
-{
-       return obj_find_symbol(f, "Using_Versions") != NULL;
-}
-/* Get the module's kernel version in the canonical integer form.  */
-
-static int
-old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
-{
-       struct obj_symbol *sym;
-       char *p, *q;
-       int a, b, c;
-
-       sym = obj_find_symbol(f, "kernel_version");
-       if (sym == NULL)
-               return -1;
-
-       p = f->sections[sym->secidx]->contents + sym->value;
-       strncpy(str, p, STRVERSIONLEN);
-
-       a = strtoul(p, &p, 10);
-       if (*p != '.')
-               return -1;
-       b = strtoul(p + 1, &p, 10);
-       if (*p != '.')
-               return -1;
-       c = strtoul(p + 1, &q, 10);
-       if (p + 1 == q)
-               return -1;
-
-       return a << 16 | b << 8 | c;
-}
-
-#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
-
-/* Fetch all the symbols and divvy them up as appropriate for the modules.  */
-
-static int old_get_kernel_symbols(const char *m_name)
-{
-       struct old_kernel_sym *ks, *k;
-       struct new_module_symbol *s;
-       struct external_module *mod;
-       int nks, nms, nmod, i;
-
-       nks = get_kernel_syms(NULL);
-       if (nks <= 0) {
-               if (nks)
-                       perror_msg("get_kernel_syms: %s", m_name);
-               else
-                       error_msg("No kernel symbols");
-               return 0;
-       }
-
-       ks = k = xmalloc(nks * sizeof(*ks));
-
-       if (get_kernel_syms(ks) != nks) {
-               perror("inconsistency with get_kernel_syms -- is someone else "
-                          "playing with modules?");
-               free(ks);
-               return 0;
-       }
-
-       /* Collect the module information.  */
-
-       mod = NULL;
-       nmod = -1;
-
-       while (k->name[0] == '#' && k->name[1]) {
-               struct old_kernel_sym *k2;
-
-               /* Find out how many symbols this module has.  */
-               for (k2 = k + 1; k2->name[0] != '#'; ++k2)
-                       continue;
-               nms = k2 - k - 1;
-
-               mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod));
-               mod[nmod].name = k->name + 1;
-               mod[nmod].addr = k->value;
-               mod[nmod].used = 0;
-               mod[nmod].nsyms = nms;
-               mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
-
-               for (i = 0, ++k; i < nms; ++i, ++s, ++k) {
-                       s->name = (unsigned long) k->name;
-                       s->value = k->value;
-               }
-
-               k = k2;
-       }
-
-       ext_modules = mod;
-       n_ext_modules = nmod + 1;
-
-       /* Now collect the symbols for the kernel proper.  */
-
-       if (k->name[0] == '#')
-               ++k;
-
-       nksyms = nms = nks - (k - ks);
-       ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
-
-       for (i = 0; i < nms; ++i, ++s, ++k) {
-               s->name = (unsigned long) k->name;
-               s->value = k->value;
-       }
-
-       return 1;
-}
-
-/* Return the kernel symbol checksum version, or zero if not used.  */
-
-static int old_is_kernel_checksummed(void)
-{
-       /* Using_Versions is the first symbol.  */
-       if (nksyms > 0
-               && strcmp((char *) ksyms[0].name,
-                                 "Using_Versions") == 0) return ksyms[0].value;
-       else
-               return 0;
-}
-
-
-static int old_create_mod_use_count(struct obj_file *f)
-{
-       struct obj_section *sec;
-
-       sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long),
-                                                                                  sizeof(long));
-
-       obj_add_symbol(f, "mod_use_count_", -1,
-                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
-                                  sizeof(long));
-
-       return 1;
-}
-
-static int
-old_init_module(const char *m_name, struct obj_file *f,
-                               unsigned long m_size)
-{
-       char *image;
-       struct old_mod_routines routines;
-       struct old_symbol_table *symtab;
-       int ret;
-
-       /* Create the symbol table */
-       {
-               int nsyms = 0, strsize = 0, total;
-
-               /* Size things first... */
-               if (flag_export) {
-                       int i;
-                       for (i = 0; i < HASH_BUCKETS; ++i) {
-                               struct obj_symbol *sym;
-                               for (sym = f->symtab[i]; sym; sym = sym->next)
-                                       if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
-                                               && sym->secidx <= SHN_HIRESERVE) 
-                                       {
-                                               sym->ksymidx = nsyms++;
-                                               strsize += strlen(sym->name) + 1;
-                                       }
-                       }
-               }
-
-               total = (sizeof(struct old_symbol_table)
-                                + nsyms * sizeof(struct old_module_symbol)
-                                + n_ext_modules_used * sizeof(struct old_module_ref)
-                                + strsize);
-               symtab = xmalloc(total);
-               symtab->size = total;
-               symtab->n_symbols = nsyms;
-               symtab->n_refs = n_ext_modules_used;
-
-               if (flag_export && nsyms) {
-                       struct old_module_symbol *ksym;
-                       char *str;
-                       int i;
-
-                       ksym = symtab->symbol;
-                       str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol)
-                                  + n_ext_modules_used * sizeof(struct old_module_ref));
-
-                       for (i = 0; i < HASH_BUCKETS; ++i) {
-                               struct obj_symbol *sym;
-                               for (sym = f->symtab[i]; sym; sym = sym->next)
-                                       if (sym->ksymidx >= 0) {
-                                               ksym->addr = obj_symbol_final_value(f, sym);
-                                               ksym->name =
-                                                       (unsigned long) str - (unsigned long) symtab;
-
-                                               strcpy(str, sym->name);
-                                               str += strlen(sym->name) + 1;
-                                               ksym++;
-                                       }
-                       }
-               }
-
-               if (n_ext_modules_used) {
-                       struct old_module_ref *ref;
-                       int i;
-
-                       ref = (struct old_module_ref *)
-                               ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
-
-                       for (i = 0; i < n_ext_modules; ++i)
-                               if (ext_modules[i].used)
-                                       ref++->module = ext_modules[i].addr;
-               }
-       }
-
-       /* Fill in routines.  */
-
-       routines.init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
-       routines.cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
-
-       /* Whew!  All of the initialization is complete.  Collect the final
-          module image and give it to the kernel.  */
-
-       image = xmalloc(m_size);
-       obj_create_image(f, image);
-
-       /* image holds the complete relocated module, accounting correctly for
-          mod_use_count.  However the old module kernel support assume that
-          it is receiving something which does not contain mod_use_count.  */
-       ret = old_sys_init_module(m_name, image + sizeof(long),
-                                                         m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN
-                                                                               : 0), &routines, symtab);
-       if (ret)
-               perror_msg("init_module: %s", m_name);
-
-       free(image);
-       free(symtab);
-
-       return ret == 0;
-}
-
-#else
-
-#define old_create_mod_use_count(x) TRUE
-#define old_init_module(x, y, z) TRUE
-
-#endif                                                 /* BB_FEATURE_OLD_MODULE_INTERFACE */
-
-
-
-/*======================================================================*/
-/* Functions relating to module loading after 2.1.18.  */
-
-static int
-new_process_module_arguments(struct obj_file *f, int argc, char **argv)
-{
-       while (argc > 0) {
-               char *p, *q, *key;
-               struct obj_symbol *sym;
-               char *contents, *loc;
-               int min, max, n;
-
-               p = *argv;
-               if ((q = strchr(p, '=')) == NULL) {
-                       argc--;
-                       continue;
-                }
-
-               key = alloca(q - p + 6);
-               memcpy(key, "parm_", 5);
-               memcpy(key + 5, p, q - p);
-               key[q - p + 5] = 0;
-
-               p = get_modinfo_value(f, key);
-               key += 5;
-               if (p == NULL) {
-                       error_msg("invalid parameter %s", key);
-                       return 0;
-               }
-
-               sym = obj_find_symbol(f, key);
-
-               /* Also check that the parameter was not resolved from the kernel.  */
-               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
-                       error_msg("symbol for parameter %s not found", key);
-                       return 0;
-               }
-
-               if (isdigit(*p)) {
-                       min = strtoul(p, &p, 10);
-                       if (*p == '-')
-                               max = strtoul(p + 1, &p, 10);
-                       else
-                               max = min;
-               } else
-                       min = max = 1;
-
-               contents = f->sections[sym->secidx]->contents;
-               loc = contents + sym->value;
-               n = (*++q != '\0');
-
-               while (1) {
-                       if ((*p == 's') || (*p == 'c')) {
-                               char *str;
-
-                               /* Do C quoting if we begin with a ", else slurp the lot.  */
-                               if (*q == '"') {
-                                       char *r;
-
-                                       str = alloca(strlen(q));
-                                       for (r = str, q++; *q != '"'; ++q, ++r) {
-                                               if (*q == '\0') {
-                                                       error_msg("improperly terminated string argument for %s",
-                                                                       key);
-                                                       return 0;
-                                               } else if (*q == '\\')
-                                                       switch (*++q) {
-                                                       case 'a':
-                                                               *r = '\a';
-                                                               break;
-                                                       case 'b':
-                                                               *r = '\b';
-                                                               break;
-                                                       case 'e':
-                                                               *r = '\033';
-                                                               break;
-                                                       case 'f':
-                                                               *r = '\f';
-                                                               break;
-                                                       case 'n':
-                                                               *r = '\n';
-                                                               break;
-                                                       case 'r':
-                                                               *r = '\r';
-                                                               break;
-                                                       case 't':
-                                                               *r = '\t';
-                                                               break;
-
-                                                       case '0':
-                                                       case '1':
-                                                       case '2':
-                                                       case '3':
-                                                       case '4':
-                                                       case '5':
-                                                       case '6':
-                                                       case '7':
-                                                               {
-                                                                       int c = *q - '0';
-                                                                       if (q[1] >= '0' && q[1] <= '7') {
-                                                                               c = (c * 8) + *++q - '0';
-                                                                               if (q[1] >= '0' && q[1] <= '7')
-                                                                                       c = (c * 8) + *++q - '0';
-                                                                       }
-                                                                       *r = c;
-                                                               }
-                                                               break;
-
-                                                       default:
-                                                               *r = *q;
-                                                               break;
-                                               } else
-                                                       *r = *q;
-                                       }
-                                       *r = '\0';
-                                       ++q;
-                               } else {
-                                       char *r;
-
-                                       /* In this case, the string is not quoted. We will break
-                                          it using the coma (like for ints). If the user wants to
-                                          include comas in a string, he just has to quote it */
-
-                                       /* Search the next coma */
-                                       r = strchr(q, ',');
-
-                                       /* Found ? */
-                                       if (r != (char *) NULL) {
-                                               /* Recopy the current field */
-                                               str = alloca(r - q + 1);
-                                               memcpy(str, q, r - q);
-
-                                               /* I don't know if it is usefull, as the previous case
-                                                  doesn't null terminate the string ??? */
-                                               str[r - q] = '\0';
-
-                                               /* Keep next fields */
-                                               q = r;
-                                       } else {
-                                               /* last string */
-                                               str = q;
-                                               q = "";
-                                       }
-                               }
-
-                               if (*p == 's') {
-                                       /* Normal string */
-                                       obj_string_patch(f, sym->secidx, loc - contents, str);
-                                       loc += tgt_sizeof_char_p;
-                               } else {
-                                       /* Array of chars (in fact, matrix !) */
-                                       unsigned long charssize;        /* size of each member */
-
-                                       /* Get the size of each member */
-                                       /* Probably we should do that outside the loop ? */
-                                       if (!isdigit(*(p + 1))) {
-                                               error_msg("parameter type 'c' for %s must be followed by"
-                                                               " the maximum size", key);
-                                               return 0;
-                                       }
-                                       charssize = strtoul(p + 1, (char **) NULL, 10);
-
-                                       /* Check length */
-                                       if (strlen(str) >= charssize) {
-                                               error_msg("string too long for %s (max %ld)", key,
-                                                               charssize - 1);
-                                               return 0;
-                                       }
-
-                                       /* Copy to location */
-                                       strcpy((char *) loc, str);
-                                       loc += charssize;
-                               }
-                       } else {
-                               long v = strtoul(q, &q, 0);
-                               switch (*p) {
-                               case 'b':
-                                       *loc++ = v;
-                                       break;
-                               case 'h':
-                                       *(short *) loc = v;
-                                       loc += tgt_sizeof_short;
-                                       break;
-                               case 'i':
-                                       *(int *) loc = v;
-                                       loc += tgt_sizeof_int;
-                                       break;
-                               case 'l':
-                                       *(long *) loc = v;
-                                       loc += tgt_sizeof_long;
-                                       break;
-
-                               default:
-                                       error_msg("unknown parameter type '%c' for %s", *p, key);
-                                       return 0;
-                               }
-                       }
-
-                 retry_end_of_value:
-                       switch (*q) {
-                       case '\0':
-                               goto end_of_arg;
-
-                       case ' ':
-                       case '\t':
-                       case '\n':
-                       case '\r':
-                               ++q;
-                               goto retry_end_of_value;
-
-                       case ',':
-                               if (++n > max) {
-                                       error_msg("too many values for %s (max %d)", key, max);
-                                       return 0;
-                               }
-                               ++q;
-                               break;
-
-                       default:
-                               error_msg("invalid argument syntax for %s", key);
-                               return 0;
-                       }
-               }
-
-         end_of_arg:
-               if (n < min) {
-                       error_msg("too few values for %s (min %d)", key, min);
-                       return 0;
-               }
-
-               argc--, argv++;
-       }
-
-       return 1;
-}
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-static int new_is_module_checksummed(struct obj_file *f)
-{
-       const char *p = get_modinfo_value(f, "using_checksums");
-       if (p)
-               return atoi(p);
-       else
-               return 0;
-}
-
-/* Get the module's kernel version in the canonical integer form.  */
-
-static int
-new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
-{
-       char *p, *q;
-       int a, b, c;
-
-       p = get_modinfo_value(f, "kernel_version");
-       if (p == NULL)
-               return -1;
-       strncpy(str, p, STRVERSIONLEN);
-
-       a = strtoul(p, &p, 10);
-       if (*p != '.')
-               return -1;
-       b = strtoul(p + 1, &p, 10);
-       if (*p != '.')
-               return -1;
-       c = strtoul(p + 1, &q, 10);
-       if (p + 1 == q)
-               return -1;
-
-       return a << 16 | b << 8 | c;
-}
-
-#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-
-/* Fetch the loaded modules, and all currently exported symbols.  */
-
-static int new_get_kernel_symbols(void)
-{
-       char *module_names, *mn;
-       struct external_module *modules, *m;
-       struct new_module_symbol *syms, *s;
-       size_t ret, bufsize, nmod, nsyms, i, j;
-
-       /* Collect the loaded modules.  */
-
-       module_names = xmalloc(bufsize = 256);
-  retry_modules_load:
-       if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
-               if (errno == ENOSPC && bufsize < ret) {
-                       module_names = xrealloc(module_names, bufsize = ret);
-                       goto retry_modules_load;
-               }
-               perror_msg("QM_MODULES");
-               return 0;
-       }
-
-       n_ext_modules = nmod = ret;
-
-       /* Collect the modules' symbols.  */
-
-       if (nmod){
-               ext_modules = modules = xmalloc(nmod * sizeof(*modules));
-               memset(modules, 0, nmod * sizeof(*modules));
-               for (i = 0, mn = module_names, m = modules;
-                        i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
-                       struct new_module_info info;
-       
-                       if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
-                               if (errno == ENOENT) {
-                                       /* The module was removed out from underneath us.  */
-                                       continue;
-                               }
-                               perror_msg("query_module: QM_INFO: %s", mn);
-                               return 0;
-                       }
-       
-                       syms = xmalloc(bufsize = 1024);
-                 retry_mod_sym_load:
-                       if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
-                               switch (errno) {
-                               case ENOSPC:
-                                       syms = xrealloc(syms, bufsize = ret);
-                                       goto retry_mod_sym_load;
-                               case ENOENT:
-                                       /* The module was removed out from underneath us.  */
-                                       continue;
-                               default:
-                                       perror_msg("query_module: QM_SYMBOLS: %s", mn);
-                                       return 0;
-                               }
-                       }
-                       nsyms = ret;
-       
-                       m->name = mn;
-                       m->addr = info.addr;
-                       m->nsyms = nsyms;
-                       m->syms = syms;
-       
-                       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
-                               s->name += (unsigned long) syms;
-                       }
-               }
-       }
-
-       /* Collect the kernel's symbols.  */
-
-       syms = xmalloc(bufsize = 16 * 1024);
-  retry_kern_sym_load:
-       if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
-               if (errno == ENOSPC && bufsize < ret) {
-                       syms = xrealloc(syms, bufsize = ret);
-                       goto retry_kern_sym_load;
-               }
-               perror_msg("kernel: QM_SYMBOLS");
-               return 0;
-       }
-       nksyms = nsyms = ret;
-       ksyms = syms;
-
-       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
-               s->name += (unsigned long) syms;
-       }
-       return 1;
-}
-
-
-/* Return the kernel symbol checksum version, or zero if not used.  */
-
-static int new_is_kernel_checksummed(void)
-{
-       struct new_module_symbol *s;
-       size_t i;
-
-       /* Using_Versions is not the first symbol, but it should be in there.  */
-
-       for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
-               if (strcmp((char *) s->name, "Using_Versions") == 0)
-                       return s->value;
-
-       return 0;
-}
-
-
-static int new_create_this_module(struct obj_file *f, const char *m_name)
-{
-       struct obj_section *sec;
-
-       sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
-                                                                                  sizeof(struct new_module));
-       memset(sec->contents, 0, sizeof(struct new_module));
-
-       obj_add_symbol(f, "__this_module", -1,
-                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
-                                  sizeof(struct new_module));
-
-       obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
-                                        m_name);
-
-       return 1;
-}
-
-
-static int new_create_module_ksymtab(struct obj_file *f)
-{
-       struct obj_section *sec;
-       int i;
-
-       /* We must always add the module references.  */
-
-       if (n_ext_modules_used) {
-               struct new_module_ref *dep;
-               struct obj_symbol *tm;
-
-               sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
-                                                                                (sizeof(struct new_module_ref)
-                                                                                 * n_ext_modules_used));
-               if (!sec)
-                       return 0;
-
-               tm = obj_find_symbol(f, "__this_module");
-               dep = (struct new_module_ref *) sec->contents;
-               for (i = 0; i < n_ext_modules; ++i)
-                       if (ext_modules[i].used) {
-                               dep->dep = ext_modules[i].addr;
-                               obj_symbol_patch(f, sec->idx,
-                                                                (char *) &dep->ref - sec->contents, tm);
-                               dep->next_ref = 0;
-                               ++dep;
-                       }
-       }
-
-       if (flag_export && !obj_find_section(f, "__ksymtab")) {
-               size_t nsyms;
-               int *loaded;
-
-               sec =
-                       obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p,
-                                                                          0);
-
-               /* We don't want to export symbols residing in sections that
-                  aren't loaded.  There are a number of these created so that
-                  we make sure certain module options don't appear twice.  */
-
-               loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
-               while (--i >= 0)
-                       loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
-
-               for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
-                       struct obj_symbol *sym;
-                       for (sym = f->symtab[i]; sym; sym = sym->next)
-                               if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
-                                       && sym->secidx <= SHN_HIRESERVE
-                                       && (sym->secidx >= SHN_LORESERVE
-                                               || loaded[sym->secidx])) {
-                                       ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
-
-                                       obj_symbol_patch(f, sec->idx, ofs, sym);
-                                       obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
-                                                                        sym->name);
-
-                                       nsyms++;
-                               }
-               }
-
-               obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
-       }
-
-       return 1;
-}
-
-
-static int
-new_init_module(const char *m_name, struct obj_file *f,
-                               unsigned long m_size)
-{
-       struct new_module *module;
-       struct obj_section *sec;
-       void *image;
-       int ret;
-       tgt_long m_addr;
-
-       sec = obj_find_section(f, ".this");
-       if (!sec || !sec->contents) { 
-               perror_msg_and_die("corrupt module %s?",m_name);
-       }
-       module = (struct new_module *) sec->contents;
-       m_addr = sec->header.sh_addr;
-
-       module->size_of_struct = sizeof(*module);
-       module->size = m_size;
-       module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
-
-       sec = obj_find_section(f, "__ksymtab");
-       if (sec && sec->header.sh_size) {
-               module->syms = sec->header.sh_addr;
-               module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
-       }
-
-       if (n_ext_modules_used) {
-               sec = obj_find_section(f, ".kmodtab");
-               module->deps = sec->header.sh_addr;
-               module->ndeps = n_ext_modules_used;
-       }
-
-       module->init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
-       module->cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
-
-       sec = obj_find_section(f, "__ex_table");
-       if (sec) {
-               module->ex_table_start = sec->header.sh_addr;
-               module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
-       }
-
-       sec = obj_find_section(f, ".text.init");
-       if (sec) {
-               module->runsize = sec->header.sh_addr - m_addr;
-       }
-       sec = obj_find_section(f, ".data.init");
-       if (sec) {
-               if (!module->runsize ||
-                       module->runsize > sec->header.sh_addr - m_addr)
-                               module->runsize = sec->header.sh_addr - m_addr;
-       }
-       sec = obj_find_section(f, ARCHDATA_SEC_NAME);
-       if (sec && sec->header.sh_size) {
-               module->archdata_start = (void*)sec->header.sh_addr;
-               module->archdata_end = module->archdata_start + sec->header.sh_size;
-       }
-       sec = obj_find_section(f, KALLSYMS_SEC_NAME);
-       if (sec && sec->header.sh_size) {
-               module->kallsyms_start = (void*)sec->header.sh_addr;
-               module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
-       }
-
-       if (!arch_init_module(f, module))
-               return 0;
-
-       /* Whew!  All of the initialization is complete.  Collect the final
-          module image and give it to the kernel.  */
-
-       image = xmalloc(m_size);
-       obj_create_image(f, image);
-
-       ret = new_sys_init_module(m_name, (struct new_module *) image);
-       if (ret)
-               perror_msg("init_module: %s", m_name);
-
-       free(image);
-
-       return ret == 0;
-}
-
-#else
-
-#define new_init_module(x, y, z) TRUE
-#define new_create_this_module(x, y) 0
-#define new_create_module_ksymtab(x)
-#define query_module(v, w, x, y, z) -1
-
-#endif                                                 /* BB_FEATURE_NEW_MODULE_INTERFACE */
-
-
-/*======================================================================*/
-
-static int
-obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                                const char *string)
-{
-       struct obj_string_patch *p;
-       struct obj_section *strsec;
-       size_t len = strlen(string) + 1;
-       char *loc;
-
-       p = xmalloc(sizeof(*p));
-       p->next = f->string_patches;
-       p->reloc_secidx = secidx;
-       p->reloc_offset = offset;
-       f->string_patches = p;
-
-       strsec = obj_find_section(f, ".kstrtab");
-       if (strsec == NULL) {
-               strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
-               p->string_offset = 0;
-               loc = strsec->contents;
-       } else {
-               p->string_offset = strsec->header.sh_size;
-               loc = obj_extend_section(strsec, len);
-       }
-       memcpy(loc, string, len);
-
-       return 1;
-}
-
-static int
-obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
-                                struct obj_symbol *sym)
-{
-       struct obj_symbol_patch *p;
-
-       p = xmalloc(sizeof(*p));
-       p->next = f->symbol_patches;
-       p->reloc_secidx = secidx;
-       p->reloc_offset = offset;
-       p->sym = sym;
-       f->symbol_patches = p;
-
-       return 1;
-}
-
-static int obj_check_undefineds(struct obj_file *f)
-{
-       unsigned long i;
-       int ret = 1;
-
-       for (i = 0; i < HASH_BUCKETS; ++i) {
-               struct obj_symbol *sym;
-               for (sym = f->symtab[i]; sym; sym = sym->next)
-                       if (sym->secidx == SHN_UNDEF) {
-                               if (ELFW(ST_BIND) (sym->info) == STB_WEAK) {
-                                       sym->secidx = SHN_ABS;
-                                       sym->value = 0;
-                               } else {
-                                       error_msg("unresolved symbol %s", sym->name);
-                                       ret = 0;
-                               }
-                       }
-       }
-
-       return ret;
-}
-
-static void obj_allocate_commons(struct obj_file *f)
-{
-       struct common_entry {
-               struct common_entry *next;
-               struct obj_symbol *sym;
-       } *common_head = NULL;
-
-       unsigned long i;
-
-       for (i = 0; i < HASH_BUCKETS; ++i) {
-               struct obj_symbol *sym;
-               for (sym = f->symtab[i]; sym; sym = sym->next)
-                       if (sym->secidx == SHN_COMMON) {
-                               /* Collect all COMMON symbols and sort them by size so as to
-                                  minimize space wasted by alignment requirements.  */
-                               {
-                                       struct common_entry **p, *n;
-                                       for (p = &common_head; *p; p = &(*p)->next)
-                                               if (sym->size <= (*p)->sym->size)
-                                                       break;
-
-                                       n = alloca(sizeof(*n));
-                                       n->next = *p;
-                                       n->sym = sym;
-                                       *p = n;
-                               }
-                       }
-       }
-
-       for (i = 1; i < f->local_symtab_size; ++i) {
-               struct obj_symbol *sym = f->local_symtab[i];
-               if (sym && sym->secidx == SHN_COMMON) {
-                       struct common_entry **p, *n;
-                       for (p = &common_head; *p; p = &(*p)->next)
-                               if (sym == (*p)->sym)
-                                       break;
-                               else if (sym->size < (*p)->sym->size) {
-                                       n = alloca(sizeof(*n));
-                                       n->next = *p;
-                                       n->sym = sym;
-                                       *p = n;
-                                       break;
-                               }
-               }
-       }
-
-       if (common_head) {
-               /* Find the bss section.  */
-               for (i = 0; i < f->header.e_shnum; ++i)
-                       if (f->sections[i]->header.sh_type == SHT_NOBITS)
-                               break;
-
-               /* If for some reason there hadn't been one, create one.  */
-               if (i == f->header.e_shnum) {
-                       struct obj_section *sec;
-
-                       f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
-                       f->sections[i] = sec = arch_new_section();
-                       f->header.e_shnum = i + 1;
-
-                       memset(sec, 0, sizeof(*sec));
-                       sec->header.sh_type = SHT_PROGBITS;
-                       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
-                       sec->name = ".bss";
-                       sec->idx = i;
-               }
-
-               /* Allocate the COMMONS.  */
-               {
-                       ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
-                       ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
-                       struct common_entry *c;
-
-                       for (c = common_head; c; c = c->next) {
-                               ElfW(Addr) align = c->sym->value;
-
-                               if (align > max_align)
-                                       max_align = align;
-                               if (bss_size & (align - 1))
-                                       bss_size = (bss_size | (align - 1)) + 1;
-
-                               c->sym->secidx = i;
-                               c->sym->value = bss_size;
-
-                               bss_size += c->sym->size;
-                       }
-
-                       f->sections[i]->header.sh_size = bss_size;
-                       f->sections[i]->header.sh_addralign = max_align;
-               }
-       }
-
-       /* For the sake of patch relocation and parameter initialization,
-          allocate zeroed data for NOBITS sections now.  Note that after
-          this we cannot assume NOBITS are really empty.  */
-       for (i = 0; i < f->header.e_shnum; ++i) {
-               struct obj_section *s = f->sections[i];
-               if (s->header.sh_type == SHT_NOBITS) {
-                       if (s->header.sh_size != 0)
-                       s->contents = memset(xmalloc(s->header.sh_size),
-                                                                0, s->header.sh_size);
-                       else
-                               s->contents = NULL;
-
-                       s->header.sh_type = SHT_PROGBITS;
-               }
-       }
-}
-
-static unsigned long obj_load_size(struct obj_file *f)
-{
-       unsigned long dot = 0;
-       struct obj_section *sec;
-
-       /* Finalize the positions of the sections relative to one another.  */
-
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-               ElfW(Addr) align;
-
-               align = sec->header.sh_addralign;
-               if (align && (dot & (align - 1)))
-                       dot = (dot | (align - 1)) + 1;
-
-               sec->header.sh_addr = dot;
-               dot += sec->header.sh_size;
-       }
-
-       return dot;
-}
-
-static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
-{
-       int i, n = f->header.e_shnum;
-       int ret = 1;
-
-       /* Finalize the addresses of the sections.  */
-
-       f->baseaddr = base;
-       for (i = 0; i < n; ++i)
-               f->sections[i]->header.sh_addr += base;
-
-       /* And iterate over all of the relocations.  */
-
-       for (i = 0; i < n; ++i) {
-               struct obj_section *relsec, *symsec, *targsec, *strsec;
-               ElfW(RelM) * rel, *relend;
-               ElfW(Sym) * symtab;
-               const char *strtab;
-
-               relsec = f->sections[i];
-               if (relsec->header.sh_type != SHT_RELM)
-                       continue;
-
-               symsec = f->sections[relsec->header.sh_link];
-               targsec = f->sections[relsec->header.sh_info];
-               strsec = f->sections[symsec->header.sh_link];
-
-               rel = (ElfW(RelM) *) relsec->contents;
-               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
-               symtab = (ElfW(Sym) *) symsec->contents;
-               strtab = (const char *) strsec->contents;
-
-               for (; rel < relend; ++rel) {
-                       ElfW(Addr) value = 0;
-                       struct obj_symbol *intsym = NULL;
-                       unsigned long symndx;
-                       ElfW(Sym) * extsym = 0;
-                       const char *errmsg;
-
-                       /* Attempt to find a value to use for this relocation.  */
-
-                       symndx = ELFW(R_SYM) (rel->r_info);
-                       if (symndx) {
-                               /* Note we've already checked for undefined symbols.  */
-
-                               extsym = &symtab[symndx];
-                               if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) {
-                                       /* Local symbols we look up in the local table to be sure
-                                          we get the one that is really intended.  */
-                                       intsym = f->local_symtab[symndx];
-                               } else {
-                                       /* Others we look up in the hash table.  */
-                                       const char *name;
-                                       if (extsym->st_name)
-                                               name = strtab + extsym->st_name;
-                                       else
-                                               name = f->sections[extsym->st_shndx]->name;
-                                       intsym = obj_find_symbol(f, name);
-                               }
-
-                               value = obj_symbol_final_value(f, intsym);
-                               intsym->referenced = 1;
-                       }
-#if SHT_RELM == SHT_RELA
-#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
-                       /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9.  */
-                       if (!extsym || !extsym->st_name ||
-                               ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL)
-#endif
-                               value += rel->r_addend;
-#endif
-
-                       /* Do it! */
-                       switch (arch_apply_relocation
-                                       (f, targsec, symsec, intsym, rel, value)) {
-                       case obj_reloc_ok:
-                               break;
-
-                       case obj_reloc_overflow:
-                               errmsg = "Relocation overflow";
-                               goto bad_reloc;
-                       case obj_reloc_dangerous:
-                               errmsg = "Dangerous relocation";
-                               goto bad_reloc;
-                       case obj_reloc_unhandled:
-                               errmsg = "Unhandled relocation";
-                         bad_reloc:
-                               if (extsym) {
-                                       error_msg("%s of type %ld for %s", errmsg,
-                                                       (long) ELFW(R_TYPE) (rel->r_info),
-                                                       strtab + extsym->st_name);
-                               } else {
-                                       error_msg("%s of type %ld", errmsg,
-                                                       (long) ELFW(R_TYPE) (rel->r_info));
-                               }
-                               ret = 0;
-                               break;
-                       }
-               }
-       }
-
-       /* Finally, take care of the patches.  */
-
-       if (f->string_patches) {
-               struct obj_string_patch *p;
-               struct obj_section *strsec;
-               ElfW(Addr) strsec_base;
-               strsec = obj_find_section(f, ".kstrtab");
-               strsec_base = strsec->header.sh_addr;
-
-               for (p = f->string_patches; p; p = p->next) {
-                       struct obj_section *targsec = f->sections[p->reloc_secidx];
-                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
-                               = strsec_base + p->string_offset;
-               }
-       }
-
-       if (f->symbol_patches) {
-               struct obj_symbol_patch *p;
-
-               for (p = f->symbol_patches; p; p = p->next) {
-                       struct obj_section *targsec = f->sections[p->reloc_secidx];
-                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
-                               = obj_symbol_final_value(f, p->sym);
-               }
-       }
-
-       return ret;
-}
-
-static int obj_create_image(struct obj_file *f, char *image)
-{
-       struct obj_section *sec;
-       ElfW(Addr) base = f->baseaddr;
-
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-               char *secimg;
-
-               if (sec->contents == 0 || sec->header.sh_size == 0)
-                       continue;
-
-               secimg = image + (sec->header.sh_addr - base);
-
-               /* Note that we allocated data for NOBITS sections earlier.  */
-               memcpy(secimg, sec->contents, sec->header.sh_size);
-       }
-
-       return 1;
-}
-
-/*======================================================================*/
-
-static struct obj_file *obj_load(FILE * fp, int loadprogbits)
-{
-       struct obj_file *f;
-       ElfW(Shdr) * section_headers;
-       int shnum, i;
-       char *shstrtab;
-
-       /* Read the file header.  */
-
-       f = arch_new_file();
-       memset(f, 0, sizeof(*f));
-       f->symbol_cmp = strcmp;
-       f->symbol_hash = obj_elf_hash;
-       f->load_order_search_start = &f->load_order;
-
-       fseek(fp, 0, SEEK_SET);
-       if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
-               perror_msg("error reading ELF header");
-               return NULL;
-       }
-
-       if (f->header.e_ident[EI_MAG0] != ELFMAG0
-               || f->header.e_ident[EI_MAG1] != ELFMAG1
-               || f->header.e_ident[EI_MAG2] != ELFMAG2
-               || f->header.e_ident[EI_MAG3] != ELFMAG3) {
-               error_msg("not an ELF file");
-               return NULL;
-       }
-       if (f->header.e_ident[EI_CLASS] != ELFCLASSM
-               || f->header.e_ident[EI_DATA] != ELFDATAM
-               || f->header.e_ident[EI_VERSION] != EV_CURRENT
-               || !MATCH_MACHINE(f->header.e_machine)) {
-               error_msg("ELF file not for this architecture");
-               return NULL;
-       }
-       if (f->header.e_type != ET_REL) {
-               error_msg("ELF file not a relocatable object");
-               return NULL;
-       }
-
-       /* Read the section headers.  */
-
-       if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
-               error_msg("section header size mismatch: %lu != %lu",
-                               (unsigned long) f->header.e_shentsize,
-                               (unsigned long) sizeof(ElfW(Shdr)));
-               return NULL;
-       }
-
-       shnum = f->header.e_shnum;
-       f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
-       memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
-
-       section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
-       fseek(fp, f->header.e_shoff, SEEK_SET);
-       if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
-               perror_msg("error reading ELF section headers");
-               return NULL;
-       }
-
-       /* Read the section data.  */
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec;
-
-               f->sections[i] = sec = arch_new_section();
-               memset(sec, 0, sizeof(*sec));
-
-               sec->header = section_headers[i];
-               sec->idx = i;
-
-               if(sec->header.sh_size) switch (sec->header.sh_type) {
-               case SHT_NULL:
-               case SHT_NOTE:
-               case SHT_NOBITS:
-                       /* ignore */
-                       break;
-
-               case SHT_PROGBITS:
-#if LOADBITS
-                       if (!loadprogbits) {
-                               sec->contents = NULL;
-                               break;
-                       }
-#endif                 
-               case SHT_SYMTAB:
-               case SHT_STRTAB:
-               case SHT_RELM:
-                       if (sec->header.sh_size > 0) {
-                               sec->contents = xmalloc(sec->header.sh_size);
-                               fseek(fp, sec->header.sh_offset, SEEK_SET);
-                               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
-                                       perror_msg("error reading ELF section data");
-                                       return NULL;
-                               }
-                       } else {
-                               sec->contents = NULL;
-                       }
-                       break;
-
-#if SHT_RELM == SHT_REL
-               case SHT_RELA:
-                       error_msg("RELA relocations not supported on this architecture");
-                       return NULL;
-#else
-               case SHT_REL:
-                       error_msg("REL relocations not supported on this architecture");
-                       return NULL;
-#endif
-
-               default:
-                       if (sec->header.sh_type >= SHT_LOPROC) {
-                               /* Assume processor specific section types are debug
-                                  info and can safely be ignored.  If this is ever not
-                                  the case (Hello MIPS?), don't put ifdefs here but
-                                  create an arch_load_proc_section().  */
-                               break;
-                       }
-
-                       error_msg("can't handle sections of type %ld",
-                                       (long) sec->header.sh_type);
-                       return NULL;
-               }
-       }
-
-       /* Do what sort of interpretation as needed by each section.  */
-
-       shstrtab = f->sections[f->header.e_shstrndx]->contents;
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec = f->sections[i];
-               sec->name = shstrtab + sec->header.sh_name;
-       }
-
-       for (i = 0; i < shnum; ++i) {
-               struct obj_section *sec = f->sections[i];
-
-               /* .modinfo should be contents only but gcc has no attribute for that.
-                * The kernel may have marked .modinfo as ALLOC, ignore this bit.
-                */
-               if (strcmp(sec->name, ".modinfo") == 0)
-                       sec->header.sh_flags &= ~SHF_ALLOC;
-
-               if (sec->header.sh_flags & SHF_ALLOC)
-                       obj_insert_section_load_order(f, sec);
-
-               switch (sec->header.sh_type) {
-               case SHT_SYMTAB:
-                       {
-                               unsigned long nsym, j;
-                               char *strtab;
-                               ElfW(Sym) * sym;
-
-                               if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
-                                       error_msg("symbol size mismatch: %lu != %lu",
-                                                       (unsigned long) sec->header.sh_entsize,
-                                                       (unsigned long) sizeof(ElfW(Sym)));
-                                       return NULL;
-                               }
-
-                               nsym = sec->header.sh_size / sizeof(ElfW(Sym));
-                               strtab = f->sections[sec->header.sh_link]->contents;
-                               sym = (ElfW(Sym) *) sec->contents;
-
-                               /* Allocate space for a table of local symbols.  */
-                               j = f->local_symtab_size = sec->header.sh_info;
-                               f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *));
-
-                               /* Insert all symbols into the hash table.  */
-                               for (j = 1, ++sym; j < nsym; ++j, ++sym) {
-                                       const char *name;
-                                       if (sym->st_name)
-                                               name = strtab + sym->st_name;
-                                       else
-                                               name = f->sections[sym->st_shndx]->name;
-
-                                       obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
-                                                                  sym->st_value, sym->st_size);
-                               }
-                       }
-                       break;
-
-               case SHT_RELM:
-                       if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
-                               error_msg("relocation entry size mismatch: %lu != %lu",
-                                               (unsigned long) sec->header.sh_entsize,
-                                               (unsigned long) sizeof(ElfW(RelM)));
-                               return NULL;
-                       }
-                       break;
-                       /* XXX  Relocation code from modutils-2.3.19 is not here.
-                        * Why?  That's about 20 lines of code from obj/obj_load.c,
-                        * which gets done in a second pass through the sections.
-                        * This BusyBox insmod does similar work in obj_relocate(). */
-               }
-       }
-
-       return f;
-}
-
-#ifdef BB_FEATURE_INSMOD_LOADINKMEM
-/*
- * load the unloaded sections directly into the memory allocated by
- * kernel for the module
- */
-
-static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
-{
-       ElfW(Addr) base = f->baseaddr;
-       struct obj_section* sec;
-       
-       for (sec = f->load_order; sec; sec = sec->load_next) {
-
-               /* section already loaded? */
-               if (sec->contents != NULL)
-                       continue;
-               
-               if (sec->header.sh_size == 0)
-                       continue;
-
-               sec->contents = imagebase + (sec->header.sh_addr - base);
-               fseek(fp, sec->header.sh_offset, SEEK_SET);
-               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
-                       error_msg("error reading ELF section data: %s\n", strerror(errno));
-                       return 0;
-               }
-
-       }
-       return 1;
-}
-#endif
-
-static void hide_special_symbols(struct obj_file *f)
-{
-       static const char *const specials[] = {
-               "cleanup_module",
-               "init_module",
-               "kernel_version",
-               NULL
-       };
-
-       struct obj_symbol *sym;
-       const char *const *p;
-
-       for (p = specials; *p; ++p)
-               if ((sym = obj_find_symbol(f, *p)) != NULL)
-                       sym->info =
-                               ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
-}
-
-
-
-extern int insmod_main( int argc, char **argv)
-{
-       int opt;
-       int k_crcs;
-       int k_new_syscalls;
-       int len;
-       char *tmp;
-       unsigned long m_size;
-       ElfW(Addr) m_addr;
-       FILE *fp;
-       struct obj_file *f;
-       struct stat st;
-       char m_name[FILENAME_MAX + 1] = "\0";
-       int exit_status = EXIT_FAILURE;
-       int m_has_modinfo;
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       struct utsname uts_info;
-       char m_strversion[STRVERSIONLEN];
-       int m_version;
-       int m_crcs;
-#endif
-
-       /* Parse any options */
-       while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) {
-               switch (opt) {
-                       case 'f':                       /* force loading */
-                               flag_force_load = 1;
-                               break;
-                       case 'k':                       /* module loaded by kerneld, auto-cleanable */
-                               flag_autoclean = 1;
-                               break;
-                       case 'v':                       /* verbose output */
-                               flag_verbose = 1;
-                               break;
-                       case 'x':                       /* do not export externs */
-                               flag_export = 0;
-                               break;
-                       case 'o':                       /* name the output module */
-                               strncpy(m_name, optarg, FILENAME_MAX);
-                               break;
-                       case 'L':                       /* Stub warning */
-                               /* This is needed for compatibility with modprobe.
-                                * In theory, this does locking, but we don't do
-                                * that.  So be careful and plan your life around not
-                                * loading the same module 50 times concurrently. */
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       
-       if (argv[optind] == NULL) {
-               show_usage();
-       }
-
-       /* Grab the module name */
-       if ((tmp = strrchr(argv[optind], '/')) != NULL) {
-               tmp++;
-       } else {
-               tmp = argv[optind];
-       }
-       len = strlen(tmp);
-
-       if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o')
-               len -= 2;
-       memcpy(m_fullName, tmp, len);
-       m_fullName[len]='\0';
-       if (*m_name == '\0') {
-               strcpy(m_name, m_fullName);
-       }
-       strcat(m_fullName, ".o");
-
-       /* Get a filedesc for the module.  Check we we have a complete path */
-       if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) ||
-                       (fp = fopen(argv[optind], "r")) == NULL) {
-               struct utsname myuname;
-
-               /* Hmm.  Could not open it.  First search under /lib/modules/`uname -r`,
-                * but do not error out yet if we fail to find it... */
-               if (uname(&myuname) == 0) {
-                       char module_dir[FILENAME_MAX];
-                       char real_module_dir[FILENAME_MAX];
-                       snprintf (module_dir, sizeof(module_dir), "%s/%s", 
-                                       _PATH_MODULES, myuname.release);
-                       /* Jump through hoops in case /lib/modules/`uname -r`
-                        * is a symlink.  We do not want recursive_action to
-                        * follow symlinks, but we do want to follow the
-                        * /lib/modules/`uname -r` dir, So resolve it ourselves
-                        * if it is a link... */
-                       if (realpath (module_dir, real_module_dir) == NULL)
-                               strcpy(real_module_dir, module_dir);
-                       recursive_action(real_module_dir, TRUE, FALSE, FALSE,
-                                       check_module_name_match, 0, m_fullName);
-               }
-
-               /* Check if we have found anything yet */
-               if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) 
-               {
-                       char module_dir[FILENAME_MAX];
-                       if (realpath (_PATH_MODULES, module_dir) == NULL)
-                               strcpy(module_dir, _PATH_MODULES);
-                       /* No module found under /lib/modules/`uname -r`, this
-                        * time cast the net a bit wider.  Search /lib/modules/ */
-                       if (recursive_action(module_dir, TRUE, FALSE, FALSE,
-                                               check_module_name_match, 0, m_fullName) == FALSE) 
-                       {
-                               if (m_filename[0] == '\0'
-                                               || ((fp = fopen(m_filename, "r")) == NULL)) 
-                               {
-                                       error_msg("%s: no module by that name found", m_fullName);
-                                       return EXIT_FAILURE;
-                               }
-                       } else
-                               error_msg_and_die("%s: no module by that name found", m_fullName);
-               }
-       } else 
-               safe_strncpy(m_filename, argv[optind], sizeof(m_filename));
-
-       printf("Using %s\n", m_filename);
-
-       if ((f = obj_load(fp, LOADBITS)) == NULL)
-               perror_msg_and_die("Could not load the module");
-
-       if (get_modinfo_value(f, "kernel_version") == NULL)
-               m_has_modinfo = 0;
-       else
-               m_has_modinfo = 1;
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       /* Version correspondence?  */
-
-       if (uname(&uts_info) < 0)
-               uts_info.release[0] = '\0';
-       if (m_has_modinfo) {
-               m_version = new_get_module_version(f, m_strversion);
-       } else {
-               m_version = old_get_module_version(f, m_strversion);
-               if (m_version == -1) {
-                       error_msg("couldn't find the kernel version the module was "
-                                       "compiled for");
-                       goto out;
-               }
-       }
-
-       if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
-               if (flag_force_load) {
-                       error_msg("Warning: kernel-module version mismatch\n"
-                                       "\t%s was compiled for kernel version %s\n"
-                                       "\twhile this kernel is version %s",
-                                       m_filename, m_strversion, uts_info.release);
-               } else {
-                       error_msg("kernel-module version mismatch\n"
-                                       "\t%s was compiled for kernel version %s\n"
-                                       "\twhile this kernel is version %s.",
-                                       m_filename, m_strversion, uts_info.release);
-                       goto out;
-               }
-       }
-       k_crcs = 0;
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-       k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
-
-       if (k_new_syscalls) {
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-               if (!new_get_kernel_symbols())
-                       goto out;
-               k_crcs = new_is_kernel_checksummed();
-#else
-               error_msg("Not configured to support new kernels");
-               goto out;
-#endif
-       } else {
-#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
-               if (!old_get_kernel_symbols(m_name))
-                       goto out;
-               k_crcs = old_is_kernel_checksummed();
-#else
-               error_msg("Not configured to support old kernels");
-               goto out;
-#endif
-       }
-
-#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
-       if (m_has_modinfo)
-               m_crcs = new_is_module_checksummed(f);
-       else
-               m_crcs = old_is_module_checksummed(f);
-
-       if (m_crcs != k_crcs)
-               obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
-#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
-
-       /* Let the module know about the kernel symbols.  */
-       add_kernel_symbols(f);
-
-       /* Allocate common symbols, symbol tables, and string tables.  */
-
-       if (k_new_syscalls 
-               ? !new_create_this_module(f, m_name)
-               : !old_create_mod_use_count(f)) 
-       {
-               goto out;
-       }
-
-       if (!obj_check_undefineds(f)) {
-               goto out;
-       }
-       obj_allocate_commons(f);
-
-       /* done with the module name, on to the optional var=value arguments */
-       ++optind;
-
-       if (optind < argc) {
-               if (m_has_modinfo
-                       ? !new_process_module_arguments(f, argc - optind, argv + optind) 
-                       : !old_process_module_arguments(f, argc - optind, argv + optind)) 
-               {
-                       goto out;
-               }
-       }
-
-       arch_create_got(f);
-       hide_special_symbols(f);
-
-       if (k_new_syscalls)
-               new_create_module_ksymtab(f);
-
-       /* Find current size of the module */
-       m_size = obj_load_size(f);
-
-
-       m_addr = create_module(m_name, m_size);
-       if (m_addr==-1) switch (errno) {
-       case EEXIST:
-               error_msg("A module named %s already exists", m_name);
-               goto out;
-       case ENOMEM:
-               error_msg("Can't allocate kernel memory for module; needed %lu bytes",
-                               m_size);
-               goto out;
-       default:
-               perror_msg("create_module: %s", m_name);
-               goto out;
-       }
-
-#if  !LOADBITS
-       /*
-        * the PROGBITS section was not loaded by the obj_load
-        * now we can load them directly into the kernel memory
-        */
-       if (!obj_load_progbits(fp, f, (char*)m_addr)) {
-               delete_module(m_name);
-               goto out;
-       }
-#endif 
-
-       if (!obj_relocate(f, m_addr)) {
-               delete_module(m_name);
-               goto out;
-       }
-
-       if (k_new_syscalls 
-               ? !new_init_module(m_name, f, m_size)
-               : !old_init_module(m_name, f, m_size)) 
-       {
-               delete_module(m_name);
-               goto out;
-       }
-
-       exit_status = EXIT_SUCCESS;
-
-out:
-       fclose(fp);
-       return(exit_status);
-}
diff --git a/busybox/modutils/lsmod.c b/busybox/modutils/lsmod.c
deleted file mode 100644 (file)
index 76ed2fd..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini lsmod implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
- * (which lack the query_module() interface).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <assert.h>
-#include <getopt.h>
-#include <sys/utsname.h>
-#include <sys/file.h>
-#include "busybox.h"
-
-
-
-#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
-
-struct module_info
-{
-       unsigned long addr;
-       unsigned long size;
-       unsigned long flags;
-       long usecount;
-};
-
-
-int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
-
-/* Values for query_module's which.  */
-static const int QM_MODULES = 1;
-static const int QM_DEPS = 2;
-static const int QM_REFS = 3;
-static const int QM_SYMBOLS = 4;
-static const int QM_INFO = 5;
-
-/* Bits of module.flags.  */
-static const int NEW_MOD_RUNNING = 1;
-static const int NEW_MOD_DELETED = 2;
-static const int NEW_MOD_AUTOCLEAN = 4;
-static const int NEW_MOD_VISITED = 8;
-static const int NEW_MOD_USED_ONCE = 16;
-static const int NEW_MOD_INITIALIZING = 64;
-
-static int my_query_module(const char *name, int which, void **buf,
-               size_t *bufsize, size_t *ret)
-{
-       int my_ret;
-
-       my_ret = query_module(name, which, *buf, *bufsize, ret);
-
-       if (my_ret == -1 && errno == ENOSPC) {
-               *buf = xrealloc(*buf, *ret);
-               *bufsize = *ret;
-
-               my_ret = query_module(name, which, *buf, *bufsize, ret);
-       }
-
-       return my_ret;
-}
-
-extern int lsmod_main(int argc, char **argv)
-{
-       struct module_info info;
-       char *module_names, *mn, *deps, *dn;
-       size_t bufsize, depsize, nmod, count, i, j;
-
-       module_names = xmalloc(bufsize = 256);
-       if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize,
-                               &nmod)) {
-               perror_msg_and_die("QM_MODULES");
-       }
-
-       deps = xmalloc(depsize = 256);
-       printf("Module                  Size  Used by\n");
-       for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
-               if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
-                       if (errno == ENOENT) {
-                               /* The module was removed out from underneath us. */
-                               continue;
-                       }
-                       /* else choke */
-                       perror_msg_and_die("module %s: QM_INFO", mn);
-               }
-               if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) {
-                       if (errno == ENOENT) {
-                               /* The module was removed out from underneath us. */
-                               continue;
-                       }
-                       perror_msg_and_die("module %s: QM_REFS", mn);
-               }
-               printf("%-20s%8lu%4ld ", mn, info.size, info.usecount);
-               if (info.flags & NEW_MOD_DELETED)
-                       printf("(deleted)");
-               else if (info.flags & NEW_MOD_INITIALIZING)
-                       printf("(initializing)");
-               else if (!(info.flags & NEW_MOD_RUNNING))
-                       printf("(uninitialized)");
-               else {
-                       if (info.flags & NEW_MOD_AUTOCLEAN)
-                               printf("(autoclean) ");
-                       if (!(info.flags & NEW_MOD_USED_ONCE))
-                               printf("(unused)");
-               }
-               if (count) printf("[");
-               for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
-                       printf("%s%s", dn, (j==count-1)? "":" ");
-               }
-               if (count) printf("] ");
-
-               printf("\n");
-       }
-
-
-       return( 0);
-}
-
-#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/
-
-extern int lsmod_main(int argc, char **argv)
-{
-       int fd, i;
-       char line[128];
-
-       puts("Module                  Size  Used by");
-       fflush(stdout);
-
-       if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
-               while ((i = read(fd, line, sizeof(line))) > 0) {
-                       write(fileno(stdout), line, i);
-               }
-               close(fd);
-               return 0;
-       }
-       perror_msg_and_die("/proc/modules");
-       return 1;
-}
-
-#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/
diff --git a/busybox/modutils/modprobe.c b/busybox/modutils/modprobe.c
deleted file mode 100644 (file)
index 05b40c5..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * really dumb modprobe implementation for busybox
- * Copyright (C) 2001 Lineo, davidm@lineo.com
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include "busybox.h"
-
-static char cmd[128];
-
-extern int modprobe_main(int argc, char** argv)
-{
-       int     ch, rc = 0;
-       int     loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0;
-       int     show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0;
-       char    *load_type = NULL, *config = NULL;
-
-       while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1)
-               switch(ch) {
-               case 'a':
-                       loadall++;
-                       break;
-               case 'c':
-                       showconfig++;
-                       break;
-               case 'd':
-                       debug++;
-                       break;
-               case 'k':
-                       autoclean++;
-                       break;
-               case 'l':
-                       list++;
-                       break;
-               case 'n':
-                       show_only++;
-                       break;
-               case 'q':
-                       quiet++;
-                       break;
-               case 'r':
-                       remove_opt++;
-                       break;
-               case 's':
-                       do_syslog++;
-                       break;
-               case 't':
-                       load_type = optarg;
-                       break;
-               case 'v':
-                       verbose++;
-                       break;
-               case 'C':
-                       config = optarg;
-                       break;
-               case 'V':
-               default:
-                       show_usage();
-                       break;
-               }
-
-       if (load_type || config) {
-               fprintf(stderr, "-t and -C not supported\n");
-               exit(EXIT_FAILURE);
-       }
-
-       if (showconfig)
-               exit(EXIT_SUCCESS);
-       
-       if (list)
-               exit(EXIT_SUCCESS);
-       
-       if (remove_opt) {
-               do {
-                       sprintf(cmd, "rmmod %s %s %s",
-                                       optind >= argc ? "-a" : "",
-                                       do_syslog ? "-s" : "",
-                                       optind < argc ? argv[optind] : "");
-                       if (do_syslog)
-                               syslog(LOG_INFO, "%s", cmd);
-                       if (show_only || verbose)
-                               printf("%s\n", cmd);
-                       if (!show_only)
-                               rc = system(cmd);
-               } while (++optind < argc);
-               exit(EXIT_SUCCESS);
-       }
-
-       if (optind >= argc) {
-               fprintf(stderr, "No module or pattern provided\n");
-               exit(EXIT_FAILURE);
-       }
-
-       sprintf(cmd, "insmod %s %s %s",
-                       do_syslog ? "-s" : "",
-                       quiet ? "-q" : "",
-                       autoclean ? "-k" : "");
-       while (optind < argc) {
-               strcat(cmd, argv[optind]);
-               strcat(cmd, " ");
-               optind++;
-       }
-       if (do_syslog)
-               syslog(LOG_INFO, "%s", cmd);
-       if (show_only || verbose)
-               printf("%s\n", cmd);
-       if (!show_only)
-               rc = system(cmd);
-       else
-               rc = 0;
-
-       exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
-}
-
-
diff --git a/busybox/modutils/rmmod.c b/busybox/modutils/rmmod.c
deleted file mode 100644 (file)
index 7596d02..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rmmod implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int delete_module(const char * name);
-
-
-extern int rmmod_main(int argc, char **argv)
-{
-       int n, ret = EXIT_SUCCESS;
-
-       /* Parse command line. */
-       while ((n = getopt(argc, argv, "a")) != EOF) {
-               switch (n) {
-                       case 'a':
-                               /* Unload _all_ unused modules via NULL delete_module() call */
-                               if (delete_module(NULL))
-                                       perror_msg_and_die("rmmod");
-                               return EXIT_SUCCESS;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)
-                       show_usage();
-
-       for (n = optind; n < argc; n++) {
-               if (delete_module(argv[n]) < 0) {
-                       perror_msg("%s", argv[n]);
-                       ret = EXIT_FAILURE;
-               }
-       }
-
-       return(ret);
-}
diff --git a/busybox/more.c b/busybox/more.c
deleted file mode 100644 (file)
index 780cddf..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini more implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * Latest version blended together by Erik Andersen <andersen@lineo.com>,
- * based on the original more implementation by Bruce, and code from the 
- * Debian boot-floppies team.
- *
- * Termios corrects by Vladimir Oleynik <vodz@usa.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-static FILE *cin;
-
-#ifdef BB_FEATURE_USE_TERMIOS
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
-#define getTermSettings(fd,argp) tcgetattr(fd, argp);
-
-static struct termios initial_settings, new_settings;
-
-static void set_tty_to_initial_mode(void)
-{
-       setTermSettings(fileno(cin), &initial_settings);
-}
-
-static void gotsig(int sig)
-{
-       putchar('\n');
-       exit(EXIT_FAILURE);
-}
-#endif /* BB_FEATURE_USE_TERMIOS */
-
-
-static int terminal_width = 79;        /* not 80 in case terminal has linefold bug */
-static int terminal_height = 24;
-
-
-extern int more_main(int argc, char **argv)
-{
-       int c, lines, input = 0;
-       int please_display_more_prompt = -1;
-       struct stat st;
-       FILE *file;
-       int len, page_height;
-
-#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
-       struct winsize win = { 0, 0, 0, 0 };
-#endif
-
-       argc--;
-       argv++;
-
-
-       /* not use inputing from terminal if usage: more > outfile */
-       if(isatty(fileno(stdout))) {
-               cin = fopen(CURRENT_TTY, "r");
-               if (!cin)
-                       cin = xfopen(CONSOLE_DEV, "r");
-               please_display_more_prompt = 0;
-#ifdef BB_FEATURE_USE_TERMIOS
-               getTermSettings(fileno(cin), &initial_settings);
-               new_settings = initial_settings;
-               new_settings.c_lflag &= ~ICANON;
-               new_settings.c_lflag &= ~ECHO;
-#ifndef linux
-                /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-               new_settings.c_cc[VMIN] = 1;
-               new_settings.c_cc[VTIME] = 0;
-#endif
-               setTermSettings(fileno(cin), &new_settings);
-               atexit(set_tty_to_initial_mode);
-               (void) signal(SIGINT, gotsig);
-               (void) signal(SIGQUIT, gotsig);
-               (void) signal(SIGTERM, gotsig);
-#endif
-       }
-
-       do {
-               if (argc == 0) {
-                       file = stdin;
-               } else
-                       file = wfopen(*argv, "r");
-               if(file==0)
-                       goto loop;
-                       
-               fstat(fileno(file), &st);
-
-               if(please_display_more_prompt>0)
-                       please_display_more_prompt = 0;
-
-#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_row > 4)
-                       terminal_height = win.ws_row - 2;
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-               len=0;
-               lines = 0;
-               page_height = terminal_height;
-               while ((c = getc(file)) != EOF) {
-
-                       if (please_display_more_prompt>0) {
-                               len = printf("--More-- ");
-                               if (file != stdin) {
-#if _FILE_OFFSET_BITS == 64
-                                       len += printf("(%d%% of %lld bytes)",
-                                                  (int) (100 * ((double) ftell(file) /
-                                                  (double) st.st_size)), (long long)st.st_size);
-#else
-                                       len += printf("(%d%% of %ld bytes)",
-                                                  (int) (100 * ((double) ftell(file) /
-                                                  (double) st.st_size)), (long)st.st_size);
-#endif
-                               }
-
-                               fflush(stdout);
-
-                               /*
-                                * We've just displayed the "--More--" prompt, so now we need
-                                * to get input from the user.
-                                */
-                               input = getc(cin);
-#ifndef BB_FEATURE_USE_TERMIOS
-                               printf("\033[A"); /* up cursor */
-#endif
-                               /* Erase the "More" message */
-                               putc('\r', stdout);
-                               while (--len >= 0)
-                                       putc(' ', stdout);
-                               putc('\r', stdout);
-                               fflush(stdout);
-                               len=0;
-                               lines = 0;
-                               page_height = terminal_height;
-                               please_display_more_prompt = 0;
-
-                               if (input == 'q')
-                                       goto end;
-                       }
-
-                       /* 
-                        * There are two input streams to worry about here:
-                        *
-                        * c     : the character we are reading from the file being "mored"
-                        * input : a character received from the keyboard
-                        *
-                        * If we hit a newline in the _file_ stream, we want to test and
-                        * see if any characters have been hit in the _input_ stream. This
-                        * allows the user to quit while in the middle of a file.
-                        */
-                       if (c == '\n') {
-                               /* increment by just one line if we are at
-                                * the end of this line */
-                               if (input == '\n')
-                                       if(please_display_more_prompt==0)
-                                       please_display_more_prompt = 1;
-                               /* Adjust the terminal height for any overlap, so that
-                                * no lines get lost off the top. */
-                               if (len >= terminal_width) {
-                                       int quot, rem;
-                                       quot = len / terminal_width;
-                                       rem  = len - (quot * terminal_width);
-                                       if (quot) {
-                                               if (rem)
-                                                       page_height-=quot;
-                                               else
-                                                       page_height-=(quot-1);
-                                       }
-                               }
-                               if (++lines >= page_height) {
-                                       if(please_display_more_prompt==0)
-                                       please_display_more_prompt = 1;
-                               }
-                               len=0;
-                       }
-                       /*
-                        * If we just read a newline from the file being 'mored' and any
-                        * key other than a return is hit, scroll by one page
-                        */
-                       putc(c, stdout);
-                       len++;
-               }
-               fclose(file);
-               fflush(stdout);
-loop:
-               argv++;
-       } while (--argc > 0);
-  end:
-       return 0;
-}
diff --git a/busybox/mount.c b/busybox/mount.c
deleted file mode 100644 (file)
index af57a76..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mount implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 3/21/1999   Charles P. Wright <cpwright@cpwright.com>
- *             searches through fstab when -a is passed
- *             will try mounting stuff with all fses when passed -t auto
- *
- * 1999-04-17  Dave Cinege...Rewrote -t auto. Fixed ro mtab.
- *
- * 1999-10-07  Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
- *              Rewrite of a lot of code. Removed mtab usage (I plan on
- *              putting it back as a compile-time option some time), 
- *              major adjustments to option parsing, and some serious 
- *              dieting all around.
- *
- * 1999-11-06  mtab suppport is back - andersee
- *
- * 2000-01-12   Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
- *              mount to add loop support.
- *
- * 2000-04-30  Dave Cinege <dcinege@psychosis.com>
- *             Rewrote fstab while loop and lower mount section. Can now do
- *             single mounts from fstab. Can override fstab options for single
- *             mount. Common mount_one call for single mounts and 'all'. Fixed
- *             mtab updating and stale entries. Removed 'remount' default. 
- *     
- */
-
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <ctype.h>
-#include "busybox.h"
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-#      include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */
-#endif
-
-enum {
-       MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
-       MS_RDONLY = 1,      /* Mount read-only */
-       MS_NOSUID = 2,      /* Ignore suid and sgid bits */
-       MS_NODEV = 4,      /* Disallow access to device special files */
-       MS_NOEXEC = 8,      /* Disallow program execution */
-       MS_SYNCHRONOUS = 16,      /* Writes are synced at once */
-       MS_REMOUNT = 32,      /* Alter flags of a mounted FS */
-       MS_MANDLOCK = 64,      /* Allow mandatory locks on an FS */
-       S_QUOTA = 128,     /* Quota initialized for file/directory/symlink */
-       S_APPEND = 256,     /* Append-only file */
-       S_IMMUTABLE = 512,     /* Immutable file */
-       MS_NOATIME = 1024,    /* Do not update access times. */
-       MS_NODIRATIME = 2048,    /* Do not update directory access times */
-       MS_BIND = 4096,    /* Use the new linux 2.4.x "mount --bind" feature */
-};
-
-
-#if defined BB_FEATURE_MOUNT_LOOP
-#include <fcntl.h>
-#include <sys/ioctl.h>
-static int use_loop = FALSE;
-#endif
-
-extern int mount (__const char *__special_file, __const char *__dir,
-                       __const char *__fstype, unsigned long int __rwflag,
-                       __const void *__data);
-extern int umount (__const char *__special_file);
-extern int umount2 (__const char *__special_file, int __flags);
-
-extern int sysfs( int option, unsigned int fs_index, char * buf);
-
-extern const char mtab_file[]; /* Defined in utility.c */
-
-struct mount_options {
-       const char *name;
-       unsigned long and;
-       unsigned long or;
-};
-
-static const struct mount_options mount_options[] = {
-       {"async", ~MS_SYNCHRONOUS, 0},
-       {"atime", ~0, ~MS_NOATIME},
-       {"defaults", ~0, 0},
-       {"dev", ~MS_NODEV, 0},
-       {"diratime", ~0, ~MS_NODIRATIME},
-       {"exec", ~MS_NOEXEC, 0},
-       {"noatime", ~0, MS_NOATIME},
-       {"nodev", ~0, MS_NODEV},
-       {"nodiratime", ~0, MS_NODIRATIME},
-       {"noexec", ~0, MS_NOEXEC},
-       {"nosuid", ~0, MS_NOSUID},
-       {"remount", ~0, MS_REMOUNT},
-       {"ro", ~0, MS_RDONLY},
-       {"rw", ~MS_RDONLY, 0},
-       {"suid", ~MS_NOSUID, 0},
-       {"sync", ~0, MS_SYNCHRONOUS},
-       {"bind", ~0, MS_BIND},
-       {0, 0, 0}
-};
-
-static int
-do_mount(char *specialfile, char *dir, char *filesystemtype,
-                long flags, void *string_flags, int useMtab, int fakeIt,
-                char *mtab_opts, int mount_all)
-{
-       int status = 0;
-#if defined BB_FEATURE_MOUNT_LOOP
-       char *lofile = NULL;
-#endif
-
-       if (fakeIt == FALSE)
-       {
-#if defined BB_FEATURE_MOUNT_LOOP
-               if (use_loop==TRUE) {
-                       int loro = flags & MS_RDONLY;
-                       
-                       lofile = specialfile;
-
-                       specialfile = find_unused_loop_device();
-                       if (specialfile == NULL) {
-                               error_msg_and_die("Could not find a spare loop device");
-                       }
-                       if (set_loop(specialfile, lofile, 0, &loro)) {
-                               error_msg_and_die("Could not setup loop device");
-                       }
-                       if (!(flags & MS_RDONLY) && loro) {     /* loop is ro, but wanted rw */
-                               error_msg("WARNING: loop device is read-only");
-                               flags |= MS_RDONLY;
-                       }
-               }
-#endif
-               status = mount(specialfile, dir, filesystemtype, flags, string_flags);
-               if (status < 0 && errno == EROFS) {
-                       error_msg("%s is write-protected, mounting read-only", specialfile);
-                       status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags);
-               }
-               /* Don't whine about already mounted filesystems when mounting all. */
-               if (status < 0 && errno == EBUSY && mount_all)
-                       return TRUE;
-       }
-
-
-       /* If the mount was sucessful, do anything needed, then return TRUE */
-       if (status == 0 || fakeIt==TRUE) {
-
-#if defined BB_FEATURE_MTAB_SUPPORT
-               if (useMtab == TRUE) {
-                       erase_mtab(specialfile);        // Clean any stale entries
-                       write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
-               }
-#endif
-               return (TRUE);
-       }
-
-       /* Bummer.  mount failed.  Clean up */
-#if defined BB_FEATURE_MOUNT_LOOP
-       if (lofile != NULL) {
-               del_loop(specialfile);
-       }
-#endif
-
-       if (errno == EPERM) {
-               error_msg_and_die("permission denied. Are you root?");
-       }
-
-       return (FALSE);
-}
-
-
-
-/* Seperate standard mount options from the nonstandard string options */
-static void
-parse_mount_options(char *options, int *flags, char *strflags)
-{
-       while (options) {
-               int gotone = FALSE;
-               char *comma = strchr(options, ',');
-               const struct mount_options *f = mount_options;
-
-               if (comma)
-                       *comma = '\0';
-
-               while (f->name != 0) {
-                       if (strcasecmp(f->name, options) == 0) {
-
-                               *flags &= f->and;
-                               *flags |= f->or;
-                               gotone = TRUE;
-                               break;
-                       }
-                       f++;
-               }
-#if defined BB_FEATURE_MOUNT_LOOP
-               if (gotone == FALSE && !strcasecmp("loop", options)) {  /* loop device support */
-                       use_loop = TRUE;
-                       gotone = TRUE;
-               }
-#endif
-               if (*strflags && strflags != '\0' && gotone == FALSE) {
-                       char *temp = strflags;
-
-                       temp += strlen(strflags);
-                       *temp++ = ',';
-                       *temp++ = '\0';
-               }
-               if (gotone == FALSE)
-                       strcat(strflags, options);
-               if (comma) {
-                       *comma = ',';
-                       options = ++comma;
-               } else {
-                       break;
-               }
-       }
-}
-
-static int
-mount_one(char *blockDevice, char *directory, char *filesystemType,
-                 unsigned long flags, char *string_flags, int useMtab, int fakeIt,
-                 char *mtab_opts, int whineOnErrors, int mount_all)
-{
-       int status = 0;
-
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-       if (strcmp(filesystemType, "auto") == 0) {
-               static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 };
-               const char **noauto_fstype;
-               const int num_of_filesystems = sysfs(3, 0, 0);
-               char buf[255];
-               int i=0;
-
-               filesystemType=buf;
-
-               while(i < num_of_filesystems) {
-                       sysfs(2, i++, filesystemType);
-                       for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) {
-                               if (!strcmp(filesystemType, *noauto_fstype)) {
-                                       break;
-                               }
-                       }
-                       if (!*noauto_fstype) {
-                               status = do_mount(blockDevice, directory, filesystemType,
-                                       flags | MS_MGC_VAL, string_flags,
-                                       useMtab, fakeIt, mtab_opts, mount_all);
-                               if (status == TRUE)
-                                       break;
-                       }
-               }
-       } 
-#else
-       if (strcmp(filesystemType, "auto") == 0) {
-               char buf[255];
-               FILE *f = xfopen("/proc/filesystems", "r");
-
-               while (fgets(buf, sizeof(buf), f) != NULL) {
-                       filesystemType = buf;
-                       if (*filesystemType == '\t') {  // Not a nodev filesystem
-
-                               // Add NULL termination to each line
-                               while (*filesystemType && *filesystemType != '\n')
-                                       filesystemType++;
-                               *filesystemType = '\0';
-
-                               filesystemType = buf;
-                               filesystemType++;       // hop past tab
-
-                               status = do_mount(blockDevice, directory, filesystemType,
-                                                                 flags | MS_MGC_VAL, string_flags,
-                                                                 useMtab, fakeIt, mtab_opts, mount_all);
-                               if (status == TRUE)
-                                       break;
-                       }
-               }
-               fclose(f);
-       }
-#endif
-       else {
-               status = do_mount(blockDevice, directory, filesystemType,
-                               flags | MS_MGC_VAL, string_flags, useMtab,
-                               fakeIt, mtab_opts, mount_all);
-       }
-
-       if (status == FALSE) {
-               if (whineOnErrors == TRUE) {
-                       perror_msg("Mounting %s on %s failed", blockDevice, directory);
-               }
-               return (FALSE);
-       }
-       return (TRUE);
-}
-
-void show_mounts(void)
-{
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-       int fd, i, numfilesystems;
-       char device[] = "/dev/mtab";
-       struct k_mntent *mntentlist;
-
-       /* open device */ 
-       fd = open(device, O_RDONLY);
-       if (fd < 0)
-               perror_msg_and_die("open failed for `%s'", device);
-
-       /* How many mounted filesystems?  We need to know to 
-        * allocate enough space for later... */
-       numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
-       if (numfilesystems<0)
-               perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS");
-       mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent));
-               
-       /* Grab the list of mounted filesystems */
-       if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
-               perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS");
-
-       for( i = 0 ; i < numfilesystems ; i++) {
-               printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
-                               mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
-                               mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
-                               mntentlist[i].mnt_passno);
-       }
-#ifdef BB_FEATURE_CLEAN_UP
-       /* Don't bother to close files or free memory.  Exit 
-        * does that automagically, so we can save a few bytes */
-       free( mntentlist);
-       close(fd);
-#endif
-       exit(EXIT_SUCCESS);
-#else
-       FILE *mountTable = setmntent(mtab_file, "r");
-
-       if (mountTable) {
-               struct mntent *m;
-
-               while ((m = getmntent(mountTable)) != 0) {
-                       char *blockDevice = m->mnt_fsname;
-                       if (strcmp(blockDevice, "/dev/root") == 0) {
-                               blockDevice = find_real_root_device_name(blockDevice);
-                       }
-                       printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
-                                  m->mnt_type, m->mnt_opts);
-#ifdef BB_FEATURE_CLEAN_UP
-                       if(blockDevice != m->mnt_fsname)
-                               free(blockDevice);
-#endif
-               }
-               endmntent(mountTable);
-       } else {
-               perror_msg_and_die("%s", mtab_file);
-       }
-       exit(EXIT_SUCCESS);
-#endif
-}
-
-extern int mount_main(int argc, char **argv)
-{
-       struct stat statbuf;
-       char string_flags_buf[1024] = "";
-       char *string_flags = string_flags_buf;
-       char *extra_opts = string_flags_buf;
-       int flags = 0;
-       char *filesystemType = "auto";
-       char *device = xmalloc(PATH_MAX);
-       char *directory = xmalloc(PATH_MAX);
-       int all = FALSE;
-       int fakeIt = FALSE;
-       int useMtab = TRUE;
-       int rc = EXIT_FAILURE;
-       int fstabmount = FALSE; 
-       int opt;
-
-       /* Parse options */
-       while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
-               switch (opt) {
-               case 'o':
-                       parse_mount_options(optarg, &flags, string_flags);
-                       break;
-               case 'r':
-                       flags |= MS_RDONLY;
-                       break;
-               case 't':
-                       filesystemType = optarg;
-                       break;
-               case 'w':
-                       flags &= ~MS_RDONLY;
-                       break;
-               case 'a':
-                       all = TRUE;
-                       break;
-               case 'f':
-                       fakeIt = TRUE;
-                       break;
-#ifdef BB_FEATURE_MTAB_SUPPORT
-               case 'n':
-                       useMtab = FALSE;
-                       break;
-#endif
-               case 'v':
-                       break; /* ignore -v */
-               }
-       }
-
-       if (!all && optind == argc)
-               show_mounts();
-
-       if (optind < argc) {
-               /* if device is a filename get its real path */
-               if (stat(argv[optind], &statbuf) == 0) {
-                       device = simplify_path(argv[optind]);
-               } else {
-                       safe_strncpy(device, argv[optind], PATH_MAX);
-               }
-       }
-
-       if (optind + 1 < argc)
-               directory = simplify_path(argv[optind + 1]);
-
-       if (all == TRUE || optind + 1 == argc) {
-               struct mntent *m = NULL;
-               FILE *f = setmntent("/etc/fstab", "r");
-               fstabmount = TRUE;
-
-               if (f == NULL)
-                       perror_msg_and_die( "\nCannot read /etc/fstab");
-
-               while ((m = getmntent(f)) != NULL) {
-                       if (all == FALSE && optind + 1 == argc && (
-                               (strcmp(device, m->mnt_fsname) != 0) &&
-                               (strcmp(device, m->mnt_dir) != 0) ) ) {
-                               continue;
-                       }
-                       
-                       if (all == TRUE && (                            // If we're mounting 'all'
-                               (strstr(m->mnt_opts, "noauto")) ||      // and the file system isn't noauto,
-                               (strstr(m->mnt_type, "swap")) ||        // and isn't swap or nfs, then mount it
-                               (strstr(m->mnt_type, "nfs")) ) ) {
-                               continue;
-                       }
-                       
-                       if (all == TRUE || flags == 0) {        // Allow single mount to override fstab flags
-                               flags = 0;
-                               *string_flags = '\0';
-                               parse_mount_options(m->mnt_opts, &flags, string_flags);
-                       }
-                       
-                       strcpy(device, m->mnt_fsname);
-                       strcpy(directory, m->mnt_dir);
-                       filesystemType = strdup(m->mnt_type);
-singlemount:                   
-                       string_flags = strdup(string_flags);
-                       rc = EXIT_SUCCESS;
-#ifdef BB_NFSMOUNT
-                       if (strchr(device, ':') != NULL)
-                               filesystemType = "nfs";
-                       if (strcmp(filesystemType, "nfs") == 0) {
-                               if (nfsmount (device, directory, &flags, &extra_opts,
-                                                       &string_flags, 1)) {
-                                       perror_msg("nfsmount failed");
-                                       rc = EXIT_FAILURE;
-                               }
-                       }
-#endif
-                       if (!mount_one(device, directory, filesystemType, flags,
-                                       string_flags, useMtab, fakeIt, extra_opts, TRUE, all))
-                               rc = EXIT_FAILURE;
-                               
-                       if (all == FALSE)
-                               break;
-               }
-               if (fstabmount == TRUE)
-                       endmntent(f);
-                       
-               if (all == FALSE && fstabmount == TRUE && m == NULL)
-                       fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
-       
-               return rc;
-       }
-       
-       goto singlemount;
-}
diff --git a/busybox/msh.c b/busybox/msh.c
deleted file mode 100644 (file)
index e16d6f3..0000000
+++ /dev/null
@@ -1,4868 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Minix shell port for busybox
- *
- * This version of the Minix shell was adapted for use in busybox
- * by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "cmdedit.h"
-#include "busybox.h"
-
-
-/* -------- sh.h -------- */
-/*
- * shell
- */
-
-#define        LINELIM 2100
-#define        NPUSH   8       /* limit to input nesting */
-
-#define        NOFILE  20      /* Number of open files */
-#define        NUFILE  10      /* Number of user-accessible files */
-#define        FDBASE  10      /* First file usable by Shell */
-
-/*
- * values returned by wait
- */
-#define        WAITSIG(s) ((s)&0177)
-#define        WAITVAL(s) (((s)>>8)&0377)
-#define        WAITCORE(s) (((s)&0200)!=0)
-
-/*
- * library and system defintions
- */
-typedef void xint;     /* base type of jmp_buf, for not broken compilers */
-
-/*
- * shell components
- */
-
-#define        QUOTE   0200
-
-#define        NOBLOCK ((struct op *)NULL)
-#define        NOWORD  ((char *)NULL)
-#define        NOWORDS ((char **)NULL)
-#define        NOPIPE  ((int *)NULL)
-
-/*
- * Description of a command or an operation on commands.
- * Might eventually use a union.
- */
-struct op {
-       int     type;   /* operation type, see below */
-       char    **words;        /* arguments to a command */
-       struct  ioword  **ioact;        /* IO actions (eg, < > >>) */
-       struct op *left;
-       struct op *right;
-       char    *str;   /* identifier for case and for */
-};
-
-#define        TCOM    1       /* command */
-#define        TPAREN  2       /* (c-list) */
-#define        TPIPE   3       /* a | b */
-#define        TLIST   4       /* a [&;] b */
-#define        TOR     5       /* || */
-#define        TAND    6       /* && */
-#define        TFOR    7
-#define        TDO     8
-#define        TCASE   9
-#define        TIF     10
-#define        TWHILE  11
-#define        TUNTIL  12
-#define        TELIF   13
-#define        TPAT    14      /* pattern in case */
-#define        TBRACE  15      /* {c-list} */
-#define        TASYNC  16      /* c & */
-
-/*
- * actions determining the environment of a process
- */
-#define        BIT(i)  (1<<(i))
-#define        FEXEC   BIT(0)  /* execute without forking */
-
-/*
- * flags to control evaluation of words
- */
-#define        DOSUB   1       /* interpret $, `, and quotes */
-#define        DOBLANK 2       /* perform blank interpretation */
-#define        DOGLOB  4       /* interpret [?* */
-#define        DOKEY   8       /* move words with `=' to 2nd arg. list */
-#define        DOTRIM  16      /* trim resulting string */
-
-#define        DOALL   (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
-
-static char    **dolv;
-static int     dolc;
-static int     exstat;
-static  char   gflg;
-static  int    interactive;    /* Is this an interactive shell */
-static  int    execflg;
-static  int    multiline;      /* \n changed to ; */
-static  struct op      *outtree;       /* result from parser */
-
-static xint    *failpt;
-static xint    *errpt;
-static struct brkcon   *brklist;
-static int     isbreak;
-static int newfile(char *s);
-static char *findeq(char *cp);
-static char *cclass(char *p, int sub);
-static void initarea(void);
-extern int msh_main(int argc, char **argv);
-
-
-struct brkcon {
-       jmp_buf brkpt;
-       struct  brkcon  *nextlev;
-} ;
-
-/*
- * redirection
- */
-struct ioword {
-       short   io_unit;        /* unit affected */
-       short   io_flag;        /* action (below) */
-       char    *io_name;       /* file name */
-};
-#define        IOREAD  1       /* < */
-#define        IOHERE  2       /* << (here file) */
-#define        IOWRITE 4       /* > */
-#define        IOCAT   8       /* >> */
-#define        IOXHERE 16      /* ${}, ` in << */
-#define        IODUP   32      /* >&digit */
-#define        IOCLOSE 64      /* >&- */
-
-#define        IODEFAULT (-1)  /* token for default IO unit */
-
-static struct  wdblock *wdlist;
-static struct  wdblock *iolist;
-
-/*
- * parsing & execution environment
- */
-static struct  env {
-       char    *linep;
-       struct  io      *iobase;
-       struct  io      *iop;
-       xint    *errpt;
-       int     iofd;
-       struct  env     *oenv;
-} e;
-
-/*
- * flags:
- * -e: quit on error
- * -k: look for name=value everywhere on command line
- * -n: no execution
- * -t: exit after reading and executing one command
- * -v: echo as read
- * -x: trace
- * -u: unset variables net diagnostic
- */
-static char    *flag;
-
-static char    *null;  /* null value for variable */
-static int     intr;   /* interrupt pending */
-
-static char    *trap[_NSIG+1];
-static char    ourtrap[_NSIG+1];
-static int     trapset;        /* trap pending */
-
-static int     heedint;        /* heed interrupt signals */
-
-static int     yynerrs;        /* yacc */
-
-static char    line[LINELIM];
-static char    *elinep;
-
-/*
- * other functions
- */
-static int (*inbuilt(char *s ))(void);
-
-static char *rexecve (char *c , char **v, char **envp );
-static char *space (int n );
-static char *strsave (char *s, int a );
-static char *evalstr (char *cp, int f );
-static char *putn (int n );
-static char *itoa (unsigned u, int n );
-static char *unquote (char *as );
-static struct var *lookup (char *n );
-static int rlookup (char *n );
-static struct wdblock *glob (char *cp, struct wdblock *wb );
-static int my_getc( int ec);
-static int subgetc (int ec, int quoted );
-static char **makenv (void);
-static char **eval (char **ap, int f );
-static int setstatus (int s );
-static int waitfor (int lastpid, int canintr );
-
-static void onintr (int s ); /* SIGINT handler */
-
-static int newenv (int f );
-static void quitenv (void);
-static void err (char *s );
-static int anys (char *s1, char *s2 );
-static int any (int c, char *s );
-static void next (int f );
-static void setdash (void);
-static void onecommand (void);
-static void runtrap (int i );
-static int gmatch (char *s, char *p );
-
-/*
- * error handling
- */
-static void leave (void); /* abort shell (or fail in subshell) */
-static void fail (void);        /* fail but return to process next command */
-static void warn (char *s );
-static void sig (int i );       /* default signal handler */
-
-
-
-/* -------- area stuff -------- */
-
-#define        REGSIZE         sizeof(struct region)
-#define GROWBY         256
-//#define      SHRINKBY   64
-#undef SHRINKBY
-#define FREE 32767
-#define BUSY 0
-#define        ALIGN (sizeof(int)-1)
-
-
-struct region {
-       struct  region *next;
-       int     area;
-};
-
-
-
-/* -------- grammar stuff -------- */
-typedef union {
-       char    *cp;
-       char    **wp;
-       int     i;
-       struct  op *o;
-} YYSTYPE;
-#define        WORD    256
-#define        LOGAND  257
-#define        LOGOR   258
-#define        BREAK   259
-#define        IF      260
-#define        THEN    261
-#define        ELSE    262
-#define        ELIF    263
-#define        FI      264
-#define        CASE    265
-#define        ESAC    266
-#define        FOR     267
-#define        WHILE   268
-#define        UNTIL   269
-#define        DO      270
-#define        DONE    271
-#define        IN      272
-#define        YYERRCODE 300
-
-/* flags to yylex */
-#define        CONTIN  01      /* skip new lines to complete command */
-
-#define        SYNTAXERR       zzerr()
-static struct op *pipeline(int cf );
-static struct op *andor(void);
-static struct op *c_list(void);
-static int synio(int cf );
-static void musthave (int c, int cf );
-static struct op *simple(void);
-static struct op *nested(int type, int mark );
-static struct op *command(int cf );
-static struct op *dogroup(int onlydone );
-static struct op *thenpart(void);
-static struct op *elsepart(void);
-static struct op *caselist(void);
-static struct op *casepart(void);
-static char **pattern(void);
-static char **wordlist(void);
-static struct op *list(struct op *t1, struct op *t2 );
-static struct op *block(int type, struct op *t1, struct op *t2, char **wp );
-static struct op *newtp(void);
-static struct op *namelist(struct op *t );
-static char **copyw(void);
-static void word(char *cp );
-static struct ioword **copyio(void);
-static struct ioword *io (int u, int f, char *cp );
-static void zzerr(void);
-static void yyerror(char *s );
-static int yylex(int cf );
-static int collect(int c, int c1 );
-static int dual(int c );
-static void diag(int ec );
-static char *tree(unsigned size );
-
-/* -------- var.h -------- */
-
-struct var {
-       char    *value;
-       char    *name;
-       struct  var     *next;
-       char    status;
-};
-#define        COPYV   1       /* flag to setval, suggesting copy */
-#define        RONLY   01      /* variable is read-only */
-#define        EXPORT  02      /* variable is to be exported */
-#define        GETCELL 04      /* name & value space was got with getcell */
-
-static struct  var     *vlist;         /* dictionary */
-
-static struct  var     *homedir;       /* home directory */
-static struct  var     *prompt;        /* main prompt */
-static struct  var     *cprompt;       /* continuation prompt */
-static struct  var     *path;          /* search path for commands */
-static struct  var     *shell;         /* shell to interpret command files */
-static struct  var     *ifs;           /* field separators */
-
-static int yyparse (void);
-static struct var *lookup (char *n );
-static void setval (struct var *vp, char *val );
-static void nameval (struct var *vp, char *val, char *name );
-static void export (struct var *vp );
-static void ronly (struct var *vp );
-static int isassign (char *s );
-static int checkname (char *cp );
-static int assign (char *s, int cf );
-static void putvlist (int f, int out );
-static int eqname (char *n1, char *n2 );
-
-static int execute (struct op *t, int *pin, int *pout, int act );
-
-/* -------- io.h -------- */
-/* io buffer */
-struct iobuf {
-  unsigned id;                         /* buffer id */
-  char buf[512];                       /* buffer */
-  char *bufp;                          /* pointer into buffer */
-  char *ebufp;                         /* pointer to end of buffer */
-};
-
-/* possible arguments to an IO function */
-struct ioarg {
-       char    *aword;
-       char    **awordlist;
-       int     afile;          /* file descriptor */
-       unsigned afid;          /* buffer id */
-       long    afpos;          /* file position */
-       struct iobuf *afbuf;    /* buffer for this file */
-};
-//static struct ioarg ioargstack[NPUSH];
-#define AFID_NOBUF     (~0)
-#define AFID_ID                0
-
-/* an input generator's state */
-struct io {
-       int     (*iofn)();
-       struct  ioarg   *argp;
-       int     peekc;
-       char    prev;           /* previous character read by readc() */
-       char    nlcount;        /* for `'s */
-       char    xchar;          /* for `'s */
-       char    task;           /* reason for pushed IO */
-};
-//static       struct  io      iostack[NPUSH];
-#define        XOTHER  0       /* none of the below */
-#define        XDOLL   1       /* expanding ${} */
-#define        XGRAVE  2       /* expanding `'s */
-#define        XIO     3       /* file IO */
-
-/* in substitution */
-#define        INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
-
-/*
- * input generators for IO structure
- */
-static int nlchar (struct ioarg *ap );
-static int strchar (struct ioarg *ap );
-static int qstrchar (struct ioarg *ap );
-static int filechar (struct ioarg *ap );
-static int herechar (struct ioarg *ap );
-static int linechar (struct ioarg *ap );
-static int gravechar (struct ioarg *ap, struct io *iop );
-static int qgravechar (struct ioarg *ap, struct io *iop );
-static int dolchar (struct ioarg *ap );
-static int wdchar (struct ioarg *ap );
-static void scraphere (void);
-static void freehere (int area );
-static void gethere (void);
-static void markhere (char *s, struct ioword *iop );
-static int herein (char *hname, int xdoll );
-static int run (struct ioarg *argp, int (*f)());
-
-/*
- * IO functions
- */
-static int eofc (void);
-static int readc (void);
-static void unget (int c );
-static void ioecho (int c );
-static void prs (char *s );
-static void prn (unsigned u );
-static void closef (int i );
-static void closeall (void);
-
-/*
- * IO control
- */
-static void pushio (struct ioarg *argp, int (*fn)());
-static int remap (int fd );
-static int openpipe (int *pv );
-static void closepipe (int *pv );
-static struct io *setbase (struct io *ip );
-
-static struct  ioarg   temparg;        /* temporary for PUSHIO */
-#define        PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
-#define        RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
-
-/* -------- word.h -------- */
-
-#define        NSTART  16      /* default number of words to allow for initially */
-
-struct wdblock {
-       short   w_bsize;
-       short   w_nword;
-       /* bounds are arbitrary */
-       char    *w_words[1];
-};
-
-static struct wdblock *addword (char *wd, struct wdblock *wb );
-static struct wdblock *newword (int nw );
-static char **getwords (struct wdblock *wb );
-
-/* -------- area.h -------- */
-
-/*
- * storage allocation
- */
-static char *getcell (unsigned nbytes );
-static void garbage (void);
-static void setarea (char *cp, int a );
-static int getarea (char *cp );
-static void freearea (int a );
-static void freecell (char *cp );
-static int     areanum;        /* current allocation area */
-
-#define        NEW(type) (type *)getcell(sizeof(type))
-#define        DELETE(obj)     freecell((char *)obj)
-
-
-/* -------- misc stuff -------- */
-
-static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked );
-static int iosetup (struct ioword *iop, int pipein, int pipeout );
-static void echo(char **wp );
-static struct op **find1case (struct op *t, char *w );
-static struct op *findcase (struct op *t, char *w );
-static void brkset(struct brkcon *bc );
-static int dolabel(void);
-static int dohelp(void);
-static int dochdir(struct op *t );
-static int doshift(struct op *t );
-static int dologin(struct op *t );
-static int doumask(struct op *t );
-static int doexec(struct op *t );
-static int dodot(struct op *t );
-static int dowait(struct op *t );
-static int doread(struct op *t );
-static int doeval(struct op *t );
-static int dotrap(struct op *t );
-static int getsig(char *s );
-static void setsig (int n, void (*f)());
-static int getn(char *as );
-static int dobreak(struct op *t );
-static int docontinue(struct op *t );
-static int brkcontin (char *cp, int val );
-static int doexit(struct op *t );
-static int doexport(struct op *t );
-static int doreadonly(struct op *t );
-static void rdexp (char **wp, void (*f)(), int key);
-static void badid(char *s );
-static int doset(struct op *t );
-static void varput (char *s, int out );
-static int dotimes(void);
-static int expand (char *cp, struct wdblock **wbp, int f );
-static char *blank(int f );
-static int dollar(int quoted );
-static int grave(int quoted );
-static void globname (char *we, char *pp );
-static char *generate (char *start1, char *end1, char *middle, char *end );
-static int anyspcl(struct wdblock *wb );
-static int xstrcmp (char *p1, char *p2 );
-static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *));
-static void glob1 (char *base, char *lim );
-static void glob2 (char *i, char *j );
-static void glob3 (char *i, char *j, char *k );
-static void readhere (char **name, char *s, int ec );
-static void pushio(struct ioarg *argp, int (*fn)());
-static int xxchar(struct ioarg *ap );
-
-struct here {
-       char    *h_tag;
-       int     h_dosub;
-       struct  ioword *h_iop;
-       struct  here    *h_next;
-};
-
-static char    *signame[] = {
-       "Signal 0",
-       "Hangup",
-       (char *)NULL,   /* interrupt */
-       "Quit",
-       "Illegal instruction",
-       "Trace/BPT trap",
-       "Abort",
-       "Bus error",
-       "Floating Point Exception",
-       "Killed",
-       "SIGUSR1",
-       "SIGSEGV",
-       "SIGUSR2",
-       (char *)NULL,   /* broken pipe */
-       "Alarm clock",
-       "Terminated",
-};
-#define        NSIGNAL (sizeof(signame)/sizeof(signame[0]))
-
-struct res {
-       char *r_name;
-       int       r_val;
-};
-static struct res restab[] = {
-    {"for",            FOR},
-    {"case",   CASE},
-    {"esac",   ESAC},
-    {"while",  WHILE},
-    {"do",             DO},
-    {"done",   DONE},
-    {"if",             IF},
-    {"in",             IN},
-    {"then",   THEN},
-    {"else",   ELSE},
-    {"elif",   ELIF},
-    {"until",  UNTIL},
-    {"fi",             FI},
-
-    {";;",             BREAK},
-    {"||",             LOGOR},
-    {"&&",             LOGAND},
-    {"{",              '{'},
-    {"}",              '}'},
-    {0,                0},
-};
-
-
-struct builtincmd {
-       const char *name;
-       int (*builtinfunc)();
-};
-static const struct    builtincmd      builtincmds[] = {
-    {".",              dodot},
-    {":",              dolabel},
-    {"break",  dobreak},
-    {"cd",             dochdir},
-    {"continue",docontinue},
-    {"eval",   doeval},
-    {"exec",   doexec},
-    {"exit",   doexit},
-    {"export", doexport},
-    {"help",   dohelp},
-    {"login",  dologin},
-    {"newgrp", dologin},
-    {"read",   doread},
-    {"readonly",doreadonly},
-    {"set",            doset},
-    {"shift",  doshift},
-    {"times",  dotimes},
-    {"trap",   dotrap},
-    {"umask",  doumask},
-    {"wait",   dowait},
-    {0,0}
-};
-
-/* Globals */
-extern char    **environ;      /* environment pointer */
-static char    **dolv;
-static int     dolc;
-static int     exstat;
-static char    gflg;
-static int     interactive;    /* Is this an interactive shell */
-static int     execflg;
-static int     multiline;      /* \n changed to ; */
-static struct  op      *outtree;       /* result from parser */
-static xint    *failpt;
-static xint    *errpt;
-static struct  brkcon  *brklist;
-static int     isbreak;
-static struct  wdblock *wdlist;
-static struct  wdblock *iolist;
-static char    *trap[_NSIG+1];
-static char    ourtrap[_NSIG+1];
-static int     trapset;        /* trap pending */
-static int     yynerrs;        /* yacc */
-static char    line[LINELIM];
-static struct  var     *vlist;         /* dictionary */
-static struct  var     *homedir;       /* home directory */
-static struct  var     *prompt;        /* main prompt */
-static struct  var     *cprompt;       /* continuation prompt */
-static struct  var     *path;          /* search path for commands */
-static struct  var     *shell;         /* shell to interpret command files */
-static struct  var     *ifs;           /* field separators */
-static struct  ioarg ioargstack[NPUSH];
-static struct  io      iostack[NPUSH];
-static int     areanum;        /* current allocation area */
-static int     intr;
-static int     inparse;
-static char    flags['z'-'a'+1];
-static char    *flag = flags-'a';
-static char    *elinep = line+sizeof(line)-5;
-static char    *null   = "";
-static int     heedint =1;
-static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL};
-static void (*qflag)(int) = SIG_IGN;
-static char    shellname[] = "/bin/sh";
-static char    search[] = ":/bin:/usr/bin";
-static int     startl;
-static int     peeksym;
-static int     nlseen;
-static int     iounit = IODEFAULT;
-static YYSTYPE yylval;
-static struct iobuf sharedbuf = {AFID_NOBUF};
-static struct iobuf mainbuf = {AFID_NOBUF};
-static unsigned bufid = AFID_ID;       /* buffer id counter */
-static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
-static struct here *inhere;            /* list of hear docs while parsing */
-static struct here *acthere;           /* list of active here documents */
-static struct region *areabot;         /* bottom of area */
-static struct region *areatop;         /* top of area */
-static struct region *areanxt;         /* starting point of scan */
-static void * brktop;
-static void * brkaddr;
-
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-static char * current_prompt;
-#endif
-
-
-/* -------- sh.c -------- */
-/*
- * shell
- */
-
-
-extern int msh_main(int argc, char **argv)
-{
-       register int f;
-       register char *s;
-       int cflag;
-       char *name, **ap;
-       int (*iof)();
-
-       initarea();
-       if ((ap = environ) != NULL) {
-               while (*ap)
-                       assign(*ap++, !COPYV);
-               for (ap = environ; *ap;)
-                       export(lookup(*ap++));
-       }
-       closeall();
-       areanum = 1;
-
-       shell = lookup("SHELL");
-       if (shell->value == null)
-               setval(shell, shellname);
-       export(shell);
-
-       homedir = lookup("HOME");
-       if (homedir->value == null)
-               setval(homedir, "/");
-       export(homedir);
-
-       setval(lookup("$"), itoa(getpid(), 5));
-
-       path = lookup("PATH");
-       if (path->value == null)
-               setval(path, search);
-       export(path);
-
-       ifs = lookup("IFS");
-       if (ifs->value == null)
-               setval(ifs, " \t\n");
-
-       prompt = lookup("PS1");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (prompt->value == null)
-#endif
-               setval(prompt, "$ ");
-       if (geteuid() == 0) {
-               setval(prompt, "# ");
-               prompt->status &= ~EXPORT;
-       }
-       cprompt = lookup("PS2");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (cprompt->value == null)
-#endif
-               setval(cprompt, "> ");
-
-       iof = filechar;
-       cflag = 0;
-       name = *argv++;
-       if (--argc >= 1) {
-               if(argv[0][0] == '-' && argv[0][1] != '\0') {
-                       for (s = argv[0]+1; *s; s++)
-                               switch (*s) {
-                               case 'c':
-                                       prompt->status &= ~EXPORT;
-                                       cprompt->status &= ~EXPORT;
-                                       setval(prompt, "");
-                                       setval(cprompt, "");
-                                       cflag = 1;
-                                       if (--argc > 0)
-                                               PUSHIO(aword, *++argv, iof = nlchar);
-                                       break;
-       
-                               case 'q':
-                                       qflag = SIG_DFL;
-                                       break;
-
-                               case 's':
-                                       /* standard input */
-                                       break;
-
-                               case 't':
-                                       prompt->status &= ~EXPORT;
-                                       setval(prompt, "");
-                                       iof = linechar;
-                                       break;
-       
-                               case 'i':
-                                       interactive++;
-                               default:
-                                       if (*s>='a' && *s<='z')
-                                               flag[(int)*s]++;
-                               }
-               } else {
-                       argv--;
-                       argc++;
-               }
-               if (iof == filechar && --argc > 0) {
-                       setval(prompt, "");
-                       setval(cprompt, "");
-                       prompt->status &= ~EXPORT;
-                       cprompt->status &= ~EXPORT;
-                       if (newfile(name = *++argv))
-                               exit(1);
-               }
-       }
-       setdash();
-       if (e.iop < iostack) {
-               PUSHIO(afile, 0, iof);
-               if (isatty(0) && isatty(1) && !cflag) {
-                       interactive++;
-                       printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
-                       printf( "Enter 'help' for a list of built-in commands.\n\n");
-               }
-       }
-       signal(SIGQUIT, qflag);
-       if (name && name[0] == '-') {
-               interactive++;
-               if ((f = open(".profile", 0)) >= 0)
-                       next(remap(f));
-               if ((f = open("/etc/profile", 0)) >= 0)
-                       next(remap(f));
-       }
-       if (interactive)
-               signal(SIGTERM, sig);
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
-               signal(SIGINT, onintr);
-       dolv = argv;
-       dolc = argc;
-       dolv[0] = name;
-       if (dolc > 1) {
-               for (ap = ++argv; --argc > 0;) {
-                       if (assign(*ap = *argv++, !COPYV)) {
-                               dolc--; /* keyword */
-                       } else {
-                               ap++;
-                       }
-               }
-       }       
-       setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
-
-       for (;;) {
-               if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                       current_prompt=prompt->value;
-#else
-                       prs(prompt->value);
-#endif
-               }
-               onecommand();
-       }
-}
-
-static void
-setdash()
-{
-       register char *cp;
-       register int c;
-       char m['z'-'a'+1];
-
-       cp = m;
-       for (c='a'; c<='z'; c++)
-               if (flag[c])
-                       *cp++ = c;
-       *cp = 0;
-       setval(lookup("-"), m);
-}
-
-static int
-newfile(s)
-register char *s;
-{
-       register int f;
-
-       if (strcmp(s, "-") != 0) {
-               f = open(s, 0);
-               if (f < 0) {
-                       prs(s);
-                       err(": cannot open");
-                       return(1);
-               }
-       } else
-               f = 0;
-       next(remap(f));
-       return(0);
-}
-
-static void
-onecommand()
-{
-       register int i;
-       jmp_buf m1;
-
-       while (e.oenv)
-               quitenv();
-       areanum = 1;
-       freehere(areanum);
-       freearea(areanum);
-       garbage();
-       wdlist = 0;
-       iolist = 0;
-       e.errpt = 0;
-       e.linep = line;
-       yynerrs = 0;
-       multiline = 0;
-       inparse = 1;
-       intr = 0;
-       execflg = 0;
-       setjmp(failpt = m1);    /* Bruce Evans' fix */
-       if (setjmp(failpt = m1) || yyparse() || intr) {
-               while (e.oenv)
-                       quitenv();
-               scraphere();
-               if (!interactive && intr)
-                       leave();
-               inparse = 0;
-               intr = 0;
-               return;
-       }
-       inparse = 0;
-       brklist = 0;
-       intr = 0;
-       execflg = 0;
-       if (!flag['n'])
-               execute(outtree, NOPIPE, NOPIPE, 0);
-       if (!interactive && intr) {
-               execflg = 0;
-               leave();
-       }
-       if ((i = trapset) != 0) {
-               trapset = 0;
-               runtrap(i);
-       }
-}
-
-static void
-fail()
-{
-       longjmp(failpt, 1);
-       /* NOTREACHED */
-}
-
-static void
-leave()
-{
-       if (execflg)
-               fail();
-       scraphere();
-       freehere(1);
-       runtrap(0);
-       exit(exstat);
-       /* NOTREACHED */
-}
-
-static void
-warn(s)
-register char *s;
-{
-       if(*s) {
-               prs(s);
-               exstat = -1;
-       }
-       prs("\n");
-       if (flag['e'])
-               leave();
-}
-
-static void
-err(s)
-char *s;
-{
-       warn(s);
-       if (flag['n'])
-               return;
-       if (!interactive)
-               leave();
-       if (e.errpt)
-               longjmp(e.errpt, 1);
-       closeall();
-       e.iop = e.iobase = iostack;
-}
-
-static int
-newenv(f)
-int f;
-{
-       register struct env *ep;
-
-       if (f) {
-               quitenv();
-               return(1);
-       }
-       ep = (struct env *) space(sizeof(*ep));
-       if (ep == NULL) {
-               while (e.oenv)
-                       quitenv();
-               fail();
-       }
-       *ep = e;
-       e.oenv = ep;
-       e.errpt = errpt;
-       return(0);
-}
-
-static void
-quitenv()
-{
-       register struct env *ep;
-       register int fd;
-
-       if ((ep = e.oenv) != NULL) {
-               fd = e.iofd;
-               e = *ep;
-               /* should close `'d files */
-               DELETE(ep);
-               while (--fd >= e.iofd)
-                       close(fd);
-       }
-}
-
-/*
- * Is any character from s1 in s2?
- */
-static int
-anys(s1, s2)
-register char *s1, *s2;
-{
-       while (*s1)
-               if (any(*s1++, s2))
-                       return(1);
-       return(0);
-}
-
-/*
- * Is character c in s?
- */
-static int
-any(c, s)
-register int c;
-register char *s;
-{
-       while (*s)
-               if (*s++ == c)
-                       return(1);
-       return(0);
-}
-
-static char *
-putn(n)
-register int n;
-{
-       return(itoa(n, -1));
-}
-
-static char *
-itoa(u, n)
-register unsigned u;
-int n;
-{
-       register char *cp;
-       static char s[20];
-       int m;
-
-       m = 0;
-       if (n < 0 && (int) u < 0) {
-               m++;
-               u = -u;
-       }
-       cp = s+sizeof(s);
-       *--cp = 0;
-       do {
-               *--cp = u%10 + '0';
-               u /= 10;
-       } while (--n > 0 || u);
-       if (m)
-               *--cp = '-';
-       return(cp);
-}
-
-static void
-next(f)
-int f;
-{
-       PUSHIO(afile, f, filechar);
-}
-
-static void
-onintr(s)
-int s;                         /* ANSI C requires a parameter */
-{
-       signal(SIGINT, onintr);
-       intr = 1;
-       if (interactive) {
-               if (inparse) {
-                       prs("\n");
-                       fail();
-               }
-       }
-       else if (heedint) {
-               execflg = 0;
-               leave();
-       }
-}
-
-static char *
-space(n)
-int n;
-{
-       register char *cp;
-
-       if ((cp = getcell(n)) == 0)
-               err("out of string space");
-       return(cp);
-}
-
-static char *
-strsave(s, a)
-register char *s;
-int a;
-{
-       register char *cp, *xp;
-
-       if ((cp = space(strlen(s)+1)) != NULL) {
-               setarea((char *)cp, a);
-               for (xp = cp; (*xp++ = *s++) != '\0';)
-                       ;
-               return(cp);
-       }
-       return("");
-}
-
-/*
- * trap handling
- */
-static void
-sig(i)
-register int i;
-{
-       trapset = i;
-       signal(i, sig);
-}
-
-static void runtrap(i)
-int i;
-{
-       char *trapstr;
-
-       if ((trapstr = trap[i]) == NULL)
-               return;
-       if (i == 0)
-               trap[i] = 0;
-       RUN(aword, trapstr, nlchar);
-}
-
-/* -------- var.c -------- */
-
-/*
- * Find the given name in the dictionary
- * and return its value.  If the name was
- * not previously there, enter it now and
- * return a null value.
- */
-static struct var *
-lookup(n)
-register char *n;
-{
-       register struct var *vp;
-       register char *cp;
-       register int c;
-       static struct var dummy;
-
-       if (isdigit(*n)) {
-               dummy.name = n;
-               for (c = 0; isdigit(*n) && c < 1000; n++)
-                       c = c*10 + *n-'0';
-               dummy.status = RONLY;
-               dummy.value = c <= dolc? dolv[c]: null;
-               return(&dummy);
-       }
-       for (vp = vlist; vp; vp = vp->next)
-               if (eqname(vp->name, n))
-                       return(vp);
-       cp = findeq(n);
-       vp = (struct var *)space(sizeof(*vp));
-       if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
-               dummy.name = dummy.value = "";
-               return(&dummy);
-       }
-       for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
-               ;
-       if (*cp == 0)
-               *cp = '=';
-       *++cp = 0;
-       setarea((char *)vp, 0);
-       setarea((char *)vp->name, 0);
-       vp->value = null;
-       vp->next = vlist;
-       vp->status = GETCELL;
-       vlist = vp;
-       return(vp);
-}
-
-/*
- * give variable at `vp' the value `val'.
- */
-static void
-setval(vp, val)
-struct var *vp;
-char *val;
-{
-       nameval(vp, val, (char *)NULL);
-}
-
-/*
- * if name is not NULL, it must be
- * a prefix of the space `val',
- * and end with `='.
- * this is all so that exporting
- * values is reasonably painless.
- */
-static void
-nameval(vp, val, name)
-register struct var *vp;
-char *val, *name;
-{
-       register char *cp, *xp;
-       char *nv;
-       int fl;
-
-       if (vp->status & RONLY) {
-               for (xp = vp->name; *xp && *xp != '=';)
-                       putc(*xp++, stderr);
-               err(" is read-only");
-               return;
-       }
-       fl = 0;
-       if (name == NULL) {
-               xp = space(strlen(vp->name)+strlen(val)+2);
-               if (xp == 0)
-                       return;
-               /* make string:  name=value */
-               setarea((char *)xp, 0);
-               name = xp;
-               for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
-                       ;
-               if (*xp++ == 0)
-                       xp[-1] = '=';
-               nv = xp;
-               for (cp = val; (*xp++ = *cp++) != '\0';)
-                       ;
-               val = nv;
-               fl = GETCELL;
-       }
-       if (vp->status & GETCELL)
-               freecell(vp->name);    /* form new string `name=value' */
-       vp->name = name;
-       vp->value = val;
-       vp->status |= fl;
-}
-
-static void
-export(vp)
-struct var *vp;
-{
-       vp->status |= EXPORT;
-}
-
-static void
-ronly(vp)
-struct var *vp;
-{
-       if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
-               vp->status |= RONLY;
-}
-
-static int
-isassign(s)
-register char *s;
-{
-       if (!isalpha((int)*s) && *s != '_')
-               return(0);
-       for (; *s != '='; s++)
-               if (*s == 0 || (!isalnum(*s) && *s != '_'))
-                       return(0);
-       return(1);
-}
-
-static int
-assign(s, cf)
-register char *s;
-int cf;
-{
-       register char *cp;
-       struct var *vp;
-
-       if (!isalpha(*s) && *s != '_')
-               return(0);
-       for (cp = s; *cp != '='; cp++)
-               if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
-                       return(0);
-       vp = lookup(s);
-       nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
-       if (cf != COPYV)
-               vp->status &= ~GETCELL;
-       return(1);
-}
-
-static int
-checkname(cp)
-register char *cp;
-{
-       if (!isalpha(*cp++) && *(cp-1) != '_')
-               return(0);
-       while (*cp)
-               if (!isalnum(*cp++) && *(cp-1) != '_')
-                       return(0);
-       return(1);
-}
-
-static void
-putvlist(f, out)
-register int f, out;
-{
-       register struct var *vp;
-
-       for (vp = vlist; vp; vp = vp->next)
-               if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
-                       if (vp->status & EXPORT)
-                               write(out, "export ", 7);
-                       if (vp->status & RONLY)
-                               write(out, "readonly ", 9);
-                       write(out, vp->name, (int)(findeq(vp->name) - vp->name));
-                       write(out, "\n", 1);
-               }
-}
-
-static int
-eqname(n1, n2)
-register char *n1, *n2;
-{
-       for (; *n1 != '=' && *n1 != 0; n1++)
-               if (*n2++ != *n1)
-                       return(0);
-       return(*n2 == 0 || *n2 == '=');
-}
-
-static char *
-findeq(cp)
-register char *cp;
-{
-       while (*cp != '\0' && *cp != '=')
-               cp++;
-       return(cp);
-}
-
-/* -------- gmatch.c -------- */
-/*
- * int gmatch(string, pattern)
- * char *string, *pattern;
- *
- * Match a pattern as in sh(1).
- */
-
-#define        CMASK   0377
-#define        QUOTE   0200
-#define        QMASK   (CMASK&~QUOTE)
-#define        NOT     '!'     /* might use ^ */
-
-static int
-gmatch(s, p)
-register char *s, *p;
-{
-       register int sc, pc;
-
-       if (s == NULL || p == NULL)
-               return(0);
-       while ((pc = *p++ & CMASK) != '\0') {
-               sc = *s++ & QMASK;
-               switch (pc) {
-               case '[':
-                       if ((p = cclass(p, sc)) == NULL)
-                               return(0);
-                       break;
-
-               case '?':
-                       if (sc == 0)
-                               return(0);
-                       break;
-
-               case '*':
-                       s--;
-                       do {
-                               if (*p == '\0' || gmatch(s, p))
-                                       return(1);
-                       } while (*s++ != '\0');
-                       return(0);
-
-               default:
-                       if (sc != (pc&~QUOTE))
-                               return(0);
-               }
-       }
-       return(*s == 0);
-}
-
-static char *
-cclass(p, sub)
-register char *p;
-register int sub;
-{
-       register int c, d, not, found;
-
-       if ((not = *p == NOT) != 0)
-               p++;
-       found = not;
-       do {
-               if (*p == '\0')
-                       return((char *)NULL);
-               c = *p & CMASK;
-               if (p[1] == '-' && p[2] != ']') {
-                       d = p[2] & CMASK;
-                       p++;
-               } else
-                       d = c;
-               if (c == sub || (c <= sub && sub <= d))
-                       found = !not;
-       } while (*++p != ']');
-       return(found? p+1: (char *)NULL);
-}
-
-
-/* -------- area.c -------- */
-
-/*
- * All memory between (char *)areabot and (char *)(areatop+1) is
- * exclusively administered by the area management routines.
- * It is assumed that sbrk() and brk() manipulate the high end.
- */
-
-#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
-
-static void
-initarea()
-{
-       brkaddr = malloc(65000);
-       brktop = brkaddr + 65000;
-
-       while ((int)sbrk(0) & ALIGN)
-               sbrk(1);
-       areabot = (struct region *)sbrk(REGSIZE);
-
-       areabot->next = areabot;
-       areabot->area = BUSY;
-       areatop = areabot;
-       areanxt = areabot;
-}
-
-char *
-getcell(nbytes)
-unsigned nbytes;
-{
-       register int nregio;
-       register struct region *p, *q;
-       register int i;
-
-       if (nbytes == 0) {
-               puts("getcell(0)");
-               abort();
-       }       /* silly and defeats the algorithm */
-       /*
-        * round upwards and add administration area
-        */
-       nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
-       for (p = areanxt;;) {
-               if (p->area > areanum) {
-                       /*
-                        * merge free cells
-                        */
-                       while ((q = p->next)->area > areanum && q != areanxt)
-                               p->next = q->next;
-                       /*
-                        * exit loop if cell big enough
-                        */
-                       if (q >= p + nregio)
-                               goto found;
-               }
-               p = p->next;
-               if (p == areanxt)
-                       break;
-       }
-       i = nregio >= GROWBY ? nregio : GROWBY;
-       p = (struct region *)sbrk(i * REGSIZE);
-       if (p == (struct region *)-1)
-               return((char *)NULL);
-       p--;
-       if (p != areatop) {
-               puts("not contig");
-               abort();        /* allocated areas are contiguous */
-       }
-       q = p + i;
-       p->next = q;
-       p->area = FREE;
-       q->next = areabot;
-       q->area = BUSY;
-       areatop = q;
-found:
-       /*
-        * we found a FREE area big enough, pointed to by 'p', and up to 'q'
-        */
-       areanxt = p + nregio;
-       if (areanxt < q) {
-               /*
-                * split into requested area and rest
-                */
-               if (areanxt+1 > q) {
-                       puts("OOM");
-                       abort();        /* insufficient space left for admin */
-               }
-               areanxt->next = q;
-               areanxt->area = FREE;
-               p->next = areanxt;
-       }
-       p->area = areanum;
-       return((char *)(p+1));
-}
-
-static void
-freecell(cp)
-char *cp;
-{
-       register struct region *p;
-
-       if ((p = (struct region *)cp) != NULL) {
-               p--;
-               if (p < areanxt)
-                       areanxt = p;
-               p->area = FREE;
-       }
-}
-
-static void
-freearea(a)
-register int a;
-{
-       register struct region *p, *top;
-
-       top = areatop;
-       for (p = areabot; p != top; p = p->next)
-               if (p->area >= a)
-                       p->area = FREE;
-}
-
-static void
-setarea(cp,a)
-char *cp;
-int a;
-{
-       register struct region *p;
-
-       if ((p = (struct region *)cp) != NULL)
-               (p-1)->area = a;
-}
-
-int
-getarea(cp)
-char *cp;
-{
-       return ((struct region*)cp-1)->area;
-}
-
-static void
-garbage()
-{
-       register struct region *p, *q, *top;
-
-       top = areatop;
-       for (p = areabot; p != top; p = p->next) {
-               if (p->area > areanum) {
-                       while ((q = p->next)->area > areanum)
-                               p->next = q->next;
-                       areanxt = p;
-               }
-       }
-#ifdef SHRINKBY
-       if (areatop >= q + SHRINKBY && q->area > areanum) {
-               brk((char *)(q+1));
-               q->next = areabot;
-               q->area = BUSY;
-               areatop = q;
-       }
-#endif
-}
-
-/* -------- csyn.c -------- */
-/*
- * shell: syntax (C version)
- */
-
-
-int
-yyparse()
-{
-       startl  = 1;
-       peeksym = 0;
-       yynerrs = 0;
-       outtree = c_list();
-       musthave('\n', 0);
-       return(yynerrs!=0);
-}
-
-static struct op *
-pipeline(cf)
-int cf;
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = command(cf);
-       if (t != NULL) {
-               while ((c = yylex(0)) == '|') {
-                       if ((p = command(CONTIN)) == NULL)
-                               SYNTAXERR;
-                       if (t->type != TPAREN && t->type != TCOM) {
-                               /* shell statement */
-                               t = block(TPAREN, t, NOBLOCK, NOWORDS);
-                       }
-                       t = block(TPIPE, t, p, NOWORDS);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-static struct op *
-andor()
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = pipeline(0);
-       if (t != NULL) {
-               while ((c = yylex(0)) == LOGAND || c == LOGOR) {
-                       if ((p = pipeline(CONTIN)) == NULL)
-                               SYNTAXERR;
-                       t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-static struct op *
-c_list()
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = andor();
-       if (t != NULL) {
-               if((peeksym = yylex(0)) == '&')
-                       t = block(TASYNC, t, NOBLOCK, NOWORDS);
-               while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) {
-                       if ((p = andor()) == NULL)
-                               return(t);
-                       if((peeksym = yylex(0)) == '&')
-                               p = block(TASYNC, p, NOBLOCK, NOWORDS);
-                       t = list(t, p);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-
-static int
-synio(cf)
-int cf;
-{
-       register struct ioword *iop;
-       register int i;
-       register int c;
-
-       if ((c = yylex(cf)) != '<' && c != '>') {
-               peeksym = c;
-               return(0);
-       }
-       i = yylval.i;
-       musthave(WORD, 0);
-       iop = io(iounit, i, yylval.cp);
-       iounit = IODEFAULT;
-       if (i & IOHERE)
-               markhere(yylval.cp, iop);
-       return(1);
-}
-
-static void
-musthave(c, cf)
-int c, cf;
-{
-       if ((peeksym = yylex(cf)) != c)
-               SYNTAXERR;
-       peeksym = 0;
-}
-
-static struct op *
-simple()
-{
-       register struct op *t;
-
-       t = NULL;
-       for (;;) {
-               switch (peeksym = yylex(0)) {
-               case '<':
-               case '>':
-                       (void) synio(0);
-                       break;
-
-               case WORD:
-                       if (t == NULL) {
-                               t = newtp();
-                               t->type = TCOM;
-                       }
-                       peeksym = 0;
-                       word(yylval.cp);
-                       break;
-
-               default:
-                       return(t);
-               }
-       }
-}
-
-static struct op *
-nested(type, mark)
-int type, mark;
-{
-       register struct op *t;
-
-       multiline++;
-       t = c_list();
-       musthave(mark, 0);
-       multiline--;
-       return(block(type, t, NOBLOCK, NOWORDS));
-}
-
-static struct op *
-command(cf)
-int cf;
-{
-       register struct op *t;
-       struct wdblock *iosave;
-       register int c;
-
-       iosave = iolist;
-       iolist = NULL;
-       if (multiline)
-               cf |= CONTIN;
-       while (synio(cf))
-               cf = 0;
-       switch (c = yylex(cf)) {
-       default:
-               peeksym = c;
-               if ((t = simple()) == NULL) {
-                       if (iolist == NULL)
-                               return((struct op *)NULL);
-                       t = newtp();
-                       t->type = TCOM;
-               }
-               break;
-
-       case '(':
-               t = nested(TPAREN, ')');
-               break;
-
-       case '{':
-               t = nested(TBRACE, '}');
-               break;
-
-       case FOR:
-               t = newtp();
-               t->type = TFOR;
-               musthave(WORD, 0);
-               startl = 1;
-               t->str = yylval.cp;
-               multiline++;
-               t->words = wordlist();
-               if ((c = yylex(0)) != '\n' && c != ';')
-                       peeksym = c;
-               t->left = dogroup(0);
-               multiline--;
-               break;
-
-       case WHILE:
-       case UNTIL:
-               multiline++;
-               t = newtp();
-               t->type = c == WHILE? TWHILE: TUNTIL;
-               t->left = c_list();
-               t->right = dogroup(1);
-               t->words = NULL;
-               multiline--;
-               break;
-
-       case CASE:
-               t = newtp();
-               t->type = TCASE;
-               musthave(WORD, 0);
-               t->str = yylval.cp;
-               startl++;
-               multiline++;
-               musthave(IN, CONTIN);
-               startl++;
-               t->left = caselist();
-               musthave(ESAC, 0);
-               multiline--;
-               break;
-
-       case IF:
-               multiline++;
-               t = newtp();
-               t->type = TIF;
-               t->left = c_list();
-               t->right = thenpart();
-               musthave(FI, 0);
-               multiline--;
-               break;
-       }
-       while (synio(0))
-               ;
-       t = namelist(t);
-       iolist = iosave;
-       return(t);
-}
-
-static struct op *
-dogroup(onlydone)
-int onlydone;
-{
-       register int c;
-       register struct op *mylist;
-
-       c = yylex(CONTIN);
-       if (c == DONE && onlydone)
-               return((struct op *)NULL);
-       if (c != DO)
-               SYNTAXERR;
-       mylist = c_list();
-       musthave(DONE, 0);
-       return(mylist);
-}
-
-static struct op *
-thenpart()
-{
-       register int c;
-       register struct op *t;
-
-       if ((c = yylex(0)) != THEN) {
-               peeksym = c;
-               return((struct op *)NULL);
-       }
-       t = newtp();
-       t->type = 0;
-       t->left = c_list();
-       if (t->left == NULL)
-               SYNTAXERR;
-       t->right = elsepart();
-       return(t);
-}
-
-static struct op *
-elsepart()
-{
-       register int c;
-       register struct op *t;
-
-       switch (c = yylex(0)) {
-       case ELSE:
-               if ((t = c_list()) == NULL)
-                       SYNTAXERR;
-               return(t);
-
-       case ELIF:
-               t = newtp();
-               t->type = TELIF;
-               t->left = c_list();
-               t->right = thenpart();
-               return(t);
-
-       default:
-               peeksym = c;
-               return((struct op *)NULL);
-       }
-}
-
-static struct op *
-caselist()
-{
-       register struct op *t;
-
-       t = NULL;
-       while ((peeksym = yylex(CONTIN)) != ESAC)
-               t = list(t, casepart());
-       return(t);
-}
-
-static struct op *
-casepart()
-{
-       register struct op *t;
-
-       t = newtp();
-       t->type = TPAT;
-       t->words = pattern();
-       musthave(')', 0);
-       t->left = c_list();
-       if ((peeksym = yylex(CONTIN)) != ESAC)
-               musthave(BREAK, CONTIN);
-       return(t);
-}
-
-static char **
-pattern()
-{
-       register int c, cf;
-
-       cf = CONTIN;
-       do {
-               musthave(WORD, cf);
-               word(yylval.cp);
-               cf = 0;
-       } while ((c = yylex(0)) == '|');
-       peeksym = c;
-       word(NOWORD);
-       return(copyw());
-}
-
-static char **
-wordlist()
-{
-       register int c;
-
-       if ((c = yylex(0)) != IN) {
-               peeksym = c;
-               return((char **)NULL);
-       }
-       startl = 0;
-       while ((c = yylex(0)) == WORD)
-               word(yylval.cp);
-       word(NOWORD);
-       peeksym = c;
-       return(copyw());
-}
-
-/*
- * supporting functions
- */
-static struct op *
-list(t1, t2)
-register struct op *t1, *t2;
-{
-       if (t1 == NULL)
-               return(t2);
-       if (t2 == NULL)
-               return(t1);
-       return(block(TLIST, t1, t2, NOWORDS));
-}
-
-static struct op *
-block(type, t1, t2, wp)
-int type;
-struct op *t1, *t2;
-char **wp;
-{
-       register struct op *t;
-
-       t = newtp();
-       t->type = type;
-       t->left = t1;
-       t->right = t2;
-       t->words = wp;
-       return(t);
-}
-
-static int
-rlookup(n)
-register char *n;
-{
-       register struct res *rp;
-
-       for (rp = restab; rp->r_name; rp++)
-               if (strcmp(rp->r_name, n) == 0)
-                       return(rp->r_val);
-       return(0);
-}
-
-static struct op *
-newtp()
-{
-       register struct op *t;
-
-       t = (struct op *)tree(sizeof(*t));
-       t->type = 0;
-       t->words = NULL;
-       t->ioact = NULL;
-       t->left = NULL;
-       t->right = NULL;
-       t->str = NULL;
-       return(t);
-}
-
-static struct op *
-namelist(t)
-register struct op *t;
-{
-       if (iolist) {
-               iolist = addword((char *)NULL, iolist);
-               t->ioact = copyio();
-       } else
-               t->ioact = NULL;
-       if (t->type != TCOM) {
-               if (t->type != TPAREN && t->ioact != NULL) {
-                       t = block(TPAREN, t, NOBLOCK, NOWORDS);
-                       t->ioact = t->left->ioact;
-                       t->left->ioact = NULL;
-               }
-               return(t);
-       }
-       word(NOWORD);
-       t->words = copyw();
-       return(t);
-}
-
-static char **
-copyw()
-{
-       register char **wd;
-
-       wd = getwords(wdlist);
-       wdlist = 0;
-       return(wd);
-}
-
-static void
-word(cp)
-char *cp;
-{
-       wdlist = addword(cp, wdlist);
-}
-
-static struct ioword **
-copyio()
-{
-       register struct ioword **iop;
-
-       iop = (struct ioword **) getwords(iolist);
-       iolist = 0;
-       return(iop);
-}
-
-static struct ioword *
-io(u, f, cp)
-int u;
-int f;
-char *cp;
-{
-       register struct ioword *iop;
-
-       iop = (struct ioword *) tree(sizeof(*iop));
-       iop->io_unit = u;
-       iop->io_flag = f;
-       iop->io_name = cp;
-       iolist = addword((char *)iop, iolist);
-       return(iop);
-}
-
-static void
-zzerr()
-{
-       yyerror("syntax error");
-}
-
-static void
-yyerror(s)
-char *s;
-{
-       yynerrs++;
-       if (interactive && e.iop <= iostack) {
-               multiline = 0;
-               while (eofc() == 0 && yylex(0) != '\n')
-                       ;
-       }
-       err(s);
-       fail();
-}
-
-static int
-yylex(cf)
-int cf;
-{
-       register int c, c1;
-       int atstart;
-
-       if ((c = peeksym) > 0) {
-               peeksym = 0;
-               if (c == '\n')
-                       startl = 1;
-               return(c);
-       }
-       nlseen = 0;
-       e.linep = line;
-       atstart = startl;
-       startl = 0;
-       yylval.i = 0;
-
-loop:
-       while ((c = my_getc(0)) == ' ' || c == '\t')
-               ;
-       switch (c) {
-       default:
-               if (any(c, "0123456789")) {
-                       unget(c1 = my_getc(0));
-                       if (c1 == '<' || c1 == '>') {
-                               iounit = c - '0';
-                               goto loop;
-                       }
-                       *e.linep++ = c;
-                       c = c1;
-               }
-               break;
-
-       case '#':
-               while ((c = my_getc(0)) != 0 && c != '\n')
-                       ;
-               unget(c);
-               goto loop;
-
-       case 0:
-               return(c);
-
-       case '$':
-               *e.linep++ = c;
-               if ((c = my_getc(0)) == '{') {
-                       if ((c = collect(c, '}')) != '\0')
-                               return(c);
-                       goto pack;
-               }
-               break;
-
-       case '`':
-       case '\'':
-       case '"':
-               if ((c = collect(c, c)) != '\0')
-                       return(c);
-               goto pack;
-
-       case '|':
-       case '&':
-       case ';':
-               if ((c1 = dual(c)) != '\0') {
-                       startl = 1;
-                       return(c1);
-               }
-               startl = 1;
-               return(c);
-       case '^':
-               startl = 1;
-               return('|');
-       case '>':
-       case '<':
-               diag(c);
-               return(c);
-
-       case '\n':
-               nlseen++;
-               gethere();
-               startl = 1;
-               if (multiline || cf & CONTIN) {
-                       if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                       current_prompt=cprompt->value;
-#else
-                       prs(cprompt->value);
-#endif
-                       }
-                       if (cf & CONTIN)
-                               goto loop;
-               }
-               return(c);
-
-       case '(':
-       case ')':
-               startl = 1;
-               return(c);
-       }
-
-       unget(c);
-
-pack:
-       while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
-               if (e.linep >= elinep)
-                       err("word too long");
-               else
-                       *e.linep++ = c;
-       unget(c);
-       if(any(c, "\"'`$"))
-               goto loop;
-       *e.linep++ = '\0';
-       if (atstart && (c = rlookup(line))!=0) {
-               startl = 1;
-               return(c);
-       }
-       yylval.cp = strsave(line, areanum);
-       return(WORD);
-}
-
-static int
-collect(c, c1)
-register int c, c1;
-{
-       char s[2];
-
-       *e.linep++ = c;
-       while ((c = my_getc(c1)) != c1) {
-               if (c == 0) {
-                       unget(c);
-                       s[0] = c1;
-                       s[1] = 0;
-                       prs("no closing "); yyerror(s);
-                       return(YYERRCODE);
-               }
-               if (interactive && c == '\n' && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                   current_prompt=cprompt->value;
-#else
-                   prs(cprompt->value);
-#endif
-               }
-               *e.linep++ = c;
-       }
-       *e.linep++ = c;
-       return(0);
-}
-
-static int
-dual(c)
-register int c;
-{
-       char s[3];
-       register char *cp = s;
-
-       *cp++ = c;
-       *cp++ = my_getc(0);
-       *cp = 0;
-       if ((c = rlookup(s)) == 0)
-               unget(*--cp);
-       return(c);
-}
-
-static void
-diag(ec)
-register int ec;
-{
-       register int c;
-
-       c = my_getc(0);
-       if (c == '>' || c == '<') {
-               if (c != ec)
-                       zzerr();
-               yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE;
-               c = my_getc(0);
-       } else
-               yylval.i = ec == '>'? IOWRITE: IOREAD;
-       if (c != '&' || yylval.i == IOHERE)
-               unget(c);
-       else
-               yylval.i |= IODUP;
-}
-
-static char *
-tree(size)
-unsigned size;
-{
-       register char *t;
-
-       if ((t = getcell(size)) == NULL) {
-               prs("command line too complicated\n");
-               fail();
-               /* NOTREACHED */
-       }
-       return(t);
-}
-
-/* VARARGS1 */
-/* ARGSUSED */
-
-/* -------- exec.c -------- */
-
-/*
- * execute tree
- */
-
-
-static int
-execute(t, pin, pout, act)
-register struct op *t;
-int *pin, *pout;
-int act;
-{
-       register struct op *t1;
-       volatile int i, rv, a;
-       char *cp, **wp, **wp2;
-       struct var *vp;
-       struct brkcon bc;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &wp;
-#endif 
-
-
-       if (t == NULL)
-               return(0);
-       rv = 0;
-       a = areanum++;
-       wp = (wp2 = t->words) != NULL
-            ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
-            : NULL;
-
-       switch(t->type) {
-       case TPAREN:
-       case TCOM:
-               {
-                       int child;
-                       rv = forkexec(t, pin, pout, act, wp, &child);
-                       if (child) {
-                               exstat = rv;
-                               leave();
-                       }
-               }
-               break;
-
-       case TPIPE:
-               {
-                   int pv[2];
-                   if ((rv = openpipe(pv)) < 0)
-                       break;
-                   pv[0] = remap(pv[0]);
-                   pv[1] = remap(pv[1]);
-                   (void) execute(t->left, pin, pv, 0);
-                   rv = execute(t->right, pv, pout, 0);
-               }
-               break;
-
-       case TLIST:
-               (void) execute(t->left, pin, pout, 0);
-               rv = execute(t->right, pin, pout, 0);
-               break;
-
-       case TASYNC:
-       {
-               int hinteractive = interactive;
-
-               i = vfork();
-               if (i != 0) {
-                       interactive = hinteractive;
-                       if (i != -1) {
-                               setval(lookup("!"), putn(i));
-                               if (pin != NULL)
-                                       closepipe(pin);
-                               if (interactive) {
-                                       prs(putn(i));
-                                       prs("\n");
-                               }
-                       } else
-                               rv = -1;
-                       setstatus(rv);
-               } else {
-                       signal(SIGINT, SIG_IGN);
-                       signal(SIGQUIT, SIG_IGN);
-                       if (interactive)
-                               signal(SIGTERM, SIG_DFL);
-                       interactive = 0;
-                       if (pin == NULL) {
-                               close(0);
-                               open("/dev/null", 0);
-                       }
-                       exit(execute(t->left, pin, pout, FEXEC));
-               }
-       }
-               break;
-
-       case TOR:
-       case TAND:
-               rv = execute(t->left, pin, pout, 0);
-               if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
-                       rv = execute(t1, pin, pout, 0);
-               break;
-
-       case TFOR:
-               if (wp == NULL) {
-                       wp = dolv+1;
-                       if ((i = dolc) < 0)
-                               i = 0;
-               } else {
-                       i = -1;
-                       while (*wp++ != NULL)
-                               ;                       
-               }
-               vp = lookup(t->str);
-               while (setjmp(bc.brkpt))
-                       if (isbreak)
-                               goto broken;
-               brkset(&bc);
-               for (t1 = t->left; i-- && *wp != NULL;) {
-                       setval(vp, *wp++);
-                       rv = execute(t1, pin, pout, 0);
-               }
-               brklist = brklist->nextlev;
-               break;
-
-       case TWHILE:
-       case TUNTIL:
-               while (setjmp(bc.brkpt))
-                       if (isbreak)
-                               goto broken;
-               brkset(&bc);
-               t1 = t->left;
-               while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
-                       rv = execute(t->right, pin, pout, 0);
-               brklist = brklist->nextlev;
-               break;
-
-       case TIF:
-       case TELIF:
-               if (t->right != NULL) {
-               rv = !execute(t->left, pin, pout, 0) ?
-                       execute(t->right->left, pin, pout, 0):
-                       execute(t->right->right, pin, pout, 0);
-               }
-               break;
-
-       case TCASE:
-               if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
-                       cp = "";
-               if ((t1 = findcase(t->left, cp)) != NULL)
-                       rv = execute(t1, pin, pout, 0);
-               break;
-
-       case TBRACE:
-/*
-               if (iopp = t->ioact)
-                       while (*iopp)
-                               if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
-                                       rv = -1;
-                                       break;
-                               }
-*/
-               if (rv >= 0 && (t1 = t->left))
-                       rv = execute(t1, pin, pout, 0);
-               break;
-       }
-
-broken:
-       t->words = wp2;
-       isbreak = 0;
-       freehere(areanum);
-       freearea(areanum);
-       areanum = a;
-       if (interactive && intr) {
-               closeall();
-               fail();
-       }
-       if ((i = trapset) != 0) {
-               trapset = 0;
-               runtrap(i);
-       }
-       return(rv);
-}
-
-static int
-forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked)
-{
-       int i, rv;
-       int (*shcom)() = NULL;
-       register int f;
-       char *cp = NULL;
-       struct ioword **iopp;
-       int resetsig;
-       char **owp;
-
-       int *hpin = pin;
-       int *hpout = pout;
-       int hforked;
-       char *hwp;
-       int hinteractive;
-       int hintr;
-       struct brkcon * hbrklist;
-       int hexecflg;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &pin;
-       (void) &pout;
-       (void) &wp;
-       (void) &shcom;
-       (void) &cp;
-       (void) &resetsig;
-       (void) &owp;
-#endif 
-
-       owp = wp;
-       resetsig = 0;
-       *pforked = 0;
-       rv = -1;        /* system-detected error */
-       if (t->type == TCOM) {
-               while ((cp = *wp++) != NULL)
-                       ;
-               cp = *wp;
-
-               /* strip all initial assignments */
-               /* not correct wrt PATH=yyy command  etc */
-               if (flag['x'])
-                       echo (cp ? wp: owp);
-               if (cp == NULL && t->ioact == NULL) {
-                       while ((cp = *owp++) != NULL && assign(cp, COPYV))
-                               ;
-                       return(setstatus(0));
-               }
-               else if (cp != NULL)
-                       shcom = inbuilt(cp);
-       }
-       t->words = wp;
-       f = act;
-       if (shcom == NULL && (f & FEXEC) == 0) {
-
-               hpin = pin;
-               hpout = pout;
-               hforked = *pforked;
-               hwp = *wp;
-               hinteractive = interactive;
-               hintr = intr;
-               hbrklist = brklist;
-               hexecflg = execflg;
-       
-               i = vfork();
-               if (i != 0) {
-                       /* who wrote this crappy non vfork safe shit? */
-                       pin = hpin;
-                       pout = hpout;
-                       *pforked = hforked;
-                       *wp = hwp;
-                       interactive = hinteractive;
-                       intr = hintr;
-                       brklist = hbrklist;
-                       execflg = hexecflg;
-
-                       *pforked = 0;
-                       if (i == -1)
-                               return(rv);
-                       if (pin != NULL)
-                               closepipe(pin);
-                       return(pout==NULL? setstatus(waitfor(i,0)): 0);
-               }
-
-               if (interactive) {
-                       signal(SIGINT, SIG_IGN);
-                       signal(SIGQUIT, SIG_IGN);
-                       resetsig = 1;
-               }
-               interactive = 0;
-               intr = 0;
-               (*pforked)++;
-               brklist = 0;
-               execflg = 0;
-       }       
-       if (owp != NULL)
-               while ((cp = *owp++) != NULL && assign(cp, COPYV))
-                       if (shcom == NULL)
-                               export(lookup(cp));
-#ifdef COMPIPE
-       if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
-               err("piping to/from shell builtins not yet done");
-               return(-1);
-       }
-#endif
-       if (pin != NULL) {
-               dup2(pin[0], 0);
-               closepipe(pin);
-       }
-       if (pout != NULL) {
-               dup2(pout[1], 1);
-               closepipe(pout);
-       }
-       if ((iopp = t->ioact) != NULL) {
-               if (shcom != NULL && shcom != doexec) {
-                       prs(cp);
-                       err(": cannot redirect shell command");
-                       return(-1);
-               }
-               while (*iopp)
-                       if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
-                               return(rv);
-       }
-       if (shcom)
-               return(setstatus((*shcom)(t)));
-       /* should use FIOCEXCL */
-       for (i=FDBASE; i<NOFILE; i++)
-               close(i);
-       if (resetsig) {
-               signal(SIGINT, SIG_DFL);
-               signal(SIGQUIT, SIG_DFL);
-       }
-       if (t->type == TPAREN)
-               exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
-       if (wp[0] == NULL)
-               exit(0);
-
-       cp = rexecve(wp[0], wp, makenv());
-       prs(wp[0]); prs(": "); warn(cp);
-       if (!execflg)
-               trap[0] = NULL;
-       leave();
-       /* NOTREACHED */
-       exit(1);
-}
-
-/*
- * 0< 1> are ignored as required
- * within pipelines.
- */
-static int
-iosetup(iop, pipein, pipeout)
-register struct ioword *iop;
-int pipein, pipeout;
-{
-       register int u = -1;
-       char *cp=NULL, *msg;
-
-       if (iop->io_unit == IODEFAULT)  /* take default */
-               iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
-       if (pipein && iop->io_unit == 0)
-               return(0);
-       if (pipeout && iop->io_unit == 1)
-               return(0);
-       msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
-       if ((iop->io_flag & IOHERE) == 0) {
-               cp = iop->io_name;
-               if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
-                       return(1);
-       }
-       if (iop->io_flag & IODUP) {
-               if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
-                       prs(cp);
-                       err(": illegal >& argument");
-                       return(1);
-               }
-               if (*cp == '-')
-                       iop->io_flag = IOCLOSE;
-               iop->io_flag &= ~(IOREAD|IOWRITE);
-       }
-       switch (iop->io_flag) {
-       case IOREAD:
-               u = open(cp, 0);
-               break;
-
-       case IOHERE:
-       case IOHERE|IOXHERE:
-               u = herein(iop->io_name, iop->io_flag&IOXHERE);
-               cp = "here file";
-               break;
-
-       case IOWRITE|IOCAT:
-               if ((u = open(cp, 1)) >= 0) {
-                       lseek(u, (long)0, 2);
-                       break;
-               }
-       case IOWRITE:
-               u = creat(cp, 0666);
-               break;
-
-       case IODUP:
-               u = dup2(*cp-'0', iop->io_unit);
-               break;
-
-       case IOCLOSE:
-               close(iop->io_unit);
-               return(0);
-       }
-       if (u < 0) {
-               prs(cp);
-               prs(": cannot ");
-               warn(msg);
-               return(1);
-       } else {
-               if (u != iop->io_unit) {
-                       dup2(u, iop->io_unit);
-                       close(u);
-               }
-       }
-       return(0);
-}
-
-static void
-echo(wp)
-register char **wp;
-{
-       register int i;
-
-       prs("+");
-       for (i=0; wp[i]; i++) {
-               if (i)
-                       prs(" ");
-               prs(wp[i]);
-       }
-       prs("\n");
-}
-
-static struct op **
-find1case(t, w)
-struct op *t;
-char *w;
-{
-       register struct op *t1;
-       struct op **tp;
-       register char **wp, *cp;
-
-       if (t == NULL)
-               return((struct op **)NULL);
-       if (t->type == TLIST) {
-               if ((tp = find1case(t->left, w)) != NULL)
-                       return(tp);
-               t1 = t->right;  /* TPAT */
-       } else
-               t1 = t;
-       for (wp = t1->words; *wp;)
-               if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
-                       return(&t1->left);
-       return((struct op **)NULL);
-}
-
-static struct op *
-findcase(t, w)
-struct op *t;
-char *w;
-{
-       register struct op **tp;
-
-       return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
-}
-
-/*
- * Enter a new loop level (marked for break/continue).
- */
-static void
-brkset(bc)
-struct brkcon *bc;
-{
-       bc->nextlev = brklist;
-       brklist = bc;
-}
-
-/*
- * Wait for the last process created.
- * Print a message for each process found
- * that was killed by a signal.
- * Ignore interrupt signals while waiting
- * unless `canintr' is true.
- */
-static int
-waitfor(lastpid, canintr)
-register int lastpid;
-int canintr;
-{
-       register int pid, rv;
-       int s;
-       int oheedint = heedint;
-
-       heedint = 0;
-       rv = 0;
-       do {
-               pid = wait(&s);
-               if (pid == -1) {
-                       if (errno != EINTR || canintr)
-                               break;
-               } else {
-                       if ((rv = WAITSIG(s)) != 0) {
-                               if (rv < NSIGNAL) {
-                                       if (signame[rv] != NULL) {
-                                               if (pid != lastpid) {
-                                                       prn(pid);
-                                                       prs(": ");
-                                               }
-                                               prs(signame[rv]);
-                                       }
-                               } else {
-                                       if (pid != lastpid) {
-                                               prn(pid);
-                                               prs(": ");
-                                       }
-                                       prs("Signal "); prn(rv); prs(" ");
-                               }
-                               if (WAITCORE(s))
-                                       prs(" - core dumped");
-                               if (rv >= NSIGNAL || signame[rv])
-                                       prs("\n");
-                               rv = -1;
-                       } else
-                               rv = WAITVAL(s);
-               }
-       } while (pid != lastpid);
-       heedint = oheedint;
-       if (intr) {
-               if (interactive) {
-                       if (canintr)
-                               intr = 0;
-               } else {
-                       if (exstat == 0) exstat = rv;
-                       onintr(0);
-               }
-       }
-       return(rv);
-}
-
-static int
-setstatus(s)
-register int s;
-{
-       exstat = s;
-       setval(lookup("?"), putn(s));
-       return(s);
-}
-
-/*
- * PATH-searching interface to execve.
- * If getenv("PATH") were kept up-to-date,
- * execvp might be used.
- */
-static char *
-rexecve(c, v, envp)
-char *c, **v, **envp;
-{
-       register int i;
-       register char *sp, *tp;
-       int eacces = 0, asis = 0;
-
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name = c;
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       name = get_last_path_component(name);
-#endif
-       optind = 1;
-       if (find_applet_by_name(name)) {
-               /* We have to exec here since we vforked.  Running 
-                * run_applet_by_name() won't work and bad things
-                * will happen. */
-               execve("/proc/self/exe", v, envp);
-               execve("busybox", v, envp);
-       }
-#endif
-
-       sp = any('/', c)? "": path->value;
-       asis = *sp == '\0';
-       while (asis || *sp != '\0') {
-               asis = 0;
-               tp = e.linep;
-               for (; *sp != '\0'; tp++)
-                       if ((*tp = *sp++) == ':') {
-                               asis = *sp == '\0';
-                               break;
-                       }
-               if (tp != e.linep)
-                       *tp++ = '/';
-               for (i = 0; (*tp++ = c[i++]) != '\0';)
-                       ;
-
-               execve(e.linep, v, envp);
-               switch (errno) {
-               case ENOEXEC:
-                       *v = e.linep;
-                       tp = *--v;
-                       *v = e.linep;
-                       execve("/bin/sh", v, envp);
-                       *v = tp;
-                       return("no Shell");
-
-               case ENOMEM:
-                       return("program too big");
-
-               case E2BIG:
-                       return("argument list too long");
-
-               case EACCES:
-                       eacces++;
-                       break;
-               }
-       }
-       return(errno==ENOENT ? "not found" : "cannot execute");
-}
-
-/*
- * Run the command produced by generator `f'
- * applied to stream `arg'.
- */
-static int
-run(argp, f)
-struct ioarg *argp;
-int (*f)();
-{
-       struct op *otree;
-       struct wdblock *swdlist;
-       struct wdblock *siolist;
-       jmp_buf ev, rt;
-       xint *ofail;
-       int rv;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &rv;
-#endif
-
-       areanum++;
-       swdlist = wdlist;
-       siolist = iolist;
-       otree = outtree;
-       ofail = failpt;
-       rv = -1;
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               wdlist = 0;
-               iolist = 0;
-               pushio(argp, f);
-               e.iobase = e.iop;
-               yynerrs = 0;
-               if (setjmp(failpt = rt) == 0 && yyparse() == 0)
-                       rv = execute(outtree, NOPIPE, NOPIPE, 0);
-               quitenv();
-       }
-       wdlist = swdlist;
-       iolist = siolist;
-       failpt = ofail;
-       outtree = otree;
-       freearea(areanum--);
-       return(rv);
-}
-
-/* -------- do.c -------- */
-
-/*
- * built-in commands: doX
- */
-
-static int dohelp()
-{
-       int col;
-       const struct builtincmd *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-
-       for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) {
-               if (!x->name)
-                       continue;
-               col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
-               if (col > 60) {
-                       printf("\n");
-                       col = 0;
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       {
-               int i;
-               const struct BB_applet *applet;
-               extern const struct BB_applet applets[];
-               extern const size_t NUM_APPLETS;
-
-               for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
-                       if (!applet->name)
-                               continue;
-               
-                       col += printf("%s%s", ((col == 0) ? "\t" : " "), 
-                                       applet->name);
-                       if (col > 60) {
-                               printf("\n");
-                               col = 0;
-                       }
-               }
-       }
-#endif
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-
-
-static int
-dolabel()
-{
-       return(0);
-}
-
-static int
-dochdir(t)
-register struct op *t;
-{
-       register char *cp, *er;
-
-       if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
-               er = ": no home directory";
-       else if(chdir(cp) < 0)
-               er = ": bad directory";
-       else
-               return(0);
-       prs(cp != NULL? cp: "cd");
-       err(er);
-       return(1);
-}
-
-static int
-doshift(t)
-register struct op *t;
-{
-       register int n;
-
-       n = t->words[1]? getn(t->words[1]): 1;
-       if(dolc < n) {
-               err("nothing to shift");
-               return(1);
-       }
-       dolv[n] = dolv[0];
-       dolv += n;
-       dolc -= n;
-       setval(lookup("#"), putn(dolc));
-       return(0);
-}
-
-/*
- * execute login and newgrp directly
- */
-static int
-dologin(t)
-struct op *t;
-{
-       register char *cp;
-
-       if (interactive) {
-               signal(SIGINT, SIG_DFL);
-               signal(SIGQUIT, SIG_DFL);
-       }
-       cp = rexecve(t->words[0], t->words, makenv());
-       prs(t->words[0]); prs(": "); err(cp);
-       return(1);
-}
-
-static int
-doumask(t)
-register struct op *t;
-{
-       register int i, n;
-       register char *cp;
-
-       if ((cp = t->words[1]) == NULL) {
-               i = umask(0);
-               umask(i);
-               for (n=3*4; (n-=3) >= 0;)
-                       putc('0'+((i>>n)&07), stderr);
-               putc('\n', stderr);
-       } else {
-               for (n=0; *cp>='0' && *cp<='9'; cp++)
-                       n = n*8 + (*cp-'0');
-               umask(n);
-       }
-       return(0);
-}
-
-static int
-doexec(t)
-register struct op *t;
-{
-       register int i;
-       jmp_buf ex;
-       xint *ofail;
-
-       t->ioact = NULL;
-       for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
-               ;
-       if (i == 0)
-               return(1);
-       execflg = 1;
-       ofail = failpt;
-       if (setjmp(failpt = ex) == 0)
-               execute(t, NOPIPE, NOPIPE, FEXEC);
-       failpt = ofail;
-       execflg = 0;
-       return(1);
-}
-
-static int
-dodot(t)
-struct op *t;
-{
-       register int i;
-       register char *sp, *tp;
-       char *cp;
-
-       if ((cp = t->words[1]) == NULL)
-               return(0);
-       sp = any('/', cp)? ":": path->value;
-       while (*sp) {
-               tp = e.linep;
-               while (*sp && (*tp = *sp++) != ':')
-                       tp++;
-               if (tp != e.linep)
-                       *tp++ = '/';
-               for (i = 0; (*tp++ = cp[i++]) != '\0';)
-                       ;
-               if ((i = open(e.linep, 0)) >= 0) {
-                       exstat = 0;
-                       next(remap(i));
-                       return(exstat);
-               }
-       }
-       prs(cp);
-       err(": not found");
-       return(-1);
-}
-
-static int
-dowait(t)
-struct op *t;
-{
-       register int i;
-       register char *cp;
-
-       if ((cp = t->words[1]) != NULL) {
-               i = getn(cp);
-               if (i == 0)
-                       return(0);
-       } else
-               i = -1;
-       setstatus(waitfor(i, 1));
-       return(0);
-}
-
-static int
-doread(t)
-struct op *t;
-{
-       register char *cp, **wp;
-       register int nb = 0;
-       register int  nl = 0;
-
-       if (t->words[1] == NULL) {
-               err("Usage: read name ...");
-               return(1);
-       }
-       for (wp = t->words+1; *wp; wp++) {
-               for (cp = e.linep; !nl && cp < elinep-1; cp++)
-                       if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
-                           (nl = (*cp == '\n')) ||
-                           (wp[1] && any(*cp, ifs->value)))
-                               break;
-               *cp = 0;
-               if (nb <= 0)
-                       break;
-               setval(lookup(*wp), e.linep);
-       }
-       return(nb <= 0);
-}
-
-static int
-doeval(t)
-register struct op *t;
-{
-       return(RUN(awordlist, t->words+1, wdchar));
-}
-
-static int
-dotrap(t)
-register struct op *t;
-{
-       register int  n, i;
-       register int  resetsig;
-
-       if (t->words[1] == NULL) {
-               for (i=0; i<=_NSIG; i++)
-                       if (trap[i]) {
-                               prn(i);
-                               prs(": ");
-                               prs(trap[i]);
-                               prs("\n");
-                       }
-               return(0);
-       }
-       resetsig = isdigit(*t->words[1]);
-       for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
-               n = getsig(t->words[i]);
-               freecell(trap[n]);
-               trap[n] = 0;
-               if (!resetsig) {
-                       if (*t->words[1] != '\0') {
-                               trap[n] = strsave(t->words[1], 0);
-                               setsig(n, sig);
-                       } else
-                               setsig(n, SIG_IGN);
-               } else {
-                       if (interactive)
-                               if (n == SIGINT)
-                                       setsig(n, onintr);
-                               else
-                                       setsig(n, n == SIGQUIT ? SIG_IGN 
-                                                              : SIG_DFL);
-                       else
-                               setsig(n, SIG_DFL);
-               }
-       }
-       return(0);
-}
-
-static int
-getsig(s)
-char *s;
-{
-       register int n;
-
-       if ((n = getn(s)) < 0 || n > _NSIG) {
-               err("trap: bad signal number");
-               n = 0;
-       }
-       return(n);
-}
-
-static void
-setsig( register int n, void (*f)(int))
-{
-       if (n == 0)
-               return;
-       if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
-               ourtrap[n] = 1;
-               signal(n, f);
-       }
-}
-
-static int
-getn(as)
-char *as;
-{
-       register char *s;
-       register int n, m;
-
-       s = as;
-       m = 1;
-       if (*s == '-') {
-               m = -1;
-               s++;
-       }
-       for (n = 0; isdigit(*s); s++)
-               n = (n*10) + (*s-'0');
-       if (*s) {
-               prs(as);
-               err(": bad number");
-       }
-       return(n*m);
-}
-
-static int
-dobreak(t)
-struct op *t;
-{
-       return(brkcontin(t->words[1], 1));
-}
-
-static int
-docontinue(t)
-struct op *t;
-{
-       return(brkcontin(t->words[1], 0));
-}
-
-static int
-brkcontin(cp, val)
-register char *cp;
-int val;
-{
-       register struct brkcon *bc;
-       register int nl;
-
-       nl = cp == NULL? 1: getn(cp);
-       if (nl <= 0)
-               nl = 999;
-       do {
-               if ((bc = brklist) == NULL)
-                       break;
-               brklist = bc->nextlev;
-       } while (--nl);
-       if (nl) {
-               err("bad break/continue level");
-               return(1);
-       }
-       isbreak = val;
-       longjmp(bc->brkpt, 1);
-       /* NOTREACHED */
-}
-
-static int
-doexit(t)
-struct op *t;
-{
-       register char *cp;
-
-       execflg = 0;
-       if ((cp = t->words[1]) != NULL)
-               setstatus(getn(cp));
-       leave();
-       /* NOTREACHED */
-       return(0);
-}
-
-static int
-doexport(t)
-struct op *t;
-{
-       rdexp(t->words+1, export, EXPORT);
-       return(0);
-}
-
-static int
-doreadonly(t)
-struct op *t;
-{
-       rdexp(t->words+1, ronly, RONLY);
-       return(0);
-}
-
-static void
-rdexp(wp, f, key)
-register char **wp;
-void (*f)();
-int key;
-{
-       if (*wp != NULL) {
-               for (; *wp != NULL; wp++) {
-                       if (isassign(*wp)) {
-                               char *cp;
-                               assign(*wp, COPYV);
-                               for (cp = *wp; *cp != '='; cp++)
-                                       ;
-                               *cp = '\0';
-                       }
-                       if (checkname(*wp))
-                               (*f)(lookup(*wp));
-                       else
-                               badid(*wp);
-               }
-       } else
-               putvlist(key, 1);
-}
-
-static void
-badid(s)
-register char *s;
-{
-       prs(s);
-       err(": bad identifier");
-}
-
-static int
-doset(t)
-register struct op *t;
-{
-       register struct var *vp;
-       register char *cp;
-       register int n;
-
-       if ((cp = t->words[1]) == NULL) {
-               for (vp = vlist; vp; vp = vp->next)
-                       varput(vp->name, 1);
-               return(0);
-       }
-       if (*cp == '-') {
-               /* bad: t->words++; */
-               for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
-                       ;
-               if (*++cp == 0)
-                       flag['x'] = flag['v'] = 0;
-               else
-                       for (; *cp; cp++)
-                               switch (*cp) {
-                               case 'e':
-                                       if (!interactive)
-                                               flag['e']++;
-                                       break;
-
-                               default:
-                                       if (*cp>='a' && *cp<='z')
-                                               flag[(int)*cp]++;
-                                       break;
-                               }
-               setdash();
-       }
-       if (t->words[1]) {
-               t->words[0] = dolv[0];
-               for (n=1; t->words[n]; n++)
-                       setarea((char *)t->words[n], 0);
-               dolc = n-1;
-               dolv = t->words;
-               setval(lookup("#"), putn(dolc));
-               setarea((char *)(dolv-1), 0);
-       }
-       return(0);
-}
-
-static void
-varput(s, out)
-register char *s;
-int out;
-{
-       if (isalnum(*s) || *s == '_') {
-               write(out, s, strlen(s));
-               write(out, "\n", 1);
-       }
-}
-
-
-/*
- * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
- * This file contains code for the times builtin.
- */
-static int dotimes ()
-{
-       struct tms buf;
-       long int clk_tck = sysconf(_SC_CLK_TCK);
-
-       times(&buf);
-       printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
-              (int) (buf.tms_utime / clk_tck / 60),
-              ((double) buf.tms_utime) / clk_tck,
-              (int) (buf.tms_stime / clk_tck / 60),
-              ((double) buf.tms_stime) / clk_tck,
-              (int) (buf.tms_cutime / clk_tck / 60),
-              ((double) buf.tms_cutime) / clk_tck,
-              (int) (buf.tms_cstime / clk_tck / 60),
-              ((double) buf.tms_cstime) / clk_tck);
-       return 0;
-}
-
-
-static int (*inbuilt(char *s))()
-{
-       const struct builtincmd *bp;
-
-       for (bp = builtincmds; bp->name != NULL; bp++)
-               if (strcmp(bp->name, s) == 0)
-                       return(bp->builtinfunc);
-
-       return((int(*)())NULL);
-}
-
-/* -------- eval.c -------- */
-
-/*
- * ${}
- * `command`
- * blank interpretation
- * quoting
- * glob
- */
-
-static char ** eval( char **ap, int f)
-{
-       struct wdblock *wb;
-       char **wp;
-       char **wf;
-       jmp_buf ev;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &wp;
-       (void) &ap;
-#endif
-       wp = NULL;
-       wb = NULL;
-       wf = NULL;
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               while (*ap && isassign(*ap))
-                       expand(*ap++, &wb, f & ~DOGLOB);
-               if (flag['k']) {
-                       for (wf = ap; *wf; wf++) {
-                               if (isassign(*wf))
-                                       expand(*wf, &wb, f & ~DOGLOB);
-                       }
-               }
-               for (wb = addword((char *)0, wb); *ap; ap++) {
-                       if (!flag['k'] || !isassign(*ap))
-                               expand(*ap, &wb, f & ~DOKEY);
-               }
-               wb = addword((char *)0, wb);
-               wp = getwords(wb);
-               quitenv();
-       } else
-               gflg = 1;
-       return(gflg? (char **)NULL: wp);
-}
-
-/*
- * Make the exported environment from the exported
- * names in the dictionary. Keyword assignments
- * will already have been done.
- */
-static char **
-makenv()
-
-{
-       register struct wdblock *wb;
-       register struct var *vp;
-
-       wb = NULL;
-       for (vp = vlist; vp; vp = vp->next)
-               if (vp->status & EXPORT)
-                       wb = addword(vp->name, wb);
-       wb = addword((char *)0, wb);
-       return(getwords(wb));
-}
-
-static char *
-evalstr(cp, f)
-register char *cp;
-int f;
-{
-       struct wdblock *wb;
-
-       wb = NULL;
-       if (expand(cp, &wb, f)) {
-               if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
-                       cp = "";
-               DELETE(wb);
-       } else
-               cp = NULL;
-       return(cp);
-}
-
-static int
-expand( char *cp, register struct wdblock **wbp, int f)
-{
-       jmp_buf ev;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &cp;
-#endif
-       gflg = 0;
-       if (cp == NULL)
-               return(0);
-       if (!anys("$`'\"", cp) &&
-           !anys(ifs->value, cp) &&
-           ((f&DOGLOB)==0 || !anys("[*?", cp))) {
-               cp = strsave(cp, areanum);
-               if (f & DOTRIM)
-                       unquote(cp);
-               *wbp = addword(cp, *wbp);
-               return(1);
-       }
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               PUSHIO(aword, cp, strchar);
-               e.iobase = e.iop;
-               while ((cp = blank(f)) && gflg == 0) {
-                       e.linep = cp;
-                       cp = strsave(cp, areanum);
-                       if ((f&DOGLOB) == 0) {
-                               if (f & DOTRIM)
-                                       unquote(cp);
-                               *wbp = addword(cp, *wbp);
-                       } else
-                               *wbp = glob(cp, *wbp);
-               }
-               quitenv();
-       } else
-               gflg = 1;
-       return(gflg == 0);
-}
-
-/*
- * Blank interpretation and quoting
- */
-static char *
-blank(f)
-int f;
-{
-       register int c, c1;
-       register char *sp;
-       int scanequals, foundequals;
-
-       sp = e.linep;
-       scanequals = f & DOKEY;
-       foundequals = 0;
-
-loop:
-       switch (c = subgetc('"', foundequals)) {
-       case 0:
-               if (sp == e.linep)
-                       return(0);
-               *e.linep++ = 0;
-               return(sp);
-
-       default:
-               if (f & DOBLANK && any(c, ifs->value))
-                       goto loop;
-               break;
-
-       case '"':
-       case '\'':
-               scanequals = 0;
-               if (INSUB())
-                       break;
-               for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
-                       if (c == 0)
-                               break;
-                       if (c == '\'' || !any(c, "$`\""))
-                               c |= QUOTE;
-                       *e.linep++ = c;
-               }
-               c = 0;
-       }
-       unget(c);
-       if (!isalpha(c) && c != '_')
-               scanequals = 0;
-       for (;;) {
-               c = subgetc('"', foundequals);
-               if (c == 0 ||
-                   f & (DOBLANK && any(c, ifs->value)) ||
-                   (!INSUB() && any(c, "\"'"))) {
-                       scanequals = 0;
-                       unget(c);
-                       if (any(c, "\"'"))
-                               goto loop;
-                       break;
-               }
-               if (scanequals) {
-                       if (c == '=') {
-                               foundequals = 1;
-                               scanequals  = 0;
-                       }
-                       else if (!isalnum(c) && c != '_')
-                               scanequals = 0;
-               }
-               *e.linep++ = c;
-       }
-       *e.linep++ = 0;
-       return(sp);
-}
-
-/*
- * Get characters, substituting for ` and $
- */
-static int
-subgetc(ec, quoted)
-register int ec;
-int quoted;
-{
-       register char c;
-
-again:
-       c = my_getc(ec);
-       if (!INSUB() && ec != '\'') {
-               if (c == '`') {
-                       if (grave(quoted) == 0)
-                               return(0);
-                       e.iop->task = XGRAVE;
-                       goto again;
-               }
-               if (c == '$' && (c = dollar(quoted)) == 0) {
-                       e.iop->task = XDOLL;
-                       goto again;
-               }
-       }
-       return(c);
-}
-
-/*
- * Prepare to generate the string returned by ${} substitution.
- */
-static int
-dollar(quoted)
-int quoted;
-{
-       int otask;
-       struct io *oiop;
-       char *dolp;
-       register char *s, c, *cp=NULL;
-       struct var *vp;
-
-       c = readc();
-       s = e.linep;
-       if (c != '{') {
-               *e.linep++ = c;
-               if (isalpha(c) || c == '_') {
-                       while ((c = readc())!=0 && (isalnum(c) || c == '_'))
-                               if (e.linep < elinep)
-                                       *e.linep++ = c;
-                       unget(c);
-               }
-               c = 0;
-       } else {
-               oiop = e.iop;
-               otask = e.iop->task;
-               e.iop->task = XOTHER;
-               while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
-                       if (e.linep < elinep)
-                               *e.linep++ = c;
-               if (oiop == e.iop)
-                       e.iop->task = otask;
-               if (c != '}') {
-                       err("unclosed ${");
-                       gflg++;
-                       return(c);
-               }
-       }
-       if (e.linep >= elinep) {
-               err("string in ${} too long");
-               gflg++;
-               e.linep -= 10;
-       }
-       *e.linep = 0;
-       if (*s)
-               for (cp = s+1; *cp; cp++)
-                       if (any(*cp, "=-+?")) {
-                               c = *cp;
-                               *cp++ = 0;
-                               break;
-                       }
-       if (s[1] == 0 && (*s == '*' || *s == '@')) {
-               if (dolc > 1) {
-                       /* currently this does not distinguish $* and $@ */
-                       /* should check dollar */
-                       e.linep = s;
-                       PUSHIO(awordlist, dolv+1, dolchar);
-                       return(0);
-               } else {        /* trap the nasty ${=} */
-                       s[0] = '1';
-                       s[1] = 0;
-               }
-       }
-       vp = lookup(s);
-       if ((dolp = vp->value) == null) {
-               switch (c) {
-               case '=':
-                       if (isdigit(*s)) {
-                               err("cannot use ${...=...} with $n");
-                               gflg++;
-                               break;
-                       }
-                       setval(vp, cp);
-                       dolp = vp->value;
-                       break;
-
-               case '-':
-                       dolp = strsave(cp, areanum);
-                       break;
-
-               case '?':
-                       if (*cp == 0) {
-                               prs("missing value for ");
-                               err(s);
-                       } else
-                               err(cp);
-                       gflg++;
-                       break;
-               }
-       } else if (c == '+')
-               dolp = strsave(cp, areanum);
-       if (flag['u'] && dolp == null) {
-               prs("unset variable: ");
-               err(s);
-               gflg++;
-       }
-       e.linep = s;
-       PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
-       return(0);
-}
-
-/*
- * Run the command in `...` and read its output.
- */
-static int
-grave(quoted)
-int quoted;
-{
-       register int i;
-       char *cp;
-       int pf[2];
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &cp;
-#endif
-       for (cp = e.iop->argp->aword; *cp != '`'; cp++)
-               if (*cp == 0) {
-                       err("no closing `");
-                       return(0);
-               }
-       if (openpipe(pf) < 0)
-               return(0);
-       if ((i = vfork()) == -1) {
-               closepipe(pf);
-               err("try again");
-               return(0);
-       }
-       if (i != 0) {
-               e.iop->argp->aword = ++cp;
-               close(pf[1]);
-               PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
-               return(1);
-       }
-       *cp = 0;
-       /* allow trapped signals */
-       for (i=0; i<=_NSIG; i++)
-               if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
-                       signal(i, SIG_DFL);
-       dup2(pf[1], 1);
-       closepipe(pf);
-       flag['e'] = 0;
-       flag['v'] = 0;
-       flag['n'] = 0;
-       cp = strsave(e.iop->argp->aword, 0);
-       areanum = 1;
-       freehere(areanum);
-       freearea(areanum);      /* free old space */
-       e.oenv = NULL;
-       e.iop = (e.iobase = iostack) - 1;
-       unquote(cp);
-       interactive = 0;
-       PUSHIO(aword, cp, nlchar);
-       onecommand();
-       exit(1);
-}
-
-static char *
-unquote(as)
-register char *as;
-{
-       register char *s;
-
-       if ((s = as) != NULL)
-               while (*s)
-                       *s++ &= ~QUOTE;
-       return(as);
-}
-
-/* -------- glob.c -------- */
-
-/*
- * glob
- */
-
-#define        scopy(x) strsave((x), areanum)
-#define        BLKSIZ  512
-#define        NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
-
-static struct wdblock  *cl, *nl;
-static char    spcl[] = "[?*";
-
-static struct wdblock *
-glob(cp, wb)
-char *cp;
-struct wdblock *wb;
-{
-       register int i;
-       register char *pp;
-
-       if (cp == 0)
-               return(wb);
-       i = 0;
-       for (pp = cp; *pp; pp++)
-               if (any(*pp, spcl))
-                       i++;
-               else if (!any(*pp & ~QUOTE, spcl))
-                       *pp &= ~QUOTE;
-       if (i != 0) {
-               for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
-                       nl = newword(cl->w_nword*2);
-                       for(i=0; i<cl->w_nword; i++) { /* for each argument */
-                               for (pp = cl->w_words[i]; *pp; pp++)
-                                       if (any(*pp, spcl)) {
-                                               globname(cl->w_words[i], pp);
-                                               break;
-                                       }
-                               if (*pp == '\0')
-                                       nl = addword(scopy(cl->w_words[i]), nl);
-                       }
-                       for(i=0; i<cl->w_nword; i++)
-                               DELETE(cl->w_words[i]);
-                       DELETE(cl);
-               }
-               for(i=0; i<cl->w_nword; i++)
-                       unquote(cl->w_words[i]);
-               glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
-               if (cl->w_nword) {
-                       for (i=0; i<cl->w_nword; i++)
-                               wb = addword(cl->w_words[i], wb);
-                       DELETE(cl);
-                       return(wb);
-               }
-       }
-       wb = addword(unquote(cp), wb);
-       return(wb);
-}
-
-static void
-globname(we, pp)
-char *we;
-register char *pp;
-{
-       register char *np, *cp;
-       char *name, *gp, *dp;
-       int k;
-       DIR *dirp;
-       struct dirent *de;
-       char dname[NAME_MAX+1];
-       struct stat dbuf;
-
-       for (np = we; np != pp; pp--)
-               if (pp[-1] == '/')
-                       break;
-       for (dp = cp = space((int)(pp-np)+3); np < pp;)
-               *cp++ = *np++;
-       *cp++ = '.';
-       *cp = '\0';
-       for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
-               *cp++ = *np++;
-       *cp = '\0';
-       dirp = opendir(dp);
-       if (dirp == 0) {
-               DELETE(dp);
-               DELETE(gp);
-               return;
-       }
-       dname[NAME_MAX] = '\0';
-       while ((de=readdir(dirp))!=NULL) {
-               /* XXX Hmmm... What this could be? (abial) */
-               /*
-               if (ent[j].d_ino == 0)
-                       continue;
-               */
-               strncpy(dname, de->d_name, NAME_MAX);
-                       if (dname[0] == '.')
-                               if (*gp != '.')
-                                       continue;
-                       for(k=0; k<NAME_MAX; k++)
-                               if (any(dname[k], spcl))
-                                       dname[k] |= QUOTE;
-                       if (gmatch(dname, gp)) {
-                               name = generate(we, pp, dname, np);
-                               if (*np && !anys(np, spcl)) {
-                                       if (stat(name,&dbuf)) {
-                                               DELETE(name);
-                                               continue;
-                                       }
-                               }
-                               nl = addword(name, nl);
-                       }
-       }
-       closedir(dirp);
-       DELETE(dp);
-       DELETE(gp);
-}
-
-/*
- * generate a pathname as below.
- * start..end1 / middle end
- * the slashes come for free
- */
-static char *
-generate(start1, end1, middle, end)
-char *start1;
-register char *end1;
-char *middle, *end;
-{
-       char *p;
-       register char *op, *xp;
-
-       p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
-       for (xp = start1; xp != end1;)
-               *op++ = *xp++;
-       for (xp = middle; (*op++ = *xp++) != '\0';)
-               ;
-       op--;
-       for (xp = end; (*op++ = *xp++) != '\0';)
-               ;
-       return(p);
-}
-
-static int
-anyspcl(wb)
-register struct wdblock *wb;
-{
-       register int i;
-       register char **wd;
-
-       wd = wb->w_words;
-       for (i=0; i<wb->w_nword; i++)
-               if (anys(spcl, *wd++))
-                       return(1);
-       return(0);
-}
-
-static int
-xstrcmp(p1, p2)
-char *p1, *p2;
-{
-       return(strcmp(*(char **)p1, *(char **)p2));
-}
-
-/* -------- word.c -------- */
-
-static struct wdblock *
-newword(nw)
-register int nw;
-{
-       register struct wdblock *wb;
-
-       wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
-       wb->w_bsize = nw;
-       wb->w_nword = 0;
-       return(wb);
-}
-
-static struct wdblock *
-addword(wd, wb)
-char *wd;
-register struct wdblock *wb;
-{
-       register struct wdblock *wb2;
-       register int nw;
-
-       if (wb == NULL)
-               wb = newword(NSTART);
-       if ((nw = wb->w_nword) >= wb->w_bsize) {
-               wb2 = newword(nw * 2);
-               memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
-               wb2->w_nword = nw;
-               DELETE(wb);
-               wb = wb2;
-       }
-       wb->w_words[wb->w_nword++] = wd;
-       return(wb);
-}
-static 
-char **
-getwords(wb)
-register struct wdblock *wb;
-{
-       register char **wd;
-       register int nb;
-
-       if (wb == NULL)
-               return((char **)NULL);
-       if (wb->w_nword == 0) {
-               DELETE(wb);
-               return((char **)NULL);
-       }
-       wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
-       memcpy((char *)wd, (char *)wb->w_words, nb);
-       DELETE(wb);     /* perhaps should done by caller */
-       return(wd);
-}
-
-int (*func)(char *, char *);
-int    globv;
-
-static void
-glob0(a0, a1, a2, a3)
-char *a0;
-unsigned a1;
-int a2;
-int (*a3) (char *, char *);
-{
-       func = a3;
-       globv = a2;
-       glob1(a0, a0 + a1 * a2);
-}
-
-static void
-glob1(base, lim)
-char *base, *lim;
-{
-       register char *i, *j;
-       int v2;
-       char *lptr, *hptr;
-       int c;
-       unsigned n;
-
-
-       v2 = globv;
-
-top:
-       if ((n=(int)(lim-base)) <= v2)
-               return;
-       n = v2 * (n / (2*v2));
-       hptr = lptr = base+n;
-       i = base;
-       j = lim-v2;
-       for(;;) {
-               if (i < lptr) {
-                       if ((c = (*func)(i, lptr)) == 0) {
-                               glob2(i, lptr -= v2);
-                               continue;
-                       }
-                       if (c < 0) {
-                               i += v2;
-                               continue;
-                       }
-               }
-
-begin:
-               if (j > hptr) {
-                       if ((c = (*func)(hptr, j)) == 0) {
-                               glob2(hptr += v2, j);
-                               goto begin;
-                       }
-                       if (c > 0) {
-                               if (i == lptr) {
-                                       glob3(i, hptr += v2, j);
-                                       i = lptr += v2;
-                                       goto begin;
-                               }
-                               glob2(i, j);
-                               j -= v2;
-                               i += v2;
-                               continue;
-                       }
-                       j -= v2;
-                       goto begin;
-               }
-
-
-               if (i == lptr) {
-                       if (lptr-base >= lim-hptr) {
-                               glob1(hptr+v2, lim);
-                               lim = lptr;
-                       } else {
-                               glob1(base, lptr);
-                               base = hptr+v2;
-                       }
-                       goto top;
-               }
-
-
-               glob3(j, lptr -= v2, i);
-               j = hptr -= v2;
-       }
-}
-
-static void
-glob2(i, j)
-char *i, *j;
-{
-       register char *index1, *index2, c;
-       int m;
-
-       m = globv;
-       index1 = i;
-       index2 = j;
-       do {
-               c = *index1;
-               *index1++ = *index2;
-               *index2++ = c;
-       } while(--m);
-}
-
-static void
-glob3(i, j, k)
-char *i, *j, *k;
-{
-       register char *index1, *index2, *index3;
-       int c;
-       int m;
-
-       m = globv;
-       index1 = i;
-       index2 = j;
-       index3 = k;
-       do {
-               c = *index1;
-               *index1++ = *index3;
-               *index3++ = *index2;
-               *index2++ = c;
-       } while(--m);
-}
-
-/* -------- io.c -------- */
-
-/*
- * shell IO
- */
-
-static int my_getc( int ec)
-{
-       register int c;
-
-       if(e.linep > elinep) {
-               while((c=readc()) != '\n' && c)
-                       ;
-               err("input line too long");
-               gflg++;
-               return(c);
-       }
-       c = readc();
-       if (ec != '\'' && e.iop->task != XGRAVE) {
-               if(c == '\\') {
-                       c = readc();
-                       if (c == '\n' && ec != '\"')
-                               return(my_getc(ec));
-                       c |= QUOTE;
-               }
-       }
-       return(c);
-}
-
-static void
-unget(c)
-int c;
-{
-       if (e.iop >= e.iobase)
-               e.iop->peekc = c;
-}
-
-static int
-eofc()
-
-{
-  return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
-}
-
-static int
-readc()
-{
-       register int c;
-
-       for (; e.iop >= e.iobase; e.iop--)
-               if ((c = e.iop->peekc) != '\0') {
-                       e.iop->peekc = 0;
-                       return(c);
-               }
-               else {
-                   if (e.iop->prev != 0) {
-                       if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
-                               if (c == -1) {
-                                       e.iop++;
-                                       continue;
-                               }
-                               if (e.iop == iostack)
-                                       ioecho(c);
-                               return(e.iop->prev = c);
-                       }
-                       else if (e.iop->task == XIO && e.iop->prev != '\n') {
-                               e.iop->prev = 0;
-                               if (e.iop == iostack)
-                                       ioecho('\n');
-                               return '\n';
-                       }
-                   }
-                   if (e.iop->task == XIO) {
-                       if (multiline)
-                           return e.iop->prev = 0;
-                       if (interactive && e.iop == iostack+1) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                           current_prompt=prompt->value;
-#else
-                           prs(prompt->value);
-#endif
-                       }
-                   }
-               }
-       if (e.iop >= iostack)
-               return(0);
-       leave();
-       /* NOTREACHED */
-       return(0);
-}
-
-static void
-ioecho(c)
-char c;
-{
-       if (flag['v'])
-               write(2, &c, sizeof c);
-}
-
-static void
-pushio(argp, fn)
-struct ioarg *argp;
-int (*fn)();
-{
-       if (++e.iop >= &iostack[NPUSH]) {
-               e.iop--;
-               err("Shell input nested too deeply");
-               gflg++;
-               return;
-       }
-       e.iop->iofn = fn;
-
-       if (argp->afid != AFID_NOBUF)
-         e.iop->argp = argp;
-       else {
-         e.iop->argp  = ioargstack + (e.iop - iostack);
-         *e.iop->argp = *argp;
-         e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
-         if (isatty(e.iop->argp->afile) == 0 &&
-             (e.iop == &iostack[0] ||
-              lseek(e.iop->argp->afile, 0L, 1) != -1)) {
-           if (++bufid == AFID_NOBUF)
-             bufid = AFID_ID;
-           e.iop->argp->afid  = bufid;
-         }
-       }
-
-       e.iop->prev  = ~'\n';
-       e.iop->peekc = 0;
-       e.iop->xchar = 0;
-       e.iop->nlcount = 0;
-       if (fn == filechar || fn == linechar)
-               e.iop->task = XIO;
-       else if (fn == gravechar || fn == qgravechar)
-               e.iop->task = XGRAVE;
-       else
-               e.iop->task = XOTHER;
-}
-
-static struct io *
-setbase(ip)
-struct io *ip;
-{
-       register struct io *xp;
-
-       xp = e.iobase;
-       e.iobase = ip;
-       return(xp);
-}
-
-/*
- * Input generating functions
- */
-
-/*
- * Produce the characters of a string, then a newline, then EOF.
- */
-static int
-nlchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL)
-               return(0);
-       if ((c = *ap->aword++) == 0) {
-               ap->aword = NULL;
-               return('\n');
-       }
-       return(c);
-}
-
-/*
- * Given a list of words, produce the characters
- * in them, with a space after each word.
- */
-static int
-wdchar(ap)
-register struct ioarg *ap;
-{
-       register char c;
-       register char **wl;
-
-       if ((wl = ap->awordlist) == NULL)
-               return(0);
-       if (*wl != NULL) {
-               if ((c = *(*wl)++) != 0)
-                       return(c & 0177);
-               ap->awordlist++;
-               return(' ');
-       }
-       ap->awordlist = NULL;
-       return('\n');
-}
-
-/*
- * Return the characters of a list of words,
- * producing a space between them.
- */
-static int
-dolchar(ap)
-register struct ioarg *ap;
-{
-       register char *wp;
-
-       if ((wp = *ap->awordlist++) != NULL) {
-               PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
-               return(-1);
-       }
-       return(0);
-}
-
-static int
-xxchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL)
-               return(0);
-       if ((c = *ap->aword++) == '\0') {
-               ap->aword = NULL;
-               return(' ');
-       }
-       return(c);
-}
-
-/*
- * Produce the characters from a single word (string).
- */
-static int
-strchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL || (c = *ap->aword++) == 0)
-               return(0);
-       return(c);
-}
-
-/*
- * Produce quoted characters from a single word (string).
- */
-static int
-qstrchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL || (c = *ap->aword++) == 0)
-               return(0);
-       return(c|QUOTE);
-}
-
-/*
- * Return the characters from a file.
- */
-static int
-filechar(ap)
-register struct ioarg *ap;
-{
-       register int i;
-       char c;
-       struct iobuf *bp = ap->afbuf;
-
-       if (ap->afid != AFID_NOBUF) {
-         if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
-           if (i)
-             lseek(ap->afile, ap->afpos, 0);
-           i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
-           if (i <= 0) {
-             closef(ap->afile);
-             return 0;
-           }
-           bp->id = ap->afid;
-           bp->ebufp = (bp->bufp  = bp->buf) + i;
-         }
-         ap->afpos++;
-         return *bp->bufp++ & 0177;
-       }
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-       if (interactive) {
-           static char mycommand[BUFSIZ];
-           static int position = 0, size = 0;
-
-           while (size == 0 || position >= size) {
-               cmdedit_read_input(current_prompt, mycommand);
-               size = strlen(mycommand);
-               position = 0;
-           }
-           c = mycommand[position];
-           position++;
-           return(c);
-       } else 
-#endif
-       {
-               i = safe_read(ap->afile, &c, sizeof(c));
-               return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
-       }
-}
-
-/*
- * Return the characters from a here temp file.
- */
-static int
-herechar(ap)
-register struct ioarg *ap;
-{
-       char c;
-
-
-       if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
-               close(ap->afile);
-               c = 0;
-       }
-       return (c);
-
-}
-
-/*
- * Return the characters produced by a process (`...`).
- * Quote them if required, and remove any trailing newline characters.
- */
-static int
-gravechar(ap, iop)
-struct ioarg *ap;
-struct io *iop;
-{
-       register int c;
-
-       if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
-               c = ' ';
-       return(c);
-}
-
-static int
-qgravechar(ap, iop)
-register struct ioarg *ap;
-struct io *iop;
-{
-       register int c;
-
-       if (iop->xchar) {
-               if (iop->nlcount) {
-                       iop->nlcount--;
-                       return('\n'|QUOTE);
-               }
-               c = iop->xchar;
-               iop->xchar = 0;
-       } else if ((c = filechar(ap)) == '\n') {
-               iop->nlcount = 1;
-               while ((c = filechar(ap)) == '\n')
-                       iop->nlcount++;
-               iop->xchar = c;
-               if (c == 0)
-                       return(c);
-               iop->nlcount--;
-               c = '\n';
-       }
-       return(c!=0? c|QUOTE: 0);
-}
-
-/*
- * Return a single command (usually the first line) from a file.
- */
-static int
-linechar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if ((c = filechar(ap)) == '\n') {
-               if (!multiline) {
-                       closef(ap->afile);
-                       ap->afile = -1; /* illegal value */
-               }
-       }
-       return(c);
-}
-
-static void
-prs(s)
-register char *s;
-{
-       if (*s)
-               write(2, s, strlen(s));
-}
-
-static void
-prn(u)
-unsigned u;
-{
-       prs(itoa(u, 0));
-}
-
-static void
-closef(i)
-register int i;
-{
-       if (i > 2)
-               close(i);
-}
-
-static void
-closeall()
-{
-       register int u;
-
-       for (u=NUFILE; u<NOFILE;)
-               close(u++);
-}
-
-/*
- * remap fd into Shell's fd space
- */
-static int
-remap(fd)
-register int fd;
-{
-       register int i;
-       int map[NOFILE];
-
-       if (fd < e.iofd) {
-               for (i=0; i<NOFILE; i++)
-                       map[i] = 0;
-               do {
-                       map[fd] = 1;
-                       fd = dup(fd);
-               } while (fd >= 0 && fd < e.iofd);
-               for (i=0; i<NOFILE; i++)
-                       if (map[i])
-                               close(i);
-               if (fd < 0)
-                       err("too many files open in shell");
-       }
-       return(fd);
-}
-
-static int
-openpipe(pv)
-register int *pv;
-{
-       register int i;
-
-       if ((i = pipe(pv)) < 0)
-               err("can't create pipe - try again");
-       return(i);
-}
-
-static void
-closepipe(pv)
-register int *pv;
-{
-       if (pv != NULL) {
-               close(*pv++);
-               close(*pv);
-       }
-}
-
-/* -------- here.c -------- */
-
-/*
- * here documents
- */
-
-static void
-markhere(s, iop)
-register char *s;
-struct ioword *iop;
-{
-       register struct here *h, *lh;
-
-       h = (struct here *) space(sizeof(struct here));
-       if (h == 0)
-               return;
-       h->h_tag = evalstr(s, DOSUB);
-       if (h->h_tag == 0)
-               return;
-       h->h_iop = iop;
-       iop->io_name = 0;
-       h->h_next = NULL;
-       if (inhere == 0)
-               inhere = h;
-       else
-               for (lh = inhere; lh!=NULL; lh = lh->h_next)
-                       if (lh->h_next == 0) {
-                               lh->h_next = h;
-                               break;
-                       }
-       iop->io_flag |= IOHERE|IOXHERE;
-       for (s = h->h_tag; *s; s++)
-               if (*s & QUOTE) {
-                       iop->io_flag &= ~ IOXHERE;
-                       *s &= ~ QUOTE;
-               }
-       h->h_dosub = iop->io_flag & IOXHERE;
-}
-
-static void
-gethere()
-{
-       register struct here *h, *hp;
-
-       /* Scan here files first leaving inhere list in place */
-       for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
-         readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
-
-       /* Make inhere list active - keep list intact for scraphere */
-       if (hp != NULL) {
-         hp->h_next = acthere;
-         acthere    = inhere;
-         inhere     = NULL;
-       }
-}
-
-static void
-readhere(name, s, ec)
-char **name;
-register char *s;
-int ec;
-{
-       int tf;
-       char tname[30] = ".msh_XXXXXX";
-       register int c;
-       jmp_buf ev;
-       char myline [LINELIM+1];
-       char *thenext;
-
-       tf = mkstemp(tname);
-       if (tf < 0)
-               return;
-       *name = strsave(tname, areanum);
-       if (newenv(setjmp(errpt = ev)) != 0)
-               unlink(tname);
-       else {
-               pushio(e.iop->argp, e.iop->iofn);
-               e.iobase = e.iop;
-               for (;;) {
-                   if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                           current_prompt=cprompt->value;
-#else
-                           prs(cprompt->value);
-#endif
-                       }
-                       thenext = myline;
-                       while ((c = my_getc(ec)) != '\n' && c) {
-                               if (ec == '\'')
-                                       c &= ~ QUOTE;
-                               if (thenext >= &myline[LINELIM]) {
-                                       c = 0;
-                                       break;
-                               }
-                               *thenext++ = c;
-                       }
-                       *thenext = 0;
-                       if (strcmp(s, myline) == 0 || c == 0)
-                               break;
-                       *thenext++ = '\n';
-                       write (tf, myline, (int)(thenext-myline));
-               }
-               if (c == 0) {
-                       prs("here document `"); prs(s); err("' unclosed");
-               }
-               quitenv();
-       }
-       close(tf);
-}
-
-/*
- * open here temp file.
- * if unquoted here, expand here temp file into second temp file.
- */
-static int
-herein(hname, xdoll)
-char *hname;
-int xdoll;
-{
-       register int hf;
-       int tf;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &tf;
-#endif
-       if (hname == 0)
-               return(-1);
-       hf = open(hname, 0);
-       if (hf < 0)
-               return (-1);
-       if (xdoll) {
-               char c;
-               char tname[30] = ".msh_XXXXXX";
-               jmp_buf ev;
-       
-               tf = mkstemp(tname);
-               if (tf < 0)
-                       return (-1);
-               if (newenv(setjmp(errpt = ev)) == 0) {
-                       PUSHIO(afile, hf, herechar);
-                       setbase(e.iop);
-                       while ((c = subgetc(0, 0)) != 0) {
-                               c &= ~ QUOTE;
-                               write(tf, &c, sizeof c);
-                       }
-                       quitenv();
-               } else
-                       unlink(tname);
-               close(tf);
-               tf = open(tname, 0);
-               unlink(tname);
-               return (tf);
-       } else
-               return (hf);
-}
-
-static void
-scraphere()
-{
-       register struct here *h;
-
-       for (h = inhere; h != NULL; h = h->h_next) {
-               if (h->h_iop && h->h_iop->io_name)
-                 unlink(h->h_iop->io_name);
-       }
-       inhere = NULL;
-}
-
-/* unlink here temp files before a freearea(area) */
-static void
-freehere(area)
-int area;
-{
-       register struct here *h, *hl;
-
-       hl = NULL;
-       for (h = acthere; h != NULL; h = h->h_next)
-               if (getarea((char *) h) >= area) {
-                       if (h->h_iop->io_name != NULL)
-                               unlink(h->h_iop->io_name);
-                       if (hl == NULL)
-                               acthere = h->h_next;
-                       else
-                               hl->h_next = h->h_next;
-               } else
-                       hl = h;
-}
-
-
-
-/*
- * Copyright (c) 1987,1997, Prentice Hall
- * All rights reserved.
- * 
- * Redistribution and use of the MINIX operating system in source and
- * binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- * 
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * 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.
- * 
- * Neither the name of Prentice Hall nor the names of the software
- * authors or contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
diff --git a/busybox/mt.c b/busybox/mt.c
deleted file mode 100644 (file)
index 49dc70a..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* vi: set sw=4 ts=4: */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mtio.h>
-#include <sys/fcntl.h>
-#include "busybox.h"
-
-struct mt_opcodes {
-       char *name;
-       short value;
-};
-
-/* missing: eod/seod, stoptions, stwrthreshold, densities */
-static const struct mt_opcodes opcodes[] = {
-       {"bsf", MTBSF},
-       {"bsfm", MTBSFM},
-       {"bsr", MTBSR},
-       {"bss", MTBSS},
-       {"datacompression", MTCOMPRESSION},
-       {"eom", MTEOM},
-       {"erase", MTERASE},
-       {"fsf", MTFSF},
-       {"fsfm", MTFSFM},
-       {"fsr", MTFSR},
-       {"fss", MTFSS},
-       {"load", MTLOAD},
-       {"lock", MTLOCK},
-       {"mkpart", MTMKPART},
-       {"nop", MTNOP},
-       {"offline", MTOFFL},
-       {"rewoffline", MTOFFL},
-       {"ras1", MTRAS1},
-       {"ras2", MTRAS2},
-       {"ras3", MTRAS3},
-       {"reset", MTRESET},
-       {"retension", MTRETEN},
-       {"rewind", MTREW},
-       {"seek", MTSEEK},
-       {"setblk", MTSETBLK},
-       {"setdensity", MTSETDENSITY},
-       {"drvbuffer", MTSETDRVBUFFER},
-       {"setpart", MTSETPART},
-       {"tell", MTTELL},
-       {"wset", MTWSM},
-       {"unload", MTUNLOAD},
-       {"unlock", MTUNLOCK},
-       {"eof", MTWEOF},
-       {"weof", MTWEOF},
-       {0, 0}
-};
-
-extern int mt_main(int argc, char **argv)
-{
-       const char *file = "/dev/tape";
-       const struct mt_opcodes *code = opcodes;
-       struct mtop op;
-       struct mtpos position;
-       int fd, mode;
-       
-       if (argc < 2) {
-               show_usage();
-       }
-
-       if (strcmp(argv[1], "-f") == 0) {
-               if (argc < 4) {
-                       show_usage();
-               }
-               file = argv[2];
-               argv += 2;
-               argc -= 2;
-       }
-
-       while (code->name != 0) {
-               if (strcmp(code->name, argv[1]) == 0)
-                       break;
-               code++;
-       }
-
-       if (code->name == 0) {
-               error_msg("unrecognized opcode %s.", argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       op.mt_op = code->value;
-       if (argc >= 3)
-               op.mt_count = atoi(argv[2]);
-       else
-               op.mt_count = 1;                /* One, not zero, right? */
-
-       switch (code->value) {
-               case MTWEOF:
-               case MTERASE:
-               case MTWSM:
-               case MTSETDRVBUFFER:
-                       mode = O_WRONLY;
-                       break;
-
-               default:
-                       mode = O_RDONLY;
-                       break;
-       }
-
-       if ((fd = open(file, mode, 0)) < 0)
-               perror_msg_and_die("%s", file);
-
-       switch (code->value) {
-               case MTTELL:
-                       if (ioctl(fd, MTIOCPOS, &position) < 0)
-                               perror_msg_and_die("%s", file);
-                       printf ("At block %d.\n", (int) position.mt_blkno);
-                       break;
-
-               default:
-                       if (ioctl(fd, MTIOCTOP, &op) != 0)
-                               perror_msg_and_die("%s", file);
-                       break;
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/mv.c b/busybox/mv.c
deleted file mode 100644 (file)
index b890abf..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mv implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-static int flags;
-
-static int manual_rename(const char *source, const char *dest)
-{
-       struct stat source_stat;
-       struct stat dest_stat;
-       int source_exists = 1;
-       int dest_exists = 1;
-
-       if (stat(source, &source_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", source);
-                       return -1;
-               }
-               source_exists = 0;
-       }
-
-       if (stat(dest, &dest_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", dest);
-                       return -1;
-               }
-               dest_exists = 0;
-       }
-
-       if (dest_exists) {
-               if (S_ISDIR(dest_stat.st_mode) &&
-                         (!source_exists || !S_ISDIR(source_stat.st_mode))) {
-                       error_msg("cannot overwrite directory with non-directory");
-                       return -1;
-               }
-
-               if (!S_ISDIR(dest_stat.st_mode) && source_exists &&
-                               S_ISDIR(source_stat.st_mode)) {
-                       error_msg("cannot overwrite non-directory with directory");
-                       return -1;
-               }
-
-               if (unlink(dest) < 0) {
-                       perror_msg("cannot remove `%s'", dest);
-                       return -1;
-               }
-       }
-
-       if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS |
-                       FILEUTILS_PRESERVE_SYMLINKS) < 0)
-               return -1;
-
-       if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int move_file(const char *source, const char *dest)
-{
-       struct stat dest_stat;
-       int dest_exists = 1;
-
-       if (stat(dest, &dest_stat) < 0) {
-               if (errno != ENOENT) {
-                       perror_msg("unable to stat `%s'", dest);
-                       return -1;
-               }
-               dest_exists = 0;
-       }
-
-       if (dest_exists && !(flags & FILEUTILS_FORCE) &&
-                       ((access(dest, W_OK) < 0 && isatty(0)) ||
-                        (flags & FILEUTILS_INTERACTIVE))) {
-               fprintf(stderr, "mv: overwrite `%s'? ", dest);
-               if (!ask_confirmation())
-                       return 0;
-       }
-
-       if (rename(source, dest) < 0) {
-               if (errno == EXDEV)
-                       return manual_rename(source, dest);
-
-               perror_msg("unable to rename `%s'", source);
-               return -1;
-       }
-       
-       return 0;
-}
-
-extern int mv_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int i;
-
-       while ((opt = getopt(argc, argv, "fi")) != -1)
-               switch (opt) {
-               case 'f':
-                       flags &= ~FILEUTILS_INTERACTIVE;
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags &= ~FILEUTILS_FORCE;
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               default:
-                       show_usage();
-               }
-
-       if (optind + 2 > argc)
-               show_usage();
-
-       if (optind + 2 == argc) {
-               struct stat dest_stat;
-               int dest_exists = 1;
-
-               if (stat(argv[optind + 1], &dest_stat) < 0) {
-                       if (errno != ENOENT)
-                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
-                       dest_exists = 0;
-               }
-
-               if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) {
-                       if (move_file(argv[optind], argv[optind + 1]) < 0)
-                               status = 1;
-                       return status;
-               }
-       }
-
-       for (i = optind; i < argc - 1; i++) {
-               char *dest = concat_path_file(argv[argc - 1],
-                               get_last_path_component(argv[i]));
-               if (move_file(argv[i], dest) < 0)
-                       status = 1;
-               free(dest);
-       }
-
-       return status;
-}
diff --git a/busybox/nc.c b/busybox/nc.c
deleted file mode 100644 (file)
index 5335872..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*  nc: mini-netcat - built from the ground up for LRP
-    Copyright (C) 1998  Charles P. Wright
-
-    0.0.1   6K      It works.
-    0.0.2   5K      Smaller and you can also check the exit condition if you wish.
-    0.0.3          Uses select()       
-
-    19980918 Busy Boxed! Dave Cinege
-    19990512 Uses Select. Charles P. Wright
-    19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-int nc_main(int argc, char **argv)
-{
-       int do_listen = 0, lport = 0, tmpfd, opt, sfd;
-       char buf[BUFSIZ];
-
-       struct sockaddr_in address;
-       struct hostent *hostinfo;
-
-       fd_set readfds, testfds;
-
-       while ((opt = getopt(argc, argv, "lp:")) > 0) {
-               switch (opt) {
-                       case 'l':
-                               do_listen++;
-                               break;
-                       case 'p':
-                               lport = atoi(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
-               show_usage();
-
-       if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die("socket");
-
-       address.sin_family = AF_INET;
-
-       if (lport != 0) {
-               memset(&address.sin_addr, 0, sizeof(address.sin_addr));
-               address.sin_port = htons(lport);
-
-               if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-                       perror_msg_and_die("bind");
-       }
-
-       if (do_listen) {
-               socklen_t addrlen = sizeof(address);
-
-               if (listen(sfd, 1) < 0)
-                       perror_msg_and_die("listen");
-
-               if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
-                       perror_msg_and_die("accept");
-
-               close(sfd);
-               sfd = tmpfd;
-       } else {
-               hostinfo = xgethostbyname(argv[optind]);
-
-               address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
-               address.sin_port = htons(atoi(argv[optind+1]));
-
-               if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-                       perror_msg_and_die("connect");
-       }
-
-       FD_ZERO(&readfds);
-       FD_SET(sfd, &readfds);
-       FD_SET(STDIN_FILENO, &readfds);
-
-       while (1) {
-               int fd;
-               int ofd;
-               int nread;
-
-               testfds = readfds;
-
-               if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
-                       perror_msg_and_die("select");
-
-               for (fd = 0; fd < FD_SETSIZE; fd++) {
-                       if (FD_ISSET(fd, &testfds)) {
-                               if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
-                                       perror_msg_and_die("read");
-
-                               if (fd == sfd) {
-                                       if (nread == 0)
-                                               exit(0);
-                                       ofd = STDOUT_FILENO;
-                               } else {
-                                       if (nread == 0)
-                                               shutdown(sfd, 1);
-                                       ofd = sfd;
-                               }
-
-                               if (full_write(ofd, buf, nread) < 0)
-                                       perror_msg_and_die("write");
-                       }
-               }
-       }
-}
diff --git a/busybox/networking/hostname.c b/busybox/networking/hostname.c
deleted file mode 100644 (file)
index d878515..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $
- * Mini hostname implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * adjusted by Erik Andersen <andersee@debian.org> to remove
- * use of long options and GNU getopt.  Improved the usage info.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <errno.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static void do_sethostname(char *s, int isfile)
-{
-       FILE *f;
-       char buf[255];
-
-       if (!s)
-               return;
-       if (!isfile) {
-               if (sethostname(s, strlen(s)) < 0) {
-                       if (errno == EPERM)
-                               error_msg_and_die("you must be root to change the hostname");
-                       else
-                               perror_msg_and_die("sethostname");
-               }
-       } else {
-               f = xfopen(s, "r");
-               fgets(buf, 255, f);
-#ifdef BB_FEATURE_CLEAN_UP
-               fclose(f);
-#endif
-               chomp(buf);
-               do_sethostname(buf, 0);
-       }
-}
-
-int hostname_main(int argc, char **argv)
-{
-       int opt_short = 0;
-       int opt_domain = 0;
-       int opt_ip = 0;
-       struct hostent *h;
-       char *filename = NULL;
-       char buf[255];
-       char *s = NULL;
-
-       if (argc < 1)
-               show_usage();
-
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 's':
-                               opt_short = 1;
-                               break;
-                       case 'i':
-                               opt_ip = 1;
-                               break;
-                       case 'd':
-                               opt_domain = 1;
-                               break;
-                       case 'F':
-                               if (--argc == 0) {
-                                       show_usage();
-                               }
-                               filename = *(++argv);
-                               break;
-                       case '-':
-                               if (strcmp(++(*argv), "file") || --argc ==0 ) {
-                                       show_usage();
-                               }
-                               filename = *(++argv);
-                               break;
-                       default:
-                               show_usage();
-                       }
-                       if (filename != NULL)
-                               break;
-               }
-       }
-
-       if (argc >= 1) {
-               do_sethostname(*argv, 0);
-       } else if (filename != NULL) {
-               do_sethostname(filename, 1);
-       } else {
-               gethostname(buf, 255);
-               if (opt_short) {
-                       s = strchr(buf, '.');
-                       if (!s)
-                               s = buf;
-                       *s = 0;
-                       puts(buf);
-               } else if (opt_domain) {
-                       s = strchr(buf, '.');
-                       puts(s ? s + 1 : "");
-               } else if (opt_ip) {
-                       h = xgethostbyname(buf);
-                       puts(inet_ntoa(*(struct in_addr *) (h->h_addr)));
-               } else {
-                       puts(buf);
-               }
-       }
-       return(0);
-}
diff --git a/busybox/networking/ifconfig.c b/busybox/networking/ifconfig.c
deleted file mode 100644 (file)
index 5f8b0ee..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/* ifconfig
- *
- * Similar to the standard Unix ifconfig, but with only the necessary
- * parts for AF_INET, and without any printing of if info (for now).
- *
- * Bjorn Wesen, Axis Communications AB
- *
- *
- * Authors of the original ifconfig was:      
- *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * This program is free software; you can redistribute it
- * and/or  modify it under  the terms of  the GNU General
- * Public  License as  published  by  the  Free  Software
- * Foundation;  either  version 2 of the License, or  (at
- * your option) any later version.
- *
- * $Id: ifconfig.c,v 1.11.2.1 2001/08/10 18:22:15 andersen Exp $
- *
- */
-
-/*
- * Heavily modified by Manuel Novoa III       Mar 6, 2001
- *
- * From initial port to busybox, removed most of the redundancy by
- * converting to a table-driven approach.  Added several (optional)
- * args missing from initial port.
- *
- * Still missing:  media, tunnel.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>   // strcmp and friends
-#include <ctype.h>    // isdigit and friends
-#include <stddef.h>                            /* offsetof */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <linux/if_ether.h>
-#include "busybox.h"
-
-#ifdef BB_FEATURE_IFCONFIG_SLIP
-#include <linux/if_slip.h>
-#endif
-
-/* I don't know if this is needed for busybox or not.  Anyone? */
-#define QUESTIONABLE_ALIAS_CASE
-
-
-/* Defines for glibc2.0 users. */
-#ifndef SIOCSIFTXQLEN
-#define SIOCSIFTXQLEN      0x8943
-#define SIOCGIFTXQLEN      0x8942
-#endif
-
-/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
-#ifndef ifr_qlen
-#define ifr_qlen        ifr_ifru.ifru_mtu
-#endif
-
-#ifndef IFF_DYNAMIC
-#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
-#endif
-
-/*
- * Here are the bit masks for the "flags" member of struct options below.
- * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
- * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
- */
-#define N_CLR            0x01
-#define M_CLR            0x02
-#define N_SET            0x04
-#define M_SET            0x08
-#define N_ARG            0x10
-#define M_ARG            0x20
-
-#define M_MASK           (M_CLR | M_SET | M_ARG)
-#define N_MASK           (N_CLR | N_SET | N_ARG)
-#define SET_MASK         (N_SET | M_SET)
-#define CLR_MASK         (N_CLR | M_CLR)
-#define SET_CLR_MASK     (SET_MASK | CLR_MASK)
-#define ARG_MASK         (M_ARG | N_ARG)
-
-/*
- * Here are the bit masks for the "arg_flags" member of struct options below.
- */
-
-/*
- * cast type:
- *   00 int
- *   01 char *
- *   02 HOST_COPY in_ether
- *   03 HOST_COPY INET_resolve
- */
-#define A_CAST_TYPE      0x03
-/*
- * map type:
- *   00 not a map type (mem_start, io_addr, irq)
- *   04 memstart (unsigned long)
- *   08 io_addr  (unsigned short)
- *   0C irq      (unsigned char)
- */
-#define A_MAP_TYPE       0x0C
-#define A_ARG_REQ        0x10  /* Set if an arg is required. */
-#define A_NETMASK        0x20  /* Set if netmask (check for multiple sets). */
-#define A_SET_AFTER      0x40  /* Set a flag at the end. */
-#define A_COLON_CHK      0x80  /* Is this needed?  See below. */
-
-/*
- * These defines are for dealing with the A_CAST_TYPE field.
- */
-#define A_CAST_CHAR_PTR  0x01
-#define A_CAST_RESOLVE   0x01
-#define A_CAST_HOST_COPY 0x02
-#define A_CAST_HOST_COPY_IN_ETHER    A_CAST_HOST_COPY
-#define A_CAST_HOST_COPY_RESOLVE     (A_CAST_HOST_COPY | A_CAST_RESOLVE)
-
-/*
- * These defines are for dealing with the A_MAP_TYPE field.
- */
-#define A_MAP_ULONG      0x04  /* memstart */
-#define A_MAP_USHORT     0x08  /* io_addr */
-#define A_MAP_UCHAR      0x0C  /* irq */
-
-/*
- * Define the bit masks signifying which operations to perform for each arg.
- */
-
-#define ARG_METRIC       (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_MTU          (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_TXQUEUELEN   (A_ARG_REQ /*| A_CAST_INT*/)
-#define ARG_MEM_START    (A_ARG_REQ | A_MAP_ULONG)
-#define ARG_IO_ADDR      (A_ARG_REQ | A_MAP_USHORT)
-#define ARG_IRQ          (A_ARG_REQ | A_MAP_UCHAR)
-#define ARG_DSTADDR      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
-#define ARG_NETMASK      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
-#define ARG_BROADCAST    (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
-#define ARG_HW           (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
-#define ARG_POINTOPOINT  (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
-#define ARG_KEEPALIVE    (A_ARG_REQ | A_CAST_CHAR_PTR)
-#define ARG_OUTFILL      (A_ARG_REQ | A_CAST_CHAR_PTR)
-#define ARG_HOSTNAME     (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
-
-
-/*
- * Set up the tables.  Warning!  They must have corresponding order!
- */
-
-struct arg1opt {
-       const char *name;
-       unsigned short selector;
-       unsigned short ifr_offset;
-};
-
-struct options {
-       const char *name;
-       const unsigned char flags;
-       const unsigned char arg_flags;
-       const unsigned short selector;
-};
-
-#define ifreq_offsetof(x)  offsetof(struct ifreq, x)
-
-static const struct arg1opt Arg1Opt[] = {
-       {"SIOCSIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric)},
-       {"SIOCSIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu)},
-       {"SIOCSIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen)},
-       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
-       {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
-       {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
-#ifdef BB_FEATURE_IFCONFIG_HW
-       {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
-#endif
-       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
-#ifdef SIOCSKEEPALIVE
-       {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
-#endif
-#ifdef SIOCSOUTFILL
-       {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
-       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)},
-#endif
-       /* Last entry if for unmatched (possibly hostname) arg. */
-       {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)},
-};
-
-static const struct options OptArray[] = {
-       {"metric",       N_ARG,         ARG_METRIC,      0},
-    {"mtu",          N_ARG,         ARG_MTU,         0},
-       {"txqueuelen",   N_ARG,         ARG_TXQUEUELEN,  0},
-       {"dstaddr",      N_ARG,         ARG_DSTADDR,     0},
-       {"netmask",      N_ARG,         ARG_NETMASK,     0},
-       {"broadcast",    N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
-#ifdef BB_FEATURE_IFCONFIG_HW
-       {"hw",           N_ARG,         ARG_HW,          0},
-#endif
-       {"pointopoint",  N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
-#ifdef SIOCSKEEPALIVE
-       {"keepalive",    N_ARG,         ARG_KEEPALIVE,   0},
-#endif
-#ifdef SIOCSOUTFILL
-       {"outfill",      N_ARG,         ARG_OUTFILL,     0},
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-       {"mem_start",    N_ARG,         ARG_MEM_START,   0},
-       {"io_addr",      N_ARG,         ARG_IO_ADDR,     0},
-       {"irq",          N_ARG,         ARG_IRQ,         0},
-#endif
-       {"arp",          N_CLR | M_SET, 0,               IFF_NOARP},
-       {"trailers",     N_CLR | M_SET, 0,               IFF_NOTRAILERS},
-       {"promisc",      N_SET | M_CLR, 0,               IFF_PROMISC},
-       {"multicast",    N_SET | M_CLR, 0,               IFF_MULTICAST},
-       {"allmulti",     N_SET | M_CLR, 0,               IFF_ALLMULTI},
-       {"dynamic",      N_SET | M_CLR, 0,               IFF_DYNAMIC},
-       {"up",           N_SET        , 0,               (IFF_UP | IFF_RUNNING)},
-       {"down",         N_CLR        , 0,               IFF_UP},
-       { NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING)}
-};
-
-/*
- * A couple of prototypes.
- */
-
-#ifdef BB_FEATURE_IFCONFIG_HW
-static int in_ether(char *bufp, struct sockaddr *sap);
-#endif
-
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-extern int interface_opt_a;
-extern int display_interfaces(char *ifname);
-#endif
-
-/*
- * Our main function.
- */
-
-int ifconfig_main(int argc, char **argv)
-{
-       struct ifreq ifr;
-       struct sockaddr_in sai;
-#ifdef BB_FEATURE_IFCONFIG_HW
-       struct sockaddr sa;
-#endif
-       const struct arg1opt *a1op;
-       const struct options *op;
-       int sockfd;  /* socket fd we use to manipulate stuff with */
-       int goterr;
-       int selector;
-       char *p;
-       char host[128];
-       unsigned char mask;
-       unsigned char did_flags;
-
-       goterr = 0;
-       did_flags = 0;
-
-       /* skip argv[0] */
-       ++argv;
-       --argc;
-
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-       if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
-               interface_opt_a = 1;
-               --argc;
-               ++argv;
-       }
-#endif
-
-       if(argc <= 1) {
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-               return display_interfaces(argc ? *argv : NULL);
-#else
-               error_msg_and_die( "ifconfig was not compiled with interface status display support.");
-#endif
-       }
-
-       /* Create a channel to the NET kernel. */
-       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror_msg_and_die("socket");
-       }
-
-       /* get interface name */
-       safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
-
-       /* Process the remaining arguments. */
-       while (*++argv != (char *) NULL) {
-               p = *argv;
-               mask = N_MASK;
-               if (*p == '-') {                /* If the arg starts with '-'... */
-                       ++p;                            /*    advance past it and */
-                       mask = M_MASK;          /*    set the appropriate mask. */
-               }
-               for (op = OptArray ; op->name ; op++) { /* Find table entry. */
-                       if (strcmp(p,op->name) == 0) { /* If name matches... */
-                               if ((mask &= op->flags)) { /* set the mask and go. */
-                                   goto FOUND_ARG;;
-                               }
-                               /* If we get here, there was a valid arg with an */
-                               /* invalid '-' prefix. */
-                               ++goterr;
-                               goto LOOP;
-                       }
-               }
-               
-               /* We fell through, so treat as possible hostname. */
-               a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
-               mask = op->arg_flags;
-               goto HOSTNAME;
-
-       FOUND_ARG:
-               if (mask & ARG_MASK) {
-                       mask = op->arg_flags;
-                       a1op = Arg1Opt + (op - OptArray);
-                       if (mask & A_NETMASK & did_flags) {
-                               show_usage();
-                       }
-                       if (*++argv == NULL) {
-                               if (mask & A_ARG_REQ) {
-                                       show_usage();
-                               } else {
-                                       --argv;
-                                       mask &= A_SET_AFTER; /* just for broadcast */
-                               }
-                       } else {                        /* got an arg so process it */
-                       HOSTNAME:
-                               did_flags |= (mask & A_NETMASK);
-                               if (mask & A_CAST_HOST_COPY) {
-#ifdef BB_FEATURE_IFCONFIG_HW
-                                       if (mask & A_CAST_RESOLVE) {
-#endif
-                                               safe_strncpy(host, *argv, (sizeof host));
-                                               sai.sin_family = AF_INET;
-                                               sai.sin_port = 0;
-                                               if (!strcmp(host, "default")) {
-                                                       /* Default is special, meaning 0.0.0.0. */
-                                                       sai.sin_addr.s_addr = INADDR_ANY;
-                                               } else if (inet_aton(host, &sai.sin_addr) == 0) {
-                                                       /* It's not a dotted quad. */
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               p = (char *) &sai;
-#ifdef BB_FEATURE_IFCONFIG_HW
-                                       } else { /* A_CAST_HOST_COPY_IN_ETHER */
-                                               /* This is the "hw" arg case. */
-                                               if (strcmp("ether", *argv) || (*++argv == NULL)) {
-                                                       show_usage();
-                                               }
-                                               safe_strncpy(host, *argv, (sizeof host));
-                                               if (in_ether(host, &sa)) {
-                                                       fprintf(stderr, "invalid hw-addr %s\n", host);
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               p = (char *) &sa;
-                                       }
-#endif
-                                       memcpy((((char *)(&ifr)) + a1op->ifr_offset),
-                                                  p, sizeof(struct sockaddr));
-                               } else {
-                                       unsigned int i = strtoul(*argv,NULL,0);
-                                       p = ((char *)(&ifr)) + a1op->ifr_offset;
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-                                       if (mask & A_MAP_TYPE) {
-                                               if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
-                                                       ++goterr;
-                                                       continue;
-                                               }
-                                               if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
-                                                       *((unsigned char *) p) = i;
-                                               } else if (mask & A_MAP_USHORT) {
-                                                       *((unsigned short *) p) = i;
-                                               } else {
-                                                       *((unsigned long *) p) = i;
-                                               }
-                                       } else
-#endif
-                                       if (mask & A_CAST_CHAR_PTR) {
-                                               *((caddr_t *) p) = (caddr_t) i;
-                                       } else { /* A_CAST_INT */
-                                               *((int *) p) = i;
-                                       }
-                               }
-                                               
-                               if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
-                                       perror(a1op->name);
-                                       ++goterr;
-                                       continue;
-                               }
-
-#ifdef QUESTIONABLE_ALIAS_CASE
-                               if (mask & A_COLON_CHK) {
-                                       /*
-                                        * Don't do the set_flag() if the address is an alias with
-                                        * a - at the end, since it's deleted already! - Roman
-                                        *
-                                        * Should really use regex.h here, not sure though how well
-                                        * it'll go with the cross-platform support etc. 
-                                        */
-                                       char *ptr;
-                                       short int found_colon = 0;
-                                       for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
-                                               if (*ptr == ':') {
-                                                       found_colon++;
-                                               }
-                                       }
-                       
-                                       if (found_colon && *(ptr - 1) == '-') {
-                                               continue;
-                                       }
-                               }
-#endif
-                       }
-                       if (!(mask & A_SET_AFTER)) {
-                               continue;
-                       }
-                       mask = N_SET;
-               }
-
-               if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
-                       perror("SIOCGIFFLAGS"); 
-                       ++goterr;
-               } else {
-                       selector = op->selector;
-                       if (mask & SET_MASK) {
-                               ifr.ifr_flags |= selector;
-                       } else {
-                               ifr.ifr_flags &= ~selector;
-                       }
-                       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
-                               perror("SIOCSIFFLAGS"); 
-                               ++goterr;
-                       }
-               }
-       LOOP:
-       } /* end of while-loop */
-
-       return goterr;
-}
-
-#ifdef BB_FEATURE_IFCONFIG_HW
-/* Input an Ethernet address and convert to binary. */
-static int
-in_ether(char *bufp, struct sockaddr *sap)
-{
-       unsigned char *ptr;
-       int i, j;
-       unsigned char val;
-       unsigned char c;
-       
-       sap->sa_family = ARPHRD_ETHER;
-       ptr = sap->sa_data;
-       
-       for (i = 0 ; i < ETH_ALEN ; i++) {
-               val = 0;
-
-               /* We might get a semicolon here - not required. */
-               if (i && (*bufp == ':')) {
-                       bufp++;
-               }
-
-               for (j=0 ; j<2 ; j++) {
-                       c = *bufp;
-                       if (c >= '0' && c <= '9') {
-                               c -= '0';
-                       } else if (c >= 'a' && c <= 'f') {
-                               c -= ('a' - 10);
-                       } else if (c >= 'A' && c <= 'F') {
-                               c -= ('A' - 10);
-                       } else if (j && (c == ':' || c == 0)) {
-                               break;
-                       } else {
-                               return -1;
-                       }
-                       ++bufp;
-                       val <<= 4;
-                       val += c;
-               }
-               *ptr++ = val;
-       }
-
-       return (int) (*bufp);           /* Error if we don't end at end of string. */
-}
-#endif
diff --git a/busybox/networking/nc.c b/busybox/networking/nc.c
deleted file mode 100644 (file)
index 5335872..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*  nc: mini-netcat - built from the ground up for LRP
-    Copyright (C) 1998  Charles P. Wright
-
-    0.0.1   6K      It works.
-    0.0.2   5K      Smaller and you can also check the exit condition if you wish.
-    0.0.3          Uses select()       
-
-    19980918 Busy Boxed! Dave Cinege
-    19990512 Uses Select. Charles P. Wright
-    19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-int nc_main(int argc, char **argv)
-{
-       int do_listen = 0, lport = 0, tmpfd, opt, sfd;
-       char buf[BUFSIZ];
-
-       struct sockaddr_in address;
-       struct hostent *hostinfo;
-
-       fd_set readfds, testfds;
-
-       while ((opt = getopt(argc, argv, "lp:")) > 0) {
-               switch (opt) {
-                       case 'l':
-                               do_listen++;
-                               break;
-                       case 'p':
-                               lport = atoi(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
-               show_usage();
-
-       if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die("socket");
-
-       address.sin_family = AF_INET;
-
-       if (lport != 0) {
-               memset(&address.sin_addr, 0, sizeof(address.sin_addr));
-               address.sin_port = htons(lport);
-
-               if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-                       perror_msg_and_die("bind");
-       }
-
-       if (do_listen) {
-               socklen_t addrlen = sizeof(address);
-
-               if (listen(sfd, 1) < 0)
-                       perror_msg_and_die("listen");
-
-               if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
-                       perror_msg_and_die("accept");
-
-               close(sfd);
-               sfd = tmpfd;
-       } else {
-               hostinfo = xgethostbyname(argv[optind]);
-
-               address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
-               address.sin_port = htons(atoi(argv[optind+1]));
-
-               if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-                       perror_msg_and_die("connect");
-       }
-
-       FD_ZERO(&readfds);
-       FD_SET(sfd, &readfds);
-       FD_SET(STDIN_FILENO, &readfds);
-
-       while (1) {
-               int fd;
-               int ofd;
-               int nread;
-
-               testfds = readfds;
-
-               if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
-                       perror_msg_and_die("select");
-
-               for (fd = 0; fd < FD_SETSIZE; fd++) {
-                       if (FD_ISSET(fd, &testfds)) {
-                               if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
-                                       perror_msg_and_die("read");
-
-                               if (fd == sfd) {
-                                       if (nread == 0)
-                                               exit(0);
-                                       ofd = STDOUT_FILENO;
-                               } else {
-                                       if (nread == 0)
-                                               shutdown(sfd, 1);
-                                       ofd = sfd;
-                               }
-
-                               if (full_write(ofd, buf, nread) < 0)
-                                       perror_msg_and_die("write");
-                       }
-               }
-       }
-}
diff --git a/busybox/networking/nslookup.c b/busybox/networking/nslookup.c
deleted file mode 100644 (file)
index 9b7cb64..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini nslookup implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <resolv.h>
-#include <arpa/inet.h>
-#include "busybox.h"
-
-/*
- |  I'm only implementing non-interactive mode;
- |  I totally forgot nslookup even had an interactive mode.
- |
- |  [ TODO ]
- |  + find out how to use non-default name servers
- */
-
-/* only works for IPv4 */
-static int addr_fprint(char *addr)
-{
-       u_int8_t split[4];
-       u_int32_t ip;
-       u_int32_t *x = (u_int32_t *) addr;
-
-       ip = ntohl(*x);
-       split[0] = (ip & 0xff000000) >> 24;
-       split[1] = (ip & 0x00ff0000) >> 16;
-       split[2] = (ip & 0x0000ff00) >> 8;
-       split[3] = (ip & 0x000000ff);
-       printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
-       return 0;
-}
-
-/* takes the NULL-terminated array h_addr_list, and
- * prints its contents appropriately
- */
-static int addr_list_fprint(char **h_addr_list)
-{
-       int i, j;
-       char *addr_string = (h_addr_list[1])
-               ? "Addresses: " : "Address:   ";
-
-       printf("%s ", addr_string);
-       for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
-               addr_fprint(h_addr_list[i]);
-
-               /* real nslookup does this */
-               if (j == 4) {
-                       if (h_addr_list[i + 1]) {
-                               printf("\n          ");
-                       }
-                       j = 0;
-               } else {
-                       if (h_addr_list[i + 1]) {
-                               printf(", ");
-                       }
-               }
-
-       }
-       printf("\n");
-       return 0;
-}
-
-/* print the results as nslookup would */
-static struct hostent *hostent_fprint(struct hostent *host)
-{
-       if (host) {
-               printf("Name:       %s\n", host->h_name);
-               addr_list_fprint(host->h_addr_list);
-       } else {
-               printf("*** Unknown host\n");
-       }
-       return host;
-}
-
-/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
- * into a u_int32_t
- */
-static u_int32_t str_to_addr(const char *addr)
-{
-       u_int32_t split[4];
-       u_int32_t ip;
-
-       sscanf(addr, "%d.%d.%d.%d",
-                  &split[0], &split[1], &split[2], &split[3]);
-
-       /* assuming sscanf worked */
-       ip = (split[0] << 24) |
-               (split[1] << 16) | (split[2] << 8) | (split[3]);
-
-       return htonl(ip);
-}
-
-/* gethostbyaddr wrapper */
-static struct hostent *gethostbyaddr_wrapper(const char *address)
-{
-       struct in_addr addr;
-
-       addr.s_addr = str_to_addr(address);
-       return gethostbyaddr((char *) &addr, 4, AF_INET);       /* IPv4 only for now */
-}
-
-#ifdef __UCLIBC__
-#warning FIXME after fixing uClibc to define struct _res 
-static inline void server_print(void)
-{
-       printf("Server:     %s\n", "default");
-       printf("Address:    %s\n\n", "default");
-}
-#else
-/* lookup the default nameserver and display it */
-static inline void server_print(void)
-{
-       struct sockaddr_in def = _res.nsaddr_list[0];
-       char *ip = inet_ntoa(def.sin_addr);
-
-       hostent_fprint(gethostbyaddr_wrapper(ip));
-       printf("\n");
-}
-#endif 
-
-/* naive function to check whether char *s is an ip address */
-static int is_ip_address(const char *s)
-{
-       while (*s) {
-               if ((isdigit(*s)) || (*s == '.')) {
-                       s++;
-                       continue;
-               }
-               return 0;
-       }
-       return 1;
-}
-
-/* ________________________________________________________________________ */
-int nslookup_main(int argc, char **argv)
-{
-       struct hostent *host;
-
-       if (argc < 2 || *argv[1]=='-') {
-               show_usage();
-       }
-
-       res_init();
-       server_print();
-       if (is_ip_address(argv[1])) {
-               host = gethostbyaddr_wrapper(argv[1]);
-       } else {
-               host = gethostbyname(argv[1]);
-       }
-       hostent_fprint(host);
-       return EXIT_SUCCESS;
-}
-
-/* $Id: nslookup.c,v 1.24 2001/07/06 17:51:29 andersen Exp $ */
diff --git a/busybox/networking/ping.c b/busybox/networking/ping.c
deleted file mode 100644 (file)
index 5ca5dd9..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $
- * Mini ping implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This version of ping is adapted from the ping in netkit-base 0.10,
- * which is:
- *
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Muuss.
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/signal.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-/* It turns out that libc5 doesn't have proper icmp support
- * built into it header files, so we have to supplement it */
-#if __GNU_LIBRARY__ < 5
-static const int ICMP_MINLEN = 8;                              /* abs minimum */
-
-struct icmp_ra_addr
-{
-  u_int32_t ira_addr;
-  u_int32_t ira_preference;
-};
-
-
-struct icmp
-{
-  u_int8_t  icmp_type; /* type of message, see below */
-  u_int8_t  icmp_code; /* type sub code */
-  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
-  union
-  {
-    u_char ih_pptr;            /* ICMP_PARAMPROB */
-    struct in_addr ih_gwaddr;  /* gateway address */
-    struct ih_idseq            /* echo datagram */
-    {
-      u_int16_t icd_id;
-      u_int16_t icd_seq;
-    } ih_idseq;
-    u_int32_t ih_void;
-
-    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
-    struct ih_pmtu
-    {
-      u_int16_t ipm_void;
-      u_int16_t ipm_nextmtu;
-    } ih_pmtu;
-
-    struct ih_rtradv
-    {
-      u_int8_t irt_num_addrs;
-      u_int8_t irt_wpa;
-      u_int16_t irt_lifetime;
-    } ih_rtradv;
-  } icmp_hun;
-#define        icmp_pptr       icmp_hun.ih_pptr
-#define        icmp_gwaddr     icmp_hun.ih_gwaddr
-#define        icmp_id         icmp_hun.ih_idseq.icd_id
-#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
-#define        icmp_void       icmp_hun.ih_void
-#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
-#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
-#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
-#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
-#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
-  union
-  {
-    struct
-    {
-      u_int32_t its_otime;
-      u_int32_t its_rtime;
-      u_int32_t its_ttime;
-    } id_ts;
-    struct
-    {
-      struct ip idi_ip;
-      /* options and then 64 bits of data */
-    } id_ip;
-    struct icmp_ra_addr id_radv;
-    u_int32_t   id_mask;
-    u_int8_t    id_data[1];
-  } icmp_dun;
-#define        icmp_otime      icmp_dun.id_ts.its_otime
-#define        icmp_rtime      icmp_dun.id_ts.its_rtime
-#define        icmp_ttime      icmp_dun.id_ts.its_ttime
-#define        icmp_ip         icmp_dun.id_ip.idi_ip
-#define        icmp_radv       icmp_dun.id_radv
-#define        icmp_mask       icmp_dun.id_mask
-#define        icmp_data       icmp_dun.id_data
-};
-#endif
-
-static const int DEFDATALEN = 56;
-static const int MAXIPLEN = 60;
-static const int MAXICMPLEN = 76;
-static const int MAXPACKET = 65468;
-#define        MAX_DUP_CHK     (8 * 128)
-static const int MAXWAIT = 10;
-static const int PINGINTERVAL = 1;             /* second */
-
-#define O_QUIET         (1 << 0)
-
-#define        A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
-#define        B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
-#define        SET(bit)        (A(bit) |= B(bit))
-#define        CLR(bit)        (A(bit) &= (~B(bit)))
-#define        TST(bit)        (A(bit) & B(bit))
-
-static void ping(const char *host);
-
-/* common routines */
-static int in_cksum(unsigned short *buf, int sz)
-{
-       int nleft = sz;
-       int sum = 0;
-       unsigned short *w = buf;
-       unsigned short ans = 0;
-
-       while (nleft > 1) {
-               sum += *w++;
-               nleft -= 2;
-       }
-
-       if (nleft == 1) {
-               *(unsigned char *) (&ans) = *(unsigned char *) w;
-               sum += ans;
-       }
-
-       sum = (sum >> 16) + (sum & 0xFFFF);
-       sum += (sum >> 16);
-       ans = ~sum;
-       return (ans);
-}
-
-/* simple version */
-#ifndef BB_FEATURE_FANCY_PING
-static char *hostname = NULL;
-
-static void noresp(int ign)
-{
-       printf("No response from %s\n", hostname);
-       exit(0);
-}
-
-static void ping(const char *host)
-{
-       struct hostent *h;
-       struct sockaddr_in pingaddr;
-       struct icmp *pkt;
-       int pingsock, c;
-       char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
-
-       pingsock = create_icmp_socket();
-
-       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
-
-       pingaddr.sin_family = AF_INET;
-       h = xgethostbyname(host);
-       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
-       hostname = h->h_name;
-
-       pkt = (struct icmp *) packet;
-       memset(pkt, 0, sizeof(packet));
-       pkt->icmp_type = ICMP_ECHO;
-       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
-
-       c = sendto(pingsock, packet, sizeof(packet), 0,
-                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
-
-       if (c < 0 || c != sizeof(packet))
-               perror_msg_and_die("sendto");
-
-       signal(SIGALRM, noresp);
-       alarm(5);                                       /* give the host 5000ms to respond */
-       /* listen for replies */
-       while (1) {
-               struct sockaddr_in from;
-               size_t fromlen = sizeof(from);
-
-               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
-                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror_msg("recvfrom");
-                       continue;
-               }
-               if (c >= 76) {                  /* ip + icmp */
-                       struct iphdr *iphdr = (struct iphdr *) packet;
-
-                       pkt = (struct icmp *) (packet + (iphdr->ihl << 2));     /* skip ip hdr */
-                       if (pkt->icmp_type == ICMP_ECHOREPLY)
-                               break;
-               }
-       }
-       printf("%s is alive!\n", hostname);
-       return;
-}
-
-extern int ping_main(int argc, char **argv)
-{
-       argc--;
-       argv++;
-       if (argc < 1)
-               show_usage();
-       ping(*argv);
-       return EXIT_SUCCESS;
-}
-
-#else /* ! BB_FEATURE_FANCY_PING */
-/* full(er) version */
-static char *hostname = NULL;
-static struct sockaddr_in pingaddr;
-static int pingsock = -1;
-static int datalen; /* intentionally uninitialized to work around gcc bug */
-
-static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0;
-static int myid = 0, options = 0;
-static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0;
-static char rcvd_tbl[MAX_DUP_CHK / 8];
-
-static void sendping(int);
-static void pingstats(int);
-static void unpack(char *, int, struct sockaddr_in *);
-
-/**************************************************************************/
-
-static void pingstats(int junk)
-{
-       int status;
-
-       signal(SIGINT, SIG_IGN);
-
-       printf("\n--- %s ping statistics ---\n", hostname);
-       printf("%ld packets transmitted, ", ntransmitted);
-       printf("%ld packets received, ", nreceived);
-       if (nrepeats)
-               printf("%ld duplicates, ", nrepeats);
-       if (ntransmitted)
-               printf("%ld%% packet loss\n",
-                          (ntransmitted - nreceived) * 100 / ntransmitted);
-       if (nreceived)
-               printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
-                          tmin / 10, tmin % 10,
-                          (tsum / (nreceived + nrepeats)) / 10,
-                          (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
-       if (nreceived != 0)
-               status = EXIT_SUCCESS;
-       else
-               status = EXIT_FAILURE;
-       exit(status);
-}
-
-static void sendping(int junk)
-{
-       struct icmp *pkt;
-       int i;
-       char packet[datalen + 8];
-
-       pkt = (struct icmp *) packet;
-
-       pkt->icmp_type = ICMP_ECHO;
-       pkt->icmp_code = 0;
-       pkt->icmp_cksum = 0;
-       pkt->icmp_seq = ntransmitted++;
-       pkt->icmp_id = myid;
-       CLR(pkt->icmp_seq % MAX_DUP_CHK);
-
-       gettimeofday((struct timeval *) &packet[8], NULL);
-       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
-
-       i = sendto(pingsock, packet, sizeof(packet), 0,
-                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
-
-       if (i < 0)
-               perror_msg_and_die("sendto");
-       else if ((size_t)i != sizeof(packet))
-               error_msg_and_die("ping wrote %d chars; %d expected", i,
-                          (int)sizeof(packet));
-
-       signal(SIGALRM, sendping);
-       if (pingcount == 0 || ntransmitted < pingcount) {       /* schedule next in 1s */
-               alarm(PINGINTERVAL);
-       } else {                                        /* done, wait for the last ping to come back */
-               /* todo, don't necessarily need to wait so long... */
-               signal(SIGALRM, pingstats);
-               alarm(MAXWAIT);
-       }
-}
-
-static char *icmp_type_name (int id)
-{
-       switch (id) {
-       case ICMP_ECHOREPLY:            return "Echo Reply";
-       case ICMP_DEST_UNREACH:         return "Destination Unreachable";
-       case ICMP_SOURCE_QUENCH:        return "Source Quench";
-       case ICMP_REDIRECT:             return "Redirect (change route)";
-       case ICMP_ECHO:                         return "Echo Request";
-       case ICMP_TIME_EXCEEDED:        return "Time Exceeded";
-       case ICMP_PARAMETERPROB:        return "Parameter Problem";
-       case ICMP_TIMESTAMP:            return "Timestamp Request";
-       case ICMP_TIMESTAMPREPLY:       return "Timestamp Reply";
-       case ICMP_INFO_REQUEST:         return "Information Request";
-       case ICMP_INFO_REPLY:           return "Information Reply";
-       case ICMP_ADDRESS:                      return "Address Mask Request";
-       case ICMP_ADDRESSREPLY:         return "Address Mask Reply";
-       default:                                        return "unknown ICMP type";
-       }
-}
-
-static void unpack(char *buf, int sz, struct sockaddr_in *from)
-{
-       struct icmp *icmppkt;
-       struct iphdr *iphdr;
-       struct timeval tv, *tp;
-       int hlen, dupflag;
-       unsigned long triptime;
-
-       gettimeofday(&tv, NULL);
-
-       /* check IP header */
-       iphdr = (struct iphdr *) buf;
-       hlen = iphdr->ihl << 2;
-       /* discard if too short */
-       if (sz < (datalen + ICMP_MINLEN))
-               return;
-
-       sz -= hlen;
-       icmppkt = (struct icmp *) (buf + hlen);
-
-       if (icmppkt->icmp_id != myid)
-           return;                             /* not our ping */
-
-       if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
-           ++nreceived;
-               tp = (struct timeval *) icmppkt->icmp_data;
-
-               if ((tv.tv_usec -= tp->tv_usec) < 0) {
-                       --tv.tv_sec;
-                       tv.tv_usec += 1000000;
-               }
-               tv.tv_sec -= tp->tv_sec;
-
-               triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
-               tsum += triptime;
-               if (triptime < tmin)
-                       tmin = triptime;
-               if (triptime > tmax)
-                       tmax = triptime;
-
-               if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) {
-                       ++nrepeats;
-                       --nreceived;
-                       dupflag = 1;
-               } else {
-                       SET(icmppkt->icmp_seq % MAX_DUP_CHK);
-                       dupflag = 0;
-               }
-
-               if (options & O_QUIET)
-                       return;
-
-               printf("%d bytes from %s: icmp_seq=%u", sz,
-                          inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
-                          icmppkt->icmp_seq);
-               printf(" ttl=%d", iphdr->ttl);
-               printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
-               if (dupflag)
-                       printf(" (DUP!)");
-               printf("\n");
-       } else 
-               if (icmppkt->icmp_type != ICMP_ECHO)
-                       error_msg("Warning: Got ICMP %d (%s)",
-                                       icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
-}
-
-static void ping(const char *host)
-{
-       struct hostent *h;
-       char buf[MAXHOSTNAMELEN];
-       char packet[datalen + MAXIPLEN + MAXICMPLEN];
-       int sockopt;
-
-       pingsock = create_icmp_socket();
-
-       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
-
-       pingaddr.sin_family = AF_INET;
-       h = xgethostbyname(host);
-       if (h->h_addrtype != AF_INET)
-               error_msg_and_die("unknown address type; only AF_INET is currently supported.");
-
-       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
-       strncpy(buf, h->h_name, sizeof(buf) - 1);
-       hostname = buf;
-
-       /* enable broadcast pings */
-       sockopt = 1;
-       setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
-                          sizeof(sockopt));
-
-       /* set recv buf for broadcast pings */
-       sockopt = 48 * 1024;
-       setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
-                          sizeof(sockopt));
-
-       printf("PING %s (%s): %d data bytes\n",
-                  hostname,
-                  inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
-                  datalen);
-
-       signal(SIGINT, pingstats);
-
-       /* start the ping's going ... */
-       sendping(0);
-
-       /* listen for replies */
-       while (1) {
-               struct sockaddr_in from;
-               socklen_t fromlen = (socklen_t) sizeof(from);
-               int c;
-
-               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
-                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror_msg("recvfrom");
-                       continue;
-               }
-               unpack(packet, c, &from);
-               if (pingcount > 0 && nreceived >= pingcount)
-                       break;
-       }
-       pingstats(0);
-}
-
-extern int ping_main(int argc, char **argv)
-{
-       char *thisarg;
-
-       datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
-
-       argc--;
-       argv++;
-       options = 0;
-       /* Parse any options */
-       while (argc >= 1 && **argv == '-') {
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'q':
-                       options |= O_QUIET;
-                       break;
-               case 'c':
-                       if (--argc <= 0)
-                               show_usage();
-                       argv++;
-                       pingcount = atoi(*argv);
-                       break;
-               case 's':
-                       if (--argc <= 0)
-                               show_usage();
-                       argv++;
-                       datalen = atoi(*argv);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc < 1)
-               show_usage();
-
-       myid = getpid() & 0xFFFF;
-       ping(*argv);
-       return EXIT_SUCCESS;
-}
-#endif /* ! BB_FEATURE_FANCY_PING */
-
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Muuss.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
diff --git a/busybox/networking/route.c b/busybox/networking/route.c
deleted file mode 100644 (file)
index 9d210af..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/* route
- *
- * Similar to the standard Unix route, but with only the necessary
- * parts for AF_INET
- *
- * Bjorn Wesen, Axis Communications AB
- *
- * Author of the original route:
- *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *              (derived from FvK's 'route.c     1.70    01/04/94')
- *
- * This program is free software; you can redistribute it
- * and/or  modify it under  the terms of  the GNU General
- * Public  License as  published  by  the  Free  Software
- * Foundation;  either  version 2 of the License, or  (at
- * your option) any later version.
- *
- * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
- * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/route.h>
-#include <linux/param.h>  // HZ
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <ctype.h>
-#include "busybox.h"
-
-#define _(x) x
-
-#define RTACTION_ADD   1
-#define RTACTION_DEL   2
-#define RTACTION_HELP  3
-#define RTACTION_FLUSH 4
-#define RTACTION_SHOW  5
-
-#define E_NOTFOUND      8
-#define E_SOCK          7
-#define E_LOOKUP        6
-#define E_VERSION       5
-#define E_USAGE         4
-#define E_OPTERR        3
-#define E_INTERN        2
-#define E_NOSUPP        1
-
-/* resolve XXX.YYY.ZZZ.QQQ -> binary */
-
-static int
-INET_resolve(char *name, struct sockaddr *sa)
-{
-       struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
-
-       s_in->sin_family = AF_INET;
-       s_in->sin_port = 0;
-
-       /* Default is special, meaning 0.0.0.0. */
-       if (strcmp(name, "default")==0) {
-               s_in->sin_addr.s_addr = INADDR_ANY;
-               return 1;
-       }
-       /* Look to see if it's a dotted quad. */
-       if (inet_aton(name, &s_in->sin_addr)) {
-               return 0;
-       }
-       /* guess not.. */
-       return -1;
-}
-
-#if defined (SIOCADDRTOLD) || defined (RTF_IRTT)        /* route */
-#define HAVE_NEW_ADDRT 1
-#endif
-#ifdef RTF_IRTT                 /* route */
-#define HAVE_RTF_IRTT 1
-#endif
-#ifdef RTF_REJECT               /* route */
-#define HAVE_RTF_REJECT 1
-#endif
-
-#if HAVE_NEW_ADDRT
-#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
-#define full_mask(x) (x)
-#else
-#define mask_in_addr(x) ((x).rt_genmask)
-#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
-#endif
-
-/* add or delete a route depending on action */
-
-static int
-INET_setroute(int action, int options, char **args)
-{
-       struct rtentry rt;
-       char target[128], gateway[128] = "NONE", netmask[128] = "default";
-       int xflag, isnet;
-       int skfd;
-
-       xflag = 0;
-
-       if (*args == NULL)
-           show_usage();
-       if (strcmp(*args, "-net")==0) {
-               xflag = 1;
-               args++;
-       } else if (strcmp(*args, "-host")==0) {
-               xflag = 2;
-               args++;
-       }
-       safe_strncpy(target, *args++, (sizeof target));
-
-       /* Clean out the RTREQ structure. */
-       memset((char *) &rt, 0, sizeof(struct rtentry));
-
-
-       if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
-               error_msg(_("can't resolve %s"), target);
-               return EXIT_FAILURE;   /* XXX change to E_something */
-       }
-
-       switch (xflag) {
-               case 1:
-                       isnet = 1;
-                       break;
-
-               case 2:
-                       isnet = 0;
-                       break;
-
-               default:
-                       break;
-       }
-
-       /* Fill in the other fields. */
-       rt.rt_flags = (RTF_UP | RTF_HOST);
-       if (isnet)
-               rt.rt_flags &= ~RTF_HOST;
-
-       while (*args) {
-               if (strcmp(*args, "metric")==0) {
-                       int metric;
-
-                       args++;
-                       if (!*args || !isdigit(**args))
-                               show_usage();
-                       metric = atoi(*args);
-#if HAVE_NEW_ADDRT
-                       rt.rt_metric = metric + 1;
-#else
-                       ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");  /* XXX Fixme */
-#endif
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "netmask")==0) {
-                       struct sockaddr mask;
-
-                       args++;
-                       if (!*args || mask_in_addr(rt))
-                               show_usage();
-                       safe_strncpy(netmask, *args, (sizeof netmask));
-                       if ((isnet = INET_resolve(netmask, &mask)) < 0) {
-                               error_msg(_("can't resolve netmask %s"), netmask);
-                               return E_LOOKUP;
-                       }
-                       rt.rt_genmask = full_mask(mask);
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       if (rt.rt_flags & RTF_GATEWAY)
-                               show_usage();
-                       safe_strncpy(gateway, *args, (sizeof gateway));
-                       if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
-                               error_msg(_("can't resolve gw %s"), gateway);
-                               return E_LOOKUP;
-                       }
-                       if (isnet) {
-                               error_msg(
-                                       _("%s: cannot use a NETWORK as gateway!"),
-                                       gateway);
-                               return E_OPTERR;
-                       }
-                       rt.rt_flags |= RTF_GATEWAY;
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "mss")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_MSS;
-                       if (!*args)
-                               show_usage();
-                       rt.rt_mss = atoi(*args);
-                       args++;
-                       if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
-                               error_msg(_("Invalid MSS."));
-                               return E_OPTERR;
-                       }
-                       continue;
-               }
-
-               if (strcmp(*args, "window")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       rt.rt_flags |= RTF_WINDOW;
-                       rt.rt_window = atoi(*args);
-                       args++;
-                       if (rt.rt_window < 128) {
-                               error_msg(_("Invalid window."));
-                               return E_OPTERR;
-                       }
-                       continue;
-               }
-
-               if (strcmp(*args, "irtt")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       args++;
-#if HAVE_RTF_IRTT
-                       rt.rt_flags |= RTF_IRTT;
-                       rt.rt_irtt = atoi(*(args - 1));
-                       rt.rt_irtt *= (HZ / 100);       /* FIXME */
-#if 0                           /* FIXME: do we need to check anything of this? */
-                       if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
-                               error_msg(_("Invalid initial rtt."));
-                               return E_OPTERR;
-                       }
-#endif
-#else
-                       ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
-#endif
-                       continue;
-               }
-
-               if (strcmp(*args, "reject")==0) {
-                       args++;
-#if HAVE_RTF_REJECT
-                       rt.rt_flags |= RTF_REJECT;
-#else
-                       ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
-#endif
-                       continue;
-               }
-               if (strcmp(*args, "mod")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_MODIFIED;
-                       continue;
-               }
-               if (strcmp(*args, "dyn")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_DYNAMIC;
-                       continue;
-               }
-               if (strcmp(*args, "reinstate")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_REINSTATE;
-                       continue;
-               }
-               if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
-                       args++;
-                       if (rt.rt_dev || *args == NULL)
-                               show_usage();
-                       rt.rt_dev = *args++;
-                       continue;
-               }
-               /* nothing matches */
-               if (!rt.rt_dev) {
-                       rt.rt_dev = *args++;
-                       if (*args)
-                               show_usage();   /* must be last to catch typos */
-               } else {
-                       show_usage();
-               }
-       }
-
-#if HAVE_RTF_REJECT
-       if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
-               rt.rt_dev = "lo";
-#endif
-
-       /* sanity checks.. */
-       if (mask_in_addr(rt)) {
-               unsigned long mask = mask_in_addr(rt);
-               mask = ~ntohl(mask);
-               if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
-                       error_msg(
-                               _("netmask %.8x doesn't make sense with host route"),
-                               (unsigned int)mask);
-                       return E_OPTERR;
-               }
-               if (mask & (mask + 1)) {
-                       error_msg(_("bogus netmask %s"), netmask);
-                       return E_OPTERR;
-               }
-               mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
-               if (mask & ~mask_in_addr(rt)) {
-                       error_msg(_("netmask doesn't match route address"));
-                       return E_OPTERR;
-               }
-       }
-       /* Fill out netmask if still unset */
-       if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
-               mask_in_addr(rt) = 0xffffffff;
-
-       /* Create a socket to the INET kernel. */
-       if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror("socket");
-               return E_SOCK;
-       }
-       /* Tell the kernel to accept this route. */
-       if (action == RTACTION_DEL) {
-               if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
-                       perror("SIOCDELRT");
-                       close(skfd);
-                       return E_SOCK;
-               }
-       } else {
-               if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
-                       perror("SIOCADDRT");
-                       close(skfd);
-                       return E_SOCK;
-               }
-       }
-
-       /* Close the socket. */
-       (void) close(skfd);
-       return EXIT_SUCCESS;
-}
-
-#ifndef RTF_UP
-/* Keep this in sync with /usr/src/linux/include/linux/route.h */
-#define RTF_UP          0x0001          /* route usable                 */
-#define RTF_GATEWAY     0x0002          /* destination is a gateway     */
-#define RTF_HOST        0x0004          /* host entry (net otherwise)   */
-#define RTF_REINSTATE   0x0008          /* reinstate route after tmout  */
-#define RTF_DYNAMIC     0x0010          /* created dyn. (by redirect)   */
-#define RTF_MODIFIED    0x0020          /* modified dyn. (by redirect)  */
-#define RTF_MTU         0x0040          /* specific MTU for this route  */
-#ifndef RTF_MSS
-#define RTF_MSS         RTF_MTU         /* Compatibility :-(            */
-#endif
-#define RTF_WINDOW      0x0080          /* per route window clamping    */
-#define RTF_IRTT        0x0100          /* Initial round trip time      */
-#define RTF_REJECT      0x0200          /* Reject route                 */
-#endif
-
-static void displayroutes(void)
-{
-       char buff[256];
-       int  nl = 0 ;
-       struct in_addr dest;
-       struct in_addr gw;
-       struct in_addr mask;
-       int flgs, ref, use, metric;
-       char flags[64];
-       unsigned long int d,g,m;
-
-       char sdest[16], sgw[16];
-
-
-       FILE *fp = xfopen("/proc/net/route", "r");
-
-       while( fgets(buff, sizeof(buff), fp) != NULL ) {
-               if(nl) {
-                       int ifl = 0;
-                       while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
-                               ifl++;
-                       buff[ifl]=0;    /* interface */
-                       if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx",
-                          &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
-                               error_msg_and_die( "Unsuported kernel route format\n");
-                       }
-                       if(nl==1)
-                       printf("Kernel IP routing table\n"
-                               "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface\n");
-
-                       ifl = 0;        /* parse flags */
-                       if(flgs&RTF_UP) {
-                               if(flgs&RTF_REJECT)
-                                       flags[ifl++]='!';
-                               else
-                                       flags[ifl++]='U';
-                               if(flgs&RTF_GATEWAY)
-                                       flags[ifl++]='G';
-                               if(flgs&RTF_HOST)
-                                       flags[ifl++]='H';
-                               if(flgs&RTF_REINSTATE)
-                                       flags[ifl++]='R';
-                               if(flgs&RTF_DYNAMIC)
-                                       flags[ifl++]='D';
-                               if(flgs&RTF_MODIFIED)
-                                       flags[ifl++]='M';
-                               flags[ifl]=0;
-                               dest.s_addr = d;
-                               gw.s_addr   = g;
-                               mask.s_addr = m;
-                               strcpy(sdest,  (dest.s_addr==0 ? "default" :
-                                       inet_ntoa(dest)));
-                               strcpy(sgw,    (gw.s_addr==0   ? "*"       :
-                                       inet_ntoa(gw)));
-                               printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
-                                       sdest, sgw,
-                                       inet_ntoa(mask),
-                                       flags, metric, ref, use, buff);
-                       }
-               }
-               nl++;
-       }
-}
-
-int route_main(int argc, char **argv)
-{
-       int what = 0;
-
-       argc--;
-       argv++;
-
-       if (*argv == NULL) {
-               displayroutes();
-               return EXIT_SUCCESS;
-       } else {
-               /* check verb */
-               if (strcmp(*argv, "add")==0)
-                       what = RTACTION_ADD;
-               else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
-                       what = RTACTION_DEL;
-               else if (strcmp(*argv, "flush")==0)
-                       what = RTACTION_FLUSH;
-               else
-                       show_usage();
-       }
-
-       return INET_setroute(what, 0, ++argv);
-}
diff --git a/busybox/networking/telnet.c b/busybox/networking/telnet.c
deleted file mode 100644 (file)
index ce82a0e..0000000
+++ /dev/null
@@ -1,711 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * telnet implementation for busybox
- *
- * Author: Tomi Ollila <too@iki.fi>
- * Copyright (C) 1994-2000 by Tomi Ollila
- *
- * Created: Thu Apr  7 13:29:41 1994 too
- * Last modified: Fri Jun  9 14:34:24 2000 too
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * HISTORY
- * Revision 3.1  1994/04/17  11:31:54  too
- * initial revision
- * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen
- * <andersen@lineo.com> 
- * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
- * <jam@ltsp.org>
- *
- */
-
-#include <termios.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <signal.h>
-#include <arpa/telnet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include "busybox.h"
-
-#if 0
-static const int DOTRACE = 1;
-#endif
-
-#ifdef DOTRACE
-#include <arpa/inet.h> /* for inet_ntoa()... */
-#define TRACE(x, y) do { if (x) printf y; } while (0)
-#else
-#define TRACE(x, y) 
-#endif
-
-#if 0
-#define USE_POLL
-#include <sys/poll.h>
-#else
-#include <sys/time.h>
-#endif
-
-#define DATABUFSIZE  128
-#define IACBUFSIZE   128
-
-static const int CHM_TRY = 0;
-static const int CHM_ON = 1;
-static const int CHM_OFF = 2;
-
-static const int UF_ECHO = 0x01;
-static const int UF_SGA = 0x02;
-
-enum {
-       TS_0 = 1,
-       TS_IAC = 2,
-       TS_OPT = 3,
-       TS_SUB1 = 4,
-       TS_SUB2 = 5,
-};
-
-#define WriteCS(fd, str) write(fd, str, sizeof str -1)
-
-typedef unsigned char byte;
-
-/* use globals to reduce size ??? */ /* test this hypothesis later */
-static struct Globalvars {
-       int             netfd; /* console fd:s are 0 and 1 (and 2) */
-    /* same buffer used both for network and console read/write */
-       char    buf[DATABUFSIZE]; /* allocating so static size is smaller */
-       byte    telstate; /* telnet negotiation state from network input */
-       byte    telwish;  /* DO, DONT, WILL, WONT */
-       byte    charmode;
-       byte    telflags;
-       byte    gotsig;
-       /* buffer to handle telnet negotiations */
-       char    iacbuf[IACBUFSIZE];
-       short   iaclen; /* could even use byte */
-       struct termios termios_def;     
-       struct termios termios_raw;     
-} G;
-
-#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
-
-#ifdef USE_GLOBALVAR_PTR
-struct Globalvars * Gptr;
-#define G (*Gptr)
-#else
-static struct Globalvars G;
-#endif
-
-static inline void iacflush()
-{
-       write(G.netfd, G.iacbuf, G.iaclen);
-       G.iaclen = 0;
-}
-
-/* Function prototypes */
-static int getport(char * p);
-static struct in_addr getserver(char * p);
-static int create_socket();
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port);
-static int remote_connect(struct in_addr addr, int port);
-static void rawmode();
-static void cookmode();
-static void do_linemode();
-static void will_charmode();
-static void telopt(byte c);
-static int subneg(byte c);
-#if 0
-static int local_bind(int port);
-#endif
-
-/* Some globals */
-static int one = 1;
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static char *ttype;
-#endif
-
-static void doexit(int ev)
-{
-       cookmode();
-       exit(ev);
-}      
-
-static void conescape()
-{
-       char b;
-
-       if (G.gotsig)   /* came from line  mode... go raw */
-               rawmode();
-
-       WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
-                       " l     go to line mode\r\n"
-                       " c     go to character mode\r\n"
-                       " z     suspend telnet\r\n"
-                       " e     exit telnet\r\n");
-
-       if (read(0, &b, 1) <= 0)
-               doexit(1);
-
-       switch (b)
-       {
-       case 'l':
-               if (!G.gotsig)
-               {
-                       do_linemode();
-                       goto rrturn;
-               }
-               break;
-       case 'c':
-               if (G.gotsig)
-               {
-                       will_charmode();
-                       goto rrturn;
-               }
-               break;
-       case 'z':
-               cookmode();
-               kill(0, SIGTSTP);
-               rawmode();
-               break;
-       case 'e':
-               doexit(0);
-       }
-
-       WriteCS(1, "continuing...\r\n");
-
-       if (G.gotsig)
-               cookmode();
-       
- rrturn:
-       G.gotsig = 0;
-       
-}
-static void handlenetoutput(int len)
-{
-       /*      here we could do smart tricks how to handle 0xFF:s in output
-        *      stream  like writing twice every sequence of FF:s (thus doing
-        *      many write()s. But I think interactive telnet application does
-        *      not need to be 100% 8-bit clean, so changing every 0xff:s to
-        *      0x7f:s */
-
-       int i;
-       byte * p = G.buf;
-
-       for (i = len; i > 0; i--, p++)
-       {
-               if (*p == 0x1d)
-               {
-                       conescape();
-                       return;
-               }
-               if (*p == 0xff)
-                       *p = 0x7f;
-       }
-       write(G.netfd, G.buf, len);
-}
-
-
-static void handlenetinput(int len)
-{
-       int i;
-       int cstart = 0;
-
-       for (i = 0; i < len; i++)
-       {
-               byte c = G.buf[i];
-
-               if (G.telstate == 0) /* most of the time state == 0 */
-               {
-                       if (c == IAC)
-                       {
-                               cstart = i;
-                               G.telstate = TS_IAC;
-                       }
-               }
-               else
-                       switch (G.telstate)
-                        {
-                        case TS_0:
-                                if (c == IAC)
-                                        G.telstate = TS_IAC;
-                                else
-                                        G.buf[cstart++] = c;
-                                break;
-
-                        case TS_IAC:
-                                if (c == IAC) /* IAC IAC -> 0xFF */
-                                {
-                                        G.buf[cstart++] = c;
-                                        G.telstate = TS_0;
-                                        break;
-                                }
-                                /* else */
-                                switch (c)
-                                {
-                                case SB:
-                                        G.telstate = TS_SUB1;
-                                        break;
-                                case DO:
-                                case DONT:
-                                case WILL:
-                                case WONT:
-                                        G.telwish =  c;
-                                        G.telstate = TS_OPT;
-                                        break;
-                                default:
-                                        G.telstate = TS_0;     /* DATA MARK must be added later */
-                                }
-                                break;
-                        case TS_OPT: /* WILL, WONT, DO, DONT */
-                                telopt(c);
-                                G.telstate = TS_0;
-                                break;
-                        case TS_SUB1: /* Subnegotiation */
-                        case TS_SUB2: /* Subnegotiation */
-                                if (subneg(c) == TRUE)
-                                        G.telstate = TS_0;
-                                break;
-                        }
-       }
-       if (G.telstate)
-       {
-               if (G.iaclen)                   iacflush();
-               if (G.telstate == TS_0) G.telstate = 0;
-
-               len = cstart;
-       }
-
-       if (len)
-               write(1, G.buf, len);
-}
-
-
-/* ******************************* */
-
-static inline void putiac(int c)
-{
-       G.iacbuf[G.iaclen++] = c;
-}
-
-
-static void putiac2(byte wwdd, byte c)
-{
-       if (G.iaclen + 3 > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(wwdd);
-       putiac(c);
-}
-
-#if 0
-static void putiac1(byte c)
-{
-       if (G.iaclen + 2 > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(c);
-}
-#endif
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static void putiac_subopt(byte c, char *str)
-{
-       int     len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
-
-       if (G.iaclen + len > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(SB);
-       putiac(c);
-       putiac(0);
-
-       while(*str)
-               putiac(*str++);
-
-       putiac(IAC);
-       putiac(SE);
-}
-#endif
-
-/* void putiacstring (subneg strings) */
-
-/* ******************************* */
-
-static char const escapecharis[] = "\r\nEscape character is ";
-
-static void setConMode()
-{
-       if (G.telflags & UF_ECHO)
-       {
-               if (G.charmode == CHM_TRY) {
-                       G.charmode = CHM_ON;
-                       printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
-                       rawmode();
-               }
-       }
-       else
-       {
-               if (G.charmode != CHM_OFF) {
-                       G.charmode = CHM_OFF;
-                       printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
-                       cookmode();
-               }
-       }
-}
-
-/* ******************************* */
-
-static void will_charmode()
-{
-       G.charmode = CHM_TRY;
-       G.telflags |= (UF_ECHO | UF_SGA);
-       setConMode();
-  
-       putiac2(DO, TELOPT_ECHO);
-       putiac2(DO, TELOPT_SGA);
-       iacflush();
-}
-
-static void do_linemode()
-{
-       G.charmode = CHM_TRY;
-       G.telflags &= ~(UF_ECHO | UF_SGA);
-       setConMode();
-
-       putiac2(DONT, TELOPT_ECHO);
-       putiac2(DONT, TELOPT_SGA);
-       iacflush();
-}
-
-/* ******************************* */
-
-static inline void to_notsup(char c)
-{
-       if      (G.telwish == WILL)     putiac2(DONT, c);
-       else if (G.telwish == DO)       putiac2(WONT, c);
-}
-
-static inline void to_echo()
-{
-       /* if server requests ECHO, don't agree */
-       if      (G.telwish == DO) {     putiac2(WONT, TELOPT_ECHO);     return; }
-       else if (G.telwish == DONT)     return;
-  
-       if (G.telflags & UF_ECHO)
-       {
-               if (G.telwish == WILL)
-                       return;
-       }
-       else
-               if (G.telwish == WONT)
-                       return;
-
-       if (G.charmode != CHM_OFF)
-               G.telflags ^= UF_ECHO;
-
-       if (G.telflags & UF_ECHO)
-               putiac2(DO, TELOPT_ECHO);
-       else
-               putiac2(DONT, TELOPT_ECHO);
-
-       setConMode();
-       WriteCS(1, "\r\n");  /* sudden modec */
-}
-
-static inline void to_sga()
-{
-       /* daemon always sends will/wont, client do/dont */
-
-       if (G.telflags & UF_SGA)
-       {
-               if (G.telwish == WILL)
-                       return;
-       }
-       else
-               if (G.telwish == WONT)
-                       return;
-  
-       if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
-               putiac2(DO, TELOPT_SGA);
-       else
-               putiac2(DONT, TELOPT_SGA);
-
-       return;
-}
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static inline void to_ttype()
-{
-       /* Tell server we will (or won't) do TTYPE */
-
-       if(ttype)
-               putiac2(WILL, TELOPT_TTYPE);
-       else
-               putiac2(WONT, TELOPT_TTYPE);
-
-       return;
-}
-#endif
-
-static void telopt(byte c)
-{
-       switch (c)
-       {
-       case TELOPT_ECHO:               to_echo(c);             break;
-       case TELOPT_SGA:                to_sga(c);              break;
-#ifdef BB_FEATURE_TELNET_TTYPE
-       case TELOPT_TTYPE:              to_ttype(c);    break;
-#endif
-       default:                                to_notsup(c);   break;
-       }
-}
-
-
-/* ******************************* */
-
-/* subnegotiation -- ignore all (except TTYPE) */
-
-static int subneg(byte c)
-{
-       switch (G.telstate)
-       {
-       case TS_SUB1:
-               if (c == IAC)
-                       G.telstate = TS_SUB2;
-#ifdef BB_FEATURE_TELNET_TTYPE
-               else
-               if (c == TELOPT_TTYPE)
-                       putiac_subopt(TELOPT_TTYPE,ttype);
-#endif
-               break;
-       case TS_SUB2:
-               if (c == SE)
-                       return TRUE;
-               G.telstate = TS_SUB1;
-               /* break; */
-       }
-       return FALSE;
-}
-
-/* ******************************* */
-
-static void fgotsig(int sig)
-{
-       G.gotsig = sig;
-}
-
-
-static void rawmode()
-{
-       tcsetattr(0, TCSADRAIN, &G.termios_raw);
-}      
-
-static void cookmode()
-{
-       tcsetattr(0, TCSADRAIN, &G.termios_def);
-}
-
-extern int telnet_main(int argc, char** argv)
-{
-       struct in_addr host;
-       int port;
-       int len;
-#ifdef USE_POLL
-       struct pollfd ufds[2];
-#else  
-       fd_set readfds;
-       int maxfd;
-#endif 
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-    ttype = getenv("TERM");
-#endif
-
-       memset(&G, 0, sizeof G);
-
-       if (tcgetattr(0, &G.termios_def) < 0)
-               exit(1);
-       
-       G.termios_raw = G.termios_def;
-       cfmakeraw(&G.termios_raw);
-       
-       if (argc < 2)   show_usage();
-       port = (argc > 2)? getport(argv[2]): 23;
-       
-       host = getserver(argv[1]);
-
-       G.netfd = remote_connect(host, port);
-
-       signal(SIGINT, fgotsig);
-
-#ifdef USE_POLL
-       ufds[0].fd = 0; ufds[1].fd = G.netfd;
-       ufds[0].events = ufds[1].events = POLLIN;
-#else  
-       FD_ZERO(&readfds);
-       FD_SET(0, &readfds);
-       FD_SET(G.netfd, &readfds);
-       maxfd = G.netfd + 1;
-#endif
-       
-       while (1)
-       {
-#ifndef USE_POLL
-               fd_set rfds = readfds;
-               
-               switch (select(maxfd, &rfds, NULL, NULL, NULL))
-#else
-               switch (poll(ufds, 2, -1))
-#endif                 
-               {
-               case 0:
-                       /* timeout */
-               case -1:
-                       /* error, ignore and/or log something, bay go to loop */
-                       if (G.gotsig)
-                               conescape();
-                       else
-                               sleep(1);
-                       break;
-               default:
-
-#ifdef USE_POLL
-                       if (ufds[0].revents) /* well, should check POLLIN, but ... */
-#else                          
-                       if (FD_ISSET(0, &rfds))
-#endif                         
-                       {
-                               len = read(0, G.buf, DATABUFSIZE);
-
-                               if (len <= 0)
-                                       doexit(0);
-
-                               TRACE(0, ("Read con: %d\n", len));
-                               
-                               handlenetoutput(len);
-                       }
-
-#ifdef USE_POLL
-                       if (ufds[1].revents) /* well, should check POLLIN, but ... */
-#else                          
-                       if (FD_ISSET(G.netfd, &rfds))
-#endif                         
-                       {
-                               len = read(G.netfd, G.buf, DATABUFSIZE);
-
-                               if (len <= 0)
-                               {
-                                       WriteCS(1, "Connection closed by foreign host.\r\n");
-                                       doexit(1);
-                               }
-                               TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
-
-                               handlenetinput(len);
-                       }
-               }
-       }
-}
-
-static int getport(char * p)
-{
-       unsigned int port = atoi(p);
-
-       if ((unsigned)(port - 1 ) > 65534)
-       {
-               error_msg_and_die("%s: bad port number", p);
-       }
-       return port;
-}
-
-static struct in_addr getserver(char * host)
-{
-       struct in_addr addr;
-
-       struct hostent * he;
-       he = xgethostbyname(host);
-       memcpy(&addr, he->h_addr, sizeof addr);
-
-       TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
-
-       return addr;
-}
-
-static int create_socket()
-{
-       return socket(AF_INET, SOCK_STREAM, 0);
-}
-
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
-{
-       memset(addr, 0, sizeof(struct sockaddr_in));
-       addr->sin_family = AF_INET;
-       addr->sin_port = htons(port);
-}
-  
-#if 0
-static int local_bind(int port)
-{
-       struct sockaddr_in s_addr;
-       int s = create_socket();
-  
-       setup_sockaddr_in(&s_addr, port);
-  
-       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-  
-       if (bind(s, &s_addr, sizeof s_addr) < 0)
-       {
-               char * e = sys_errlist[errno];
-               syserrorexit("bind");
-               exit(1);
-       }
-       listen(s, 1);
-       
-       return s;
-}
-#endif
-
-static int remote_connect(struct in_addr addr, int port)
-{
-       struct sockaddr_in s_addr;
-       int s = create_socket();
-
-       setup_sockaddr_in(&s_addr, port);
-       s_addr.sin_addr = addr;
-
-       setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
-
-       if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
-       {
-               perror_msg_and_die("Unable to connect to remote host");
-       }
-       return s;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/busybox/networking/tftp.c b/busybox/networking/tftp.c
deleted file mode 100644 (file)
index 999b5d7..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* tftp.c                                                                    */
-/*                                                                           */
-/* A simple tftp client for busybox.                                         */
-/* Tries to follow RFC1350.                                                  */
-/* Only "octet" mode and 512-byte data blocks are supported.                 */
-/*                                                                           */
-/* Copyright (C) 2001 Magnus Damm <damm@opensource.se>                       */
-/*                                                                           */
-/* Parts of the code based on:                                               */
-/*                                                                           */
-/* atftp:  Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>   */
-/*                        and Remi Lefebvre <remi@debian.org>                */
-/*                                                                           */
-/* utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>                         */
-/*                                                                           */
-/* This program is free software; you can redistribute it and/or modify      */
-/* it under the terms of the GNU General Public License as published by      */
-/* the Free Software Foundation; either version 2 of the License, or         */
-/* (at your option) any later version.                                       */
-/*                                                                           */
-/* This program is distributed in the hope that it will be useful,           */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          */
-/* General Public License for more details.                                  */
-/*                                                                           */
-/* You should have received a copy of the GNU General Public License         */
-/* along with this program; if not, write to the Free Software               */
-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */
-/*                                                                           */
-/* ------------------------------------------------------------------------- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "busybox.h"
-
-//#define BB_FEATURE_TFTP_DEBUG
-
-static const char *tftp_error_msg[] = {
-       "Undefined error",
-       "File not found",
-       "Access violation",
-       "Disk full or allocation error",
-       "Illegal TFTP operation",
-       "Unknown transfer ID",
-       "File already exists",
-       "No such user"
-};
-
-const int tftp_cmd_get = 1;
-const int tftp_cmd_put = 2;
-
-static inline int tftp(const int cmd, const struct hostent *host,
-       const char *serverfile, int localfd, const int port, int tftp_bufsize)
-{
-       const int cmd_get = cmd & tftp_cmd_get;
-       const int cmd_put = cmd & tftp_cmd_put;
-       const int bb_tftp_num_retries = 5;
-
-       struct sockaddr_in sa;
-       struct sockaddr_in from;
-       struct timeval tv;
-       socklen_t fromlen;
-       fd_set rfds;
-       char *cp;
-       unsigned short tmp;
-       int socketfd;
-       int len;
-       int opcode = 0;
-       int finished = 0;
-       int timeout = bb_tftp_num_retries;
-       int block_nr = 1;
-       RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); // Why 4 ?
-
-       tftp_bufsize += 4;
-
-       if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror_msg("socket");
-               return EXIT_FAILURE;
-       }
-
-       len = sizeof(sa);
-
-       memset(&sa, 0, len);
-       bind(socketfd, (struct sockaddr *)&sa, len);
-
-       sa.sin_family = host->h_addrtype;
-       sa.sin_port = htons(port);
-       memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
-                  sizeof(sa.sin_addr));
-
-       /* build opcode */
-
-       if (cmd_get) {
-               opcode = 1;     // read request = 1
-       }
-
-       if (cmd_put) {
-               opcode = 2;     // write request = 2
-       }
-
-       while (1) {
-
-
-               /* build packet of type "opcode" */
-
-
-               cp = buf;
-
-               *((unsigned short *) cp) = htons(opcode);
-
-               cp += 2;
-
-               /* add filename and mode */
-
-               if ((cmd_get && (opcode == 1)) || // read request = 1
-                       (cmd_put && (opcode == 2))) { // write request = 2
-
-                       /* what is this trying to do ? */
-                       while (cp != &buf[tftp_bufsize - 1]) {
-                               if ((*cp = *serverfile++) == '\0')
-                                       break;
-                               cp++;
-                       }
-                       /* and this ? */
-                       if ((*cp != '\0') || (&buf[tftp_bufsize - 1] - cp) < 7) {
-                               error_msg("too long server-filename");
-                               break;
-                       }
-
-                       memcpy(cp + 1, "octet", 6);
-                       cp += 7;
-               }
-
-               /* add ack and data */
-
-               if ((cmd_get && (opcode == 4)) || // acknowledgement = 4
-                       (cmd_put && (opcode == 3))) { // data packet == 3
-
-                       *((unsigned short *) cp) = htons(block_nr);
-
-                       cp += 2;
-
-                       block_nr++;
-
-                       if (cmd_put && (opcode == 3)) { // data packet == 3
-                               len = read(localfd, cp, tftp_bufsize - 4);
-
-                               if (len < 0) {
-                                       perror_msg("read");
-                                       break;
-                               }
-
-                               if (len != (tftp_bufsize - 4)) {
-                                       finished++;
-                               }
-
-                               cp += len;
-                       } else if (finished) {
-                               break;
-                       }
-               }
-
-
-               /* send packet */
-
-
-               do {
-
-                       len = cp - buf;
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-                       printf("sending %u bytes\n", len);
-                       for (cp = buf; cp < &buf[len]; cp++)
-                               printf("%02x ", *cp);
-                       printf("\n");
-#endif
-                       if (sendto(socketfd, buf, len, 0,
-                                       (struct sockaddr *) &sa, sizeof(sa)) < 0) {
-                               perror_msg("send");
-                               len = -1;
-                               break;
-                       }
-
-
-                       /* receive packet */
-
-
-                       memset(&from, 0, sizeof(from));
-                       fromlen = sizeof(from);
-
-                       tv.tv_sec = 5; // BB_TFPT_TIMEOUT = 5
-                       tv.tv_usec = 0;
-
-                       FD_ZERO(&rfds);
-                       FD_SET(socketfd, &rfds);
-
-                       switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
-                       case 1:
-                               len = recvfrom(socketfd, buf, tftp_bufsize, 0,
-                                               (struct sockaddr *) &from, &fromlen);
-
-                               if (len < 0) {
-                                       perror_msg("recvfrom");
-                                       break;
-                               }
-
-                               timeout = 0;
-
-                               if (sa.sin_port == htons(port)) {
-                                       sa.sin_port = from.sin_port;
-                               }
-                               if (sa.sin_port == from.sin_port) {
-                                       break;
-                               }
-
-                               /* fall-through for bad packets! */
-                               /* discard the packet - treat as timeout */
-                               timeout = bb_tftp_num_retries;
-
-                       case 0:
-                               error_msg("timeout");
-
-                               if (timeout == 0) {
-                                       len = -1;
-                                       error_msg("last timeout");
-                               } else {
-                                       timeout--;
-                               }
-                               break;
-
-                       default:
-                               perror_msg("select");
-                               len = -1;
-                       }
-
-               } while (timeout && (len >= 0));
-
-               if (len < 0) {
-                       break;
-               }
-
-               /* process received packet */
-
-
-               opcode = ntohs(*((unsigned short *) buf));
-               tmp = ntohs(*((unsigned short *) &buf[2]));
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-               printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
-#endif
-
-               if (cmd_get && (opcode == 3)) { // data packet == 3
-
-                       if (tmp == block_nr) {
-                               len = write(localfd, &buf[4], len - 4);
-
-                               if (len < 0) {
-                                       perror_msg("write");
-                                       break;
-                               }
-
-                               if (len != (tftp_bufsize - 4)) {
-                                       finished++;
-                               }
-
-                               opcode = 4; // acknowledgement = 4
-                               continue;
-                       }
-               }
-
-               if (cmd_put && (opcode == 4)) { // acknowledgement = 4
-
-                       if (tmp == (block_nr - 1)) {
-                               if (finished) {
-                                       break;
-                               }
-
-                               opcode = 3; // data packet == 3
-                               continue;
-                       }
-               }
-
-               if (opcode == 5) { // error code == 5
-                       char *msg = NULL;
-
-                       if (buf[4] != '\0') {
-                               msg = &buf[4];
-                               buf[tftp_bufsize - 1] = '\0';
-                       } else if (tmp < (sizeof(tftp_error_msg) / sizeof(char *))) {
-                               msg = (char *) tftp_error_msg[tmp];
-                       }
-
-                       if (msg) {
-                               error_msg("server says: %s", msg);
-                       }
-
-                       break;
-               }
-       }
-
-       close(socketfd);
-
-       return finished ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-int tftp_main(int argc, char **argv)
-{
-       struct hostent *host = NULL;
-       char *localfile = NULL;
-       char *remotefile = NULL;
-       int port = 69;
-       int cmd = 0;
-       int fd = -1;
-       int flags = 0;
-       int opt;
-       int result;
-       int blocksize = 512;
-
-       while ((opt = getopt(argc, argv, "b:gpl:r:")) != -1) {
-               switch (opt) {
-               case 'b':
-                       blocksize = atoi(optarg);
-                       break;
-#ifdef BB_FEATURE_TFTP_GET
-               case 'g':
-                       cmd = tftp_cmd_get;
-                       flags = O_WRONLY | O_CREAT;
-                       break;
-#endif
-#ifdef BB_FEATURE_TFTP_PUT
-               case 'p':
-                       cmd = tftp_cmd_put;
-                       flags = O_RDONLY;
-                       break;
-#endif
-               case 'l': 
-                       localfile = xstrdup(optarg);
-                       break;
-               case 'r':
-                       remotefile = xstrdup(optarg);
-                       break;
-               }
-       }
-
-       if ((cmd == 0) || (optind == argc)) {
-               show_usage();
-       }
-
-       fd = open(localfile, flags, 0644);
-       if (fd < 0) {
-               perror_msg_and_die("local file");
-       }
-
-       host = xgethostbyname(argv[optind]);
-
-       if (optind + 2 == argc) {
-               port = atoi(argv[optind + 1]);
-       }
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-       printf("using server \"%s\", serverfile \"%s\","
-               "localfile \"%s\".\n",
-               inet_ntoa(*((struct in_addr *) host->h_addr)),
-               remotefile, localfile);
-#endif
-
-       result = tftp(cmd, host, remotefile, fd, port, blocksize);
-       close(fd);
-
-       return(result);
-}
\ No newline at end of file
diff --git a/busybox/networking/traceroute.c b/busybox/networking/traceroute.c
deleted file mode 100644 (file)
index a3abd0a..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Van Jacobson.
- *
- * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by the University of
- *      California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * traceroute host  - trace the route ip packets follow going to "host".
- * Notes
- * -----
- * This program must be run by root or be setuid.  (I suggest that
- * you *don't* make it setuid -- casual use could result in a lot
- * of unnecessary traffic on our poor, congested nets.)
- *
- * I stole the idea for this program from Steve Deering.  Since
- * the first release, I've learned that had I attended the right
- * IETF working group meetings, I also could have stolen it from Guy
- * Almes or Matt Mathis.  I don't know (or care) who came up with
- * the idea first.  I envy the originators' perspicacity and I'm
- * glad they didn't keep the idea a secret.
- *
- * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
- * enhancements to the original distribution.
- *
- * I've hacked up a round-trip-route version of this that works by
- * sending a loose-source-routed udp datagram through the destination
- * back to yourself.  Unfortunately, SO many gateways botch source
- * routing, the thing is almost worthless.  Maybe one day...
- *
- *  -- Van Jacobson (van@helios.ee.lbl.gov)
- *     Tue Dec 20 03:50:13 PST 1988
- */
-
-#undef BB_FEATURE_TRACEROUTE_VERBOSE
-//#define BB_FEATURE_TRACEROUTE_VERBOSE
-#undef BB_FEATURE_TRACEROUTE_SO_DEBUG   /* not in documentation man */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <endian.h>
-#include <arpa/inet.h>
-#include <netinet/udp.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-
- /* It turns out that libc5 doesn't have proper icmp support
- * built into it header files, so we have to supplement it */
-#if __GNU_LIBRARY__ < 5
-static const int ICMP_MINLEN = 8;                              /* abs minimum */
-
-struct icmp_ra_addr
-{
-  u_int32_t ira_addr;
-  u_int32_t ira_preference;
-};
-
-
-struct icmp
-{
-  u_int8_t  icmp_type; /* type of message, see below */
-  u_int8_t  icmp_code; /* type sub code */
-  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
-  union
-  {
-    u_char ih_pptr;            /* ICMP_PARAMPROB */
-    struct in_addr ih_gwaddr;  /* gateway address */
-    struct ih_idseq            /* echo datagram */
-    {
-      u_int16_t icd_id;
-      u_int16_t icd_seq;
-    } ih_idseq;
-    u_int32_t ih_void;
-
-    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
-    struct ih_pmtu
-    {
-      u_int16_t ipm_void;
-      u_int16_t ipm_nextmtu;
-    } ih_pmtu;
-
-    struct ih_rtradv
-    {
-      u_int8_t irt_num_addrs;
-      u_int8_t irt_wpa;
-      u_int16_t irt_lifetime;
-    } ih_rtradv;
-  } icmp_hun;
-#define        icmp_pptr       icmp_hun.ih_pptr
-#define        icmp_gwaddr     icmp_hun.ih_gwaddr
-#define        icmp_id         icmp_hun.ih_idseq.icd_id
-#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
-#define        icmp_void       icmp_hun.ih_void
-#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
-#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
-#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
-#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
-#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
-  union
-  {
-    struct
-    {
-      u_int32_t its_otime;
-      u_int32_t its_rtime;
-      u_int32_t its_ttime;
-    } id_ts;
-    struct
-    {
-      struct ip idi_ip;
-      /* options and then 64 bits of data */
-    } id_ip;
-    struct icmp_ra_addr id_radv;
-    u_int32_t   id_mask;
-    u_int8_t    id_data[1];
-  } icmp_dun;
-#define        icmp_otime      icmp_dun.id_ts.its_otime
-#define        icmp_rtime      icmp_dun.id_ts.its_rtime
-#define        icmp_ttime      icmp_dun.id_ts.its_ttime
-#define        icmp_ip         icmp_dun.id_ip.idi_ip
-#define        icmp_radv       icmp_dun.id_radv
-#define        icmp_mask       icmp_dun.id_mask
-#define        icmp_data       icmp_dun.id_data
-};
-
-#define        ICMP_MINLEN     8                               /* abs minimum */
-#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
-#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
-#define        ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
-#define        ICMP_UNREACH_NET                0       /* bad net */
-#define        ICMP_UNREACH_HOST               1       /* bad host */
-#define        ICMP_UNREACH_PROTOCOL           2       /* bad protocol */
-#define        ICMP_UNREACH_PORT               3       /* bad port */
-#define        ICMP_UNREACH_NEEDFRAG           4       /* IP_DF caused drop */
-#define        ICMP_UNREACH_SRCFAIL            5       /* src route failed */
-#endif
-
-
-#define MAXPACKET       65535   /* max ip packet size */
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN  64
-#endif
-
-/*
- * format of a (udp) probe packet.
- */
-struct opacket {
-       struct ip ip;
-       struct udphdr udp;
-       u_char seq;             /* sequence number of this packet */
-       u_char ttl;             /* ttl packet left with */
-       struct timeval tv;      /* time packet left */
-};
-
-/*
- * Definitions for internet protocol version 4.
- * Per RFC 791, September 1981.
- */
-#define IPVERSION       4
-
-
-#include "busybox.h"
-
-static u_char  packet[512];            /* last inbound (icmp) packet */
-static struct opacket  *outpacket;     /* last output (udp) packet */
-
-static int s;                          /* receive (icmp) socket file descriptor */
-static int sndsock;                    /* send (udp) socket file descriptor */
-
-static struct sockaddr whereto;        /* Who to try to reach */
-static int datalen;                    /* How much data */
-
-static char *hostname;
-
-static int max_ttl = 30;
-static u_short ident;
-static u_short port = 32768+666;       /* start udp dest port # for probe packets */
-
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-static int verbose;
-#endif
-static int waittime = 5;               /* time to wait for response (in seconds) */
-static int nflag;                      /* print addresses numerically */
-
-/*
- * Construct an Internet address representation.
- * If the nflag has been supplied, give
- * numeric value, otherwise try for symbolic name.
- */
-static inline void
-inetname(struct sockaddr_in *from)
-{
-       char *cp;
-       struct hostent *hp;
-       static char domain[MAXHOSTNAMELEN + 1];
-       static int first = 1;
-       const char *ina;
-
-       if (first && !nflag) {
-               first = 0;
-               if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
-                   (cp = strchr(domain, '.')))
-                       (void) strcpy(domain, cp + 1);
-               else
-                       domain[0] = 0;
-       }
-       cp = 0;
-       if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
-               hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
-               if (hp) {
-                       if ((cp = strchr(hp->h_name, '.')) &&
-                           !strcmp(cp + 1, domain))
-                               *cp = 0;
-                       cp = (char *)hp->h_name;
-               }
-       }
-       ina = inet_ntoa(from->sin_addr);
-       if (nflag)
-               printf(" %s", ina);
-       else
-               printf(" %s (%s)", (cp ? cp : ina), ina);
-}
-
-static inline void
-print(u_char *buf, int cc, struct sockaddr_in *from)
-{
-       struct ip *ip;
-       int hlen;
-
-       ip = (struct ip *) buf;
-       hlen = ip->ip_hl << 2;
-       cc -= hlen;
-
-       inetname(from);
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-       if (verbose)
-               printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
-#endif
-}
-
-static inline double
-deltaT(struct timeval *t1p, struct timeval *t2p)
-{
-       double dt;
-
-       dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
-            (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
-       return (dt);
-}
-
-static inline int
-wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
-{
-       fd_set fds;
-       static struct timeval wait;
-       int cc = 0;
-       int fromlen = sizeof (*from);
-
-       FD_ZERO(&fds);
-       FD_SET(sock, &fds);
-       if (reset_timer) {
-               /*
-                * traceroute could hang if someone else has a ping
-                * running and our ICMP reply gets dropped but we don't
-                * realize it because we keep waking up to handle those
-                * other ICMP packets that keep coming in.  To fix this,
-                * "reset_timer" will only be true if the last packet that
-                * came in was for us or if this is the first time we're
-                * waiting for a reply since sending out a probe.  Note
-                * that this takes advantage of the select() feature on
-                * Linux where the remaining timeout is written to the
-                * struct timeval area.
-                */
-               wait.tv_sec = waittime;
-               wait.tv_usec = 0;
-       }
-
-       if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
-               cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
-                           (struct sockaddr *)from, &fromlen);
-
-       return(cc);
-}
-
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-/*
- * Convert an ICMP "type" field to a printable string.
- */
-static inline const char *
-pr_type(t)
-       u_char t;
-{
-       static const char * const ttab[] = {
-       "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
-       "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
-       "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
-       "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
-       "Info Reply"
-       };
-
-       if(t > 16)
-               return("OUT-OF-RANGE");
-
-       return(ttab[t]);
-}
-#endif
-
-static inline int
-packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
-{
-       struct icmp *icp;
-       u_char type, code;
-       int hlen;
-       struct ip *ip;
-
-       ip = (struct ip *) buf;
-       hlen = ip->ip_hl << 2;
-       if (cc < hlen + ICMP_MINLEN) {
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-               if (verbose)
-                       printf("packet too short (%d bytes) from %s\n", cc,
-                               inet_ntoa(from->sin_addr));
-#endif
-               return (0);
-       }
-       cc -= hlen;
-       icp = (struct icmp *)(buf + hlen);
-       type = icp->icmp_type; code = icp->icmp_code;
-       if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
-           type == ICMP_UNREACH) {
-               struct ip *hip;
-               struct udphdr *up;
-
-               hip = &icp->icmp_ip;
-               hlen = hip->ip_hl << 2;
-               up = (struct udphdr *)((u_char *)hip + hlen);
-               if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
-                   up->source == htons(ident) &&
-                   up->dest == htons(port+seq))
-                       return (type == ICMP_TIMXCEED? -1 : code+1);
-       }
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-       if (verbose) {
-               int i;
-               u_long *lp = (u_long *)&icp->icmp_ip;
-
-               printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
-                       cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
-                       type, pr_type(type), icp->icmp_code);
-               for (i = 4; i < cc ; i += sizeof(long))
-                       printf("%2d: x%8.8lx\n", i, *lp++);
-       }
-#endif
-       return(0);
-}
-
-static void             /* not inline */
-send_probe(int seq, int ttl)
-{
-       struct opacket *op = outpacket;
-       struct ip *ip = &op->ip;
-       struct udphdr *up = &op->udp;
-       int i;
-       struct timezone tz;
-
-       ip->ip_off = 0;
-       ip->ip_hl = sizeof(*ip) >> 2;
-       ip->ip_p = IPPROTO_UDP;
-       ip->ip_len = datalen;
-       ip->ip_ttl = ttl;
-       ip->ip_v = IPVERSION;
-       ip->ip_id = htons(ident+seq);
-
-       up->source = htons(ident);
-       up->dest = htons(port+seq);
-       up->len = htons((u_short)(datalen - sizeof(struct ip)));
-       up->check = 0;
-
-       op->seq = seq;
-       op->ttl = ttl;
-       (void) gettimeofday(&op->tv, &tz);
-
-       i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
-                  sizeof(struct sockaddr));
-       if (i < 0 || i != datalen)  {
-               if (i<0)
-                       perror("sendto");
-               printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
-                       datalen, i);
-               (void) fflush(stdout);
-       }
-}
-
-
-int
-#ifndef BB_TRACEROUTE
-main(argc, argv)
-#else
-traceroute_main(argc, argv)
-#endif
-       int argc;
-       char *argv[];
-{
-       extern char *optarg;
-       extern int optind;
-       struct hostent *hp;
-       struct sockaddr_in from, *to;
-       int ch, i, on, probe, seq, tos, ttl;
-
-       int options = 0;                /* socket options */
-       char *source = 0;
-       int nprobes = 3;
-
-       on = 1;
-       seq = tos = 0;
-       to = (struct sockaddr_in *)&whereto;
-       while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
-               switch(ch) {
-               case 'd':
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-                       options |= SO_DEBUG;
-#endif
-                       break;
-               case 'm':
-                       max_ttl = atoi(optarg);
-                       if (max_ttl <= 1)
-                               error_msg_and_die("max ttl must be >1.");
-                       break;
-               case 'n':
-                       nflag++;
-                       break;
-               case 'p':
-                       port = atoi(optarg);
-                       if (port < 1)
-                               error_msg_and_die("port must be >0.");
-                       break;
-               case 'q':
-                       nprobes = atoi(optarg);
-                       if (nprobes < 1)
-                               error_msg_and_die("nprobes must be >0.");
-                       break;
-               case 'r':
-                       options |= SO_DONTROUTE;
-                       break;
-               case 's':
-                       /*
-                        * set the ip source address of the outbound
-                        * probe (e.g., on a multi-homed host).
-                        */
-                       source = optarg;
-                       break;
-               case 't':
-                       tos = atoi(optarg);
-                       if (tos < 0 || tos > 255)
-                               error_msg_and_die("tos must be 0 to 255.");
-                       break;
-               case 'v':
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-                       verbose++;
-#endif
-                       break;
-               case 'w':
-                       waittime = atoi(optarg);
-                       if (waittime <= 1)
-                               error_msg_and_die("wait must be >1 sec.");
-                       break;
-               default:
-                       show_usage();
-               }
-       argc -= optind;
-       argv += optind;
-
-       if (argc < 1)
-               show_usage();
-
-       setlinebuf (stdout);
-
-       memset(&whereto, 0, sizeof(struct sockaddr));
-       hp = xgethostbyname(*argv);
-                       to->sin_family = hp->h_addrtype;
-       memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
-                       hostname = (char *)hp->h_name;
-       if (*++argv)
-               datalen = atoi(*argv);
-       if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
-               error_msg_and_die("packet size must be 0 <= s < %d.",
-                   MAXPACKET - sizeof(struct opacket));
-       datalen += sizeof(struct opacket);
-       outpacket = (struct opacket *)xmalloc((unsigned)datalen);
-       memset(outpacket, 0, datalen);
-       outpacket->ip.ip_dst = to->sin_addr;
-       outpacket->ip.ip_tos = tos;
-       outpacket->ip.ip_v = IPVERSION;
-       outpacket->ip.ip_id = 0;
-
-       ident = (getpid() & 0xffff) | 0x8000;
-
-       if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
-               perror_msg_and_die(can_not_create_raw_socket);
-
-       s = create_icmp_socket();
-
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-       if (options & SO_DEBUG)
-               (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
-                                 (char *)&on, sizeof(on));
-#endif
-       if (options & SO_DONTROUTE)
-               (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
-                                 (char *)&on, sizeof(on));
-#ifdef SO_SNDBUF
-       if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
-                      sizeof(datalen)) < 0)
-               perror_msg_and_die("SO_SNDBUF");
-#endif SO_SNDBUF
-#ifdef IP_HDRINCL
-       if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
-                      sizeof(on)) < 0)
-               perror_msg_and_die("IP_HDRINCL");
-#endif IP_HDRINCL
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-       if (options & SO_DEBUG)
-               (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
-                                 (char *)&on, sizeof(on));
-#endif
-       if (options & SO_DONTROUTE)
-               (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
-                                 (char *)&on, sizeof(on));
-
-       if (source) {
-               memset(&from, 0, sizeof(struct sockaddr));
-               from.sin_family = AF_INET;
-               from.sin_addr.s_addr = inet_addr(source);
-               if (from.sin_addr.s_addr == -1)
-                       error_msg_and_die("unknown host %s", source);
-               outpacket->ip.ip_src = from.sin_addr;
-#ifndef IP_HDRINCL
-               if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
-                       perror_msg_and_die("bind");
-#endif IP_HDRINCL
-       }
-
-       fprintf(stderr, "traceroute to %s (%s)", hostname,
-               inet_ntoa(to->sin_addr));
-       if (source)
-               fprintf(stderr, " from %s", source);
-       fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
-
-       for (ttl = 1; ttl <= max_ttl; ++ttl) {
-               u_long lastaddr = 0;
-               int got_there = 0;
-               int unreachable = 0;
-
-               printf("%2d ", ttl);
-               for (probe = 0; probe < nprobes; ++probe) {
-                       int cc, reset_timer;
-                       struct timeval t1, t2;
-                       struct timezone tz;
-                       struct ip *ip;
-
-                       (void) gettimeofday(&t1, &tz);
-                       send_probe(++seq, ttl);
-                       reset_timer = 1;
-                       while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
-                               (void) gettimeofday(&t2, &tz);
-                               if ((i = packet_ok(packet, cc, &from, seq))) {
-                                       reset_timer = 1;
-                                       if (from.sin_addr.s_addr != lastaddr) {
-                                               print(packet, cc, &from);
-                                               lastaddr = from.sin_addr.s_addr;
-                                       }
-                                       printf("  %g ms", deltaT(&t1, &t2));
-                                       switch(i - 1) {
-                                       case ICMP_UNREACH_PORT:
-                                               ip = (struct ip *)packet;
-                                               if (ip->ip_ttl <= 1)
-                                                       printf(" !");
-                                               ++got_there;
-                                               break;
-                                       case ICMP_UNREACH_NET:
-                                               ++unreachable;
-                                               printf(" !N");
-                                               break;
-                                       case ICMP_UNREACH_HOST:
-                                               ++unreachable;
-                                               printf(" !H");
-                                               break;
-                                       case ICMP_UNREACH_PROTOCOL:
-                                               ++got_there;
-                                               printf(" !P");
-                                               break;
-                                       case ICMP_UNREACH_NEEDFRAG:
-                                               ++unreachable;
-                                               printf(" !F");
-                                               break;
-                                       case ICMP_UNREACH_SRCFAIL:
-                                               ++unreachable;
-                                               printf(" !S");
-                                               break;
-                                       }
-                                       break;
-                               } else
-                                       reset_timer = 0;
-                       }
-                       if (cc == 0)
-                               printf(" *");
-                       (void) fflush(stdout);
-               }
-               putchar('\n');
-               if (got_there || unreachable >= nprobes-1)
-                       exit(0);
-       }
-
-       return 0;
-}
diff --git a/busybox/networking/wget.c b/busybox/networking/wget.c
deleted file mode 100644 (file)
index 59373d1..0000000
+++ /dev/null
@@ -1,834 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * wget - retrieve a file using HTTP or FTP
- *
- * Chip Rosenthal Covad Communications <chip@laserlink.net>
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <getopt.h>
-
-#include "busybox.h"
-
-/* Stupid libc5 doesn't define this... */
-#ifndef timersub
-#define        timersub(a, b, result)                                                \
-  do {                                                                       \
-    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                            \
-    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                         \
-    if ((result)->tv_usec < 0) {                                             \
-      --(result)->tv_sec;                                                    \
-      (result)->tv_usec += 1000000;                                          \
-    }                                                                        \
-  } while (0)
-#endif 
-
-struct host_info {
-       char *host;
-       int port;
-       char *path;
-       int is_ftp;
-       char *user;
-};
-
-static void parse_url(char *url, struct host_info *h);
-static FILE *open_socket(char *host, int port);
-static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
-static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
-
-/* Globals (can be accessed from signal handlers */
-static off_t filesize = 0;             /* content-length of the file */
-static int chunked = 0;                        /* chunked transfer encoding */
-#ifdef BB_FEATURE_WGET_STATUSBAR
-static void progressmeter(int flag);
-static char *curfile;                  /* Name of current file being transferred. */
-static struct timeval start;   /* Time a transfer started. */
-static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */
-/* For progressmeter() -- number of seconds before xfer considered "stalled" */
-static const int STALLTIME = 5;
-#endif
-               
-static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
-{
-       if (output != stdout && do_continue==0) {
-               fclose(output);
-               unlink(fname_out);
-       }
-}
-
-/* Read NMEMB elements of SIZE bytes into PTR from STREAM.  Returns the
- * number of elements read, and a short count if an eof or non-interrupt
- * error is encountered.  */
-static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-       size_t ret = 0;
-
-       do {
-               clearerr(stream);
-               ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
-       } while (ret < nmemb && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-/* Write NMEMB elements of SIZE bytes from PTR to STREAM.  Returns the
- * number of elements written, and a short count if an eof or non-interrupt
- * error is encountered.  */
-static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-       size_t ret = 0;
-
-       do {
-               clearerr(stream);
-               ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
-       } while (ret < nmemb && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
- * Returns S, or NULL if an eof or non-interrupt error is encountered.  */
-static char *safe_fgets(char *s, int size, FILE *stream)
-{
-       char *ret;
-
-       do {
-               clearerr(stream);
-               ret = fgets(s, size, stream);
-       } while (ret == NULL && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-#define close_delete_and_die(s...) { \
-       close_and_delete_outfile(output, fname_out, do_continue); \
-       error_msg_and_die(s); }
-
-
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
-/*
- *  Base64-encode character string
- *  oops... isn't something similar in uuencode.c?
- *  It would be better to use already existing code
- */
-char *base64enc(char *p, char *buf, int len) {
-
-        char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-                    "0123456789+/";
-               char *s = buf;
-
-        while(*p) {
-                               if (s >= buf+len-4)
-                                       error_msg_and_die("buffer overflow");
-                *(s++) = al[(*p >> 2) & 0x3F];
-                *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
-                *s = *(s+1) = '=';
-                *(s+2) = 0;
-                if (! *(++p)) break;
-                *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
-                if (! *(++p)) break;
-                *(s++) = al[*(p++) & 0x3F];
-        }
-
-               return buf;
-}
-#endif
-
-int wget_main(int argc, char **argv)
-{
-       int n, try=5, status;
-       int port;
-       char *proxy;
-       char *dir_prefix=NULL;
-       char *s, buf[512];
-       struct stat sbuf;
-       char extra_headers[1024];
-       char *extra_headers_ptr = extra_headers;
-       int extra_headers_left = sizeof(extra_headers);
-       int which_long_opt = 0, option_index = -1;
-       struct host_info server, target;
-
-       FILE *sfp = NULL;                       /* socket to web/ftp server                     */
-       FILE *dfp = NULL;                       /* socket to ftp server (data)          */
-       char *fname_out = NULL;         /* where to direct output (-O)          */
-       int do_continue = 0;            /* continue a prev transfer (-c)        */
-       long beg_range = 0L;            /*   range at which continue begins     */
-       int got_clen = 0;                       /* got content-length: from server      */
-       FILE *output;                           /* socket to web server                         */
-       int quiet_flag = FALSE;         /* Be verry, verry quiet...                     */
-
-#define LONG_HEADER    1
-       struct option long_options[] = {
-               { "continue",           0, NULL, 'c' },
-               { "quiet",              0, NULL, 'q' },
-               { "output-document",    1, NULL, 'O' },
-               { "header",             1, &which_long_opt, LONG_HEADER },
-               { 0,                    0, 0, 0 }
-       };
-       /*
-        * Crack command line.
-        */
-       while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) {
-               switch (n) {
-               case 'c':
-                       ++do_continue;
-                       break;
-               case 'P':
-                       dir_prefix = optarg;
-                       break;
-               case 'q':
-                       quiet_flag = TRUE;
-                       break;
-               case 'O':
-                       /* can't set fname_out to NULL if outputting to stdout, because
-                        * this gets interpreted as the auto-gen output filename
-                        * case below  - tausq@debian.org
-                        */
-                       fname_out = optarg;
-                       break;
-               case 0:
-                       switch (which_long_opt) {
-                               case LONG_HEADER: {
-                                       int arglen = strlen(optarg);
-                                       if(extra_headers_left - arglen - 2 <= 0)
-                                               error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
-                                       strcpy(extra_headers_ptr, optarg);
-                                       extra_headers_ptr += arglen;
-                                       extra_headers_left -= ( arglen + 2 );
-                                       *extra_headers_ptr++ = '\r';
-                                       *extra_headers_ptr++ = '\n';
-                                       *(extra_headers_ptr + 1) = 0;
-                                       break;
-                               }
-                       }
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if (argc - optind != 1)
-                       show_usage();
-
-       parse_url(argv[optind], &target);
-       server.host = target.host;
-       server.port = target.port;
-
-       /*
-        * Use the proxy if necessary.
-        */
-       proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
-       if (proxy)
-               parse_url(xstrdup(proxy), &server);
-       
-       /* Guess an output filename */
-       if (!fname_out) {
-               fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
-                       curfile = 
-#endif
-                       get_last_path_component(target.path);
-               if (fname_out==NULL || strlen(fname_out)<1) {
-                       fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
-                               curfile = 
-#endif
-                               "index.html";
-               }
-               if (dir_prefix != NULL)
-                       fname_out = concat_path_file(dir_prefix, fname_out);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       } else {
-               curfile = get_last_path_component(fname_out);
-#endif
-       }
-       if (do_continue && !fname_out)
-               error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
-
-
-       /*
-        * Open the output file stream.
-        */
-       if (strcmp(fname_out, "-") == 0) {
-               output = stdout;
-               quiet_flag = TRUE;
-       } else {
-               output = xfopen(fname_out, (do_continue ? "a" : "w"));
-       }
-
-       /*
-        * Determine where to start transfer.
-        */
-       if (do_continue) {
-               if (fstat(fileno(output), &sbuf) < 0)
-                       perror_msg_and_die("fstat()");
-               if (sbuf.st_size > 0)
-                       beg_range = sbuf.st_size;
-               else
-                       do_continue = 0;
-       }
-
-       if (proxy || !target.is_ftp) {
-               /*
-                *  HTTP session
-                */
-               do {
-                       if (! --try)
-                               close_delete_and_die("too many redirections");
-
-                       /*
-                        * Open socket to http server
-                        */
-                       if (sfp) fclose(sfp);
-                       sfp = open_socket(server.host, server.port);
-                       
-                       /*
-                        * Send HTTP request.
-                        */
-                       if (proxy) {
-                               fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n",
-                                       target.is_ftp ? "f" : "ht", target.host,
-                                       target.port, target.path);
-                       } else {
-                               fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
-                       }
-
-                       fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
-
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
-                       if (target.user) {
-                               fprintf(sfp, "Authorization: Basic %s\r\n",
-                                       base64enc(target.user, buf, sizeof(buf)));
-                       }
-                       if (proxy && server.user) {
-                               fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
-                                       base64enc(server.user, buf, sizeof(buf)));
-                       }
-#endif
-
-                       if (do_continue)
-                               fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
-                       if(extra_headers_left < sizeof(extra_headers))
-                               fputs(extra_headers,sfp);
-                       fprintf(sfp,"Connection: close\r\n\r\n");
-
-                       /*
-                       * Retrieve HTTP response line and check for "200" status code.
-                       */
-read_response:         if (fgets(buf, sizeof(buf), sfp) == NULL)
-                               close_delete_and_die("no response from server");
-                               
-                       for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
-                       ;
-                       for ( ; isspace(*s) ; ++s)
-                       ;
-                       switch (status = atoi(s)) {
-                               case 0:
-                               case 100:
-                                       while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
-                                       goto read_response;
-                               case 200:
-                                       if (do_continue && output != stdout)
-                                               output = freopen(fname_out, "w", output);
-                                       do_continue = 0;
-                                       break;
-                               case 300:       /* redirection */
-                               case 301:
-                               case 302:
-                               case 303:
-                                       break;
-                               case 206:
-                                       if (do_continue)
-                                               break;
-                                       /*FALLTHRU*/
-                               default:
-                                       chomp(buf);
-                                       close_delete_and_die("server returned error %d: %s", atoi(s), buf);
-                       }
-               
-                       /*
-                        * Retrieve HTTP headers.
-                        */
-                       while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
-                               if (strcasecmp(buf, "content-length") == 0) {
-                                       filesize = atol(s);
-                                       got_clen = 1;
-                                       continue;
-                               }
-                               if (strcasecmp(buf, "transfer-encoding") == 0) {
-                                       if (strcasecmp(s, "chunked") == 0) {
-                                               chunked = got_clen = 1;
-                                       } else {
-                                       close_delete_and_die("server wants to do %s transfer encoding", s);
-                                       }
-                               }
-                               if (strcasecmp(buf, "location") == 0) {
-                                       if (s[0] == '/')
-                                               target.path = xstrdup(s+1);
-                                       else {
-                                               parse_url(xstrdup(s), &target);
-                                               if (!proxy) {
-                                                       server.host = target.host;
-                                                       server.port = target.port;
-                                               }
-                                       }
-                               }
-                       }
-               } while(status >= 300);
-               
-               dfp = sfp;
-       }
-       else
-       {
-               /*
-                *  FTP session
-                */
-               if (! target.user)
-                       target.user = xstrdup("anonymous:busybox@");
-
-               sfp = open_socket(server.host, server.port);
-               if (ftpcmd(NULL, NULL, sfp, buf) != 220)
-                       close_delete_and_die("%s", buf+4);
-
-               /* 
-                * Splitting username:password pair,
-                * trying to log in
-                */
-               s = strchr(target.user, ':');
-               if (s)
-                       *(s++) = '\0';
-               switch(ftpcmd("USER ", target.user, sfp, buf)) {
-                       case 230:
-                               break;
-                       case 331:
-                               if (ftpcmd("PASS ", s, sfp, buf) == 230)
-                                       break;
-                               /* FALLTHRU (failed login) */
-                       default:
-                               close_delete_and_die("ftp login: %s", buf+4);
-               }
-               
-               ftpcmd("CDUP", NULL, sfp, buf);
-               ftpcmd("TYPE I", NULL, sfp, buf);
-               
-               /*
-                * Querying file size
-                */
-               if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) {
-                       filesize = atol(buf+4);
-                       got_clen = 1;
-               }
-               
-               /*
-                * Entering passive mode
-                */
-               if (ftpcmd("PASV", NULL, sfp, buf) !=  227)
-                       close_delete_and_die("PASV: %s", buf+4);
-               s = strrchr(buf, ',');
-               *s = 0;
-               port = atoi(s+1);
-               s = strrchr(buf, ',');
-               port += atoi(s+1) * 256;
-               dfp = open_socket(server.host, port);
-
-               if (do_continue) {
-                       sprintf(buf, "REST %ld", beg_range);
-                       if (ftpcmd(buf, NULL, sfp, buf) != 350) {
-                               if (output != stdout)
-                                       output = freopen(fname_out, "w", output);
-                               do_continue = 0;
-                       } else
-                               filesize -= beg_range;
-               }
-               
-               if (ftpcmd("RETR /", target.path, sfp, buf) > 150)
-                       close_delete_and_die("RETR: %s", buf+4);
-
-       }
-
-
-       /*
-        * Retrieve file
-        */
-       if (chunked) {
-               fgets(buf, sizeof(buf), dfp);
-               filesize = strtol(buf, (char **) NULL, 16);
-       }
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       if (quiet_flag==FALSE)
-               progressmeter(-1);
-#endif
-       do {
-               while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
-               safe_fwrite(buf, 1, n, output);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-               statbytes+=n;
-#endif
-               if (got_clen)
-                       filesize -= n;
-       }
-
-               if (chunked) {
-                       safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
-                       safe_fgets(buf, sizeof(buf), dfp);
-                       filesize = strtol(buf, (char **) NULL, 16);
-                       if (filesize==0) chunked = 0; /* all done! */
-               }
-
-       if (n == 0 && ferror(dfp))
-               perror_msg_and_die("network read error");
-       } while (chunked);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       if (quiet_flag==FALSE)
-               progressmeter(1);
-#endif
-       if (!proxy && target.is_ftp) {
-               fclose(dfp);
-               if (ftpcmd(NULL, NULL, sfp, buf) != 226)
-                       error_msg_and_die("ftp error: %s", buf+4);
-               ftpcmd("QUIT", NULL, sfp, buf);
-       }
-       exit(EXIT_SUCCESS);
-}
-
-
-void parse_url(char *url, struct host_info *h)
-{
-       char *cp, *sp, *up;
-
-       if (strncmp(url, "http://", 7) == 0) {
-               h->port = 80;
-               h->host = url + 7;
-               h->is_ftp = 0;
-       } else if (strncmp(url, "ftp://", 6) == 0) {
-               h->port = 21;
-               h->host = url + 6;
-               h->is_ftp = 1;
-       } else
-               error_msg_and_die("not an http or ftp url: %s", url);
-
-       sp = strchr(h->host, '/');
-       if (sp != NULL) {
-               *sp++ = '\0';
-               h->path = sp;
-       } else
-               h->path = "";
-
-       up = strrchr(h->host, '@');
-       if (up != NULL) {
-               h->user = h->host;
-               *up++ = '\0';
-               h->host = up;
-       } else
-               h->user = NULL;
-
-       cp = strchr(h->host, ':');
-       if (cp != NULL) {
-               *cp++ = '\0';
-               h->port = atoi(cp);
-       }
-
-}
-
-
-FILE *open_socket(char *host, int port)
-{
-       struct sockaddr_in s_in;
-       struct hostent *hp;
-       int fd;
-       FILE *fp;
-
-       memset(&s_in, 0, sizeof(s_in));
-       s_in.sin_family = AF_INET;
-       hp = xgethostbyname(host);
-       memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length);
-       s_in.sin_port = htons(port);
-
-       /*
-        * Get the server onto a stdio stream.
-        */
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die("socket()");
-       if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0)
-               perror_msg_and_die("connect(%s)", host);
-       if ((fp = fdopen(fd, "r+")) == NULL)
-               perror_msg_and_die("fdopen()");
-
-       return fp;
-}
-
-
-char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
-{
-       char *s, *hdrval;
-       int c;
-
-       *istrunc = 0;
-
-       /* retrieve header line */
-       if (fgets(buf, bufsiz, fp) == NULL)
-               return NULL;
-
-       /* see if we are at the end of the headers */
-       for (s = buf ; *s == '\r' ; ++s)
-               ;
-       if (s[0] == '\n')
-               return NULL;
-
-       /* convert the header name to lower case */
-       for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
-               *s = tolower(*s);
-
-       /* verify we are at the end of the header name */
-       if (*s != ':')
-               error_msg_and_die("bad header line: %s", buf);
-
-       /* locate the start of the header value */
-       for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
-               ;
-       hdrval = s;
-
-       /* locate the end of header */
-       while (*s != '\0' && *s != '\r' && *s != '\n')
-               ++s;
-
-       /* end of header found */
-       if (*s != '\0') {
-               *s = '\0';
-               return hdrval;
-       }
-
-       /* Rats!  The buffer isn't big enough to hold the entire header value. */
-       while (c = getc(fp), c != EOF && c != '\n')
-               ;
-       *istrunc = 1;
-       return hdrval;
-}
-
-static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
-{
-       char *p;
-       
-       if (s1) {
-               if (!s2) s2="";
-               fprintf(fp, "%s%s\n", s1, s2);
-               fflush(fp);
-       }
-       
-       do {
-               p = fgets(buf, 510, fp);
-               if (!p)
-                       perror_msg_and_die("fgets()");
-       } while (! isdigit(buf[0]) || buf[3] != ' ');
-       
-       return atoi(buf);
-}
-
-#ifdef BB_FEATURE_WGET_STATUSBAR
-/* Stuff below is from BSD rcp util.c, as added to openshh. 
- * Original copyright notice is retained at the end of this file.
- * 
- */ 
-
-
-static int
-getttywidth(void)
-{
-       struct winsize winsize;
-
-       if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
-               return (winsize.ws_col ? winsize.ws_col : 80);
-       else
-               return (80);
-}
-
-static void
-updateprogressmeter(int ignore)
-{
-       int save_errno = errno;
-
-       progressmeter(0);
-       errno = save_errno;
-}
-
-static void
-alarmtimer(int wait)
-{
-       struct itimerval itv;
-
-       itv.it_value.tv_sec = wait;
-       itv.it_value.tv_usec = 0;
-       itv.it_interval = itv.it_value;
-       setitimer(ITIMER_REAL, &itv, NULL);
-}
-
-
-static void
-progressmeter(int flag)
-{
-       static const char prefixes[] = " KMGTP";
-       static struct timeval lastupdate;
-       static off_t lastsize, totalsize;
-       struct timeval now, td, wait;
-       off_t cursize, abbrevsize;
-       double elapsed;
-       int ratio, barlength, i, remaining;
-       char buf[256];
-
-       if (flag == -1) {
-               (void) gettimeofday(&start, (struct timezone *) 0);
-               lastupdate = start;
-               lastsize = 0;
-               totalsize = filesize; /* as filesize changes.. */
-       }
-
-       (void) gettimeofday(&now, (struct timezone *) 0);
-       cursize = statbytes;
-       if (totalsize != 0 && !chunked) {
-               ratio = 100.0 * cursize / totalsize;
-               ratio = MAX(ratio, 0);
-               ratio = MIN(ratio, 100);
-       } else
-               ratio = 100;
-
-       snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
-
-       barlength = getttywidth() - 51;
-       if (barlength > 0) {
-               i = barlength * ratio / 100;
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "|%.*s%*s|", i,
-                        "*****************************************************************************"
-                        "*****************************************************************************",
-                        barlength - i, "");
-       }
-       i = 0;
-       abbrevsize = cursize;
-       while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
-               i++;
-               abbrevsize >>= 10;
-       }
-       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ",
-            (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
-                'B');
-
-       timersub(&now, &lastupdate, &wait);
-       if (cursize > lastsize) {
-               lastupdate = now;
-               lastsize = cursize;
-               if (wait.tv_sec >= STALLTIME) {
-                       start.tv_sec += wait.tv_sec;
-                       start.tv_usec += wait.tv_usec;
-               }
-               wait.tv_sec = 0;
-       }
-       timersub(&now, &start, &td);
-       elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
-
-       if (wait.tv_sec >= STALLTIME) {
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        " - stalled -");
-       } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) {
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "   --:-- ETA");
-       } else {
-               remaining = (int) (totalsize / (statbytes / elapsed) - elapsed);
-               i = remaining / 3600;
-               if (i)
-                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                "%2d:", i);
-               else
-                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                "   ");
-               i = remaining % 3600;
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "%02d:%02d ETA", i / 60, i % 60);
-       }
-       write(fileno(stderr), buf, strlen(buf));
-
-       if (flag == -1) {
-               struct sigaction sa;
-               sa.sa_handler = updateprogressmeter;
-               sigemptyset(&sa.sa_mask);
-               sa.sa_flags = SA_RESTART;
-               sigaction(SIGALRM, &sa, NULL);
-               alarmtimer(1);
-       } else if (flag == 1) {
-               alarmtimer(0);
-               statbytes = 0;
-               putc('\n', stderr);
-       }
-}
-#endif
-
-/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff,
- * much of which was blatently stolen from openssh.  */
-/*-
- * Copyright (c) 1992, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- *
- *     $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $
- */
-
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
-
-
diff --git a/busybox/nfsmount.c b/busybox/nfsmount.c
deleted file mode 100644 (file)
index cd722ac..0000000
+++ /dev/null
@@ -1,977 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * nfsmount.c -- Linux NFS mount
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
- * numbers to be specified on the command line.
- *
- * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
- * Omit the call to connect() for Linux version 1.3.11 or later.
- *
- * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
- * Implemented the "bg", "fg" and "retry" mount options for NFS.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- * 
- * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
- * plus NFSv3 stuff.
- */
-
-/*
- * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <sys/utsname.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include "busybox.h"
-#undef TRUE
-#undef FALSE
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
-#include <linux/nfs.h>  /* For the kernels nfs stuff */
-#include "nfsmount.h"
-
-#ifndef NFS_FHSIZE
-static const int NFS_FHSIZE = 32;
-#endif
-#ifndef NFS_PORT
-static const int NFS_PORT = 2049;
-#endif
-
-/* Disable the nls stuff */
-# undef bindtextdomain
-# define bindtextdomain(Domain, Directory) /* empty */
-# undef textdomain
-# define textdomain(Domain) /* empty */
-# define _(Text) (Text)
-# define N_(Text) (Text)
-
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_RDONLY = 1;      /* Mount read-only */
-static const int MS_NOSUID = 2;      /* Ignore suid and sgid bits */
-static const int MS_NODEV = 4;      /* Disallow access to device special files */
-static const int MS_NOEXEC = 8;      /* Disallow program execution */
-static const int MS_SYNCHRONOUS = 16;      /* Writes are synced at once */
-static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS */
-static const int MS_MANDLOCK = 64;      /* Allow mandatory locks on an FS */
-static const int S_QUOTA = 128;     /* Quota initialized for file/directory/symlink */
-static const int S_APPEND = 256;     /* Append-only file */
-static const int S_IMMUTABLE = 512;     /* Immutable file */
-static const int MS_NOATIME = 1024;    /* Do not update access times. */
-static const int MS_NODIRATIME = 2048;    /* Do not update directory access times */
-
-
-/*
- * We want to be able to compile mount on old kernels in such a way
- * that the binary will work well on more recent kernels.
- * Thus, if necessary we teach nfsmount.c the structure of new fields
- * that will come later.
- *
- * Moreover, the new kernel includes conflict with glibc includes
- * so it is easiest to ignore the kernel altogether (at compile time).
- */
-
-/* NOTE: Do not make this into a 'static const int' because the pre-processor
- * needs to test this value in some #if statements. */
-#define NFS_MOUNT_VERSION 4
-
-struct nfs2_fh {
-        char                    data[32];
-};
-struct nfs3_fh {
-        unsigned short          size;
-        unsigned char           data[64];
-};
-
-struct nfs_mount_data {
-       int             version;                /* 1 */
-       int             fd;                     /* 1 */
-       struct nfs2_fh  old_root;               /* 1 */
-       int             flags;                  /* 1 */
-       int             rsize;                  /* 1 */
-       int             wsize;                  /* 1 */
-       int             timeo;                  /* 1 */
-       int             retrans;                /* 1 */
-       int             acregmin;               /* 1 */
-       int             acregmax;               /* 1 */
-       int             acdirmin;               /* 1 */
-       int             acdirmax;               /* 1 */
-       struct sockaddr_in addr;                /* 1 */
-       char            hostname[256];          /* 1 */
-       int             namlen;                 /* 2 */
-       unsigned int    bsize;                  /* 3 */
-       struct nfs3_fh  root;                   /* 4 */
-};
-
-/* bits in the flags field */
-
-static const int NFS_MOUNT_SOFT = 0x0001;      /* 1 */
-static const int NFS_MOUNT_INTR = 0x0002;      /* 1 */
-static const int NFS_MOUNT_SECURE = 0x0004;    /* 1 */
-static const int NFS_MOUNT_POSIX = 0x0008;     /* 1 */
-static const int NFS_MOUNT_NOCTO = 0x0010;     /* 1 */
-static const int NFS_MOUNT_NOAC = 0x0020;      /* 1 */
-static const int NFS_MOUNT_TCP = 0x0040;       /* 2 */
-static const int NFS_MOUNT_VER3 = 0x0080;      /* 3 */
-static const int NFS_MOUNT_KERBEROS = 0x0100;  /* 3 */
-static const int NFS_MOUNT_NONLM = 0x0200;     /* 3 */
-
-
-#define UTIL_LINUX_VERSION "2.10m"
-#define util_linux_version "util-linux-2.10m"
-
-#define HAVE_inet_aton
-#define HAVE_scsi_h
-#define HAVE_blkpg_h
-#define HAVE_kd_h
-#define HAVE_termcap
-#define HAVE_locale_h
-#define HAVE_libintl_h
-#define ENABLE_NLS
-#define HAVE_langinfo_h
-#define HAVE_progname
-#define HAVE_openpty
-#define HAVE_nanosleep
-#define HAVE_personality
-#define HAVE_tm_gmtoff
-
-static char *nfs_strerror(int status);
-
-#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
-#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
-
-static const int EX_FAIL = 32;       /* mount failure */
-static const int EX_BG = 256;       /* retry in background (internal only) */
-
-
-/*
- * nfs_mount_version according to the sources seen at compile time.
- */
-static int nfs_mount_version;
-
-/*
- * Unfortunately, the kernel prints annoying console messages
- * in case of an unexpected nfs mount version (instead of
- * just returning some error).  Therefore we'll have to try
- * and figure out what version the kernel expects.
- *
- * Variables:
- *     KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
- *     NFS_MOUNT_VERSION: these nfsmount sources at compile time
- *     nfs_mount_version: version this source and running kernel can handle
- */
-static void
-find_kernel_nfs_mount_version(void)
-{
-       static int kernel_version = 0;
-
-       if (kernel_version)
-               return;
-
-       nfs_mount_version = NFS_MOUNT_VERSION; /* default */
-
-       kernel_version = get_kernel_revision();
-       if (kernel_version) {
-               if (kernel_version < MAKE_VERSION(2,1,32))
-                       nfs_mount_version = 1;
-               else if (kernel_version < MAKE_VERSION(2,2,18) ||
-                               (kernel_version >=   MAKE_VERSION(2,3,0) &&
-                                kernel_version < MAKE_VERSION(2,3,99)))
-                       nfs_mount_version = 3;
-               else
-                       nfs_mount_version = 4; /* since 2.3.99pre4 */
-       }
-       if (nfs_mount_version > NFS_MOUNT_VERSION)
-               nfs_mount_version = NFS_MOUNT_VERSION;
-}
-
-static struct pmap *
-get_mountport(struct sockaddr_in *server_addr,
-      long unsigned prog,
-      long unsigned version,
-      long unsigned proto,
-      long unsigned port)
-{
-struct pmaplist *pmap;
-static struct pmap p = {0, 0, 0, 0};
-
-server_addr->sin_port = PMAPPORT;
-pmap = pmap_getmaps(server_addr);
-
-if (version > MAX_NFSPROT)
-       version = MAX_NFSPROT;
-if (!prog)
-       prog = MOUNTPROG;
-p.pm_prog = prog;
-p.pm_vers = version;
-p.pm_prot = proto;
-p.pm_port = port;
-
-while (pmap) {
-       if (pmap->pml_map.pm_prog != prog)
-               goto next;
-       if (!version && p.pm_vers > pmap->pml_map.pm_vers)
-               goto next;
-       if (version > 2 && pmap->pml_map.pm_vers != version)
-               goto next;
-       if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
-               goto next;
-       if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
-           (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
-           (port && pmap->pml_map.pm_port != port))
-               goto next;
-       memcpy(&p, &pmap->pml_map, sizeof(p));
-next:
-       pmap = pmap->pml_next;
-}
-if (!p.pm_vers)
-       p.pm_vers = MOUNTVERS;
-if (!p.pm_port)
-       p.pm_port = MOUNTPORT;
-if (!p.pm_prot)
-       p.pm_prot = IPPROTO_TCP;
-return &p;
-}
-
-int nfsmount(const char *spec, const char *node, int *flags,
-            char **extra_opts, char **mount_opts, int running_bg)
-{
-       static char *prev_bg_host;
-       char hostdir[1024];
-       CLIENT *mclient;
-       char *hostname;
-       char *pathname;
-       char *old_opts;
-       char *mounthost=NULL;
-       char new_opts[1024];
-       struct timeval total_timeout;
-       enum clnt_stat clnt_stat;
-       static struct nfs_mount_data data;
-       char *opt, *opteq;
-       int val;
-       struct hostent *hp;
-       struct sockaddr_in server_addr;
-       struct sockaddr_in mount_server_addr;
-       struct pmap* pm_mnt;
-       int msock, fsock;
-       struct timeval retry_timeout;
-       union {
-               struct fhstatus nfsv2;
-               struct mountres3 nfsv3;
-       } status;
-       struct stat statbuf;
-       char *s;
-       int port;
-       int mountport;
-       int proto;
-       int bg;
-       int soft;
-       int intr;
-       int posix;
-       int nocto;
-       int noac;
-       int nolock;
-       int retry;
-       int tcp;
-       int mountprog;
-       int mountvers;
-       int nfsprog;
-       int nfsvers;
-       int retval;
-       time_t t;
-       time_t prevt;
-       time_t timeout;
-
-       find_kernel_nfs_mount_version();
-
-       retval = EX_FAIL;
-       msock = fsock = -1;
-       mclient = NULL;
-       if (strlen(spec) >= sizeof(hostdir)) {
-               error_msg("excessively long host:dir argument");
-               goto fail;
-       }
-       strcpy(hostdir, spec);
-       if ((s = strchr(hostdir, ':'))) {
-               hostname = hostdir;
-               pathname = s + 1;
-               *s = '\0';
-               /* Ignore all but first hostname in replicated mounts
-                  until they can be fully supported. (mack@sgi.com) */
-               if ((s = strchr(hostdir, ','))) {
-                       *s = '\0';
-                       error_msg("warning: multiple hostnames not supported");
-               }
-       } else {
-               error_msg("directory to mount not in host:dir format");
-               goto fail;
-       }
-
-       server_addr.sin_family = AF_INET;
-#ifdef HAVE_inet_aton
-       if (!inet_aton(hostname, &server_addr.sin_addr))
-#endif
-       {
-               if ((hp = gethostbyname(hostname)) == NULL) {
-                       herror_msg("%s", hostname);
-                       goto fail;
-               } else {
-                       if (hp->h_length > sizeof(struct in_addr)) {
-                               error_msg("got bad hp->h_length");
-                               hp->h_length = sizeof(struct in_addr);
-                       }
-                       memcpy(&server_addr.sin_addr,
-                              hp->h_addr, hp->h_length);
-               }
-       }
-
-       memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
-
-       /* add IP address to mtab options for use when unmounting */
-
-       s = inet_ntoa(server_addr.sin_addr);
-       old_opts = *extra_opts;
-       if (!old_opts)
-               old_opts = "";
-       if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
-               error_msg("excessively long option argument");
-               goto fail;
-       }
-       sprintf(new_opts, "%s%saddr=%s",
-               old_opts, *old_opts ? "," : "", s);
-       *extra_opts = xstrdup(new_opts);
-
-       /* Set default options.
-        * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
-        * let the kernel decide.
-        * timeo is filled in after we know whether it'll be TCP or UDP. */
-       memset(&data, 0, sizeof(data));
-       data.retrans    = 3;
-       data.acregmin   = 3;
-       data.acregmax   = 60;
-       data.acdirmin   = 30;
-       data.acdirmax   = 60;
-#if NFS_MOUNT_VERSION >= 2
-       data.namlen     = NAME_MAX;
-#endif
-
-       bg = 0;
-       soft = 0;
-       intr = 0;
-       posix = 0;
-       nocto = 0;
-       nolock = 0;
-       noac = 0;
-       retry = 10000;          /* 10000 minutes ~ 1 week */
-       tcp = 0;
-
-       mountprog = MOUNTPROG;
-       mountvers = 0;
-       port = 0;
-       mountport = 0;
-       nfsprog = NFS_PROGRAM;
-       nfsvers = 0;
-
-       /* parse options */
-
-       for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
-               if ((opteq = strchr(opt, '='))) {
-                       val = atoi(opteq + 1);  
-                       *opteq = '\0';
-                       if (!strcmp(opt, "rsize"))
-                               data.rsize = val;
-                       else if (!strcmp(opt, "wsize"))
-                               data.wsize = val;
-                       else if (!strcmp(opt, "timeo"))
-                               data.timeo = val;
-                       else if (!strcmp(opt, "retrans"))
-                               data.retrans = val;
-                       else if (!strcmp(opt, "acregmin"))
-                               data.acregmin = val;
-                       else if (!strcmp(opt, "acregmax"))
-                               data.acregmax = val;
-                       else if (!strcmp(opt, "acdirmin"))
-                               data.acdirmin = val;
-                       else if (!strcmp(opt, "acdirmax"))
-                               data.acdirmax = val;
-                       else if (!strcmp(opt, "actimeo")) {
-                               data.acregmin = val;
-                               data.acregmax = val;
-                               data.acdirmin = val;
-                               data.acdirmax = val;
-                       }
-                       else if (!strcmp(opt, "retry"))
-                               retry = val;
-                       else if (!strcmp(opt, "port"))
-                               port = val;
-                       else if (!strcmp(opt, "mountport"))
-                               mountport = val;
-                       else if (!strcmp(opt, "mounthost"))
-                               mounthost=xstrndup(opteq+1,
-                                                 strcspn(opteq+1," \t\n\r,"));
-                       else if (!strcmp(opt, "mountprog"))
-                               mountprog = val;
-                       else if (!strcmp(opt, "mountvers"))
-                               mountvers = val;
-                       else if (!strcmp(opt, "nfsprog"))
-                               nfsprog = val;
-                       else if (!strcmp(opt, "nfsvers") ||
-                                !strcmp(opt, "vers"))
-                               nfsvers = val;
-                       else if (!strcmp(opt, "proto")) {
-                               if (!strncmp(opteq+1, "tcp", 3))
-                                       tcp = 1;
-                               else if (!strncmp(opteq+1, "udp", 3))
-                                       tcp = 0;
-                               else
-                                       printf(_("Warning: Unrecognized proto= option.\n"));
-                       } else if (!strcmp(opt, "namlen")) {
-#if NFS_MOUNT_VERSION >= 2
-                               if (nfs_mount_version >= 2)
-                                       data.namlen = val;
-                               else
-#endif
-                               printf(_("Warning: Option namlen is not supported.\n"));
-                       } else if (!strcmp(opt, "addr"))
-                               /* ignore */;
-                       else {
-                               printf(_("unknown nfs mount parameter: "
-                                      "%s=%d\n"), opt, val);
-                               goto fail;
-                       }
-               }
-               else {
-                       val = 1;
-                       if (!strncmp(opt, "no", 2)) {
-                               val = 0;
-                               opt += 2;
-                       }
-                       if (!strcmp(opt, "bg")) 
-                               bg = val;
-                       else if (!strcmp(opt, "fg")) 
-                               bg = !val;
-                       else if (!strcmp(opt, "soft"))
-                               soft = val;
-                       else if (!strcmp(opt, "hard"))
-                               soft = !val;
-                       else if (!strcmp(opt, "intr"))
-                               intr = val;
-                       else if (!strcmp(opt, "posix"))
-                               posix = val;
-                       else if (!strcmp(opt, "cto"))
-                               nocto = !val;
-                       else if (!strcmp(opt, "ac"))
-                               noac = !val;
-                       else if (!strcmp(opt, "tcp"))
-                               tcp = val;
-                       else if (!strcmp(opt, "udp"))
-                               tcp = !val;
-                       else if (!strcmp(opt, "lock")) {
-                               if (nfs_mount_version >= 3)
-                                       nolock = !val;
-                               else
-                                       printf(_("Warning: option nolock is not supported.\n"));
-                       } else {
-                               printf(_("unknown nfs mount option: "
-                                          "%s%s\n"), val ? "" : "no", opt);
-                               goto fail;
-                       }
-               }
-       }
-       proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
-
-       data.flags = (soft ? NFS_MOUNT_SOFT : 0)
-               | (intr ? NFS_MOUNT_INTR : 0)
-               | (posix ? NFS_MOUNT_POSIX : 0)
-               | (nocto ? NFS_MOUNT_NOCTO : 0)
-               | (noac ? NFS_MOUNT_NOAC : 0);
-#if NFS_MOUNT_VERSION >= 2
-       if (nfs_mount_version >= 2)
-               data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
-#endif
-#if NFS_MOUNT_VERSION >= 3
-       if (nfs_mount_version >= 3)
-               data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
-#endif
-       if (nfsvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!", nfsvers);
-               return 0;
-       }
-       if (mountvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!", nfsvers);
-               return 0;
-       }
-       if (nfsvers && !mountvers)
-               mountvers = (nfsvers < 3) ? 1 : nfsvers;
-       if (nfsvers && nfsvers < mountvers) {
-               mountvers = nfsvers;
-       }
-
-       /* Adjust options if none specified */
-       if (!data.timeo)
-               data.timeo = tcp ? 70 : 7;
-
-#ifdef NFS_MOUNT_DEBUG
-       printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
-               data.rsize, data.wsize, data.timeo, data.retrans);
-       printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
-               data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
-       printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
-               port, bg, retry, data.flags);
-       printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
-               mountprog, mountvers, nfsprog, nfsvers);
-       printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
-               (data.flags & NFS_MOUNT_SOFT) != 0,
-               (data.flags & NFS_MOUNT_INTR) != 0,
-               (data.flags & NFS_MOUNT_POSIX) != 0,
-               (data.flags & NFS_MOUNT_NOCTO) != 0,
-               (data.flags & NFS_MOUNT_NOAC) != 0);
-#if NFS_MOUNT_VERSION >= 2
-       printf("tcp = %d\n",
-               (data.flags & NFS_MOUNT_TCP) != 0);
-#endif
-#endif
-
-       data.version = nfs_mount_version;
-       *mount_opts = (char *) &data;
-
-       if (*flags & MS_REMOUNT)
-               return 0;
-
-       /*
-        * If the previous mount operation on the same host was
-        * backgrounded, and the "bg" for this mount is also set,
-        * give up immediately, to avoid the initial timeout.
-        */
-       if (bg && !running_bg &&
-           prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
-               if (retry > 0)
-                       retval = EX_BG;
-               return retval;
-       }
-
-       /* create mount deamon client */
-       /* See if the nfs host = mount host. */
-       if (mounthost) {
-         if (mounthost[0] >= '0' && mounthost[0] <= '9') {
-           mount_server_addr.sin_family = AF_INET;
-           mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
-         } else {
-                 if ((hp = gethostbyname(mounthost)) == NULL) {
-                         herror_msg("%s", mounthost);
-                         goto fail;
-                 } else {
-                         if (hp->h_length > sizeof(struct in_addr)) {
-                                 error_msg("got bad hp->h_length?");
-                                 hp->h_length = sizeof(struct in_addr);
-                         }
-                         mount_server_addr.sin_family = AF_INET;
-                         memcpy(&mount_server_addr.sin_addr,
-                                hp->h_addr, hp->h_length);
-                 }
-         }
-       }
-
-       /*
-        * The following loop implements the mount retries. On the first
-        * call, "running_bg" is 0. When the mount times out, and the
-        * "bg" option is set, the exit status EX_BG will be returned.
-        * For a backgrounded mount, there will be a second call by the
-        * child process with "running_bg" set to 1.
-        *
-        * The case where the mount point is not present and the "bg"
-        * option is set, is treated as a timeout. This is done to
-        * support nested mounts.
-        *
-        * The "retry" count specified by the user is the number of
-        * minutes to retry before giving up.
-        *
-        * Only the first error message will be displayed.
-        */
-       retry_timeout.tv_sec = 3;
-       retry_timeout.tv_usec = 0;
-       total_timeout.tv_sec = 20;
-       total_timeout.tv_usec = 0;
-       timeout = time(NULL) + 60 * retry;
-       prevt = 0;
-       t = 30;
-       val = 1;
-       for (;;) {
-               if (bg && stat(node, &statbuf) == -1) {
-                       if (running_bg) {
-                               sleep(val);     /* 1, 2, 4, 8, 16, 30, ... */
-                               val *= 2;
-                               if (val > 30)
-                                       val = 30;
-                       }
-               } else {
-                       /* be careful not to use too many CPU cycles */
-                       if (t - prevt < 30)
-                               sleep(30);
-
-                       pm_mnt = get_mountport(&mount_server_addr,
-                                      mountprog,
-                                      mountvers,
-                                      proto,
-                                      mountport);
-
-                       /* contact the mount daemon via TCP */
-                       mount_server_addr.sin_port = htons(pm_mnt->pm_port);
-                       msock = RPC_ANYSOCK;
-
-                       switch (pm_mnt->pm_prot) {
-                       case IPPROTO_UDP:
-                               mclient = clntudp_create(&mount_server_addr,
-                                                pm_mnt->pm_prog,
-                                                pm_mnt->pm_vers,
-                                                retry_timeout,
-                                                &msock);
-                 if (mclient)
-                         break;
-                 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
-                 msock = RPC_ANYSOCK;
-               case IPPROTO_TCP:
-                       mclient = clnttcp_create(&mount_server_addr,
-                                                pm_mnt->pm_prog,
-                                                pm_mnt->pm_vers,
-                                                &msock, 0, 0);
-                       break;
-               default:
-                       mclient = 0;
-                       }
-                       if (mclient) {
-                               /* try to mount hostname:pathname */
-                               mclient->cl_auth = authunix_create_default();
-
-                       /* make pointers in xdr_mountres3 NULL so
-                        * that xdr_array allocates memory for us
-                        */
-                       memset(&status, 0, sizeof(status));
-
-                       if (pm_mnt->pm_vers == 3)
-                               clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
-                                                     (xdrproc_t) xdr_dirpath,
-                                                     (caddr_t) &pathname,
-                                                     (xdrproc_t) xdr_mountres3,
-                                                     (caddr_t) &status,
-                                       total_timeout);
-                       else
-                               clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
-                                                     (xdrproc_t) xdr_dirpath,
-                                                     (caddr_t) &pathname,
-                                                     (xdrproc_t) xdr_fhstatus,
-                                                     (caddr_t) &status,
-                                                     total_timeout);
-
-                               if (clnt_stat == RPC_SUCCESS)
-                                       break;          /* we're done */
-                               if (errno != ECONNREFUSED) {
-                                       clnt_perror(mclient, "mount");
-                                       goto fail;      /* don't retry */
-                               }
-                               if (!running_bg && prevt == 0)
-                                       clnt_perror(mclient, "mount");
-                               auth_destroy(mclient->cl_auth);
-                               clnt_destroy(mclient);
-                               mclient = 0;
-                               close(msock);
-                       } else {
-                               if (!running_bg && prevt == 0)
-                                       clnt_pcreateerror("mount");
-                       }
-                       prevt = t;
-               }
-               if (!bg)
-                       goto fail;
-               if (!running_bg) {
-                       prev_bg_host = xstrdup(hostname);
-                       if (retry > 0)
-                               retval = EX_BG;
-                       goto fail;
-               }
-               t = time(NULL);
-               if (t >= timeout)
-                       goto fail;
-       }
-       nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
-
-       if (nfsvers == 2) {
-               if (status.nfsv2.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s",
-                               hostname, pathname,
-                               nfs_strerror(status.nfsv2.fhs_status));
-                       goto fail;
-               }
-               memcpy(data.root.data,
-                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
-                      NFS_FHSIZE);
-#if NFS_MOUNT_VERSION >= 4
-               data.root.size = NFS_FHSIZE;
-               memcpy(data.old_root.data,
-                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
-                      NFS_FHSIZE);
-#endif
-       } else {
-#if NFS_MOUNT_VERSION >= 4
-               fhandle3 *my_fhandle;
-               if (status.nfsv3.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s",
-                               hostname, pathname,
-                               nfs_strerror(status.nfsv3.fhs_status));
-                       goto fail;
-               }
-               my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
-               memset(data.old_root.data, 0, NFS_FHSIZE);
-               memset(&data.root, 0, sizeof(data.root));
-               data.root.size = my_fhandle->fhandle3_len;
-               memcpy(data.root.data,
-                      (char *) my_fhandle->fhandle3_val,
-                      my_fhandle->fhandle3_len);
-
-               data.flags |= NFS_MOUNT_VER3;
-#endif
-       }
-
-       /* create nfs socket for kernel */
-
-       if (tcp) {
-               if (nfs_mount_version < 3) {
-                       printf(_("NFS over TCP is not supported.\n"));
-                       goto fail;
-               }
-               fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       } else
-               fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (fsock < 0) {
-               perror(_("nfs socket"));
-               goto fail;
-       }
-       if (bindresvport(fsock, 0) < 0) {
-               perror(_("nfs bindresvport"));
-               goto fail;
-       }
-       if (port == 0) {
-               server_addr.sin_port = PMAPPORT;
-               port = pmap_getport(&server_addr, nfsprog, nfsvers,
-                       tcp ? IPPROTO_TCP : IPPROTO_UDP);
-               if (port == 0)
-                       port = NFS_PORT;
-#ifdef NFS_MOUNT_DEBUG
-               else
-                       printf(_("used portmapper to find NFS port\n"));
-#endif
-       }
-#ifdef NFS_MOUNT_DEBUG
-       printf(_("using port %d for nfs deamon\n"), port);
-#endif
-       server_addr.sin_port = htons(port);
-        /*
-         * connect() the socket for kernels 1.3.10 and below only,
-         * to avoid problems with multihomed hosts.
-         * --Swen
-         */
-       if (get_kernel_revision() <= 66314
-           && connect(fsock, (struct sockaddr *) &server_addr,
-                      sizeof (server_addr)) < 0) {
-               perror(_("nfs connect"));
-               goto fail;
-       }
-
-       /* prepare data structure for kernel */
-
-       data.fd = fsock;
-       memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
-       strncpy(data.hostname, hostname, sizeof(data.hostname));
-
-       /* clean up */
-
-       auth_destroy(mclient->cl_auth);
-       clnt_destroy(mclient);
-       close(msock);
-       return 0;
-
-       /* abort */
-
-fail:
-       if (msock != -1) {
-               if (mclient) {
-                       auth_destroy(mclient->cl_auth);
-                       clnt_destroy(mclient);
-               }
-               close(msock);
-       }
-       if (fsock != -1)
-               close(fsock);
-       return retval;
-}      
-
-/*
- * We need to translate between nfs status return values and
- * the local errno values which may not be the same.
- *
- * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
- * "after #include <errno.h> the symbol errno is reserved for any use,
- *  it cannot even be used as a struct tag or field name".
- */
-
-#ifndef EDQUOT
-#define EDQUOT ENOSPC
-#endif
-
-static struct {
-       enum nfs_stat stat;
-       int errnum;
-} nfs_errtbl[] = {
-       { NFS_OK,               0               },
-       { NFSERR_PERM,          EPERM           },
-       { NFSERR_NOENT,         ENOENT          },
-       { NFSERR_IO,            EIO             },
-       { NFSERR_NXIO,          ENXIO           },
-       { NFSERR_ACCES,         EACCES          },
-       { NFSERR_EXIST,         EEXIST          },
-       { NFSERR_NODEV,         ENODEV          },
-       { NFSERR_NOTDIR,        ENOTDIR         },
-       { NFSERR_ISDIR,         EISDIR          },
-#ifdef NFSERR_INVAL
-       { NFSERR_INVAL,         EINVAL          },      /* that Sun forgot */
-#endif
-       { NFSERR_FBIG,          EFBIG           },
-       { NFSERR_NOSPC,         ENOSPC          },
-       { NFSERR_ROFS,          EROFS           },
-       { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
-       { NFSERR_NOTEMPTY,      ENOTEMPTY       },
-       { NFSERR_DQUOT,         EDQUOT          },
-       { NFSERR_STALE,         ESTALE          },
-#ifdef EWFLUSH
-       { NFSERR_WFLUSH,        EWFLUSH         },
-#endif
-       /* Throw in some NFSv3 values for even more fun (HP returns these) */
-       { 71,                   EREMOTE         },
-
-       { -1,                   EIO             }
-};
-
-static char *nfs_strerror(int status)
-{
-       int i;
-       static char buf[256];
-
-       for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-               if (nfs_errtbl[i].stat == status)
-                       return strerror(nfs_errtbl[i].errnum);
-       }
-       sprintf(buf, _("unknown nfs status return value: %d"), status);
-       return buf;
-}
-
-static bool_t
-xdr_fhandle (XDR *xdrs, fhandle objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_opaque (xdrs, objp, FHSIZE))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_fhstatus (XDR *xdrs, fhstatus *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_u_int (xdrs, &objp->fhs_status))
-                return FALSE;
-       switch (objp->fhs_status) {
-       case 0:
-                if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
-                        return FALSE;
-               break;
-       default:
-               break;
-       }
-       return TRUE;
-}
-
-bool_t
-xdr_dirpath (XDR *xdrs, dirpath *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_string (xdrs, objp, MNTPATHLEN))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_fhandle3 (xdrs, &objp->fhandle))
-                return FALSE;
-        if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
-               sizeof (int), (xdrproc_t) xdr_int))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_enum (xdrs, (enum_t *) objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountres3 (XDR *xdrs, mountres3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
-                return FALSE;
-       switch (objp->fhs_status) {
-       case MNT_OK:
-                if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
-                        return FALSE;
-               break;
-       default:
-               break;
-       }
-       return TRUE;
-}
-
diff --git a/busybox/nfsmount.h b/busybox/nfsmount.h
deleted file mode 100644 (file)
index b3d5a51..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * This file was originally generated using rpcgen.
- * But now we edit it by hand as needed to make it
- * shut up...
- */
-
-#ifndef _NFSMOUNT_H_RPCGEN
-#define _NFSMOUNT_H_RPCGEN
-
-#include <rpc/rpc.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
- * unrestricted use provided that this legend is included on all tape
- * media and as a part of the software program in whole or part.  Users
- * may copy or modify Sun RPC without charge, but are not authorized
- * to license or distribute it to anyone else except as part of a product or
- * program developed by the user or with the express written consent of
- * Sun Microsystems, Inc.
- *
- * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
- * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * Sun RPC is provided with no support and without any obligation on the
- * part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
- *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
- * OR ANY PART THEREOF.
- *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
- *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California  94043
- */
-/*
- * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
- */
-
-/* from @(#)mount.x    1.3 91/03/11 TIRPC 1.0 */
-#ifndef _rpcsvc_mount_h
-#define _rpcsvc_mount_h
-#include <asm/types.h>
-#define MOUNTPORT 635
-#define MNTPATHLEN 1024
-#define MNTNAMLEN 255
-#define FHSIZE 32
-#define FHSIZE3 64
-
-typedef char fhandle[FHSIZE];
-
-typedef struct {
-       u_int fhandle3_len;
-       char *fhandle3_val;
-} fhandle3;
-
-enum mountstat3 {
-       MNT_OK = 0,
-       MNT3ERR_PERM = 1,
-       MNT3ERR_NOENT = 2,
-       MNT3ERR_IO = 5,
-       MNT3ERR_ACCES = 13,
-       MNT3ERR_NOTDIR = 20,
-       MNT3ERR_INVAL = 22,
-       MNT3ERR_NAMETOOLONG = 63,
-       MNT3ERR_NOTSUPP = 10004,
-       MNT3ERR_SERVERFAULT = 10006,
-};
-typedef enum mountstat3 mountstat3;
-
-struct fhstatus {
-       u_int fhs_status;
-       union {
-               fhandle fhs_fhandle;
-       } fhstatus_u;
-};
-typedef struct fhstatus fhstatus;
-
-struct mountres3_ok {
-       fhandle3 fhandle;
-       struct {
-               u_int auth_flavours_len;
-               int *auth_flavours_val;
-       } auth_flavours;
-};
-typedef struct mountres3_ok mountres3_ok;
-
-struct mountres3 {
-       mountstat3 fhs_status;
-       union {
-               mountres3_ok mountinfo;
-       } mountres3_u;
-};
-typedef struct mountres3 mountres3;
-
-typedef char *dirpath;
-
-typedef char *name;
-
-typedef struct mountbody *mountlist;
-
-struct mountbody {
-       name ml_hostname;
-       dirpath ml_directory;
-       mountlist ml_next;
-};
-typedef struct mountbody mountbody;
-
-typedef struct groupnode *groups;
-
-struct groupnode {
-       name gr_name;
-       groups gr_next;
-};
-typedef struct groupnode groupnode;
-
-typedef struct exportnode *exports;
-
-struct exportnode {
-       dirpath ex_dir;
-       groups ex_groups;
-       exports ex_next;
-};
-typedef struct exportnode exportnode;
-
-struct ppathcnf {
-       int pc_link_max;
-       short pc_max_canon;
-       short pc_max_input;
-       short pc_name_max;
-       short pc_path_max;
-       short pc_pipe_buf;
-       u_char pc_vdisable;
-       char pc_xxx;
-       short pc_mask[2];
-};
-typedef struct ppathcnf ppathcnf;
-#endif /*!_rpcsvc_mount_h*/
-
-#define MOUNTPROG 100005
-#define MOUNTVERS 1
-
-#define MOUNTPROC_NULL 0
-extern  void * mountproc_null_1(void *, CLIENT *);
-extern  void * mountproc_null_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_MNT 1
-extern  fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
-extern  fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_DUMP 2
-extern  mountlist * mountproc_dump_1(void *, CLIENT *);
-extern  mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_UMNT 3
-extern  void * mountproc_umnt_1(dirpath *, CLIENT *);
-extern  void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_UMNTALL 4
-extern  void * mountproc_umntall_1(void *, CLIENT *);
-extern  void * mountproc_umntall_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORT 5
-extern  exports * mountproc_export_1(void *, CLIENT *);
-extern  exports * mountproc_export_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORTALL 6
-extern  exports * mountproc_exportall_1(void *, CLIENT *);
-extern  exports * mountproc_exportall_1_svc(void *, struct svc_req *);
-extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNTVERS_POSIX 2
-
-extern  void * mountproc_null_2(void *, CLIENT *);
-extern  void * mountproc_null_2_svc(void *, struct svc_req *);
-extern  fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
-extern  fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
-extern  mountlist * mountproc_dump_2(void *, CLIENT *);
-extern  mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
-extern  void * mountproc_umnt_2(dirpath *, CLIENT *);
-extern  void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
-extern  void * mountproc_umntall_2(void *, CLIENT *);
-extern  void * mountproc_umntall_2_svc(void *, struct svc_req *);
-extern  exports * mountproc_export_2(void *, CLIENT *);
-extern  exports * mountproc_export_2_svc(void *, struct svc_req *);
-extern  exports * mountproc_exportall_2(void *, CLIENT *);
-extern  exports * mountproc_exportall_2_svc(void *, struct svc_req *);
-#define MOUNTPROC_PATHCONF 7
-extern  ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
-extern  ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
-extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNT_V3 3
-
-#define MOUNTPROC3_NULL 0
-extern  void * mountproc3_null_3(void *, CLIENT *);
-extern  void * mountproc3_null_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_MNT 1
-extern  mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
-extern  mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_DUMP 2
-extern  mountlist * mountproc3_dump_3(void *, CLIENT *);
-extern  mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_UMNT 3
-extern  void * mountproc3_umnt_3(dirpath *, CLIENT *);
-extern  void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_UMNTALL 4
-extern  void * mountproc3_umntall_3(void *, CLIENT *);
-extern  void * mountproc3_umntall_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_EXPORT 5
-extern  exports * mountproc3_export_3(void *, CLIENT *);
-extern  exports * mountproc3_export_3_svc(void *, struct svc_req *);
-extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-/* the xdr functions */
-
-static  bool_t xdr_fhandle (XDR *, fhandle);
-extern  bool_t xdr_fhandle3 (XDR *, fhandle3*);
-extern  bool_t xdr_mountstat3 (XDR *, mountstat3*);
-extern  bool_t xdr_fhstatus (XDR *, fhstatus*);
-extern  bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
-extern  bool_t xdr_mountres3 (XDR *, mountres3*);
-extern  bool_t xdr_dirpath (XDR *, dirpath*);
-extern  bool_t xdr_name (XDR *, name*);
-extern  bool_t xdr_mountlist (XDR *, mountlist*);
-extern  bool_t xdr_mountbody (XDR *, mountbody*);
-extern  bool_t xdr_groups (XDR *, groups*);
-extern  bool_t xdr_groupnode (XDR *, groupnode*);
-extern  bool_t xdr_exports (XDR *, exports*);
-extern  bool_t xdr_exportnode (XDR *, exportnode*);
-extern  bool_t xdr_ppathcnf (XDR *, ppathcnf*);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_NFSMOUNT_H_RPCGEN */
diff --git a/busybox/nslookup.c b/busybox/nslookup.c
deleted file mode 100644 (file)
index 9b7cb64..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini nslookup implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <resolv.h>
-#include <arpa/inet.h>
-#include "busybox.h"
-
-/*
- |  I'm only implementing non-interactive mode;
- |  I totally forgot nslookup even had an interactive mode.
- |
- |  [ TODO ]
- |  + find out how to use non-default name servers
- */
-
-/* only works for IPv4 */
-static int addr_fprint(char *addr)
-{
-       u_int8_t split[4];
-       u_int32_t ip;
-       u_int32_t *x = (u_int32_t *) addr;
-
-       ip = ntohl(*x);
-       split[0] = (ip & 0xff000000) >> 24;
-       split[1] = (ip & 0x00ff0000) >> 16;
-       split[2] = (ip & 0x0000ff00) >> 8;
-       split[3] = (ip & 0x000000ff);
-       printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
-       return 0;
-}
-
-/* takes the NULL-terminated array h_addr_list, and
- * prints its contents appropriately
- */
-static int addr_list_fprint(char **h_addr_list)
-{
-       int i, j;
-       char *addr_string = (h_addr_list[1])
-               ? "Addresses: " : "Address:   ";
-
-       printf("%s ", addr_string);
-       for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
-               addr_fprint(h_addr_list[i]);
-
-               /* real nslookup does this */
-               if (j == 4) {
-                       if (h_addr_list[i + 1]) {
-                               printf("\n          ");
-                       }
-                       j = 0;
-               } else {
-                       if (h_addr_list[i + 1]) {
-                               printf(", ");
-                       }
-               }
-
-       }
-       printf("\n");
-       return 0;
-}
-
-/* print the results as nslookup would */
-static struct hostent *hostent_fprint(struct hostent *host)
-{
-       if (host) {
-               printf("Name:       %s\n", host->h_name);
-               addr_list_fprint(host->h_addr_list);
-       } else {
-               printf("*** Unknown host\n");
-       }
-       return host;
-}
-
-/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
- * into a u_int32_t
- */
-static u_int32_t str_to_addr(const char *addr)
-{
-       u_int32_t split[4];
-       u_int32_t ip;
-
-       sscanf(addr, "%d.%d.%d.%d",
-                  &split[0], &split[1], &split[2], &split[3]);
-
-       /* assuming sscanf worked */
-       ip = (split[0] << 24) |
-               (split[1] << 16) | (split[2] << 8) | (split[3]);
-
-       return htonl(ip);
-}
-
-/* gethostbyaddr wrapper */
-static struct hostent *gethostbyaddr_wrapper(const char *address)
-{
-       struct in_addr addr;
-
-       addr.s_addr = str_to_addr(address);
-       return gethostbyaddr((char *) &addr, 4, AF_INET);       /* IPv4 only for now */
-}
-
-#ifdef __UCLIBC__
-#warning FIXME after fixing uClibc to define struct _res 
-static inline void server_print(void)
-{
-       printf("Server:     %s\n", "default");
-       printf("Address:    %s\n\n", "default");
-}
-#else
-/* lookup the default nameserver and display it */
-static inline void server_print(void)
-{
-       struct sockaddr_in def = _res.nsaddr_list[0];
-       char *ip = inet_ntoa(def.sin_addr);
-
-       hostent_fprint(gethostbyaddr_wrapper(ip));
-       printf("\n");
-}
-#endif 
-
-/* naive function to check whether char *s is an ip address */
-static int is_ip_address(const char *s)
-{
-       while (*s) {
-               if ((isdigit(*s)) || (*s == '.')) {
-                       s++;
-                       continue;
-               }
-               return 0;
-       }
-       return 1;
-}
-
-/* ________________________________________________________________________ */
-int nslookup_main(int argc, char **argv)
-{
-       struct hostent *host;
-
-       if (argc < 2 || *argv[1]=='-') {
-               show_usage();
-       }
-
-       res_init();
-       server_print();
-       if (is_ip_address(argv[1])) {
-               host = gethostbyaddr_wrapper(argv[1]);
-       } else {
-               host = gethostbyname(argv[1]);
-       }
-       hostent_fprint(host);
-       return EXIT_SUCCESS;
-}
-
-/* $Id: nslookup.c,v 1.24 2001/07/06 17:51:29 andersen Exp $ */
diff --git a/busybox/pidof.c b/busybox/pidof.c
deleted file mode 100644 (file)
index 50dffd3..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * pidof implementation for busybox
- *
- * Copyright (C) 2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-extern int pidof_main(int argc, char **argv)
-{
-       int opt;
-
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
-               switch (opt) {
-#if 0
-                       case 'g':
-                               break;
-                       case 'e':
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a process name, then we need to choke and die here */
-       if (argv[optind] == NULL)
-               show_usage();
-
-       /* Looks like everything is set to go. */
-       while(optind < argc) {
-               pid_t* pidList;
-
-               pidList = find_pid_by_name( argv[optind]);
-               if (!pidList || *pidList<=0) {
-                       break;
-               }
-
-               for(; pidList && *pidList!=0; pidList++) {
-                       printf("%ld ", (long)*pidList);
-               }
-               /* Note that we don't bother to free the memory
-                * allocated in find_pid_by_name().  It will be freed
-                * upon exit, so we can save a byte or two */
-               optind++;
-       }
-       printf("\n");
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/ping.c b/busybox/ping.c
deleted file mode 100644 (file)
index 5ca5dd9..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $
- * Mini ping implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This version of ping is adapted from the ping in netkit-base 0.10,
- * which is:
- *
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Muuss.
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/signal.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-/* It turns out that libc5 doesn't have proper icmp support
- * built into it header files, so we have to supplement it */
-#if __GNU_LIBRARY__ < 5
-static const int ICMP_MINLEN = 8;                              /* abs minimum */
-
-struct icmp_ra_addr
-{
-  u_int32_t ira_addr;
-  u_int32_t ira_preference;
-};
-
-
-struct icmp
-{
-  u_int8_t  icmp_type; /* type of message, see below */
-  u_int8_t  icmp_code; /* type sub code */
-  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
-  union
-  {
-    u_char ih_pptr;            /* ICMP_PARAMPROB */
-    struct in_addr ih_gwaddr;  /* gateway address */
-    struct ih_idseq            /* echo datagram */
-    {
-      u_int16_t icd_id;
-      u_int16_t icd_seq;
-    } ih_idseq;
-    u_int32_t ih_void;
-
-    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
-    struct ih_pmtu
-    {
-      u_int16_t ipm_void;
-      u_int16_t ipm_nextmtu;
-    } ih_pmtu;
-
-    struct ih_rtradv
-    {
-      u_int8_t irt_num_addrs;
-      u_int8_t irt_wpa;
-      u_int16_t irt_lifetime;
-    } ih_rtradv;
-  } icmp_hun;
-#define        icmp_pptr       icmp_hun.ih_pptr
-#define        icmp_gwaddr     icmp_hun.ih_gwaddr
-#define        icmp_id         icmp_hun.ih_idseq.icd_id
-#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
-#define        icmp_void       icmp_hun.ih_void
-#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
-#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
-#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
-#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
-#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
-  union
-  {
-    struct
-    {
-      u_int32_t its_otime;
-      u_int32_t its_rtime;
-      u_int32_t its_ttime;
-    } id_ts;
-    struct
-    {
-      struct ip idi_ip;
-      /* options and then 64 bits of data */
-    } id_ip;
-    struct icmp_ra_addr id_radv;
-    u_int32_t   id_mask;
-    u_int8_t    id_data[1];
-  } icmp_dun;
-#define        icmp_otime      icmp_dun.id_ts.its_otime
-#define        icmp_rtime      icmp_dun.id_ts.its_rtime
-#define        icmp_ttime      icmp_dun.id_ts.its_ttime
-#define        icmp_ip         icmp_dun.id_ip.idi_ip
-#define        icmp_radv       icmp_dun.id_radv
-#define        icmp_mask       icmp_dun.id_mask
-#define        icmp_data       icmp_dun.id_data
-};
-#endif
-
-static const int DEFDATALEN = 56;
-static const int MAXIPLEN = 60;
-static const int MAXICMPLEN = 76;
-static const int MAXPACKET = 65468;
-#define        MAX_DUP_CHK     (8 * 128)
-static const int MAXWAIT = 10;
-static const int PINGINTERVAL = 1;             /* second */
-
-#define O_QUIET         (1 << 0)
-
-#define        A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
-#define        B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
-#define        SET(bit)        (A(bit) |= B(bit))
-#define        CLR(bit)        (A(bit) &= (~B(bit)))
-#define        TST(bit)        (A(bit) & B(bit))
-
-static void ping(const char *host);
-
-/* common routines */
-static int in_cksum(unsigned short *buf, int sz)
-{
-       int nleft = sz;
-       int sum = 0;
-       unsigned short *w = buf;
-       unsigned short ans = 0;
-
-       while (nleft > 1) {
-               sum += *w++;
-               nleft -= 2;
-       }
-
-       if (nleft == 1) {
-               *(unsigned char *) (&ans) = *(unsigned char *) w;
-               sum += ans;
-       }
-
-       sum = (sum >> 16) + (sum & 0xFFFF);
-       sum += (sum >> 16);
-       ans = ~sum;
-       return (ans);
-}
-
-/* simple version */
-#ifndef BB_FEATURE_FANCY_PING
-static char *hostname = NULL;
-
-static void noresp(int ign)
-{
-       printf("No response from %s\n", hostname);
-       exit(0);
-}
-
-static void ping(const char *host)
-{
-       struct hostent *h;
-       struct sockaddr_in pingaddr;
-       struct icmp *pkt;
-       int pingsock, c;
-       char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
-
-       pingsock = create_icmp_socket();
-
-       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
-
-       pingaddr.sin_family = AF_INET;
-       h = xgethostbyname(host);
-       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
-       hostname = h->h_name;
-
-       pkt = (struct icmp *) packet;
-       memset(pkt, 0, sizeof(packet));
-       pkt->icmp_type = ICMP_ECHO;
-       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
-
-       c = sendto(pingsock, packet, sizeof(packet), 0,
-                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
-
-       if (c < 0 || c != sizeof(packet))
-               perror_msg_and_die("sendto");
-
-       signal(SIGALRM, noresp);
-       alarm(5);                                       /* give the host 5000ms to respond */
-       /* listen for replies */
-       while (1) {
-               struct sockaddr_in from;
-               size_t fromlen = sizeof(from);
-
-               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
-                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror_msg("recvfrom");
-                       continue;
-               }
-               if (c >= 76) {                  /* ip + icmp */
-                       struct iphdr *iphdr = (struct iphdr *) packet;
-
-                       pkt = (struct icmp *) (packet + (iphdr->ihl << 2));     /* skip ip hdr */
-                       if (pkt->icmp_type == ICMP_ECHOREPLY)
-                               break;
-               }
-       }
-       printf("%s is alive!\n", hostname);
-       return;
-}
-
-extern int ping_main(int argc, char **argv)
-{
-       argc--;
-       argv++;
-       if (argc < 1)
-               show_usage();
-       ping(*argv);
-       return EXIT_SUCCESS;
-}
-
-#else /* ! BB_FEATURE_FANCY_PING */
-/* full(er) version */
-static char *hostname = NULL;
-static struct sockaddr_in pingaddr;
-static int pingsock = -1;
-static int datalen; /* intentionally uninitialized to work around gcc bug */
-
-static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0;
-static int myid = 0, options = 0;
-static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0;
-static char rcvd_tbl[MAX_DUP_CHK / 8];
-
-static void sendping(int);
-static void pingstats(int);
-static void unpack(char *, int, struct sockaddr_in *);
-
-/**************************************************************************/
-
-static void pingstats(int junk)
-{
-       int status;
-
-       signal(SIGINT, SIG_IGN);
-
-       printf("\n--- %s ping statistics ---\n", hostname);
-       printf("%ld packets transmitted, ", ntransmitted);
-       printf("%ld packets received, ", nreceived);
-       if (nrepeats)
-               printf("%ld duplicates, ", nrepeats);
-       if (ntransmitted)
-               printf("%ld%% packet loss\n",
-                          (ntransmitted - nreceived) * 100 / ntransmitted);
-       if (nreceived)
-               printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
-                          tmin / 10, tmin % 10,
-                          (tsum / (nreceived + nrepeats)) / 10,
-                          (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
-       if (nreceived != 0)
-               status = EXIT_SUCCESS;
-       else
-               status = EXIT_FAILURE;
-       exit(status);
-}
-
-static void sendping(int junk)
-{
-       struct icmp *pkt;
-       int i;
-       char packet[datalen + 8];
-
-       pkt = (struct icmp *) packet;
-
-       pkt->icmp_type = ICMP_ECHO;
-       pkt->icmp_code = 0;
-       pkt->icmp_cksum = 0;
-       pkt->icmp_seq = ntransmitted++;
-       pkt->icmp_id = myid;
-       CLR(pkt->icmp_seq % MAX_DUP_CHK);
-
-       gettimeofday((struct timeval *) &packet[8], NULL);
-       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
-
-       i = sendto(pingsock, packet, sizeof(packet), 0,
-                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
-
-       if (i < 0)
-               perror_msg_and_die("sendto");
-       else if ((size_t)i != sizeof(packet))
-               error_msg_and_die("ping wrote %d chars; %d expected", i,
-                          (int)sizeof(packet));
-
-       signal(SIGALRM, sendping);
-       if (pingcount == 0 || ntransmitted < pingcount) {       /* schedule next in 1s */
-               alarm(PINGINTERVAL);
-       } else {                                        /* done, wait for the last ping to come back */
-               /* todo, don't necessarily need to wait so long... */
-               signal(SIGALRM, pingstats);
-               alarm(MAXWAIT);
-       }
-}
-
-static char *icmp_type_name (int id)
-{
-       switch (id) {
-       case ICMP_ECHOREPLY:            return "Echo Reply";
-       case ICMP_DEST_UNREACH:         return "Destination Unreachable";
-       case ICMP_SOURCE_QUENCH:        return "Source Quench";
-       case ICMP_REDIRECT:             return "Redirect (change route)";
-       case ICMP_ECHO:                         return "Echo Request";
-       case ICMP_TIME_EXCEEDED:        return "Time Exceeded";
-       case ICMP_PARAMETERPROB:        return "Parameter Problem";
-       case ICMP_TIMESTAMP:            return "Timestamp Request";
-       case ICMP_TIMESTAMPREPLY:       return "Timestamp Reply";
-       case ICMP_INFO_REQUEST:         return "Information Request";
-       case ICMP_INFO_REPLY:           return "Information Reply";
-       case ICMP_ADDRESS:                      return "Address Mask Request";
-       case ICMP_ADDRESSREPLY:         return "Address Mask Reply";
-       default:                                        return "unknown ICMP type";
-       }
-}
-
-static void unpack(char *buf, int sz, struct sockaddr_in *from)
-{
-       struct icmp *icmppkt;
-       struct iphdr *iphdr;
-       struct timeval tv, *tp;
-       int hlen, dupflag;
-       unsigned long triptime;
-
-       gettimeofday(&tv, NULL);
-
-       /* check IP header */
-       iphdr = (struct iphdr *) buf;
-       hlen = iphdr->ihl << 2;
-       /* discard if too short */
-       if (sz < (datalen + ICMP_MINLEN))
-               return;
-
-       sz -= hlen;
-       icmppkt = (struct icmp *) (buf + hlen);
-
-       if (icmppkt->icmp_id != myid)
-           return;                             /* not our ping */
-
-       if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
-           ++nreceived;
-               tp = (struct timeval *) icmppkt->icmp_data;
-
-               if ((tv.tv_usec -= tp->tv_usec) < 0) {
-                       --tv.tv_sec;
-                       tv.tv_usec += 1000000;
-               }
-               tv.tv_sec -= tp->tv_sec;
-
-               triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
-               tsum += triptime;
-               if (triptime < tmin)
-                       tmin = triptime;
-               if (triptime > tmax)
-                       tmax = triptime;
-
-               if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) {
-                       ++nrepeats;
-                       --nreceived;
-                       dupflag = 1;
-               } else {
-                       SET(icmppkt->icmp_seq % MAX_DUP_CHK);
-                       dupflag = 0;
-               }
-
-               if (options & O_QUIET)
-                       return;
-
-               printf("%d bytes from %s: icmp_seq=%u", sz,
-                          inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
-                          icmppkt->icmp_seq);
-               printf(" ttl=%d", iphdr->ttl);
-               printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
-               if (dupflag)
-                       printf(" (DUP!)");
-               printf("\n");
-       } else 
-               if (icmppkt->icmp_type != ICMP_ECHO)
-                       error_msg("Warning: Got ICMP %d (%s)",
-                                       icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
-}
-
-static void ping(const char *host)
-{
-       struct hostent *h;
-       char buf[MAXHOSTNAMELEN];
-       char packet[datalen + MAXIPLEN + MAXICMPLEN];
-       int sockopt;
-
-       pingsock = create_icmp_socket();
-
-       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
-
-       pingaddr.sin_family = AF_INET;
-       h = xgethostbyname(host);
-       if (h->h_addrtype != AF_INET)
-               error_msg_and_die("unknown address type; only AF_INET is currently supported.");
-
-       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
-       strncpy(buf, h->h_name, sizeof(buf) - 1);
-       hostname = buf;
-
-       /* enable broadcast pings */
-       sockopt = 1;
-       setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
-                          sizeof(sockopt));
-
-       /* set recv buf for broadcast pings */
-       sockopt = 48 * 1024;
-       setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
-                          sizeof(sockopt));
-
-       printf("PING %s (%s): %d data bytes\n",
-                  hostname,
-                  inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
-                  datalen);
-
-       signal(SIGINT, pingstats);
-
-       /* start the ping's going ... */
-       sendping(0);
-
-       /* listen for replies */
-       while (1) {
-               struct sockaddr_in from;
-               socklen_t fromlen = (socklen_t) sizeof(from);
-               int c;
-
-               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
-                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror_msg("recvfrom");
-                       continue;
-               }
-               unpack(packet, c, &from);
-               if (pingcount > 0 && nreceived >= pingcount)
-                       break;
-       }
-       pingstats(0);
-}
-
-extern int ping_main(int argc, char **argv)
-{
-       char *thisarg;
-
-       datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
-
-       argc--;
-       argv++;
-       options = 0;
-       /* Parse any options */
-       while (argc >= 1 && **argv == '-') {
-               thisarg = *argv;
-               thisarg++;
-               switch (*thisarg) {
-               case 'q':
-                       options |= O_QUIET;
-                       break;
-               case 'c':
-                       if (--argc <= 0)
-                               show_usage();
-                       argv++;
-                       pingcount = atoi(*argv);
-                       break;
-               case 's':
-                       if (--argc <= 0)
-                               show_usage();
-                       argv++;
-                       datalen = atoi(*argv);
-                       break;
-               default:
-                       show_usage();
-               }
-               argc--;
-               argv++;
-       }
-       if (argc < 1)
-               show_usage();
-
-       myid = getpid() & 0xFFFF;
-       ping(*argv);
-       return EXIT_SUCCESS;
-}
-#endif /* ! BB_FEATURE_FANCY_PING */
-
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Muuss.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
diff --git a/busybox/pivot_root.c b/busybox/pivot_root.c
deleted file mode 100644 (file)
index ba26b9c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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. 
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include "busybox.h"
-
-extern int pivot_root(const char * new_root,const char * put_old);
-
-int pivot_root_main(int argc, char **argv)
-{
-    if (argc != 3)
-        show_usage();
-
-       if (pivot_root(argv[1],argv[2]) < 0)
-               perror_msg_and_die("pivot_root");
-
-    return EXIT_SUCCESS;
-
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/poweroff.c b/busybox/poweroff.c
deleted file mode 100644 (file)
index db20a45..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini poweroff implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int poweroff_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGUSR2));
-#else
-       return(kill(1, SIGUSR2));
-#endif
-}
diff --git a/busybox/printf.c b/busybox/printf.c
deleted file mode 100644 (file)
index d579a9b..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* printf - format and print data
-   Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Usage: printf format [argument...]
-
-   A front end to the printf function that lets it be used from the shell.
-
-   Backslash escapes:
-
-   \" = double quote
-   \\ = backslash
-   \a = alert (bell)
-   \b = backspace
-   \c = produce no further output
-   \f = form feed
-   \n = new line
-   \r = carriage return
-   \t = horizontal tab
-   \v = vertical tab
-   \0ooo = octal number (ooo is 0 to 3 digits)
-   \xhhh = hexadecimal number (hhh is 1 to 3 digits)
-
-   Additional directive:
-
-   %b = print an argument string, interpreting backslash escapes
-
-   The `format' argument is re-used as many times as necessary
-   to convert all of the given arguments.
-
-   David MacKenzie <djm@gnu.ai.mit.edu> */
-
-
-//   19990508 Busy Boxed! Dave Cinege
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include "busybox.h"
-
-
-#ifndef S_IFMT
-static const int S_IFMT = 0170000;
-#endif
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-# define       S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-# define       S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-# define       S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG) && defined(S_IFREG)
-# define       S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-# define       S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define       S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-# define       S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISMPB) && defined(S_IFMPB)      /* V7 */
-# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
-# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
-#endif
-#if !defined(S_ISNWK) && defined(S_IFNWK)      /* HP/UX */
-# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
-#endif
-
-#define IN_CTYPE_DOMAIN(c) 1
-
-#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
-#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
-#define ISDIGIT(c) (((unsigned char) (c)) - '0' <= 9)
-
-#define isodigit(c) ((c) >= '0' && (c) <= '7')
-#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
-#define octtobin(c) ((c) - '0')
-
-static double xstrtod __P((char *s));
-static int print_esc __P((char *escstart));
-static int print_formatted __P((char *format, int argc, char **argv));
-static long xstrtol __P((char *s));
-static unsigned long xstrtoul __P((char *s));
-static void print_direc
-__P(
-
-       (char *start, size_t length, int field_width, int precision,
-        char *argument));
-static void print_esc_char __P((int c));
-static void print_esc_string __P((char *str));
-static void verify __P((char *s, char *end));
-
-/* The value to return to the calling program.  */
-static int exit_status;
-
-int printf_main(int argc, char **argv)
-{
-       char *format;
-       int args_used;
-
-       exit_status = 0;
-       if (argc <= 1 || **(argv + 1) == '-') {
-               show_usage();
-       }
-
-       format = argv[1];
-       argc -= 2;
-       argv += 2;
-
-       do {
-               args_used = print_formatted(format, argc, argv);
-               argc -= args_used;
-               argv += args_used;
-       }
-       while (args_used > 0 && argc > 0);
-
-/*
-  if (argc > 0)
-    fprintf(stderr, "excess args ignored");
-*/
-
-       return(exit_status);
-}
-
-/* Print the text in FORMAT, using ARGV (with ARGC elements) for
-   arguments to any `%' directives.
-   Return the number of elements of ARGV used.  */
-
-static int print_formatted(char *format, int argc, char **argv)
-{
-       int save_argc = argc;           /* Preserve original value.  */
-       char *f;                                        /* Pointer into `format'.  */
-       char *direc_start;                      /* Start of % directive.  */
-       size_t direc_length;            /* Length of % directive.  */
-       int field_width;                        /* Arg to first '*', or -1 if none.  */
-       int precision;                          /* Arg to second '*', or -1 if none.  */
-
-       for (f = format; *f; ++f) {
-               switch (*f) {
-               case '%':
-                       direc_start = f++;
-                       direc_length = 1;
-                       field_width = precision = -1;
-                       if (*f == '%') {
-                               putchar('%');
-                               break;
-                       }
-                       if (*f == 'b') {
-                               if (argc > 0) {
-                                       print_esc_string(*argv);
-                                       ++argv;
-                                       --argc;
-                               }
-                               break;
-                       }
-                       if (strchr("-+ #", *f)) {
-                               ++f;
-                               ++direc_length;
-                       }
-                       if (*f == '*') {
-                               ++f;
-                               ++direc_length;
-                               if (argc > 0) {
-                                       field_width = xstrtoul(*argv);
-                                       ++argv;
-                                       --argc;
-                               } else
-                                       field_width = 0;
-                       } else
-                               while (ISDIGIT(*f)) {
-                                       ++f;
-                                       ++direc_length;
-                               }
-                       if (*f == '.') {
-                               ++f;
-                               ++direc_length;
-                               if (*f == '*') {
-                                       ++f;
-                                       ++direc_length;
-                                       if (argc > 0) {
-                                               precision = xstrtoul(*argv);
-                                               ++argv;
-                                               --argc;
-                                       } else
-                                               precision = 0;
-                               } else
-                                       while (ISDIGIT(*f)) {
-                                               ++f;
-                                               ++direc_length;
-                                       }
-                       }
-                       if (*f == 'l' || *f == 'L' || *f == 'h') {
-                               ++f;
-                               ++direc_length;
-                       }
-                       /*  
-                          if (!strchr ("diouxXfeEgGcs", *f))
-                          fprintf(stderr, "%%%c: invalid directive", *f);
-                        */
-                       ++direc_length;
-                       if (argc > 0) {
-                               print_direc(direc_start, direc_length, field_width,
-                                                       precision, *argv);
-                               ++argv;
-                               --argc;
-                       } else
-                               print_direc(direc_start, direc_length, field_width,
-                                                       precision, "");
-                       break;
-
-               case '\\':
-                       f += print_esc(f);
-                       break;
-
-               default:
-                       putchar(*f);
-               }
-       }
-
-       return save_argc - argc;
-}
-
-/* Print a \ escape sequence starting at ESCSTART.
-   Return the number of characters in the escape sequence
-   besides the backslash. */
-
-static int print_esc(char *escstart)
-{
-       register char *p = escstart + 1;
-       int esc_value = 0;                      /* Value of \nnn escape. */
-       int esc_length;                         /* Length of \nnn escape. */
-
-       /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
-       if (*p == 'x') {
-               for (esc_length = 0, ++p;
-                        esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
-                       esc_value = esc_value * 16 + hextobin(*p);
-/*      if (esc_length == 0)
-       fprintf(stderr, "missing hex in esc");
-*/
-               putchar(esc_value);
-       } else if (*p == '0') {
-               for (esc_length = 0, ++p;
-                        esc_length < 3 && isodigit(*p); ++esc_length, ++p)
-                       esc_value = esc_value * 8 + octtobin(*p);
-               putchar(esc_value);
-       } else if (strchr("\"\\abcfnrtv", *p))
-               print_esc_char(*p++);
-/*  else
-    fprintf(stderr, "\\%c: invalid esc", *p);
-*/
-       return p - escstart - 1;
-}
-
-/* Output a single-character \ escape.  */
-
-static void print_esc_char(int c)
-{
-       switch (c) {
-       case 'a':                                       /* Alert. */
-               putchar(7);
-               break;
-       case 'b':                                       /* Backspace. */
-               putchar(8);
-               break;
-       case 'c':                                       /* Cancel the rest of the output. */
-               exit(0);
-               break;
-       case 'f':                                       /* Form feed. */
-               putchar(12);
-               break;
-       case 'n':                                       /* New line. */
-               putchar(10);
-               break;
-       case 'r':                                       /* Carriage return. */
-               putchar(13);
-               break;
-       case 't':                                       /* Horizontal tab. */
-               putchar(9);
-               break;
-       case 'v':                                       /* Vertical tab. */
-               putchar(11);
-               break;
-       default:
-               putchar(c);
-               break;
-       }
-}
-
-/* Print string STR, evaluating \ escapes. */
-
-static void print_esc_string(char *str)
-{
-       for (; *str; str++)
-               if (*str == '\\')
-                       str += print_esc(str);
-               else
-                       putchar(*str);
-}
-
-static void
-print_direc(char *start, size_t length, int field_width, int precision,
-                       char *argument)
-{
-       char *p;                                        /* Null-terminated copy of % directive. */
-
-       p = xmalloc((unsigned) (length + 1));
-       strncpy(p, start, length);
-       p[length] = 0;
-
-       switch (p[length - 1]) {
-       case 'd':
-       case 'i':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtol(argument));
-                       else
-                               printf(p, precision, xstrtol(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtol(argument));
-                       else
-                               printf(p, field_width, precision, xstrtol(argument));
-               }
-               break;
-
-       case 'o':
-       case 'u':
-       case 'x':
-       case 'X':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtoul(argument));
-                       else
-                               printf(p, precision, xstrtoul(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtoul(argument));
-                       else
-                               printf(p, field_width, precision, xstrtoul(argument));
-               }
-               break;
-
-       case 'f':
-       case 'e':
-       case 'E':
-       case 'g':
-       case 'G':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, xstrtod(argument));
-                       else
-                               printf(p, precision, xstrtod(argument));
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, xstrtod(argument));
-                       else
-                               printf(p, field_width, precision, xstrtod(argument));
-               }
-               break;
-
-       case 'c':
-               printf(p, *argument);
-               break;
-
-       case 's':
-               if (field_width < 0) {
-                       if (precision < 0)
-                               printf(p, argument);
-                       else
-                               printf(p, precision, argument);
-               } else {
-                       if (precision < 0)
-                               printf(p, field_width, argument);
-                       else
-                               printf(p, field_width, precision, argument);
-               }
-               break;
-       }
-
-       free(p);
-}
-
-static unsigned long xstrtoul(char *s)
-{
-       char *end;
-       unsigned long val;
-
-       errno = 0;
-       val = strtoul(s, &end, 0);
-       verify(s, end);
-       return val;
-}
-
-static long xstrtol(char *s)
-{
-       char *end;
-       long val;
-
-       errno = 0;
-       val = strtol(s, &end, 0);
-       verify(s, end);
-       return val;
-}
-
-static double xstrtod(char *s)
-{
-       char *end;
-       double val;
-
-       errno = 0;
-       val = strtod(s, &end);
-       verify(s, end);
-       return val;
-}
-
-static void verify(char *s, char *end)
-{
-       if (errno) {
-               fprintf(stderr, "%s", s);
-               exit_status = 1;
-       } else if (*end) {
-               /*
-                  if (s == end)
-                  fprintf(stderr, "%s: expected numeric", s);
-                  else
-                  fprintf(stderr, "%s: not completely converted", s);
-                */
-               exit_status = 1;
-       }
-}
diff --git a/busybox/pristine_setup.sh b/busybox/pristine_setup.sh
deleted file mode 100755 (executable)
index 9e638f9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-#
-# To compile BusyBox without touching the original sources
-# (as might be interesting for multi-target builds), create 
-# an empty directory, cd into it, and run this program by
-# giving its explicit path (kind of like how you would run
-# configure, if BusyBox had one).  Then you should be ready
-# to "make".  Files in the build tree, in particular Config.h,
-# will override those in the pristine source tree.
-#
-# If you use a ? in your path name, you lose, see sed command below.
-
-export LC_ALL=POSIX
-export LC_CTYPE=POSIX
-
-DIR=${0%%/pristine_setup.sh}
-if [ ! -d $DIR ]; then
-  echo "unexpected problem: $DIR is not a directory.  Aborting pristine setup"
-  exit
-fi
-
-echo " "
-
-if [ -e ./Config.h ]; then
-    echo "./Config.h already exists: not overwriting"
-    exit
-fi
-
-if [ -e ./Makefile ]; then
-    echo "./Makefile already exists: not overwriting"
-fi
-
-sed -e "s?BB_SRC_DIR =.*?BB_SRC_DIR = $DIR?" <$DIR/Makefile >Makefile || exit
-cp $DIR/Config.h Config.h || exit
-#mkdir -p pwd_grp
-
-if [ ! -r $DIR/sh.c ]; then
-    echo "Warning: no shell selected.  You must make the symlink (sh.c to either"
-    echo "lash.c or hush.c) in $DIR, not here."
-fi
-
-echo " "
-echo "You may now type 'make' to build busybox in this directory"
-echo "($PWD) using the pristine sources in $DIR"
-echo " "
-
diff --git a/busybox/procps/free.c b/busybox/procps/free.c
deleted file mode 100644 (file)
index 2e34a97..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini free implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int free_main(int argc, char **argv)
-{
-       struct sysinfo info;
-       sysinfo(&info);
-
-       /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
-       if (info.mem_unit==0) {
-               info.mem_unit=1;
-       }
-       info.mem_unit*=1024;
-       
-       /* TODO:  Make all this stuff not overflow when mem >= 4 Gib */
-       info.totalram/=info.mem_unit;
-       info.freeram/=info.mem_unit;
-       info.totalswap/=info.mem_unit;
-       info.freeswap/=info.mem_unit;
-       info.sharedram/=info.mem_unit;
-       info.bufferram/=info.mem_unit;
-
-       if (argc > 1 && **(argv + 1) == '-')
-               show_usage();
-
-       printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", 
-                       "shared", "buffers");
-
-       printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, 
-                       info.totalram-info.freeram, info.freeram, 
-                       info.sharedram, info.bufferram);
-
-       printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap,
-                       info.totalswap-info.freeswap, info.freeswap);
-
-       printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap,
-                       (info.totalram-info.freeram)+(info.totalswap-info.freeswap),
-                       info.freeram+info.freeswap);
-       return EXIT_SUCCESS;
-}
-
-
diff --git a/busybox/procps/kill.c b/busybox/procps/kill.c
deleted file mode 100644 (file)
index 3884ebd..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini kill/killall implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-static const int KILL = 0;
-static const int KILLALL = 1;
-
-
-extern int kill_main(int argc, char **argv)
-{
-       int whichApp, sig = SIGTERM;
-       const char *name;
-
-#ifdef BB_KILLALL
-       /* Figure out what we are trying to do here */
-       whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; 
-#else
-       whichApp = KILL;
-#endif
-
-       argc--;
-       argv++;
-       /* Parse any options */
-       if (argc < 1)
-               show_usage();
-
-       while (argc > 0 && **argv == '-') {
-               while (*++(*argv)) {
-                       switch (**argv) {
-                       case 'l':
-                               if(argc>1) {
-                                       for(argv++; *argv; argv++) {
-                                               name = u_signal_names(*argv, &sig, -1);
-                                               if(name!=NULL)
-                                                       printf("%s\n", name);
-                                       }
-                               } else {
-                                       int col = 0;
-                                       for(sig=1; sig < NSIG; sig++) {
-                                               name = u_signal_names(0, &sig, 1);
-                                               if(name==NULL)  /* unnamed */
-                                                       continue;
-                                               col += printf("%2d) %-16s", sig, name);
-                                               if (col > 60) {
-                                                       printf("\n");
-                                                       col = 0;
-                                               }
-                                       }
-                                       printf("\n");
-                               }
-                               return EXIT_SUCCESS;
-                       case '-':
-                               show_usage();
-                       default:
-                               name = u_signal_names(*argv, &sig, 0);
-                               if(name==NULL)
-                                       error_msg_and_die( "bad signal name: %s", *argv);
-                                                               argc--;
-                                                               argv++;
-                                                               goto do_it_now;
-                                                       }
-                       argc--;
-                       argv++;
-               }
-       }
-
-  do_it_now:
-
-       if (whichApp == KILL) {
-               /* Looks like they want to do a kill. Do that */
-               while (--argc >= 0) {
-                       int pid;
-
-                       if (!isdigit(**argv))
-                               perror_msg_and_die( "Bad PID");
-                       pid = strtol(*argv, NULL, 0);
-                       if (kill(pid, sig) != 0) 
-                               perror_msg_and_die( "Could not kill pid '%d'", pid);
-                       argv++;
-               }
-       } 
-#ifdef BB_KILLALL
-       else {
-               int all_found = TRUE;
-               pid_t myPid=getpid();
-               /* Looks like they want to do a killall.  Do that */
-               while (--argc >= 0) {
-                       pid_t* pidList;
-
-                       pidList = find_pid_by_name( *argv);
-                       if (!pidList || *pidList<=0) {
-                               all_found = FALSE;
-                               error_msg_and_die( "%s: no process killed", *argv);
-                       }
-
-                       for(; pidList && *pidList!=0; pidList++) {
-                               if (*pidList==myPid)
-                                       continue;
-                               if (kill(*pidList, sig) != 0) 
-                                       perror_msg_and_die( "Could not kill pid '%d'", *pidList);
-                       }
-                       /* Note that we don't bother to free the memory
-                        * allocated in find_pid_by_name().  It will be freed
-                        * upon exit, so we can save a byte or two */
-                       argv++;
-               }
-               if (all_found == FALSE)
-                       return EXIT_FAILURE;
-       }
-#endif
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/procps/pidof.c b/busybox/procps/pidof.c
deleted file mode 100644 (file)
index 50dffd3..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * pidof implementation for busybox
- *
- * Copyright (C) 2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-extern int pidof_main(int argc, char **argv)
-{
-       int opt;
-
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
-               switch (opt) {
-#if 0
-                       case 'g':
-                               break;
-                       case 'e':
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a process name, then we need to choke and die here */
-       if (argv[optind] == NULL)
-               show_usage();
-
-       /* Looks like everything is set to go. */
-       while(optind < argc) {
-               pid_t* pidList;
-
-               pidList = find_pid_by_name( argv[optind]);
-               if (!pidList || *pidList<=0) {
-                       break;
-               }
-
-               for(; pidList && *pidList!=0; pidList++) {
-                       printf("%ld ", (long)*pidList);
-               }
-               /* Note that we don't bother to free the memory
-                * allocated in find_pid_by_name().  It will be freed
-                * upon exit, so we can save a byte or two */
-               optind++;
-       }
-       printf("\n");
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/procps/ps.c b/busybox/procps/ps.c
deleted file mode 100644 (file)
index 9e96a54..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ps implementation(s) for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.  
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- *
- * This contains _two_ implementations of ps for Linux.  One uses the
- * traditional /proc virtual filesystem, and the other use the devps kernel
- * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
- *
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <string.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-static const int TERMINAL_WIDTH = 79;      /* not 80 in case terminal has linefold bug */
-
-
-
-#if ! defined BB_FEATURE_USE_DEVPS_PATCH
-
-/* The following is the first ps implementation --
- * the one using the /proc virtual filesystem.
- */
-
-typedef struct proc_s {
-       char
-        cmd[16];                                       /* basename of executable file in call to exec(2) */
-       int
-        ruid,                                          /* real only (sorry) */
-        pid,                                           /* process id */
-        ppid;                                          /* pid of parent process */
-       char
-        state;                                         /* single-char code for process state (S=sleeping) */
-} proc_t;
-
-
-
-static int file2str(char *filename, char *ret, int cap)
-{
-       int fd, num_read;
-
-       if ((fd = open(filename, O_RDONLY, 0)) == -1)
-               return -1;
-       if ((num_read = read(fd, ret, cap - 1)) <= 0)
-               return -1;
-       ret[num_read] = 0;
-       close(fd);
-       return num_read;
-}
-
-
-static void parse_proc_status(char *S, proc_t * P)
-{
-       char *tmp;
-
-       memset(P->cmd, 0, sizeof P->cmd);
-       sscanf(S, "Name:\t%15c", P->cmd);
-       tmp = strchr(P->cmd, '\n');
-       if (tmp)
-               *tmp = '\0';
-       tmp = strstr(S, "State");
-       sscanf(tmp, "State:\t%c", &P->state);
-
-       tmp = strstr(S, "Pid:");
-       if (tmp)
-               sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid);
-       else
-               error_msg("Internal error!");
-
-       /* For busybox, ignoring effective, saved, etc. */
-       tmp = strstr(S, "Uid:");
-       if (tmp)
-               sscanf(tmp, "Uid:\t%d", &P->ruid);
-       else
-               error_msg("Internal error!");
-
-
-}
-
-extern int ps_main(int argc, char **argv)
-{
-       proc_t p;
-       DIR *dir;
-       FILE *file;
-       struct dirent *entry;
-       char path[32], sbuf[512];
-       char uidName[9];
-       int len, i, c;
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-       int terminal_width = TERMINAL_WIDTH;
-#else
-#define terminal_width  TERMINAL_WIDTH
-#endif
-
-
-
-       dir = opendir("/proc");
-       if (!dir)
-               error_msg_and_die("Can't open /proc");
-
-#ifdef BB_FEATURE_AUTOWIDTH
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-
-       printf("  PID  Uid     Stat Command\n");
-       while ((entry = readdir(dir)) != NULL) {
-               if (!isdigit(*entry->d_name))
-                       continue;
-               sprintf(path, "/proc/%s/status", entry->d_name);
-               if ((file2str(path, sbuf, sizeof sbuf)) != -1) {
-                       parse_proc_status(sbuf, &p);
-               }
-
-               /* Make some adjustments as needed */
-               my_getpwuid(uidName, p.ruid);
-               if (*uidName == '\0')
-                       sprintf(uidName, "%d", p.ruid);
-
-               sprintf(path, "/proc/%s/cmdline", entry->d_name);
-               file = fopen(path, "r");
-               if (file == NULL)
-                       continue;
-               i = 0;
-               len = printf("%5d %-8s %c    ", p.pid, uidName, p.state);
-               while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) {
-                       i++;
-                       if (c == '\0')
-                               c = ' ';
-                       putc(c, stdout);
-               }
-               fclose(file);
-               if (i == 0)
-                       printf("[%s]", p.cmd);
-               putchar('\n');
-       }
-       closedir(dir);
-       return EXIT_SUCCESS;
-}
-
-
-#else /* BB_FEATURE_USE_DEVPS_PATCH */
-
-
-/* The following is the second ps implementation --
- * this one uses the nifty new devps kernel device.
- */
-
-#include <linux/devps.h> /* For Erik's nifty devps device driver */
-
-
-extern int ps_main(int argc, char **argv)
-{
-       char device[] = "/dev/ps";
-       int i, j, len, fd;
-       pid_t num_pids;
-       pid_t* pid_array = NULL;
-       struct pid_info info;
-       char uidName[9];
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-       int terminal_width = TERMINAL_WIDTH;
-#else
-#define terminal_width  TERMINAL_WIDTH
-#endif
-
-       if (argc > 1 && **(argv + 1) == '-') 
-               show_usage();
-
-       /* open device */ 
-       fd = open(device, O_RDONLY);
-       if (fd < 0) 
-               perror_msg_and_die( "open failed for `%s'", device);
-
-       /* Find out how many processes there are */
-       if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
-               perror_msg_and_die( "\nDEVPS_GET_PID_LIST");
-       
-       /* Allocate some memory -- grab a few extras just in case 
-        * some new processes start up while we wait. The kernel will
-        * just ignore any extras if we give it too many, and will trunc.
-        * the list if we give it too few.  */
-       pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
-       pid_array[0] = num_pids+10;
-
-       /* Now grab the pid list */
-       if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
-               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-
-#ifdef BB_FEATURE_AUTOWIDTH
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-
-       /* Print up a ps listing */
-       printf("  PID  Uid     Stat Command\n");
-
-       for (i=1; i<pid_array[0] ; i++) {
-           info.pid = pid_array[i];
-
-           if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
-                       perror_msg_and_die("\nDEVPS_GET_PID_INFO");
-           
-               /* Make some adjustments as needed */
-               my_getpwuid(uidName, info.euid);
-               if (*uidName == '\0')
-                       sprintf(uidName, "%ld", info.euid);
-
-               len = printf("%5d %-8s %c    ", info.pid, uidName, info.state);
-
-               if (strlen(info.command_line) > 1) {
-                       for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) {
-                               if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
-                                       *(info.command_line+j) = ' ';
-                               }
-                       }
-                       *(info.command_line+j) = '\0';
-                       puts(info.command_line);
-               } else {
-                       printf("[%s]\n", info.name);
-               }
-       }
-
-       /* Free memory */
-       free( pid_array);
-
-       /* close device */
-       if (close (fd) != 0) 
-               perror_msg_and_die("close failed for `%s'", device);
-       exit (0);
-}
-
-#endif /* BB_FEATURE_USE_DEVPS_PATCH */
-
diff --git a/busybox/procps/renice.c b/busybox/procps/renice.c
deleted file mode 100644 (file)
index ec35bdc..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Mini renice implementation for busybox
- *
- *
- * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include "busybox.h"
-
-
-extern int renice_main(int argc, char **argv)
-{
-       int prio, status = EXIT_SUCCESS;
-       
-       if (argc < 3)   show_usage();
-               
-       prio = atoi(*++argv);
-       if (prio > 20)          prio = 20;
-       if (prio < -20)         prio = -20;
-       
-       while (*++argv) {
-               int ps = atoi(*argv);
-               int oldp = getpriority(PRIO_PROCESS, ps);
-               
-               if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
-                       printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
-               } else {
-                       perror_msg("%d: setpriority", ps);
-                       status = EXIT_FAILURE;
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/procps/uptime.c b/busybox/procps/uptime.c
deleted file mode 100644 (file)
index 6758d95..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini uptime implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* This version of uptime doesn't display the number of users on the system,
- * since busybox init doesn't mess with utmp.  For folks using utmp that are
- * just dying to have # of users reported, feel free to write it as some type
- * of BB_FEATURE_UTMP_SUPPORT #define
- */
-
-/* getopt not needed */
-
-
-#include <stdio.h>
-#include <time.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static const int FSHIFT = 16;              /* nr of bits of precision */
-#define FIXED_1         (1<<FSHIFT)     /* 1.0 as fixed-point */
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-
-extern int uptime_main(int argc, char **argv)
-{
-       int updays, uphours, upminutes;
-       struct sysinfo info;
-       struct tm *current_time;
-       time_t current_secs;
-
-       time(&current_secs);
-       current_time = localtime(&current_secs);
-
-       sysinfo(&info);
-
-       printf(" %2d:%02d%s  up ", 
-                       current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, 
-                       current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am");
-       updays = (int) info.uptime / (60*60*24);
-       if (updays)
-               printf("%d day%s, ", updays, (updays != 1) ? "s" : "");
-       upminutes = (int) info.uptime / 60;
-       uphours = (upminutes / 60) % 24;
-       upminutes %= 60;
-       if(uphours)
-               printf("%2d:%02d, ", uphours, upminutes);
-       else
-               printf("%d min, ", upminutes);
-
-       printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", 
-                       LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), 
-                       LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), 
-                       LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2]));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/ps.c b/busybox/ps.c
deleted file mode 100644 (file)
index 9e96a54..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini ps implementation(s) for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.  
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- *
- * This contains _two_ implementations of ps for Linux.  One uses the
- * traditional /proc virtual filesystem, and the other use the devps kernel
- * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
- *
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <string.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-static const int TERMINAL_WIDTH = 79;      /* not 80 in case terminal has linefold bug */
-
-
-
-#if ! defined BB_FEATURE_USE_DEVPS_PATCH
-
-/* The following is the first ps implementation --
- * the one using the /proc virtual filesystem.
- */
-
-typedef struct proc_s {
-       char
-        cmd[16];                                       /* basename of executable file in call to exec(2) */
-       int
-        ruid,                                          /* real only (sorry) */
-        pid,                                           /* process id */
-        ppid;                                          /* pid of parent process */
-       char
-        state;                                         /* single-char code for process state (S=sleeping) */
-} proc_t;
-
-
-
-static int file2str(char *filename, char *ret, int cap)
-{
-       int fd, num_read;
-
-       if ((fd = open(filename, O_RDONLY, 0)) == -1)
-               return -1;
-       if ((num_read = read(fd, ret, cap - 1)) <= 0)
-               return -1;
-       ret[num_read] = 0;
-       close(fd);
-       return num_read;
-}
-
-
-static void parse_proc_status(char *S, proc_t * P)
-{
-       char *tmp;
-
-       memset(P->cmd, 0, sizeof P->cmd);
-       sscanf(S, "Name:\t%15c", P->cmd);
-       tmp = strchr(P->cmd, '\n');
-       if (tmp)
-               *tmp = '\0';
-       tmp = strstr(S, "State");
-       sscanf(tmp, "State:\t%c", &P->state);
-
-       tmp = strstr(S, "Pid:");
-       if (tmp)
-               sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid);
-       else
-               error_msg("Internal error!");
-
-       /* For busybox, ignoring effective, saved, etc. */
-       tmp = strstr(S, "Uid:");
-       if (tmp)
-               sscanf(tmp, "Uid:\t%d", &P->ruid);
-       else
-               error_msg("Internal error!");
-
-
-}
-
-extern int ps_main(int argc, char **argv)
-{
-       proc_t p;
-       DIR *dir;
-       FILE *file;
-       struct dirent *entry;
-       char path[32], sbuf[512];
-       char uidName[9];
-       int len, i, c;
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-       int terminal_width = TERMINAL_WIDTH;
-#else
-#define terminal_width  TERMINAL_WIDTH
-#endif
-
-
-
-       dir = opendir("/proc");
-       if (!dir)
-               error_msg_and_die("Can't open /proc");
-
-#ifdef BB_FEATURE_AUTOWIDTH
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-
-       printf("  PID  Uid     Stat Command\n");
-       while ((entry = readdir(dir)) != NULL) {
-               if (!isdigit(*entry->d_name))
-                       continue;
-               sprintf(path, "/proc/%s/status", entry->d_name);
-               if ((file2str(path, sbuf, sizeof sbuf)) != -1) {
-                       parse_proc_status(sbuf, &p);
-               }
-
-               /* Make some adjustments as needed */
-               my_getpwuid(uidName, p.ruid);
-               if (*uidName == '\0')
-                       sprintf(uidName, "%d", p.ruid);
-
-               sprintf(path, "/proc/%s/cmdline", entry->d_name);
-               file = fopen(path, "r");
-               if (file == NULL)
-                       continue;
-               i = 0;
-               len = printf("%5d %-8s %c    ", p.pid, uidName, p.state);
-               while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) {
-                       i++;
-                       if (c == '\0')
-                               c = ' ';
-                       putc(c, stdout);
-               }
-               fclose(file);
-               if (i == 0)
-                       printf("[%s]", p.cmd);
-               putchar('\n');
-       }
-       closedir(dir);
-       return EXIT_SUCCESS;
-}
-
-
-#else /* BB_FEATURE_USE_DEVPS_PATCH */
-
-
-/* The following is the second ps implementation --
- * this one uses the nifty new devps kernel device.
- */
-
-#include <linux/devps.h> /* For Erik's nifty devps device driver */
-
-
-extern int ps_main(int argc, char **argv)
-{
-       char device[] = "/dev/ps";
-       int i, j, len, fd;
-       pid_t num_pids;
-       pid_t* pid_array = NULL;
-       struct pid_info info;
-       char uidName[9];
-#ifdef BB_FEATURE_AUTOWIDTH
-       struct winsize win = { 0, 0, 0, 0 };
-       int terminal_width = TERMINAL_WIDTH;
-#else
-#define terminal_width  TERMINAL_WIDTH
-#endif
-
-       if (argc > 1 && **(argv + 1) == '-') 
-               show_usage();
-
-       /* open device */ 
-       fd = open(device, O_RDONLY);
-       if (fd < 0) 
-               perror_msg_and_die( "open failed for `%s'", device);
-
-       /* Find out how many processes there are */
-       if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
-               perror_msg_and_die( "\nDEVPS_GET_PID_LIST");
-       
-       /* Allocate some memory -- grab a few extras just in case 
-        * some new processes start up while we wait. The kernel will
-        * just ignore any extras if we give it too many, and will trunc.
-        * the list if we give it too few.  */
-       pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
-       pid_array[0] = num_pids+10;
-
-       /* Now grab the pid list */
-       if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
-               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-
-#ifdef BB_FEATURE_AUTOWIDTH
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-
-       /* Print up a ps listing */
-       printf("  PID  Uid     Stat Command\n");
-
-       for (i=1; i<pid_array[0] ; i++) {
-           info.pid = pid_array[i];
-
-           if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
-                       perror_msg_and_die("\nDEVPS_GET_PID_INFO");
-           
-               /* Make some adjustments as needed */
-               my_getpwuid(uidName, info.euid);
-               if (*uidName == '\0')
-                       sprintf(uidName, "%ld", info.euid);
-
-               len = printf("%5d %-8s %c    ", info.pid, uidName, info.state);
-
-               if (strlen(info.command_line) > 1) {
-                       for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) {
-                               if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
-                                       *(info.command_line+j) = ' ';
-                               }
-                       }
-                       *(info.command_line+j) = '\0';
-                       puts(info.command_line);
-               } else {
-                       printf("[%s]\n", info.name);
-               }
-       }
-
-       /* Free memory */
-       free( pid_array);
-
-       /* close device */
-       if (close (fd) != 0) 
-               perror_msg_and_die("close failed for `%s'", device);
-       exit (0);
-}
-
-#endif /* BB_FEATURE_USE_DEVPS_PATCH */
-
diff --git a/busybox/pwd.c b/busybox/pwd.c
deleted file mode 100644 (file)
index f6a00bf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini pwd implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int pwd_main(int argc, char **argv)
-{
-       static char *buf; 
-       
-       buf = xgetcwd(buf);
-       
-       if (buf != NULL) {
-               puts(buf);
-               return EXIT_SUCCESS;
-       }
-       return EXIT_FAILURE;
-}
diff --git a/busybox/rdate.c b/busybox/rdate.c
deleted file mode 100644 (file)
index 50be4de..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* 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>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-static const int RFC_868_BIAS = 2208988800UL;
-
-static time_t askremotedate(const char *host)
-{
-       struct hostent *h;
-       struct sockaddr_in s_in;
-       struct servent *tserv;
-       unsigned long int nett, localt;
-       int fd;
-
-       h = xgethostbyname(host);         /* get the IP addr */
-
-       if ((tserv = getservbyname("time", "tcp")) == NULL)   /* find port # */
-               perror_msg_and_die("time");
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    /* get net connection */
-               perror_msg_and_die("socket");
-
-       memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr));
-       s_in.sin_port= tserv->s_port;
-       s_in.sin_family = AF_INET;
-
-       if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)      /* connect to time server */
-               perror_msg_and_die("%s", host);
-
-       if (read(fd, (void *)&nett, 4) != 4)    /* read time from server */
-               error_msg_and_die("%s did not send the complete time", host);
-
-       close(fd);
-
-       /* convert from network byte order to local byte order.
-        * RFC 868 time is the number of seconds
-        *  since 00:00 (midnight) 1 January 1900 GMT
-        *  the RFC 868 time 2,208,988,800 corresponds to 00:00  1 Jan 1970 GMT
-        * Subtract the RFC 868 time  to get Linux epoch
-        */
-       localt= ntohl(nett) - RFC_868_BIAS;
-
-       return(localt);
-}
-
-int rdate_main(int argc, char **argv)
-{
-       time_t remote_time;
-       int opt;
-       int setdate = 1;
-       int printdate = 1;
-
-       /* Interpret command line args */
-       while ((opt = getopt(argc, argv, "sp")) > 0) {
-               switch (opt) {
-                       case 's':
-                               printdate = 0;
-                               setdate = 1;
-                               break;
-                       case 'p':
-                               printdate = 1;
-                               setdate = 0;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)
-               show_usage();
-
-       remote_time = askremotedate(argv[optind]);
-
-       if (setdate) {
-               if (stime(&remote_time) < 0)
-                       perror_msg_and_die("Could not set time of day");
-       }
-
-       if (printdate)
-               printf("%s", ctime(&remote_time));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/readlink.c b/busybox/readlink.c
deleted file mode 100644 (file)
index c46ebd1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini readlink implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-int readlink_main(int argc, char **argv)
-{
-       char *buf = NULL;
-
-       /* no options, no getopt */
-
-       if (argc != 2)
-               show_usage();
-
-       buf = xreadlink(argv[1]);
-       if (!buf)
-               return EXIT_FAILURE;
-       puts(buf);
-#ifdef BB_FEATURE_CLEAN_UP
-       free(buf);
-#endif
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/reboot.c b/busybox/reboot.c
deleted file mode 100644 (file)
index 35afd74..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini reboot implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <signal.h>
-
-extern int reboot_main(int argc, char **argv)
-{
-#ifdef BB_FEATURE_LINUXRC
-       /* don't assume init's pid == 1 */
-       pid_t *pid = find_pid_by_name("init");
-       if (!pid || *pid<=0) {
-               pid = find_pid_by_name("linuxrc");
-               if (!pid || *pid<=0)
-                       error_msg_and_die("no process killed");
-       }
-       return(kill(*pid, SIGTERM));
-#else
-       return(kill(1, SIGTERM));
-#endif
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/renice.c b/busybox/renice.c
deleted file mode 100644 (file)
index ec35bdc..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Mini renice implementation for busybox
- *
- *
- * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include "busybox.h"
-
-
-extern int renice_main(int argc, char **argv)
-{
-       int prio, status = EXIT_SUCCESS;
-       
-       if (argc < 3)   show_usage();
-               
-       prio = atoi(*++argv);
-       if (prio > 20)          prio = 20;
-       if (prio < -20)         prio = -20;
-       
-       while (*++argv) {
-               int ps = atoi(*argv);
-               int oldp = getpriority(PRIO_PROCESS, ps);
-               
-               if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
-                       printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
-               } else {
-                       perror_msg("%d: setpriority", ps);
-                       status = EXIT_FAILURE;
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/reset.c b/busybox/reset.c
deleted file mode 100644 (file)
index 755c4c3..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini reset implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *        and Kent Robotti <robotti@metconnect.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int reset_main(int argc, char **argv)
-{
-       printf("\033c");
-       return EXIT_SUCCESS;
-}
-
diff --git a/busybox/rm.c b/busybox/rm.c
deleted file mode 100644 (file)
index 51c9f4c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rm implementation for busybox
- *
- *
- * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <utime.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int rm_main(int argc, char **argv)
-{
-       int status = 0;
-       int opt;
-       int flags = 0;
-       int i;
-
-       while ((opt = getopt(argc, argv, "fiRr")) != -1) {
-               switch (opt) {
-               case 'f':
-                       flags &= ~FILEUTILS_INTERACTIVE;
-                       flags |= FILEUTILS_FORCE;
-                       break;
-               case 'i':
-                       flags &= ~FILEUTILS_FORCE;
-                       flags |= FILEUTILS_INTERACTIVE;
-                       break;
-               case 'R':
-               case 'r':
-                       flags |= FILEUTILS_RECUR;
-                       break;
-               }
-       }
-
-       if (!(flags & FILEUTILS_FORCE) && optind == argc)
-               show_usage();
-
-       for (i = optind; i < argc; i++) {
-               char *base = get_last_path_component(argv[i]);
-
-               if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) {
-                       error_msg("cannot remove `.' or `..'");
-                       status = 1;
-                       continue;
-               }
-
-               if (remove_file(argv[i], flags) < 0)
-                       status = 1;
-       }
-
-       return status;
-}
diff --git a/busybox/rmdir.c b/busybox/rmdir.c
deleted file mode 100644 (file)
index cac27ca..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rmdir implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <getopt.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-
-
-/* Return true if a path is composed of multiple components.  */
-
-static int
-multiple_components_p (const char *path)
-{
-       const char *s = path;
-
-       while (s[0] != '\0' && s[0] != '/')
-               s++;
-
-       while (s[0] == '/')
-               s++;
-
-       return (s[0] != '\0');
-}
-
-
-/* Remove a directory.  Returns 0 if successful, -1 on error.  */
-
-static int
-remove_directory (char *path, int flags)
-{
-       if (!(flags & FILEUTILS_RECUR)) {
-               if (rmdir (path) < 0) {
-                       perror_msg ("unable to remove `%s'", path);
-                       return -1;
-               }
-       } else {
-               if (remove_directory (path, 0) < 0)
-                       return -1;
-
-               if (multiple_components_p (path))
-                       if (remove_directory (dirname (path), flags) < 0)
-                               return -1;
-       }
-
-       return 0;
-}
-
-
-extern int
-rmdir_main (int argc, char **argv)
-{
-       int status = EXIT_SUCCESS;
-       int flags = 0;
-       int i, opt;
-
-       while ((opt = getopt (argc, argv, "p")) != -1)
-               switch (opt) {
-                       case 'p':
-                               flags |= FILEUTILS_RECUR;
-                               break;
-
-                       default:
-                               show_usage ();
-               }
-
-       if (optind == argc)
-               show_usage();
-
-       for (i = optind; i < argc; i++)
-               if (remove_directory (argv[i], flags) < 0)
-                       status = EXIT_FAILURE;
-
-       return status;
-}
diff --git a/busybox/rmmod.c b/busybox/rmmod.c
deleted file mode 100644 (file)
index 7596d02..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rmmod implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "busybox.h"
-
-extern int delete_module(const char * name);
-
-
-extern int rmmod_main(int argc, char **argv)
-{
-       int n, ret = EXIT_SUCCESS;
-
-       /* Parse command line. */
-       while ((n = getopt(argc, argv, "a")) != EOF) {
-               switch (n) {
-                       case 'a':
-                               /* Unload _all_ unused modules via NULL delete_module() call */
-                               if (delete_module(NULL))
-                                       perror_msg_and_die("rmmod");
-                               return EXIT_SUCCESS;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)
-                       show_usage();
-
-       for (n = optind; n < argc; n++) {
-               if (delete_module(argv[n]) < 0) {
-                       perror_msg("%s", argv[n]);
-                       ret = EXIT_FAILURE;
-               }
-       }
-
-       return(ret);
-}
diff --git a/busybox/route.c b/busybox/route.c
deleted file mode 100644 (file)
index 9d210af..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/* route
- *
- * Similar to the standard Unix route, but with only the necessary
- * parts for AF_INET
- *
- * Bjorn Wesen, Axis Communications AB
- *
- * Author of the original route:
- *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *              (derived from FvK's 'route.c     1.70    01/04/94')
- *
- * This program is free software; you can redistribute it
- * and/or  modify it under  the terms of  the GNU General
- * Public  License as  published  by  the  Free  Software
- * Foundation;  either  version 2 of the License, or  (at
- * your option) any later version.
- *
- * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
- * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/route.h>
-#include <linux/param.h>  // HZ
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <ctype.h>
-#include "busybox.h"
-
-#define _(x) x
-
-#define RTACTION_ADD   1
-#define RTACTION_DEL   2
-#define RTACTION_HELP  3
-#define RTACTION_FLUSH 4
-#define RTACTION_SHOW  5
-
-#define E_NOTFOUND      8
-#define E_SOCK          7
-#define E_LOOKUP        6
-#define E_VERSION       5
-#define E_USAGE         4
-#define E_OPTERR        3
-#define E_INTERN        2
-#define E_NOSUPP        1
-
-/* resolve XXX.YYY.ZZZ.QQQ -> binary */
-
-static int
-INET_resolve(char *name, struct sockaddr *sa)
-{
-       struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
-
-       s_in->sin_family = AF_INET;
-       s_in->sin_port = 0;
-
-       /* Default is special, meaning 0.0.0.0. */
-       if (strcmp(name, "default")==0) {
-               s_in->sin_addr.s_addr = INADDR_ANY;
-               return 1;
-       }
-       /* Look to see if it's a dotted quad. */
-       if (inet_aton(name, &s_in->sin_addr)) {
-               return 0;
-       }
-       /* guess not.. */
-       return -1;
-}
-
-#if defined (SIOCADDRTOLD) || defined (RTF_IRTT)        /* route */
-#define HAVE_NEW_ADDRT 1
-#endif
-#ifdef RTF_IRTT                 /* route */
-#define HAVE_RTF_IRTT 1
-#endif
-#ifdef RTF_REJECT               /* route */
-#define HAVE_RTF_REJECT 1
-#endif
-
-#if HAVE_NEW_ADDRT
-#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
-#define full_mask(x) (x)
-#else
-#define mask_in_addr(x) ((x).rt_genmask)
-#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
-#endif
-
-/* add or delete a route depending on action */
-
-static int
-INET_setroute(int action, int options, char **args)
-{
-       struct rtentry rt;
-       char target[128], gateway[128] = "NONE", netmask[128] = "default";
-       int xflag, isnet;
-       int skfd;
-
-       xflag = 0;
-
-       if (*args == NULL)
-           show_usage();
-       if (strcmp(*args, "-net")==0) {
-               xflag = 1;
-               args++;
-       } else if (strcmp(*args, "-host")==0) {
-               xflag = 2;
-               args++;
-       }
-       safe_strncpy(target, *args++, (sizeof target));
-
-       /* Clean out the RTREQ structure. */
-       memset((char *) &rt, 0, sizeof(struct rtentry));
-
-
-       if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
-               error_msg(_("can't resolve %s"), target);
-               return EXIT_FAILURE;   /* XXX change to E_something */
-       }
-
-       switch (xflag) {
-               case 1:
-                       isnet = 1;
-                       break;
-
-               case 2:
-                       isnet = 0;
-                       break;
-
-               default:
-                       break;
-       }
-
-       /* Fill in the other fields. */
-       rt.rt_flags = (RTF_UP | RTF_HOST);
-       if (isnet)
-               rt.rt_flags &= ~RTF_HOST;
-
-       while (*args) {
-               if (strcmp(*args, "metric")==0) {
-                       int metric;
-
-                       args++;
-                       if (!*args || !isdigit(**args))
-                               show_usage();
-                       metric = atoi(*args);
-#if HAVE_NEW_ADDRT
-                       rt.rt_metric = metric + 1;
-#else
-                       ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");  /* XXX Fixme */
-#endif
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "netmask")==0) {
-                       struct sockaddr mask;
-
-                       args++;
-                       if (!*args || mask_in_addr(rt))
-                               show_usage();
-                       safe_strncpy(netmask, *args, (sizeof netmask));
-                       if ((isnet = INET_resolve(netmask, &mask)) < 0) {
-                               error_msg(_("can't resolve netmask %s"), netmask);
-                               return E_LOOKUP;
-                       }
-                       rt.rt_genmask = full_mask(mask);
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       if (rt.rt_flags & RTF_GATEWAY)
-                               show_usage();
-                       safe_strncpy(gateway, *args, (sizeof gateway));
-                       if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
-                               error_msg(_("can't resolve gw %s"), gateway);
-                               return E_LOOKUP;
-                       }
-                       if (isnet) {
-                               error_msg(
-                                       _("%s: cannot use a NETWORK as gateway!"),
-                                       gateway);
-                               return E_OPTERR;
-                       }
-                       rt.rt_flags |= RTF_GATEWAY;
-                       args++;
-                       continue;
-               }
-
-               if (strcmp(*args, "mss")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_MSS;
-                       if (!*args)
-                               show_usage();
-                       rt.rt_mss = atoi(*args);
-                       args++;
-                       if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
-                               error_msg(_("Invalid MSS."));
-                               return E_OPTERR;
-                       }
-                       continue;
-               }
-
-               if (strcmp(*args, "window")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       rt.rt_flags |= RTF_WINDOW;
-                       rt.rt_window = atoi(*args);
-                       args++;
-                       if (rt.rt_window < 128) {
-                               error_msg(_("Invalid window."));
-                               return E_OPTERR;
-                       }
-                       continue;
-               }
-
-               if (strcmp(*args, "irtt")==0) {
-                       args++;
-                       if (!*args)
-                               show_usage();
-                       args++;
-#if HAVE_RTF_IRTT
-                       rt.rt_flags |= RTF_IRTT;
-                       rt.rt_irtt = atoi(*(args - 1));
-                       rt.rt_irtt *= (HZ / 100);       /* FIXME */
-#if 0                           /* FIXME: do we need to check anything of this? */
-                       if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
-                               error_msg(_("Invalid initial rtt."));
-                               return E_OPTERR;
-                       }
-#endif
-#else
-                       ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
-#endif
-                       continue;
-               }
-
-               if (strcmp(*args, "reject")==0) {
-                       args++;
-#if HAVE_RTF_REJECT
-                       rt.rt_flags |= RTF_REJECT;
-#else
-                       ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
-#endif
-                       continue;
-               }
-               if (strcmp(*args, "mod")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_MODIFIED;
-                       continue;
-               }
-               if (strcmp(*args, "dyn")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_DYNAMIC;
-                       continue;
-               }
-               if (strcmp(*args, "reinstate")==0) {
-                       args++;
-                       rt.rt_flags |= RTF_REINSTATE;
-                       continue;
-               }
-               if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
-                       args++;
-                       if (rt.rt_dev || *args == NULL)
-                               show_usage();
-                       rt.rt_dev = *args++;
-                       continue;
-               }
-               /* nothing matches */
-               if (!rt.rt_dev) {
-                       rt.rt_dev = *args++;
-                       if (*args)
-                               show_usage();   /* must be last to catch typos */
-               } else {
-                       show_usage();
-               }
-       }
-
-#if HAVE_RTF_REJECT
-       if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
-               rt.rt_dev = "lo";
-#endif
-
-       /* sanity checks.. */
-       if (mask_in_addr(rt)) {
-               unsigned long mask = mask_in_addr(rt);
-               mask = ~ntohl(mask);
-               if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
-                       error_msg(
-                               _("netmask %.8x doesn't make sense with host route"),
-                               (unsigned int)mask);
-                       return E_OPTERR;
-               }
-               if (mask & (mask + 1)) {
-                       error_msg(_("bogus netmask %s"), netmask);
-                       return E_OPTERR;
-               }
-               mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
-               if (mask & ~mask_in_addr(rt)) {
-                       error_msg(_("netmask doesn't match route address"));
-                       return E_OPTERR;
-               }
-       }
-       /* Fill out netmask if still unset */
-       if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
-               mask_in_addr(rt) = 0xffffffff;
-
-       /* Create a socket to the INET kernel. */
-       if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror("socket");
-               return E_SOCK;
-       }
-       /* Tell the kernel to accept this route. */
-       if (action == RTACTION_DEL) {
-               if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
-                       perror("SIOCDELRT");
-                       close(skfd);
-                       return E_SOCK;
-               }
-       } else {
-               if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
-                       perror("SIOCADDRT");
-                       close(skfd);
-                       return E_SOCK;
-               }
-       }
-
-       /* Close the socket. */
-       (void) close(skfd);
-       return EXIT_SUCCESS;
-}
-
-#ifndef RTF_UP
-/* Keep this in sync with /usr/src/linux/include/linux/route.h */
-#define RTF_UP          0x0001          /* route usable                 */
-#define RTF_GATEWAY     0x0002          /* destination is a gateway     */
-#define RTF_HOST        0x0004          /* host entry (net otherwise)   */
-#define RTF_REINSTATE   0x0008          /* reinstate route after tmout  */
-#define RTF_DYNAMIC     0x0010          /* created dyn. (by redirect)   */
-#define RTF_MODIFIED    0x0020          /* modified dyn. (by redirect)  */
-#define RTF_MTU         0x0040          /* specific MTU for this route  */
-#ifndef RTF_MSS
-#define RTF_MSS         RTF_MTU         /* Compatibility :-(            */
-#endif
-#define RTF_WINDOW      0x0080          /* per route window clamping    */
-#define RTF_IRTT        0x0100          /* Initial round trip time      */
-#define RTF_REJECT      0x0200          /* Reject route                 */
-#endif
-
-static void displayroutes(void)
-{
-       char buff[256];
-       int  nl = 0 ;
-       struct in_addr dest;
-       struct in_addr gw;
-       struct in_addr mask;
-       int flgs, ref, use, metric;
-       char flags[64];
-       unsigned long int d,g,m;
-
-       char sdest[16], sgw[16];
-
-
-       FILE *fp = xfopen("/proc/net/route", "r");
-
-       while( fgets(buff, sizeof(buff), fp) != NULL ) {
-               if(nl) {
-                       int ifl = 0;
-                       while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
-                               ifl++;
-                       buff[ifl]=0;    /* interface */
-                       if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx",
-                          &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
-                               error_msg_and_die( "Unsuported kernel route format\n");
-                       }
-                       if(nl==1)
-                       printf("Kernel IP routing table\n"
-                               "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface\n");
-
-                       ifl = 0;        /* parse flags */
-                       if(flgs&RTF_UP) {
-                               if(flgs&RTF_REJECT)
-                                       flags[ifl++]='!';
-                               else
-                                       flags[ifl++]='U';
-                               if(flgs&RTF_GATEWAY)
-                                       flags[ifl++]='G';
-                               if(flgs&RTF_HOST)
-                                       flags[ifl++]='H';
-                               if(flgs&RTF_REINSTATE)
-                                       flags[ifl++]='R';
-                               if(flgs&RTF_DYNAMIC)
-                                       flags[ifl++]='D';
-                               if(flgs&RTF_MODIFIED)
-                                       flags[ifl++]='M';
-                               flags[ifl]=0;
-                               dest.s_addr = d;
-                               gw.s_addr   = g;
-                               mask.s_addr = m;
-                               strcpy(sdest,  (dest.s_addr==0 ? "default" :
-                                       inet_ntoa(dest)));
-                               strcpy(sgw,    (gw.s_addr==0   ? "*"       :
-                                       inet_ntoa(gw)));
-                               printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
-                                       sdest, sgw,
-                                       inet_ntoa(mask),
-                                       flags, metric, ref, use, buff);
-                       }
-               }
-               nl++;
-       }
-}
-
-int route_main(int argc, char **argv)
-{
-       int what = 0;
-
-       argc--;
-       argv++;
-
-       if (*argv == NULL) {
-               displayroutes();
-               return EXIT_SUCCESS;
-       } else {
-               /* check verb */
-               if (strcmp(*argv, "add")==0)
-                       what = RTACTION_ADD;
-               else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
-                       what = RTACTION_DEL;
-               else if (strcmp(*argv, "flush")==0)
-                       what = RTACTION_FLUSH;
-               else
-                       show_usage();
-       }
-
-       return INET_setroute(what, 0, ++argv);
-}
diff --git a/busybox/rpm2cpio.c b/busybox/rpm2cpio.c
deleted file mode 100644 (file)
index 8d639d6..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini rpm2cpio implementation for busybox
- *
- * Copyright (C) 2001 by Laurence Anderson
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "busybox.h"
-#include <netinet/in.h> /* For ntohl & htonl function */
-#include <string.h>
-
-#define RPM_MAGIC "\355\253\356\333"
-#define RPM_HEADER_MAGIC "\216\255\350"
-
-struct rpm_lead {
-    unsigned char magic[4];
-    u_int8_t major, minor;
-    u_int16_t type;
-    u_int16_t archnum;
-    char name[66];
-    u_int16_t osnum;
-    u_int16_t signature_type;
-    char reserved[16];
-};
-
-struct rpm_header {
-       char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
-       u_int8_t version; /* 1 byte version number */
-       u_int32_t reserved; /* 4 bytes reserved */
-       u_int32_t entries; /* Number of entries in header (4 bytes) */
-       u_int32_t size; /* Size of store (4 bytes) */
-};
-
-void skip_header(FILE *rpmfile)
-{
-       struct rpm_header header;
-
-       fread(&header, sizeof(struct rpm_header), 1, rpmfile);
-       if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */
-       if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */
-       header.entries = ntohl(header.entries);
-       header.size = ntohl(header.size);
-       fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
-       fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */
-}
-
-/* No getopt required */
-extern int rpm2cpio_main(int argc, char **argv)
-{
-       struct rpm_lead lead;
-       int gunzip_pid;
-       FILE *rpmfile, *cpiofile;
-
-       if (argc == 1) {
-               rpmfile = stdin;
-       } else {
-               rpmfile = fopen(argv[1], "r");
-               if (!rpmfile) perror_msg_and_die("Can't open rpm file");
-               /* set the buffer size */
-               setvbuf(rpmfile, NULL, _IOFBF, 0x8000);
-       }
-
-       fread (&lead, sizeof(struct rpm_lead), 1, rpmfile);
-       if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
-       /* Skip the signature header */
-       skip_header(rpmfile);
-       fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */
-       /* Skip the main header */
-       skip_header(rpmfile);
-
-       cpiofile = gz_open(rpmfile, &gunzip_pid);
-
-       copyfd(fileno(cpiofile), fileno(stdout));
-       gz_close(gunzip_pid);
-       fclose(rpmfile);
-       return 0;
-}
diff --git a/busybox/scripts/depmod.pl b/busybox/scripts/depmod.pl
deleted file mode 100755 (executable)
index e65f07b..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/perl -w
-# vi: set ts=4:
-# Copyright (c) 2001 David Schleef <ds@schleef.org>
-# Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
-# Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
-# This program is free software; you can redistribute it and/or modify it 
-# under the same terms as Perl itself.
-
-# TODO -- use strict mode...
-#use strict;
-
-use Getopt::Long;
-use File::Find;
-
-
-# Set up some default values
-
-my $basedir="";
-my $kernel;
-my $kernelsyms;
-my $stdout=1;
-my $verbose=0;
-
-
-# get command-line options
-
-my %opt;
-
-GetOptions(
-       \%opt,
-       "help|h",
-       "basedir|b=s" => \$basedir,
-       "kernel|k=s" => \$kernel,
-       "kernelsyms|F=s" => \$kernelsyms,
-       "stdout|n" => \$stdout,
-       "verbose|v" => \$verbose,
-);
-
-if (defined $opt{help}) {
-       print
-               "$0 [OPTION]... [basedir]\n",
-               "\t-h --help\t\tShow this help screen\n",
-               "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n",
-               "\t-k --kernel\t\tKernel binary for the target\n",
-               "\t-F --kernelsyms\t\tKernel symbol file\n",
-               "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n",
-               "\t-v --verbose\t\tPrint out lots of debugging stuff\n",
-       ;
-       exit 1;
-}
-
-if($basedir !~ m-/lib/modules-) {
-    warn "WARNING: base directory does not match ..../lib/modules\n";
-}
-
-# Find the list of .o files living under $basedir 
-#if ($verbose) { printf "Locating all modules\n"; }
-my($file) = "";
-my(@liblist) = ();
-find sub { 
-       if ( -f $_  && ! -d $_ ) { 
-               $file = $File::Find::name;
-               if ( $file =~ /.o$/ ) {
-                       push(@liblist, $file);
-                       if ($verbose) { printf "$file\n"; }
-               }
-       }
-}, $basedir;
-if ($verbose) { printf "Finished locating modules\n"; }
-
-foreach $obj ( @liblist, $kernel ){
-    # turn the input file name into a target tag name
-    # vmlinux is a special that is only used to resolve symbols
-    if($obj =~ /vmlinux/) {
-        $tgtname = "vmlinux";
-    } else {
-        ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
-    }
-
-    warn "MODULE = $tgtname\n" if $verbose;
-
-    # get a list of symbols
-       @output=`nm $obj`;
-       $ksymtab=grep m/ __ksymtab/, @output;
-
-    # gather the exported symbols
-       if($ksymtab){
-        # explicitly exported
-        foreach ( @output ) {
-            / __ksymtab_(.*)$/ and do {
-                warn "sym = $1\n" if $verbose;
-                $exp->{$1} = $tgtname;
-            };
-        }
-       } else {
-        # exporting all symbols
-        foreach ( @output) {
-            / [ABCDGRST] (.*)$/ and do {
-                warn "syma = $1\n" if $verbose;
-                $exp->{$1} = $tgtname;
-            };
-        }
-       }
-    # gather the unresolved symbols
-    foreach ( @output ) {
-        !/ __this_module/ && / U (.*)$/ and do {
-            warn "und = $1\n" if $verbose;
-            push @{$dep->{$tgtname}}, $1;
-        };
-    }
-}
-
-
-# reduce dependancies: remove unresolvable and resolved from vmlinux
-# remove duplicates
-foreach $module (keys %$dep) {
-    $mod->{$module} = {};
-    foreach (@{$dep->{$module}}) {
-        if( $exp->{$_} ) { 
-            warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
-            next if $exp->{$_} =~ /vmlinux/;
-            $mod->{$module}{$exp->{$_}} = 1;
-        } else {
-            warn "unresolved symbol $_ in file $module\n";
-        }
-    } 
-}
-
-# resolve the dependancies for each module
-foreach $module ( keys %$mod )  {
-    print "$module:\t";
-    @sorted = sort bydep keys %{$mod->{$module}};
-    print join(" \\\n\t",@sorted);
-#    foreach $m (@sorted ) {
-#        print "\t$m\n";
-#    }
-    print "\n\n";
-}
-
-sub bydep
-{
-    foreach my $f ( keys %{$mod->{$b}} ) {
-        if($f eq $a) {
-            return 1;
-        }
-    }
-    return -1;
-}
-
-
-
-__END__
-
-=head1 NAME
-
-depmod.pl - a cross platform script to generate kernel module dependency
-               lists which can then be used by modprobe.
-
-=head1 SYNOPSIS
-
-depmod.pl [OPTION]... [FILE]...
-
-Example:
-
-       depmod.pl -F linux/System.map target/lib/modules
-
-=head1 DESCRIPTION
-
-The purpose of this script is to automagically generate a list of of kernel
-module dependancies.  This script produces dependancy lists that should be
-identical to the depmod program from the modutils package.  Unlike the depmod
-binary, however, depmod.pl is designed to be run on your host system, not
-on your target system.
-
-This script was written by David Schleef <ds@schleef.org> to be used in
-conjunction with the BusyBox modprobe applet.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-h --help>
-
-This displays the help message.
-
-=item B<-b --basedir>
-
-The base directory uner which the target's modules will be found.  This
-defaults to the /lib/modules directory.
-
-=item B<-k --kernel>
-
-Kernel binary for the target.  You must either supply a kernel binary
-or a kernel symbol file (using the -F option).
-
-=item B<-F --kernelsyms>
-
-Kernel symbol file for the target.  You must supply either a kernel symbol file
-kernel binary for the target (using the -k option).
-
-=item B<-n --stdout>
-
-Write to stdout instead of modules.dep.  This is currently hard coded...
-kernel binary for the target (using the -k option).
-
-=item B<--verbose>
-
-Be verbose (not implemented)
-
-=back
-
-=head1 COPYRIGHT
-
-Copyright (c) 2001 David Schleef <ds@schleef.org>
-Copyright (c) 2001 Erik Andersen <andersen@lineo.com>
-Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
-This program is free software; you can redistribute it and/or modify it 
-under the same terms as Perl itself.
-
-=head1 AUTHOR
-
-David Schleef <ds@schleef.org>
-
-=cut
-
-# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $
-
diff --git a/busybox/scripts/inittab b/busybox/scripts/inittab
deleted file mode 100644 (file)
index 8e7e945..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# /etc/inittab init(8) configuration for BusyBox
-#
-# Copyright (C) 1999 by Lineo, inc.  Written by Erik Andersen
-# <andersen@lineo.com>, <andersee@debian.org>
-#
-#
-# Note, BusyBox init doesn't support runlevels.  The runlevels field is
-# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
-#
-#
-# Format for each entry: <id>:<runlevels>:<action>:<process>
-#
-# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
-#
-#      The id field is used by BusyBox init to specify the controlling tty for
-#      the specified process to run on.  The contents of this field are
-#      appended to "/dev/" and used as-is.  There is no need for this field to
-#      be unique, although if it isn't you may have strange results.  If this
-#      field is left blank, it is completely ignored.  Also note that if
-#      BusyBox detects that a serial console is in use, then all entries
-#      containing non-empty id fields will _not_ be run.  BusyBox init does
-#      nothing with utmp.  We don't need no stinkin' utmp.
-#
-# <runlevels>: The runlevels field is completely ignored.
-#
-# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once, 
-#                                  ctrlaltdel, and shutdown.
-#
-#       Note: askfirst acts just like respawn, but before running the specified
-#       process it displays the line "Please press Enter to activate this
-#       console." and then waits for the user to press enter before starting
-#       the specified process.
-#
-#       Note: unrecognised actions (like initdefault) will cause init to emit
-#       an error message, and then go along with its business.
-#
-# <process>: Specifies the process to be executed and it's command line.
-#
-# Note: BusyBox init works just fine without an inittab. If no inittab is
-# found, it has the following default behavior:
-#         ::sysinit:/etc/init.d/rcS
-#         ::askfirst:/bin/sh
-#         ::ctrlaltdel:/sbin/reboot
-#         ::shutdown:/sbin/swapoff -a
-#         ::shutdown:/bin/umount -a -r
-# if it detects that /dev/console is _not_ a serial console, it will
-# also run:
-#         tty2::askfirst:/bin/sh
-#         tty3::askfirst:/bin/sh
-#         tty4::askfirst:/bin/sh
-#
-# Boot-time system configuration/initialization script.
-# This is run first except when booting in single-user mode.
-#
-::sysinit:/etc/init.d/rcS
-
-# /bin/sh invocations on selected ttys
-#
-# Note below that we prefix the shell commands with a "-" to indicate to the
-# shell that it is supposed to be a login shell.  Normally this is handled by
-# login, but since we are bypassing login in this case, BusyBox lets you do
-# this yourself...
-#
-# Start an "askfirst" shell on the console (whatever that may be)
-::askfirst:-/bin/sh
-# Start an "askfirst" shell on /dev/tty2-4
-tty2::askfirst:-/bin/sh
-tty3::askfirst:-/bin/sh
-tty4::askfirst:-/bin/sh
-
-# /sbin/getty invocations for selected ttys
-tty4::respawn:/sbin/getty 38400 tty5
-tty5::respawn:/sbin/getty 38400 tty6
-
-# Example of how to put a getty on a serial line (for a terminal)
-#::respawn:/sbin/getty -L ttyS0 9600 vt100
-#::respawn:/sbin/getty -L ttyS1 9600 vt100
-#
-# Example how to put a getty on a modem line.
-#::respawn:/sbin/getty 57600 ttyS2
-
-# Stuff to do before rebooting
-::ctrlaltdel:/sbin/reboot
-::shutdown:/bin/umount -a -r
-::shutdown:/sbin/swapoff -a
-
diff --git a/busybox/scripts/mk2knr.pl b/busybox/scripts/mk2knr.pl
deleted file mode 100755 (executable)
index aaf4963..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/perl -w
-#
-# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
-#
-# How to use this script:
-#  - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert'
-#  - Review the 'convertme.pl' script generated and remove / edit any of the
-#    substitutions in there (please especially check for false positives)
-#  - Type './convertme.pl same-files-as-before'
-#  - Compile and see if it works
-#
-# BUGS: This script does not ignore strings inside comments or strings inside
-# quotes (it probably should).
-
-# set this to something else if you want
-$convertme = 'convertme.pl';
-
-# internal-use variables (don't touch)
-$convert = 0;
-%converted = ();
-
-# if no files were specified, print usage
-die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0;
-
-# prepare the "convert me" file
-open(CM, ">$convertme") or die "convertme.pl $!";
-print CM "#!/usr/bin/perl -p -i\n\n";
-
-# process each file passed on the cmd line
-while (<>) {
-
-       # if the line says "getopt" in it anywhere, we don't want to muck with it
-       # because option lists tend to include strings like "cxtzvOf:" which get
-       # matched by the "check for mixed case" regexps below
-       next if /getopt/;
-
-       # tokenize the string into just the variables
-       while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) {
-               $var = $1;
-
-               # ignore the word "BusyBox"
-               next if ($var =~ /BusyBox/);
-
-               # this checks for javaStyle or szHungarianNotation
-               $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/);
-
-               # this checks for PascalStyle
-               $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/);
-
-               # if we want to add more checks, we can add 'em here, but the above
-               # checks catch "just enough" and not too much, so prolly not.
-
-               if ($convert) {
-                       $convert = 0;
-
-                       # skip ahead if we've already dealt with this one
-                       next if ($converted{$var});
-
-                       # record that we've dealt with this var
-                       $converted{$var} = 1;
-
-                       print CM "s/\\b$var\\b/"; # more to come in just a minute
-
-                       # change the first letter to lower-case
-                       $var = lcfirst($var);
-
-                       # put underscores before all remaining upper-case letters
-                       $var =~ s/([A-Z])/_$1/g;
-
-                       # now change the remaining characters to lower-case
-                       $var = lc($var);
-
-                       print CM "$var/g;\n";
-               }
-       }
-}
-
-# tidy up and make the $convertme script executable
-close(CM);
-chmod 0755, $convertme;
-
-# print a helpful help message
-print "Done. Scheduled name changes are in $convertme.\n";
-print "Please review/modify it and then type ./$convertme to do the search & replace.\n";
diff --git a/busybox/scripts/undeb b/busybox/scripts/undeb
deleted file mode 100644 (file)
index a72e1e2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-#
-# This should work with the GNU version of tar and gzip!
-# This should work with the bash or ash shell!
-# Requires the programs (ar, tar, gzip, and the pager more or less).
-#
-usage() {
-echo "Usage: undeb -c package.deb            <Print control file info>"
-echo "       undeb -l package.deb            <List contents of deb package>"
-echo "       undeb -x package.deb /foo/boo   <Extract deb package to this directory,"
-echo "                                        put . for current directory>"  
-exit
-}
-
-deb=$2
-exist() {
-if [ "$deb" = "" ]; then
-usage
-elif [ ! -s "$deb" ]; then
-echo "Can't find $deb!"
-exit
-fi
-}
-
-if [ "$1" = "" ]; then
-usage
-elif [ "$1" = "-l" ]; then
-exist
-type more >/dev/null 2>&1 && pager=more
-type less >/dev/null 2>&1 && pager=less
-[ "$pager" = "" ] && echo "No pager found!" && exit
-(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager 
-exit
-elif [ "$1" = "-c" ]; then
-exist
-ar -p $deb control.tar.gz | tar -xzO *control  
-exit
-elif [ "$1" = "-x" ]; then
-exist
-if [ "$3" = "" ]; then
-usage
-elif [ ! -d "$3" ]; then
-echo "No such directory $3!"
-exit
-fi
-ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit 
-echo
-echo "Extracted $deb to $3!"
-exit
-else
-usage
-fi
diff --git a/busybox/scripts/unrpm b/busybox/scripts/unrpm
deleted file mode 100644 (file)
index 376286a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/sh
-#
-# This should work with the GNU version of cpio and gzip!
-# This should work with the bash or ash shell!
-# Requires the programs (cpio, gzip, and the pager more or less).
-#
-usage() {
-echo "Usage: unrpm -l package.rpm            <List contents of rpm package>"
-echo "       unrpm -x package.rpm /foo/boo   <Extract rpm package to this directory,"
-echo "                                        put . for current directory>"  
-exit
-}
-
-rpm=$2
-exist() {
-if [ "$rpm" = "" ]; then
-usage
-elif [ ! -s "$rpm" ]; then
-echo "Can't find $rpm!"
-exit
-fi
-}
-
-if [ "$1" = "" ]; then
-usage
-elif [ "$1" = "-l" ]; then
-exist
-type more >/dev/null 2>&1 && pager=more
-type less >/dev/null 2>&1 && pager=less
-[ "$pager" = "" ] && echo "No pager found!" && exit
-(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager
-exit
-elif [ "$1" = "-x" ]; then
-exist
-if [ "$3" = "" ]; then
-usage
-elif [ ! -d "$3" ]; then
-echo "No such directory $3!"
-exit
-fi
-rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit
-echo
-echo "Extracted $rpm to $3!"
-exit
-else
-usage
-fi
diff --git a/busybox/sed.c b/busybox/sed.c
deleted file mode 100644 (file)
index 709fb13..0000000
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * sed.c - very minimalist version of sed
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/*
-       Supported features and commands in this version of sed:
-
-        - comments ('#')
-        - address matching: num|/matchstr/[,num|/matchstr/|$]command
-        - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
-        - edit commands: (a)ppend, (i)nsert, (c)hange
-        - file commands: (r)ead
-        - backreferences in substitution expressions (\1, \2...\9)
-        
-        (Note: Specifying an address (range) to match is *optional*; commands
-        default to the whole pattern space if no specific address match was
-        requested.)
-
-       Unsupported features:
-
-        - transliteration (y/source-chars/dest-chars/) (use 'tr')
-        - no pattern space hold space storing / swapping (x, etc.)
-        - no labels / branching (: label, b, t, and friends)
-        - and lots, lots more.
-*/
-
-#include <stdio.h>
-#include <unistd.h> /* for getopt() */
-#include <regex.h>
-#include <string.h> /* for strdup() */
-#include <errno.h>
-#include <ctype.h> /* for isspace() */
-#include <stdlib.h>
-#include "busybox.h"
-
-/* externs */
-extern void xregcomp(regex_t *preg, const char *regex, int cflags);
-extern int optind; /* in unistd.h */
-extern char *optarg; /* ditto */
-
-/* options */
-static int be_quiet = 0;
-
-
-struct sed_cmd {
-
-
-       /* GENERAL FIELDS */
-       char delimiter;     /* The delimiter used to separate regexps */
-
-       /* address storage */
-       int beg_line; /* 'sed 1p'   0 == no begining line, apply commands to all lines */
-       int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */
-       regex_t *beg_match; /* sed -e '/match/cmd' */
-       regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
-
-       /* the command */
-       char cmd; /* p,d,s (add more at your leisure :-) */
-
-
-       /* SUBSTITUTION COMMAND SPECIFIC FIELDS */
-
-       /* sed -e 's/sub_match/replace/' */
-       regex_t *sub_match;
-       char *replace;
-       unsigned int num_backrefs:4; /* how many back references (\1..\9) */
-                       /* Note:  GNU/POSIX sed does not save more than nine backrefs, so
-                        * we only use 4 bits to hold the number */
-       unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
-       unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */
-
-
-       /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */
-
-       char *editline;
-
-
-       /* FILE COMMAND (r) SPEICIFIC FIELDS */
-
-       char *filename;
-};
-
-/* globals */
-static struct sed_cmd *sed_cmds = NULL; /* growable arrary holding a sequence of sed cmds */
-static int ncmds = 0; /* number of sed commands */
-
-/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */
-
-#ifdef BB_FEATURE_CLEAN_UP
-static void destroy_cmd_strs()
-{
-       if (sed_cmds == NULL)
-               return;
-
-       /* destroy all the elements in the array */
-       while (--ncmds >= 0) {
-
-               if (sed_cmds[ncmds].beg_match) {
-                       regfree(sed_cmds[ncmds].beg_match);
-                       free(sed_cmds[ncmds].beg_match);
-               }
-               if (sed_cmds[ncmds].end_match) {
-                       regfree(sed_cmds[ncmds].end_match);
-                       free(sed_cmds[ncmds].end_match);
-               }
-               if (sed_cmds[ncmds].sub_match) {
-                       regfree(sed_cmds[ncmds].sub_match);
-                       free(sed_cmds[ncmds].sub_match);
-               }
-               if (sed_cmds[ncmds].replace)
-                       free(sed_cmds[ncmds].replace);
-       }
-
-       /* destroy the array */
-       free(sed_cmds);
-       sed_cmds = NULL;
-}
-#endif
-
-
-/*
- * index_of_next_unescaped_regexp_delim - walks left to right through a string
- * beginning at a specified index and returns the index of the next regular
- * expression delimiter (typically a forward * slash ('/')) not preceeded by 
- * a backslash ('\').
- */
-static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const char *str, int idx)
-{
-       int bracket = -1;
-       int escaped = 0;
-
-       for ( ; str[idx]; idx++) {
-               if (bracket != -1) {
-                       if (str[idx] == ']' && !(bracket == idx - 1 ||
-                                                                        (bracket == idx - 2 && str[idx-1] == '^')))
-                               bracket = -1;
-               } else if (escaped)
-                       escaped = 0;
-               else if (str[idx] == '\\')
-                       escaped = 1;
-               else if (str[idx] == '[')
-                       bracket = idx;
-               else if (str[idx] == sed_cmd->delimiter)
-                       return idx;
-       }
-
-       /* if we make it to here, we've hit the end of the string */
-       return -1;
-}
-
-/*
- * returns the index in the string just past where the address ends.
- */
-static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
-{
-       char *my_str = strdup(str);
-       int idx = 0;
-       char olddelimiter;
-       olddelimiter = sed_cmd->delimiter;
-       sed_cmd->delimiter = '/';
-
-       if (isdigit(my_str[idx])) {
-               do {
-                       idx++;
-               } while (isdigit(my_str[idx]));
-               my_str[idx] = 0;
-               *linenum = atoi(my_str);
-       }
-       else if (my_str[idx] == '$') {
-               *linenum = -1;
-               idx++;
-       }
-       else if (my_str[idx] == '/') {
-               idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx);
-               if (idx == -1)
-                       error_msg_and_die("unterminated match expression");
-               my_str[idx] = '\0';
-               *regex = (regex_t *)xmalloc(sizeof(regex_t));
-               xregcomp(*regex, my_str+1, REG_NEWLINE);
-               idx++; /* so it points to the next character after the last '/' */
-       }
-       else {
-               error_msg("get_address: no address found in string\n"
-                               "\t(you probably didn't check the string you passed me)");
-               idx = -1;
-       }
-
-       free(my_str);
-       sed_cmd->delimiter = olddelimiter;
-       return idx;
-}
-
-static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
-{
-       int oldidx, cflags = REG_NEWLINE;
-       char *match;
-       int idx = 0;
-       int j;
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *    s/match/replace/gIp
-        *    ||     |        |||
-        *    mandatory       optional
-        *
-        *    (all three of the '/' slashes are mandatory)
-        */
-
-       /* verify that the 's' is followed by something.  That something
-        * (typically a 'slash') is now our regexp delimiter... */
-       if (!substr[++idx])
-               error_msg_and_die("bad format in substitution expression");
-       else
-           sed_cmd->delimiter=substr[idx];
-
-       /* save the match string */
-       oldidx = idx+1;
-       idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
-       if (idx == -1)
-               error_msg_and_die("bad format in substitution expression");
-       match = xstrndup(substr + oldidx, idx - oldidx);
-
-       /* determine the number of back references in the match string */
-       /* Note: we compute this here rather than in the do_subst_command()
-        * function to save processor time, at the expense of a little more memory
-        * (4 bits) per sed_cmd */
-       
-       /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ 
-       for (j = 0; match[j]; j++) {
-               /* GNU/POSIX sed does not save more than nine backrefs */
-               if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9)
-                       sed_cmd->num_backrefs++;
-       }
-
-       /* save the replacement string */
-       oldidx = idx+1;
-       idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx);
-       if (idx == -1)
-               error_msg_and_die("bad format in substitution expression");
-       sed_cmd->replace = xstrndup(substr + oldidx, idx - oldidx);
-
-       /* process the flags */
-       while (substr[++idx]) {
-               switch (substr[idx]) {
-                       case 'g':
-                               sed_cmd->sub_g = 1;
-                               break;
-                       case 'I':
-                               cflags |= REG_ICASE;
-                               break;
-                       case 'p':
-                               sed_cmd->sub_p = 1;
-                               break;
-                       default:
-                               /* any whitespace or semicolon trailing after a s/// is ok */
-                               if (strchr("; \t\v\n\r", substr[idx]))
-                                       goto out;
-                               /* else */
-                               error_msg_and_die("bad option in substitution expression");
-               }
-       }
-
-out:   
-       /* compile the match string into a regex */
-       sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
-       xregcomp(sed_cmd->sub_match, match, cflags);
-       free(match);
-
-       return idx;
-}
-
-static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
-{
-       int idx = 0;
-       int slashes_eaten = 0;
-       char *ptr; /* shorthand */
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *
-        *    need one of these 
-        *    |
-        *    |    this backslash (immediately following the edit command) is mandatory
-        *    |    |
-        *    [aic]\
-        *    TEXT1\
-        *    TEXT2\
-        *    TEXTN
-        *
-        * as soon as we hit a TEXT line that has no trailing '\', we're done.
-        * this means a command like:
-        *
-        * i\
-        * INSERTME
-        *
-        * is a-ok.
-        *
-        */
-
-       if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r'))
-               error_msg_and_die("bad format in edit expression");
-
-       /* store the edit line text */
-       /* make editline big enough to accomodate the extra '\n' we will tack on
-        * to the end */
-       sed_cmd->editline = xmalloc(strlen(&editstr[3]) + 2);
-       strcpy(sed_cmd->editline, &editstr[3]);
-       ptr = sed_cmd->editline;
-
-       /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */
-       while (ptr[idx]) {
-               while (ptr[idx] != '\\' || (ptr[idx+1] != '\n' && ptr[idx+1] != '\r')) {
-                       idx++;
-                       if (!ptr[idx]) {
-                               goto out;
-                       }
-               }
-               /* move the newline over the '\' before it (effectively eats the '\') */
-               memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1]));
-               ptr[strlen(ptr)-1] = 0;
-               slashes_eaten++;
-               /* substitue \r for \n if needed */
-               if (ptr[idx] == '\r')
-                       ptr[idx] = '\n';
-       }
-
-out:
-       /* this accounts for discrepancies between the modified string and the
-        * original string passed in to this function */
-       idx += slashes_eaten;
-
-       /* figure out if we need to add a newline */
-       if (ptr[idx-1] != '\n') {
-               ptr[idx] = '\n';
-               idx++;
-       }
-
-       /* terminate string */
-       ptr[idx]= 0;
-       /* adjust for opening 2 chars [aic]\ */
-       idx += 2;
-
-       return idx;
-}
-
-
-static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr)
-{
-       int idx = 0;
-       int filenamelen = 0;
-
-       /*
-        * the string that gets passed to this function should look like this:
-        *    '[ ]filename'
-        *      |  |
-        *      |  a filename
-        *      |
-        *     optional whitespace
-
-        *   re: the file to be read, the GNU manual says the following: "Note that
-        *   if filename cannot be read, it is treated as if it were an empty file,
-        *   without any error indication." Thus, all of the following commands are
-        *   perfectly leagal:
-        *
-        *   sed -e '1r noexist'
-        *   sed -e '1r ;'
-        *   sed -e '1r'
-        */
-
-       /* the file command may be followed by whitespace; move past it. */
-       while (isspace(filecmdstr[++idx]))
-               { ; }
-               
-       /* the first non-whitespace we get is a filename. the filename ends when we
-        * hit a normal sed command terminator or end of string */
-       filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0");
-       sed_cmd->filename = xmalloc(filenamelen + 1);
-       safe_strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen + 1);
-
-       return idx + filenamelen;
-}
-
-
-static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
-{
-       int idx = 0;
-
-       /* parse the command
-        * format is: [addr][,addr]cmd
-        *            |----||-----||-|
-        *            part1 part2  part3
-        */
-
-       /* first part (if present) is an address: either a number or a /regex/ */
-       if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
-               idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
-
-       /* second part (if present) will begin with a comma */
-       if (cmdstr[idx] == ',')
-               idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match);
-
-       /* last part (mandatory) will be a command */
-       if (cmdstr[idx] == '\0')
-               error_msg_and_die("missing command");
-       sed_cmd->cmd = cmdstr[idx];
-
-       /* if it was a single-letter command that takes no arguments (such as 'p'
-        * or 'd') all we need to do is increment the index past that command */
-       if (strchr("pd", cmdstr[idx])) {
-               idx++;
-       }
-       /* handle (s)ubstitution command */
-       else if (sed_cmd->cmd == 's') {
-               idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
-       else if (strchr("aic", sed_cmd->cmd)) {
-               if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
-                       error_msg_and_die("only a beginning address can be specified for edit commands");
-               idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       /* handle file cmds: (r)ead */
-       else if (sed_cmd->cmd == 'r') {
-               if (sed_cmd->end_line || sed_cmd->end_match)
-                       error_msg_and_die("Command only uses one address");
-               idx += parse_file_cmd(sed_cmd, &cmdstr[idx]);
-       }
-       else {
-               error_msg_and_die("invalid command");
-       }
-
-       /* give back whatever's left over */
-       return (char *)&cmdstr[idx];
-}
-
-static void add_cmd_str(const char *cmdstr)
-{
-       char *mystr = (char *)cmdstr;
-
-       do {
-
-               /* trim leading whitespace and semicolons */
-               memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
-               /* if we ate the whole thing, that means there was just trailing
-                * whitespace or a final / no-op semicolon. either way, get out */
-               if (strlen(mystr) == 0)
-                       return;
-               /* if this is a comment, jump past it and keep going */
-               if (mystr[0] == '#') {
-                       mystr = strpbrk(mystr, ";\n\r");
-                       continue;
-               }
-               /* grow the array */
-               sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));
-               /* zero new element */
-               memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));
-               /* load command string into new array element, get remainder */
-               mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);
-
-       } while (mystr && strlen(mystr));
-}
-
-
-static void load_cmd_file(char *filename)
-{
-       FILE *cmdfile;
-       char *line;
-       char *nextline;
-
-       cmdfile = xfopen(filename, "r");
-
-       while ((line = get_line_from_file(cmdfile)) != NULL) {
-               /* if a line ends with '\' it needs the next line appended to it */
-               while (line[strlen(line)-2] == '\\' &&
-                               (nextline = get_line_from_file(cmdfile)) != NULL) {
-                       line = xrealloc(line, strlen(line) + strlen(nextline) + 1);
-                       strcat(line, nextline);
-                       free(nextline);
-               }
-               /* eat trailing newline (if any) --if I don't do this, edit commands
-                * (aic) will print an extra newline */
-               chomp(line);
-               add_cmd_str(line);
-               free(line);
-       }
-}
-
-#define PIPE_MAGIC 0x7f
-#define PIPE_GROW 64  
-#define pipeputc(c) \
-{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \
-       pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \
-       memset(pipeline+pipeline_len, 0, PIPE_GROW); \
-       pipeline_len += PIPE_GROW; \
-       pipeline[pipeline_len-1] = PIPE_MAGIC; } \
-       pipeline[pipeline_idx++] = (c); }
-
-static void print_subst_w_backrefs(const char *line, const char *replace, 
-       regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, 
-       int *pipeline_len_p, int matches)
-{
-       char *pipeline = *pipeline_p;
-       int pipeline_idx = *pipeline_idx_p;
-       int pipeline_len = *pipeline_len_p;
-       int i;
-
-       /* go through the replacement string */
-       for (i = 0; replace[i]; i++) {
-               /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
-               if (replace[i] == '\\' && isdigit(replace[i+1])) {
-                       int j;
-                       char tmpstr[2];
-                       int backref;
-                       ++i; /* i now indexes the backref number, instead of the leading slash */
-                       tmpstr[0] = replace[i];
-                       tmpstr[1] = 0;
-                       backref = atoi(tmpstr);
-                       /* print out the text held in regmatch[backref] */
-                       if (backref <= matches && regmatch[backref].rm_so != -1)
-                               for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++)
-                                       pipeputc(line[j]);
-               }
-
-               /* if we find a backslash escaped character, print the character */
-               else if (replace[i] == '\\') {
-                       ++i;
-                       pipeputc(replace[i]);
-               }
-
-               /* if we find an unescaped '&' print out the whole matched text.
-                * fortunately, regmatch[0] contains the indicies to the whole matched
-                * expression (kinda seems like it was designed for just such a
-                * purpose...) */
-               else if (replace[i] == '&' && replace[i-1] != '\\') {
-                       int j;
-                       for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++)
-                               pipeputc(line[j]);
-               }
-               /* nothing special, just print this char of the replacement string to stdout */
-               else
-                       pipeputc(replace[i]);
-       }
-       *pipeline_p = pipeline;
-       *pipeline_idx_p = pipeline_idx;
-       *pipeline_len_p = pipeline_len;
-}
-
-static int do_subst_command(const struct sed_cmd *sed_cmd, char **line)
-{
-       char *hackline = *line;
-       char *pipeline = 0;
-       int pipeline_idx = 0;
-       int pipeline_len = 0;
-       int altered = 0;
-       regmatch_t *regmatch = NULL;
-
-       /* we only proceed if the substitution 'search' expression matches */
-       if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH)
-               return 0;
-
-       /* whaddaya know, it matched. get the number of back references */
-       regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1));
-
-       /* allocate more PIPE_GROW bytes
-          if replaced string is larger than original */
-       pipeline_len = strlen(hackline)+PIPE_GROW;
-       pipeline = xmalloc(pipeline_len);
-       memset(pipeline, 0, pipeline_len);
-       /* buffer magic */
-       pipeline[pipeline_len-1] = PIPE_MAGIC;
-
-       /* and now, as long as we've got a line to try matching and if we can match
-        * the search string, we make substitutions */
-       while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline,
-                                       sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) {
-               int i;
-
-               /* print everything before the match */
-               for (i = 0; i < regmatch[0].rm_so; i++)
-                       pipeputc(hackline[i]);
-
-               /* then print the substitution string */
-               print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, 
-                               &pipeline, &pipeline_idx, &pipeline_len,
-                               sed_cmd->num_backrefs);
-
-               /* advance past the match */
-               hackline += regmatch[0].rm_eo;
-               /* flag that something has changed */
-               altered++;
-
-               /* if we're not doing this globally, get out now */
-               if (!sed_cmd->sub_g)
-                       break;
-       }
-
-       for (; *hackline; hackline++) pipeputc(*hackline);
-       if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0;
-
-       /* cleanup */
-       free(regmatch);
-
-       free(*line);
-       *line = pipeline;
-       return altered;
-}
-
-
-static void process_file(FILE *file)
-{
-       char *line = NULL;
-       static int linenum = 0; /* GNU sed does not restart counting lines at EOF */
-       unsigned int still_in_range = 0;
-       int altered;
-       int i;
-
-       /* go through every line in the file */
-       while ((line = get_line_from_file(file)) != NULL) {
-
-               chomp(line);
-               linenum++;
-               altered = 0;
-
-               /* for every line, go through all the commands */
-               for (i = 0; i < ncmds; i++) {
-
-
-                       /*
-                        * entry point into sedding...
-                        */
-                       if (
-                                       /* no range necessary */
-                                       (sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 &&
-                                        sed_cmds[i].beg_match == NULL &&
-                                        sed_cmds[i].end_match == NULL) ||
-                                       /* this line number is the first address we're looking for */
-                                       (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||
-                                       /* this line matches our first address regex */
-                                       (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||
-                                       /* we are currently within the beginning & ending address range */
-                                       still_in_range
-                          ) {
-
-                               /*
-                                * actual sedding
-                                */
-                               switch (sed_cmds[i].cmd) {
-
-                                       case 'p':
-                                               puts(line);
-                                               break;
-
-                                       case 'd':
-                                               altered++;
-                                               break;
-
-                                       case 's':
-
-                                               /*
-                                                * Some special cases for 's' printing to make it compliant with
-                                                * GNU sed printing behavior (aka "The -n | s///p Matrix"):
-                                                *
-                                                *    -n ONLY = never print anything regardless of any successful
-                                                *    substitution
-                                                *
-                                                *    s///p ONLY = always print successful substitutions, even if
-                                                *    the line is going to be printed anyway (line will be printed
-                                                *    twice).
-                                                *
-                                                *    -n AND s///p = print ONLY a successful substitution ONE TIME;
-                                                *    no other lines are printed - this is the reason why the 'p'
-                                                *    flag exists in the first place.
-                                                */
-
-                                               /* if the user specified that they didn't want anything printed (i.e., a -n
-                                                * flag and no 'p' flag after the s///), then there's really no point doing
-                                                * anything here. */
-                                               if (be_quiet && !sed_cmds[i].sub_p)
-                                                       break;
-
-                                               /* we print the line once, unless we were told to be quiet */
-                                               if (!be_quiet)
-                                                       altered |= do_subst_command(&sed_cmds[i], &line);
-
-                                               /* we also print the line if we were given the 'p' flag
-                                                * (this is quite possibly the second printing) */
-                                               if (sed_cmds[i].sub_p)
-                                                       altered |= do_subst_command(&sed_cmds[i], &line);
-                                               if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's'))
-                                                       puts(line);
-
-                                               break;
-
-                                       case 'a':
-                                               puts(line);
-                                               fputs(sed_cmds[i].editline, stdout);
-                                               altered++;
-                                               break;
-
-                                       case 'i':
-                                               fputs(sed_cmds[i].editline, stdout);
-                                               break;
-
-                                       case 'c':
-                                               /* single-address case */
-                                               if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {
-                                                       fputs(sed_cmds[i].editline, stdout);
-                                               }
-                                               /* multi-address case */
-                                               else {
-                                                       /* matching text */
-                                                       if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
-                                                               fputs(sed_cmds[i].editline, stdout);
-                                                       /* matching line numbers */
-                                                       if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)
-                                                               fputs(sed_cmds[i].editline, stdout);
-                                               }
-                                               altered++;
-
-                                               break;
-
-                                       case 'r': {
-                                                                 FILE *outfile;
-                                                                 puts(line);
-                                                                 outfile = fopen(sed_cmds[i].filename, "r");
-                                                                 if (outfile)
-                                                                         print_file(outfile);
-                                                                 /* else if we couldn't open the output file,
-                                                                  * no biggie, just don't print anything */
-                                                                 altered++;
-                                                         }
-                                                         break;
-                               }
-
-                               /*
-                                * exit point from sedding...
-                                */
-                               if (
-                                       /* this is a single-address command or... */
-                                       (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (
-                                               /* we were in the middle of our address range (this
-                                                * isn't the first time through) and.. */
-                                               (still_in_range == 1) && (
-                                                       /* this line number is the last address we're looking for or... */
-                                                       (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||
-                                                       /* this line matches our last address regex */
-                                                       (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
-                                               )
-                                       )
-                               ) {
-                                       /* we're out of our address range */
-                                       still_in_range = 0;
-                               }
-
-                               /* didn't hit the exit? then we're still in the middle of an address range */
-                               else {
-                                       still_in_range = 1;
-                               }
-                       }
-               }
-
-               /* we will print the line unless we were told to be quiet or if the
-                * line was altered (via a 'd'elete or 's'ubstitution), in which case
-                * the altered line was already printed */
-               if (!be_quiet && !altered)
-                       puts(line);
-
-               free(line);
-       }
-}
-
-extern int sed_main(int argc, char **argv)
-{
-       int opt;
-
-#ifdef BB_FEATURE_CLEAN_UP
-       /* destroy command strings on exit */
-       if (atexit(destroy_cmd_strs) == -1)
-               perror_msg_and_die("atexit");
-#endif
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
-               switch (opt) {
-                       case 'n':
-                               be_quiet++;
-                               break;
-                       case 'e':
-                               add_cmd_str(optarg);
-                               break;
-                       case 'f': 
-                               load_cmd_file(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* if we didn't get a pattern from a -e and no command file was specified,
-        * argv[optind] should be the pattern. no pattern, no worky */
-       if (ncmds == 0) {
-               if (argv[optind] == NULL)
-                       show_usage();
-               else {
-                       add_cmd_str(argv[optind]);
-                       optind++;
-               }
-       }
-
-
-       /* argv[(optind)..(argc-1)] should be names of file to process. If no
-        * files were specified or '-' was specified, take input from stdin.
-        * Otherwise, we process all the files specified. */
-       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
-               process_file(stdin);
-       }
-       else {
-               int i;
-               FILE *file;
-               for (i = optind; i < argc; i++) {
-                       file = fopen(argv[i], "r");
-                       if (file == NULL) {
-                               perror_msg("%s", argv[i]);
-                       } else {
-                               process_file(file);
-                               fclose(file);
-                       }
-               }
-       }
-       
-       return 0;
-}
diff --git a/busybox/setkeycodes.c b/busybox/setkeycodes.c
deleted file mode 100644 (file)
index c3c7e09..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * setkeycodes
- *
- * Copyright (C) 1994-1998 Andries E. Brouwer <aeb@cwi.nl>
- *
- * Adjusted for BusyBox by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-
-/* From <linux/kd.h> */
-struct kbkeycode {
-       unsigned int scancode, keycode;
-};
-static const int KDSETKEYCODE = 0x4B4D;  /* write kernel keycode table entry */
-
-extern int 
-setkeycodes_main(int argc, char** argv)
-{
-    char *ep;
-    int fd, sc;
-    struct kbkeycode a;
-
-    if (argc % 2 != 1 || argc < 2) {
-      show_usage();
-       }
-        
-       fd = get_console_fd("/dev/console");
-
-    while (argc > 2) {
-       a.keycode = atoi(argv[2]);
-       a.scancode = sc = strtol(argv[1], &ep, 16);
-       if (*ep) {
-      error_msg_and_die("error reading SCANCODE: '%s'", argv[1]);
-       }
-       if (a.scancode > 127) {
-           a.scancode -= 0xe000;
-           a.scancode += 128;
-       }
-       if (a.scancode > 255 || a.keycode > 127) {
-      error_msg_and_die("SCANCODE or KEYCODE outside bounds");
-       }
-       if (ioctl(fd,KDSETKEYCODE,&a)) {
-           perror("KDSETKEYCODE");
-               error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode);
-       }
-       argc -= 2;
-       argv += 2;
-    }
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/shell/ash.c b/busybox/shell/ash.c
deleted file mode 100644 (file)
index c0d4755..0000000
+++ /dev/null
@@ -1,12888 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * ash shell port for busybox
- *
- * Copyright (c) 1989, 1991, 1993, 1994
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This version of ash is adapted from the source in Debian's ash 0.3.8-5
- * package.
- *
- * Modified by Erik Andersen <andersee@debian.org> and
- * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
- *
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-
-/* These defines allow you to adjust the feature set to be compiled
- * into the ash shell.   As a rule, enabling these options will make
- * ash get bigger...   With all of these options off, ash adds about
- * 60k to busybox on an x86 system.*/
-
-
-/* Enable job control.  This allows you to run jobs in the background,
- * which is great when ash is being  used as an interactive shell, but
- * it completely useless for is all you are doing is running scripts.
- * This adds about 2.5k on an x86 system. */
-#undef JOBS
-
-/* This enables alias support in ash.  If you want to support things
- * like "alias ls='ls -l'" with ash, enable this.  This is only useful
- * when ash is used as an intractive shell.   This adds about 1.5k */
-#define ASH_ALIAS
-
-/* If you need ash to act as a full Posix shell, with full math
- * support, enable this.   This adds a bit over 2k an x86 system. */
-//#undef ASH_MATH_SUPPORT
-#define ASH_MATH_SUPPORT
-
-/* Getopts is used by shell procedures to parse positional parameters.
- * You probably want to leave this disabled, and use the busybox getopt
- * applet if you want to do this sort of thing.  There are some scripts
- * out there that use it, so if you need it, enable it.  Most people will
- * leave this disabled.  This adds 1k on an x86 system. */
-#undef ASH_GETOPTS
-
-/* This allows you to override shell builtins and use whatever is on
- * the filesystem.  This is most useful when ash is acting as a
- * standalone shell.   Adds about 272 bytes. */
-#undef ASH_CMDCMD
-
-
-/* Optimize size vs speed as size */
-#define ASH_OPTIMIZE_FOR_SIZE
-
-/* Enable this to compile in extra debugging noise.  When debugging is
- * on, debugging info will be written to $HOME/trace and a quit signal
- * will generate a core dump. */
-#undef DEBUG
-
-/* These are here to work with glibc -- Don't change these... */
-#undef FNMATCH_BROKEN
-#undef GLOB_BROKEN
-#define IFS_BROKEN
-
-#include <assert.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <paths.h>
-#include <pwd.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/cdefs.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-
-#if !defined(FNMATCH_BROKEN)
-#include <fnmatch.h>
-#endif
-#if !defined(GLOB_BROKEN)
-#include <glob.h>
-#endif
-
-#ifdef JOBS
-#include <termios.h>
-#endif
-
-#include "busybox.h"
-#include "cmdedit.h"
-
-/*
- * This file was generated by the mksyntax program.
- */
-
-/* Syntax classes */
-#define CWORD 0                 /* character is nothing special */
-#define CNL 1                   /* newline character */
-#define CBACK 2                 /* a backslash character */
-#define CSQUOTE 3               /* single quote */
-#define CDQUOTE 4               /* double quote */
-#define CENDQUOTE 5             /* a terminating quote */
-#define CBQUOTE 6               /* backwards single quote */
-#define CVAR 7                  /* a dollar sign */
-#define CENDVAR 8               /* a '}' character */
-#define CLP 9                   /* a left paren in arithmetic */
-#define CRP 10                  /* a right paren in arithmetic */
-#define CENDFILE 11             /* end of file */
-#define CCTL 12                 /* like CWORD, except it must be escaped */
-#define CSPCL 13                /* these terminate a word */
-#define CIGN 14                 /* character should be ignored */
-
-/* Syntax classes for is_ functions */
-#define ISDIGIT 01              /* a digit */
-#define ISUPPER 02              /* an upper case letter */
-#define ISLOWER 04              /* a lower case letter */
-#define ISUNDER 010             /* an underscore */
-#define ISSPECL 020             /* the name of a special parameter */
-
-#define SYNBASE 130
-#define PEOF -130
-
-#define PEOA -129
-
-#define TEOF 0
-#define TNL 1
-#define TSEMI 2
-#define TBACKGND 3
-#define TAND 4
-#define TOR 5
-#define TPIPE 6
-#define TLP 7
-#define TRP 8
-#define TENDCASE 9
-#define TENDBQUOTE 10
-#define TREDIR 11
-#define TWORD 12
-#define TASSIGN 13
-#define TNOT 14
-#define TCASE 15
-#define TDO 16
-#define TDONE 17
-#define TELIF 18
-#define TELSE 19
-#define TESAC 20
-#define TFI 21
-#define TFOR 22
-#define TIF 23
-#define TIN 24
-#define TTHEN 25
-#define TUNTIL 26
-#define TWHILE 27
-#define TBEGIN 28
-#define TEND 29
-
-
-#define BASESYNTAX (basesyntax + SYNBASE)
-#define DQSYNTAX (dqsyntax + SYNBASE)
-#define SQSYNTAX (sqsyntax + SYNBASE)
-#define ARISYNTAX (arisyntax + SYNBASE)
-
-/* control characters in argument strings */
-#define CTLESC '\201'
-#define CTLVAR '\202'
-#define CTLENDVAR '\203'
-#define CTLBACKQ '\204'
-#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
-/*      CTLBACKQ | CTLQUOTE == '\205' */
-#define CTLARI  '\206'
-#define CTLENDARI '\207'
-#define CTLQUOTEMARK '\210'
-
-#define is_digit(c)     ((c)>='0' && (c)<='9')
-#define is_alpha(c)     (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
-#define is_name(c)      (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
-#define is_in_name(c)   (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
-#define is_special(c)   ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
-#define digit_val(c)    ((c) - '0')
-
-
-#define _DIAGASSERT(x)
-
-
-
-#define S_DFL 1                 /* default signal handling (SIG_DFL) */
-#define S_CATCH 2               /* signal is caught */
-#define S_IGN 3                 /* signal is ignored (SIG_IGN) */
-#define S_HARD_IGN 4            /* signal is ignored permenantly */
-#define S_RESET 5               /* temporary - to reset a hard ignored sig */
-
-
-/* variable substitution byte (follows CTLVAR) */
-#define VSTYPE  0x0f            /* type of variable substitution */
-#define VSNUL   0x10            /* colon--treat the empty string as unset */
-#define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
-
-/* values of VSTYPE field */
-#define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
-#define VSMINUS         0x2             /* ${var-text} */
-#define VSPLUS          0x3             /* ${var+text} */
-#define VSQUESTION      0x4             /* ${var?message} */
-#define VSASSIGN        0x5             /* ${var=text} */
-#define VSTRIMLEFT      0x6             /* ${var#pattern} */
-#define VSTRIMLEFTMAX   0x7             /* ${var##pattern} */
-#define VSTRIMRIGHT     0x8             /* ${var%pattern} */
-#define VSTRIMRIGHTMAX  0x9             /* ${var%%pattern} */
-#define VSLENGTH        0xa             /* ${#var} */
-
-/* flags passed to redirect */
-#define REDIR_PUSH 01           /* save previous values of file descriptors */
-#define REDIR_BACKQ 02          /* save the command output to pipe */
-
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD)
-#define setjmp(jmploc)  _setjmp(jmploc)
-#define longjmp(jmploc, val)    _longjmp(jmploc, val)
-#endif
-
-/*
- * Most machines require the value returned from malloc to be aligned
- * in some way.  The following macro will get this right on many machines.
- */
-
-#ifndef ALIGN
-union align {
-       int i;
-       char *cp;
-};
-
-#define ALIGN(nbytes)   (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
-#endif
-
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-static void change_lc_all(const char *value);
-static void change_lc_ctype(const char *value);
-#endif
-
-/*
- * These macros allow the user to suspend the handling of interrupt signals
- * over a period of time.  This is similar to SIGHOLD to or sigblock, but
- * much more efficient and portable.  (But hacking the kernel is so much
- * more fun than worrying about efficiency and portability. :-))
- */
-
-static void onint (void);
-static volatile int suppressint;
-static volatile int intpending;
-
-#define INTOFF suppressint++
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define INTON { if (--suppressint == 0 && intpending) onint(); }
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
-#else
-static void __inton (void);
-static void forceinton (void);
-#define INTON __inton()
-#define FORCEINTON forceinton()
-#endif
-
-#define CLEAR_PENDING_INT intpending = 0
-#define int_pending() intpending
-
-
-typedef void *pointer;
-#ifndef NULL
-#define NULL (void *)0
-#endif
-
-static inline pointer  ckmalloc (int sz)          { return xmalloc(sz);     }
-static inline pointer  ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
-static inline char *   savestr  (const char *s)   { return xstrdup(s);      }
-
-static pointer stalloc (int);
-static void stunalloc (pointer);
-static void ungrabstackstr (char *, char *);
-static char * growstackstr(void);
-static char * makestrspace(size_t newlen);
-static char *sstrdup (const char *);
-
-/*
- * Parse trees for commands are allocated in lifo order, so we use a stack
- * to make this more efficient, and also to avoid all sorts of exception
- * handling code to handle interrupts in the middle of a parse.
- *
- * The size 504 was chosen because the Ultrix malloc handles that size
- * well.
- */
-
-#define MINSIZE 504             /* minimum size of a block */
-
-
-struct stack_block {
-       struct stack_block *prev;
-       char space[MINSIZE];
-};
-
-static struct stack_block stackbase;
-static struct stack_block *stackp = &stackbase;
-static struct stackmark *markp;
-static char *stacknxt = stackbase.space;
-static int stacknleft = MINSIZE;
-
-
-#define equal(s1, s2)   (strcmp(s1, s2) == 0)
-
-#define stackblock() stacknxt
-#define stackblocksize() stacknleft
-#define STARTSTACKSTR(p)        p = stackblock(), sstrnleft = stackblocksize()
-
-#define STPUTC(c, p)    (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
-#define CHECKSTRSPACE(n, p)     { if (sstrnleft < n) p = makestrspace(n); }
-#define STACKSTRNUL(p)  (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
-
-
-#define USTPUTC(c, p)   (--sstrnleft, *p++ = (c))
-#define STUNPUTC(p)     (++sstrnleft, --p)
-#define STTOPC(p)       p[-1]
-#define STADJUST(amount, p)     (p += (amount), sstrnleft -= (amount))
-#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
-
-#define ckfree(p)       free((pointer)(p))
-
-
-#ifdef DEBUG
-#define TRACE(param)    trace param
-static void trace (const char *, ...);
-static void trargs (char **);
-static void showtree (union node *);
-static void trputc (int);
-static void trputs (const char *);
-static void opentrace (void);
-#else
-#define TRACE(param)
-#endif
-
-#define NSEMI 0
-#define NCMD 1
-#define NPIPE 2
-#define NREDIR 3
-#define NBACKGND 4
-#define NSUBSHELL 5
-#define NAND 6
-#define NOR 7
-#define NIF 8
-#define NWHILE 9
-#define NUNTIL 10
-#define NFOR 11
-#define NCASE 12
-#define NCLIST 13
-#define NDEFUN 14
-#define NARG 15
-#define NTO 16
-#define NFROM 17
-#define NFROMTO 18
-#define NAPPEND 19
-#define NTOOV 20
-#define NTOFD 21
-#define NFROMFD 22
-#define NHERE 23
-#define NXHERE 24
-#define NNOT 25
-
-/*
- * expandarg() flags
- */
-#define EXP_FULL        0x1     /* perform word splitting & file globbing */
-#define EXP_TILDE       0x2     /* do normal tilde expansion */
-#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
-#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
-#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
-#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
-
-
-#define NOPTS   16
-
-static char optet_vals[NOPTS];
-
-static const char * const optlist[NOPTS] = {
-       "e" "errexit",
-       "f" "noglob",
-       "I" "ignoreeof",
-       "i" "interactive",
-       "m" "monitor",
-       "n" "noexec",
-       "s" "stdin",
-       "x" "xtrace",
-       "v" "verbose",
-       "V" "vi",
-       "E" "emacs",
-       "C" "noclobber",
-       "a" "allexport",
-       "b" "notify",
-       "u" "nounset",
-       "q" "quietprofile"
-};
-
-#define optent_name(optent) (optent+1)
-#define optent_letter(optent) optent[0]
-#define optent_val(optent) optet_vals[optent]
-
-#define eflag optent_val(0)
-#define fflag optent_val(1)
-#define Iflag optent_val(2)
-#define iflag optent_val(3)
-#define mflag optent_val(4)
-#define nflag optent_val(5)
-#define sflag optent_val(6)
-#define xflag optent_val(7)
-#define vflag optent_val(8)
-#define Vflag optent_val(9)
-#define Eflag optent_val(10)
-#define Cflag optent_val(11)
-#define aflag optent_val(12)
-#define bflag optent_val(13)
-#define uflag optent_val(14)
-#define qflag optent_val(15)
-
-
-/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
-#define FORK_FG 0
-#define FORK_BG 1
-#define FORK_NOJOB 2
-
-
-struct nbinary {
-      int type;
-      union node *ch1;
-      union node *ch2;
-};
-
-
-struct ncmd {
-      int type;
-      int backgnd;
-      union node *assign;
-      union node *args;
-      union node *redirect;
-};
-
-
-struct npipe {
-      int type;
-      int backgnd;
-      struct nodelist *cmdlist;
-};
-
-
-struct nredir {
-      int type;
-      union node *n;
-      union node *redirect;
-};
-
-
-struct nif {
-      int type;
-      union node *test;
-      union node *ifpart;
-      union node *elsepart;
-};
-
-
-struct nfor {
-      int type;
-      union node *args;
-      union node *body;
-      char *var;
-};
-
-
-struct ncase {
-      int type;
-      union node *expr;
-      union node *cases;
-};
-
-
-struct nclist {
-      int type;
-      union node *next;
-      union node *pattern;
-      union node *body;
-};
-
-
-struct narg {
-      int type;
-      union node *next;
-      char *text;
-      struct nodelist *backquote;
-};
-
-
-struct nfile {
-      int type;
-      union node *next;
-      int fd;
-      union node *fname;
-      char *expfname;
-};
-
-
-struct ndup {
-      int type;
-      union node *next;
-      int fd;
-      int dupfd;
-      union node *vname;
-};
-
-
-struct nhere {
-      int type;
-      union node *next;
-      int fd;
-      union node *doc;
-};
-
-
-struct nnot {
-      int type;
-      union node *com;
-};
-
-
-union node {
-      int type;
-      struct nbinary nbinary;
-      struct ncmd ncmd;
-      struct npipe npipe;
-      struct nredir nredir;
-      struct nif nif;
-      struct nfor nfor;
-      struct ncase ncase;
-      struct nclist nclist;
-      struct narg narg;
-      struct nfile nfile;
-      struct ndup ndup;
-      struct nhere nhere;
-      struct nnot nnot;
-};
-
-
-struct nodelist {
-       struct nodelist *next;
-       union node *n;
-};
-
-struct backcmd {                /* result of evalbackcmd */
-       int fd;                 /* file descriptor to read from */
-       char *buf;              /* buffer */
-       int nleft;              /* number of chars in buffer */
-       struct job *jp;         /* job structure for command */
-};
-
-struct cmdentry {
-       int cmdtype;
-       union param {
-               int index;
-               union node *func;
-               const struct builtincmd *cmd;
-       } u;
-};
-
-struct strlist {
-       struct strlist *next;
-       char *text;
-};
-
-
-struct arglist {
-       struct strlist *list;
-       struct strlist **lastp;
-};
-
-struct strpush {
-       struct strpush *prev;   /* preceding string on stack */
-       char *prevstring;
-       int prevnleft;
-#ifdef ASH_ALIAS
-       struct alias *ap;       /* if push was associated with an alias */
-#endif
-       char *string;           /* remember the string since it may change */
-};
-
-struct parsefile {
-       struct parsefile *prev; /* preceding file on stack */
-       int linno;              /* current line */
-       int fd;                 /* file descriptor (or -1 if string) */
-       int nleft;              /* number of chars left in this line */
-       int lleft;              /* number of chars left in this buffer */
-       char *nextc;            /* next char in buffer */
-       char *buf;              /* input buffer */
-       struct strpush *strpush; /* for pushing strings at this level */
-       struct strpush basestrpush; /* so pushing one is fast */
-};
-
-struct stackmark {
-       struct stack_block *stackp;
-       char *stacknxt;
-       int stacknleft;
-       struct stackmark *marknext;
-};
-
-struct shparam {
-       int nparam;             /* # of positional parameters (without $0) */
-       unsigned char malloc;   /* if parameter list dynamically allocated */
-       char **p;               /* parameter list */
-       int optind;             /* next parameter to be processed by getopts */
-       int optoff;             /* used by getopts */
-};
-
-/*
- * When commands are first encountered, they are entered in a hash table.
- * This ensures that a full path search will not have to be done for them
- * on each invocation.
- *
- * We should investigate converting to a linear search, even though that
- * would make the command name "hash" a misnomer.
- */
-#define CMDTABLESIZE 31         /* should be prime */
-#define ARB 1                   /* actual size determined at run time */
-
-
-
-struct tblentry {
-       struct tblentry *next;  /* next entry in hash chain */
-       union param param;      /* definition of builtin function */
-       short cmdtype;          /* index identifying command */
-       char rehash;            /* if set, cd done since entry created */
-       char cmdname[ARB];      /* name of command */
-};
-
-
-static struct tblentry *cmdtable[CMDTABLESIZE];
-static int builtinloc = -1;             /* index in path of %builtin, or -1 */
-static int exerrno = 0;                 /* Last exec error */
-
-
-static void tryexec (char *, char **, char **);
-static void printentry (struct tblentry *, int);
-static void clearcmdentry (int);
-static struct tblentry *cmdlookup (const char *, int);
-static void delete_cmd_entry (void);
-static int path_change (const char *, int *);
-
-
-static void flushall (void);
-static void out2fmt (const char *, ...)
-    __attribute__((__format__(__printf__,1,2)));
-static int xwrite (int, const char *, int);
-
-static void outstr (const char *p, FILE *file) { fputs(p, file); }
-static void out1str(const char *p) { outstr(p, stdout); }
-static void out2str(const char *p) { outstr(p, stderr); }
-
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define out2c(c)        putc((c), stderr)
-#else
-static void out2c(int c)           { putc(c, stderr); }
-#endif
-
-/* syntax table used when not in quotes */
-static const char basesyntax[257] = {
-      CENDFILE,   CSPCL,   CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CSPCL,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CSPCL,   CWORD,
-      CDQUOTE, CWORD,   CVAR,    CWORD,
-      CSPCL,   CSQUOTE, CSPCL,   CSPCL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CSPCL,   CSPCL,   CWORD,
-      CSPCL,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CBACK,   CWORD,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CSPCL,   CENDVAR,
-      CWORD
-};
-
-/* syntax table used when in double quotes */
-static const char dqsyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CCTL,
-      CENDQUOTE,CWORD,  CVAR,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CCTL,    CBACK,   CCTL,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CENDVAR,
-      CCTL
-};
-
-/* syntax table used when in single quotes */
-static const char sqsyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CCTL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CENDQUOTE,CWORD,  CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL,    CWORD,   CWORD,   CCTL,
-      CWORD,   CCTL,    CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CCTL,    CCTL,    CCTL,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CCTL
-};
-
-/* syntax table used when in arithmetic */
-static const char arisyntax[257] = {
-      CENDFILE,   CIGN,    CWORD,   CCTL,
-      CCTL,    CCTL,    CCTL,    CCTL,
-      CCTL,    CCTL,    CCTL,    CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CNL,     CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CDQUOTE, CWORD,   CVAR,    CWORD,
-      CWORD,   CSQUOTE, CLP,     CRP,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CBACK,   CWORD,
-      CWORD,   CWORD,   CBQUOTE, CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CWORD,
-      CWORD,   CWORD,   CWORD,   CENDVAR,
-      CWORD
-};
-
-/* character classification table */
-static const char is_type[257] = {
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       0,
-      0,       0,       0,       ISSPECL,
-      0,       ISSPECL, ISSPECL, 0,
-      0,       0,       0,       0,
-      ISSPECL, 0,       0,       ISSPECL,
-      0,       0,       ISDIGIT, ISDIGIT,
-      ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
-      ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
-      0,       0,       0,       0,
-      0,       ISSPECL, ISSPECL, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, ISUPPER, ISUPPER, ISUPPER,
-      ISUPPER, 0,       0,       0,
-      0,       ISUNDER, 0,       ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, ISLOWER, ISLOWER, ISLOWER,
-      ISLOWER, 0,       0,       0,
-      0
-};
-
-/* Array indicating which tokens mark the end of a list */
-static const char tokendlist[] = {
-       1,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       1,
-       1,
-       1,
-       0,
-       0,
-       0,
-       0,
-       0,
-       1,
-       1,
-       1,
-       1,
-       1,
-       1,
-       0,
-       0,
-       0,
-       1,
-       0,
-       0,
-       0,
-       1,
-};
-
-static const char *const tokname[] = {
-       "end of file",
-       "newline",
-       "\";\"",
-       "\"&\"",
-       "\"&&\"",
-       "\"||\"",
-       "\"|\"",
-       "\"(\"",
-       "\")\"",
-       "\";;\"",
-       "\"`\"",
-       "redirection",
-       "word",
-       "assignment",
-       "\"!\"",
-       "\"case\"",
-       "\"do\"",
-       "\"done\"",
-       "\"elif\"",
-       "\"else\"",
-       "\"esac\"",
-       "\"fi\"",
-       "\"for\"",
-       "\"if\"",
-       "\"in\"",
-       "\"then\"",
-       "\"until\"",
-       "\"while\"",
-       "\"{\"",
-       "\"}\"",
-};
-
-#define KWDOFFSET 14
-
-static const char *const parsekwd[] = {
-       "!",
-       "case",
-       "do",
-       "done",
-       "elif",
-       "else",
-       "esac",
-       "fi",
-       "for",
-       "if",
-       "in",
-       "then",
-       "until",
-       "while",
-       "{",
-       "}"
-};
-
-
-static int plinno = 1;          /* input line number */
-
-static int parselleft;          /* copy of parsefile->lleft */
-
-static struct parsefile basepf; /* top level input file */
-static char basebuf[BUFSIZ];    /* buffer for top level input file */
-static struct parsefile *parsefile = &basepf;  /* current input file */
-
-/*
- * NEOF is returned by parsecmd when it encounters an end of file.  It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
- */
-
-static int tokpushback;         /* last token pushed back */
-#define NEOF ((union node *)&tokpushback)
-static int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
-
-
-static void error (const char *, ...) __attribute__((__noreturn__));
-static void exerror (int, const char *, ...) __attribute__((__noreturn__));
-static void shellexec (char **, char **, const char *, int)
-    __attribute__((noreturn));
-static void exitshell (int) __attribute__((noreturn));
-
-static int  goodname(const char *);
-static void ignoresig (int);
-static void onsig (int);
-static void dotrap (void);
-static int  decode_signal (const char *, int);
-
-static void shprocvar(void);
-static void deletefuncs(void);
-static void setparam (char **);
-static void freeparam (volatile struct shparam *);
-
-/* reasons for skipping commands (see comment on breakcmd routine) */
-#define SKIPBREAK       1
-#define SKIPCONT        2
-#define SKIPFUNC        3
-#define SKIPFILE        4
-
-/* values of cmdtype */
-#define CMDUNKNOWN -1           /* no entry in table for command */
-#define CMDNORMAL 0             /* command is an executable program */
-#define CMDBUILTIN 1            /* command is a shell builtin */
-#define CMDFUNCTION 2           /* command is a shell function */
-
-#define DO_ERR  1               /* find_command prints errors */
-#define DO_ABS  2               /* find_command checks absolute paths */
-#define DO_NOFUN        4       /* find_command ignores functions */
-#define DO_BRUTE        8       /* find_command ignores hash table */
-
-/*
- * Shell variables.
- */
-
-/* flags */
-#define VEXPORT         0x01    /* variable is exported */
-#define VREADONLY       0x02    /* variable cannot be modified */
-#define VSTRFIXED       0x04    /* variable struct is staticly allocated */
-#define VTEXTFIXED      0x08    /* text is staticly allocated */
-#define VSTACK          0x10    /* text is allocated on the stack */
-#define VUNSET          0x20    /* the variable is not set */
-#define VNOFUNC         0x40    /* don't call the callback function */
-
-
-struct var {
-       struct var *next;               /* next entry in hash list */
-       int flags;                      /* flags are defined above */
-       char *text;                     /* name=value */
-       void (*func) (const char *);
-                                       /* function to be called when  */
-                                       /* the variable gets set/unset */
-};
-
-struct localvar {
-       struct localvar *next;          /* next local variable in list */
-       struct var *vp;                 /* the variable that was made local */
-       int flags;                      /* saved flags */
-       char *text;                     /* saved text */
-};
-
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-#define rmescapes(p) _rmescapes((p), 0)
-static char *_rmescapes (char *, int);
-#else
-static void rmescapes (char *);
-#endif
-
-static int  casematch (union node *, const char *);
-static void clearredir(void);
-static void popstring(void);
-static void readcmdfile (const char *);
-
-static int number (const char *);
-static int is_number (const char *, int *num);
-static char *single_quote (const char *);
-static int nextopt (const char *);
-
-static void redirect (union node *, int);
-static void popredir (void);
-static int dup_as_newfd (int, int);
-
-static void changepath(const char *newval);
-static void getoptsreset(const char *value);
-
-
-static int parsenleft;                  /* copy of parsefile->nleft */
-static char *parsenextc;                /* copy of parsefile->nextc */
-static int rootpid;     /* pid of main shell */
-static int rootshell;   /* true if we aren't a child of the main shell */
-
-static const char spcstr[] = " ";
-static const char snlfmt[] = "%s\n";
-
-static int sstrnleft;
-static int herefd = -1;
-
-static struct localvar *localvars;
-
-static struct var vifs;
-static struct var vmail;
-static struct var vmpath;
-static struct var vpath;
-static struct var vps1;
-static struct var vps2;
-static struct var voptind;
-#ifdef BB_LOCALE_SUPPORT
-static struct var vlc_all;
-static struct var vlc_ctype;
-#endif
-
-struct varinit {
-       struct var *var;
-       int flags;
-       const char *text;
-       void (*func) (const char *);
-};
-
-static const char defpathvar[] =
-       "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
-#define defpath (defpathvar + 5)
-
-#ifdef IFS_BROKEN
-static const char defifsvar[] = "IFS= \t\n";
-#define defifs (defifsvar + 4)
-#else
-static const char defifs[] = " \t\n";
-#endif
-
-static const struct varinit varinit[] = {
-#ifdef IFS_BROKEN
-       { &vifs,        VSTRFIXED|VTEXTFIXED,           defifsvar,
-#else
-       { &vifs,        VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS=",
-#endif
-         NULL },
-       { &vmail,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
-         NULL },
-       { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
-         NULL },
-       { &vpath,       VSTRFIXED|VTEXTFIXED,           defpathvar,
-         changepath },
-       /*
-        * vps1 depends on uid
-        */
-       { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
-         NULL },
-       { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
-         getoptsreset },
-#ifdef BB_LOCALE_SUPPORT
-       { &vlc_all,     VSTRFIXED|VTEXTFIXED|VUNSET,    "LC_ALL=",
-         change_lc_all },
-       { &vlc_ctype,   VSTRFIXED|VTEXTFIXED|VUNSET,    "LC_CTYPE=",
-         change_lc_ctype },
-#endif
-       { NULL, 0,                              NULL,
-         NULL }
-};
-
-#define VTABSIZE 39
-
-static struct var *vartab[VTABSIZE];
-
-/*
- * The following macros access the values of the above variables.
- * They have to skip over the name.  They return the null string
- * for unset variables.
- */
-
-#define ifsval()        (vifs.text + 4)
-#define ifsset()        ((vifs.flags & VUNSET) == 0)
-#define mailval()       (vmail.text + 5)
-#define mpathval()      (vmpath.text + 9)
-#define pathval()       (vpath.text + 5)
-#define ps1val()        (vps1.text + 4)
-#define ps2val()        (vps2.text + 4)
-#define optindval()     (voptind.text + 7)
-
-#define mpathset()      ((vmpath.flags & VUNSET) == 0)
-
-static void initvar (void);
-static void setvar (const char *, const char *, int);
-static void setvareq (char *, int);
-static void listsetvar (struct strlist *);
-static const char *lookupvar (const char *);
-static const char *bltinlookup (const char *);
-static char **environment (void);
-static int showvarscmd (int, char **);
-static void mklocal (char *);
-static void poplocalvars (void);
-static int unsetvar (const char *);
-static int varequal (const char *, const char *);
-
-
-static char *arg0;                      /* value of $0 */
-static struct shparam shellparam;       /* current positional parameters */
-static char **argptr;                   /* argument list for builtin commands */
-static char *optionarg;                 /* set by nextopt (like getopt) */
-static char *optptr;                    /* used by nextopt */
-static char *minusc;                    /* argument to -c option */
-
-
-#ifdef ASH_ALIAS
-
-#define ALIASINUSE      1
-#define ALIASDEAD       2
-
-#define ATABSIZE 39
-
-struct alias {
-       struct alias *next;
-       char *name;
-       char *val;
-       int flag;
-};
-
-static struct alias *atab[ATABSIZE];
-
-static void setalias (char *, char *);
-static struct alias **hashalias (const char *);
-static struct alias *freealias (struct alias *);
-static struct alias **__lookupalias (const char *);
-
-static void
-setalias(name, val)
-       char *name, *val;
-{
-       struct alias *ap, **app;
-
-       app = __lookupalias(name);
-       ap = *app;
-       INTOFF;
-       if (ap) {
-               if (!(ap->flag & ALIASINUSE)) {
-                       ckfree(ap->val);
-               }
-               ap->val = savestr(val);
-               ap->flag &= ~ALIASDEAD;
-       } else {
-               /* not found */
-               ap = ckmalloc(sizeof (struct alias));
-               ap->name = savestr(name);
-               ap->val = savestr(val);
-               ap->flag = 0;
-               ap->next = 0;
-               *app = ap;
-       }
-       INTON;
-}
-
-static int
-unalias(char *name)
-{
-       struct alias **app;
-
-       app = __lookupalias(name);
-
-       if (*app) {
-               INTOFF;
-               *app = freealias(*app);
-               INTON;
-               return (0);
-       }
-
-       return (1);
-}
-
-static void
-rmaliases(void)
-{
-       struct alias *ap, **app;
-       int i;
-
-       INTOFF;
-       for (i = 0; i < ATABSIZE; i++) {
-               app = &atab[i];
-               for (ap = *app; ap; ap = *app) {
-                       *app = freealias(*app);
-                       if (ap == *app) {
-                               app = &ap->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-static struct alias *
-lookupalias(const char *name, int check)
-{
-       struct alias *ap = *__lookupalias(name);
-
-       if (check && ap && (ap->flag & ALIASINUSE))
-               return (NULL);
-       return (ap);
-}
-
-static void
-printalias(const struct alias *ap) {
-       char *p;
-
-       p = single_quote(ap->val);
-       printf("alias %s=%s\n", ap->name, p);
-       stunalloc(p);
-}
-
-
-/*
- * TODO - sort output
- */
-static int
-aliascmd(int argc, char **argv)
-{
-       char *n, *v;
-       int ret = 0;
-       struct alias *ap;
-
-       if (argc == 1) {
-               int i;
-
-               for (i = 0; i < ATABSIZE; i++)
-                       for (ap = atab[i]; ap; ap = ap->next) {
-                               printalias(ap);
-                       }
-               return (0);
-       }
-       while ((n = *++argv) != NULL) {
-               if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
-                       if ((ap = *__lookupalias(n)) == NULL) {
-                               out2fmt("%s: %s not found\n", "alias", n);
-                               ret = 1;
-                       } else
-                               printalias(ap);
-               }
-               else {
-                       *v++ = '\0';
-                       setalias(n, v);
-               }
-       }
-
-       return (ret);
-}
-
-static int
-unaliascmd(int argc, char **argv)
-{
-       int i;
-
-       while ((i = nextopt("a")) != '\0') {
-               if (i == 'a') {
-                       rmaliases();
-                       return (0);
-               }
-       }
-       for (i = 0; *argptr; argptr++) {
-               if (unalias(*argptr)) {
-                       out2fmt("%s: %s not found\n", "unalias", *argptr);
-                       i = 1;
-               }
-       }
-
-       return (i);
-}
-
-static struct alias **
-hashalias(p)
-       const char *p;
-       {
-       unsigned int hashval;
-
-       hashval = *p << 4;
-       while (*p)
-               hashval+= *p++;
-       return &atab[hashval % ATABSIZE];
-}
-
-static struct alias *
-freealias(struct alias *ap) {
-       struct alias *next;
-
-       if (ap->flag & ALIASINUSE) {
-               ap->flag |= ALIASDEAD;
-               return ap;
-       }
-
-       next = ap->next;
-       ckfree(ap->name);
-       ckfree(ap->val);
-       ckfree(ap);
-       return next;
-}
-
-
-static struct alias **
-__lookupalias(const char *name) {
-       struct alias **app = hashalias(name);
-
-       for (; *app; app = &(*app)->next) {
-               if (equal(name, (*app)->name)) {
-                       break;
-               }
-       }
-
-       return app;
-}
-#endif
-
-#ifdef ASH_MATH_SUPPORT
-/* The generated file arith.c has been replaced with a custom hand
- * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.  
- * This is now part of libbb, so that it can be used by all the shells 
- * in busybox. */
-#define ARITH_NUM 257
-#define ARITH_LPAREN 258
-#define ARITH_RPAREN 259
-#define ARITH_OR 260
-#define ARITH_AND 261
-#define ARITH_BOR 262
-#define ARITH_BXOR 263
-#define ARITH_BAND 264
-#define ARITH_EQ 265
-#define ARITH_NE 266
-#define ARITH_LT 267
-#define ARITH_GT 268
-#define ARITH_GE 269
-#define ARITH_LE 270
-#define ARITH_LSHIFT 271
-#define ARITH_RSHIFT 272
-#define ARITH_ADD 273
-#define ARITH_SUB 274
-#define ARITH_MUL 275
-#define ARITH_DIV 276
-#define ARITH_REM 277
-#define ARITH_UNARYMINUS 278
-#define ARITH_UNARYPLUS 279
-#define ARITH_NOT 280
-#define ARITH_BNOT 281
-
-static void expari (int);
-#endif
-
-static char *trap[NSIG];                /* trap handler commands */
-static char sigmode[NSIG - 1];  /* current value of signal */
-static char gotsig[NSIG - 1];           /* indicates specified signal received */
-static int pendingsigs;                 /* indicates some signal received */
-
-/*
- * This file was generated by the mkbuiltins program.
- */
-
-#ifdef JOBS
-static int bgcmd (int, char **);
-static int fgcmd (int, char **);
-static int killcmd (int, char **);
-#endif
-static int bltincmd (int, char **);
-static int cdcmd (int, char **);
-static int breakcmd (int, char **);
-#ifdef ASH_CMDCMD
-static int commandcmd (int, char **);
-#endif
-static int dotcmd (int, char **);
-static int evalcmd (int, char **);
-static int execcmd (int, char **);
-static int exitcmd (int, char **);
-static int exportcmd (int, char **);
-static int histcmd (int, char **);
-static int hashcmd (int, char **);
-static int helpcmd (int, char **);
-static int jobscmd (int, char **);
-static int localcmd (int, char **);
-#ifndef BB_PWD
-static int pwdcmd (int, char **);
-#endif
-static int readcmd (int, char **);
-static int returncmd (int, char **);
-static int setcmd (int, char **);
-static int setvarcmd (int, char **);
-static int shiftcmd (int, char **);
-static int trapcmd (int, char **);
-static int umaskcmd (int, char **);
-#ifdef ASH_ALIAS
-static int aliascmd (int, char **);
-static int unaliascmd (int, char **);
-#endif
-static int unsetcmd (int, char **);
-static int waitcmd (int, char **);
-static int ulimitcmd (int, char **);
-static int timescmd (int, char **);
-#ifdef ASH_MATH_SUPPORT
-static int letcmd (int, char **);
-#endif
-static int typecmd (int, char **);
-#ifdef ASH_GETOPTS
-static int getoptscmd (int, char **);
-#endif
-
-#ifndef BB_TRUE_FALSE
-static int true_main (int, char **);
-static int false_main (int, char **);
-#endif
-
-static void     setpwd (const char *, int);
-
-
-#define BUILTIN_NOSPEC  "0"
-#define BUILTIN_SPECIAL "1"
-#define BUILTIN_REGULAR "2"
-#define BUILTIN_ASSIGN  "4"
-#define BUILTIN_SPEC_ASSG  "5"
-#define BUILTIN_REG_ASSG   "6"
-
-#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
-#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
-#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
-
-struct builtincmd {
-       const char *name;
-       int (*const builtinfunc) (int, char **);
-       //unsigned flags;
-};
-
-
-/* It is CRUCIAL that this listing be kept in ascii order, otherwise
- * the binary search in find_builtin() will stop working. If you value
- * your kneecaps, you'll be sure to *make sure* that any changes made
- * to this array result in the listing remaining in ascii order. You
- * have been warned.
- */
-static const struct builtincmd builtincmds[] = {
-       { BUILTIN_SPECIAL   ".", dotcmd },    /* first, see declare DOTCMD */
-       { BUILTIN_SPECIAL   ":", true_main },
-#ifdef ASH_ALIAS
-       { BUILTIN_REG_ASSG  "alias", aliascmd },
-#endif
-#ifdef JOBS
-       { BUILTIN_REGULAR   "bg", bgcmd },
-#endif
-       { BUILTIN_SPECIAL   "break", breakcmd },
-       { BUILTIN_SPECIAL   "builtin", bltincmd },
-       { BUILTIN_REGULAR   "cd", cdcmd },
-       { BUILTIN_NOSPEC    "chdir", cdcmd },
-#ifdef ASH_CMDCMD
-       { BUILTIN_REGULAR   "command", commandcmd },
-#endif
-       { BUILTIN_SPECIAL   "continue", breakcmd },
-       { BUILTIN_SPECIAL   "eval", evalcmd },
-       { BUILTIN_SPECIAL   "exec", execcmd },
-       { BUILTIN_SPECIAL   "exit", exitcmd },
-       { BUILTIN_SPEC_ASSG "export", exportcmd },
-       { BUILTIN_REGULAR   "false", false_main },
-       { BUILTIN_REGULAR   "fc", histcmd },
-#ifdef JOBS
-       { BUILTIN_REGULAR   "fg", fgcmd },
-#endif
-#ifdef ASH_GETOPTS
-       { BUILTIN_REGULAR   "getopts", getoptscmd },
-#endif
-       { BUILTIN_NOSPEC    "hash", hashcmd },
-       { BUILTIN_NOSPEC    "help", helpcmd },
-       { BUILTIN_REGULAR   "jobs", jobscmd },
-#ifdef JOBS
-       { BUILTIN_REGULAR   "kill", killcmd },
-#endif
-#ifdef ASH_MATH_SUPPORT
-       { BUILTIN_REGULAR    "let", letcmd },
-#endif
-       { BUILTIN_ASSIGN    "local", localcmd },
-#ifndef BB_PWD
-       { BUILTIN_NOSPEC    "pwd", pwdcmd },
-#endif
-       { BUILTIN_REGULAR   "read", readcmd },
-       { BUILTIN_SPEC_ASSG "readonly", exportcmd },
-       { BUILTIN_SPECIAL   "return", returncmd },
-       { BUILTIN_SPECIAL   "set", setcmd },
-       { BUILTIN_NOSPEC    "setvar", setvarcmd },
-       { BUILTIN_SPECIAL   "shift", shiftcmd },
-       { BUILTIN_SPECIAL   "times", timescmd },
-       { BUILTIN_SPECIAL   "trap", trapcmd },
-       { BUILTIN_REGULAR   "true", true_main },
-       { BUILTIN_NOSPEC    "type", typecmd },
-       { BUILTIN_NOSPEC    "ulimit", ulimitcmd },
-       { BUILTIN_REGULAR   "umask", umaskcmd },
-#ifdef ASH_ALIAS
-       { BUILTIN_REGULAR   "unalias", unaliascmd },
-#endif
-       { BUILTIN_SPECIAL   "unset", unsetcmd },
-       { BUILTIN_REGULAR   "wait", waitcmd },
-};
-#define NUMBUILTINS  (sizeof (builtincmds) / sizeof (struct builtincmd) )
-
-static const struct builtincmd *DOTCMD = &builtincmds[0];
-static struct builtincmd *BLTINCMD;
-static struct builtincmd *EXECCMD;
-static struct builtincmd *EVALCMD;
-
-/* states */
-#define JOBSTOPPED 1            /* all procs are stopped */
-#define JOBDONE 2               /* all procs are completed */
-
-/*
- * A job structure contains information about a job.  A job is either a
- * single process or a set of processes contained in a pipeline.  In the
- * latter case, pidlist will be non-NULL, and will point to a -1 terminated
- * array of pids.
- */
-
-struct procstat {
-       pid_t pid;              /* process id */
-       int status;             /* status flags (defined above) */
-       char *cmd;              /* text of command being run */
-};
-
-
-static int job_warning;         /* user was warned about stopped jobs */
-
-#ifdef JOBS
-static void setjobctl(int enable);
-#else
-#define setjobctl(on)   /* do nothing */
-#endif
-
-
-struct job {
-       struct procstat ps0;    /* status of process */
-       struct procstat *ps;    /* status or processes when more than one */
-       short nprocs;           /* number of processes */
-       short pgrp;             /* process group of this job */
-       char state;             /* true if job is finished */
-       char used;              /* true if this entry is in used */
-       char changed;           /* true if status has changed */
-#ifdef JOBS
-       char jobctl;            /* job running under job control */
-#endif
-};
-
-static struct job *jobtab;      /* array of jobs */
-static int njobs;               /* size of array */
-static int backgndpid = -1;     /* pid of last background process */
-#ifdef JOBS
-static int initialpgrp;         /* pgrp of shell on invocation */
-static int curjob;              /* current job */
-static int jobctl;
-#endif
-static int intreceived;
-
-static struct job *makejob (const union node *, int);
-static int forkshell (struct job *, const union node *, int);
-static int waitforjob (struct job *);
-
-static int docd (char *, int);
-static char *getcomponent (void);
-static void updatepwd (const char *);
-static void getpwd (void);
-
-static char *padvance (const char **, const char *);
-
-static char nullstr[1];         /* zero length string */
-static char *curdir = nullstr;          /* current working directory */
-static char *cdcomppath;
-
-static int
-cdcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       const char *dest;
-       const char *path;
-       char *p;
-       struct stat statb;
-       int print = 0;
-
-       nextopt(nullstr);
-       if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
-               error("HOME not set");
-       if (*dest == '\0')
-               dest = ".";
-       if (dest[0] == '-' && dest[1] == '\0') {
-               dest = bltinlookup("OLDPWD");
-               if (!dest || !*dest) {
-                       dest = curdir;
-               }
-               print = 1;
-               if (dest)
-                       print = 1;
-               else
-                       dest = ".";
-       }
-       if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
-               path = nullstr;
-       while ((p = padvance(&path, dest)) != NULL) {
-               if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
-                       if (!print) {
-                               /*
-                                * XXX - rethink
-                                */
-                               if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
-                                       p += 2;
-                               print = strcmp(p, dest);
-                       }
-                       if (docd(p, print) >= 0)
-                               return 0;
-
-               }
-       }
-       error("can't cd to %s", dest);
-       /* NOTREACHED */
-}
-
-
-/*
- * Actually do the chdir.  In an interactive shell, print the
- * directory name if "print" is nonzero.
- */
-
-static int
-docd(dest, print)
-       char *dest;
-       int print;
-{
-       char *p;
-       char *q;
-       char *component;
-       struct stat statb;
-       int first;
-       int badstat;
-
-       TRACE(("docd(\"%s\", %d) called\n", dest, print));
-
-       /*
-        *  Check each component of the path. If we find a symlink or
-        *  something we can't stat, clear curdir to force a getcwd()
-        *  next time we get the value of the current directory.
-        */
-       badstat = 0;
-       cdcomppath = sstrdup(dest);
-       STARTSTACKSTR(p);
-       if (*dest == '/') {
-               STPUTC('/', p);
-               cdcomppath++;
-       }
-       first = 1;
-       while ((q = getcomponent()) != NULL) {
-               if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
-                       continue;
-               if (! first)
-                       STPUTC('/', p);
-               first = 0;
-               component = q;
-               while (*q)
-                       STPUTC(*q++, p);
-               if (equal(component, ".."))
-                       continue;
-               STACKSTRNUL(p);
-               if ((lstat(stackblock(), &statb) < 0)
-                   || (S_ISLNK(statb.st_mode)))  {
-                       /* print = 1; */
-                       badstat = 1;
-                       break;
-               }
-       }
-
-       INTOFF;
-       if (chdir(dest) < 0) {
-               INTON;
-               return -1;
-       }
-       updatepwd(badstat ? NULL : dest);
-       INTON;
-       if (print && iflag)
-               printf(snlfmt, curdir);
-       return 0;
-}
-
-
-/*
- * Get the next component of the path name pointed to by cdcomppath.
- * This routine overwrites the string pointed to by cdcomppath.
- */
-
-static char *
-getcomponent() {
-       char *p;
-       char *start;
-
-       if ((p = cdcomppath) == NULL)
-               return NULL;
-       start = cdcomppath;
-       while (*p != '/' && *p != '\0')
-               p++;
-       if (*p == '\0') {
-               cdcomppath = NULL;
-       } else {
-               *p++ = '\0';
-               cdcomppath = p;
-       }
-       return start;
-}
-
-
-
-/*
- * Update curdir (the name of the current directory) in response to a
- * cd command.  We also call hashcd to let the routines in exec.c know
- * that the current directory has changed.
- */
-
-static void hashcd (void);
-
-static void
-updatepwd(const char *dir)
-{
-       char *new;
-       char *p;
-       size_t len;
-
-       hashcd();                               /* update command hash table */
-
-       /*
-        * If our argument is NULL, we don't know the current directory
-        * any more because we traversed a symbolic link or something
-        * we couldn't stat().
-        */
-       if (dir == NULL || curdir == nullstr)  {
-               setpwd(0, 1);
-               return;
-       }
-       len = strlen(dir);
-       cdcomppath = sstrdup(dir);
-       STARTSTACKSTR(new);
-       if (*dir != '/') {
-               p = curdir;
-               while (*p)
-                       STPUTC(*p++, new);
-               if (p[-1] == '/')
-                       STUNPUTC(new);
-       }
-       while ((p = getcomponent()) != NULL) {
-               if (equal(p, "..")) {
-                       while (new > stackblock() && (STUNPUTC(new), *new) != '/');
-               } else if (*p != '\0' && ! equal(p, ".")) {
-                       STPUTC('/', new);
-                       while (*p)
-                               STPUTC(*p++, new);
-               }
-       }
-       if (new == stackblock())
-               STPUTC('/', new);
-       STACKSTRNUL(new);
-       setpwd(stackblock(), 1);
-}
-
-
-#ifndef BB_PWD
-static int
-pwdcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       printf(snlfmt, curdir);
-       return 0;
-}
-#endif
-
-/*
- * Find out what the current directory is. If we already know the current
- * directory, this routine returns immediately.
- */
-static void
-getpwd(void)
-{
-       curdir = xgetcwd(0);
-       if(curdir==0)
-               curdir = nullstr;
-}
-
-static void
-setpwd(const char *val, int setold)
-{
-       if (setold) {
-               setvar("OLDPWD", curdir, VEXPORT);
-       }
-       INTOFF;
-       if (curdir != nullstr) {
-               free(curdir);
-               curdir = nullstr;
-       }
-       if (!val) {
-               getpwd();
-       } else {
-               curdir = savestr(val);
-       }
-       INTON;
-       setvar("PWD", curdir, VEXPORT);
-}
-
-/*
- * Errors and exceptions.
- */
-
-/*
- * Code to handle exceptions in C.
- */
-
-/*
- * We enclose jmp_buf in a structure so that we can declare pointers to
- * jump locations.  The global variable handler contains the location to
- * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exeception.  To implement nested
- * exception handlers, the user should save the value of handler on entry
- * to an inner scope, set handler to point to a jmploc structure for the
- * inner scope, and restore handler on exit from the scope.
- */
-
-struct jmploc {
-       jmp_buf loc;
-};
-
-/* exceptions */
-#define EXINT 0         /* SIGINT received */
-#define EXERROR 1       /* a generic error */
-#define EXSHELLPROC 2   /* execute a shell procedure */
-#define EXEXEC 3        /* command execution failed */
-
-static struct jmploc *handler;
-static int exception;
-
-static void exverror (int, const char *, va_list)
-    __attribute__((__noreturn__));
-
-/*
- * Called to raise an exception.  Since C doesn't include exceptions, we
- * just do a longjmp to the exception handler.  The type of exception is
- * stored in the global variable "exception".
- */
-
-static void exraise (int) __attribute__((__noreturn__));
-
-static void
-exraise(int e)
-{
-#ifdef DEBUG
-       if (handler == NULL)
-               abort();
-#endif
-       flushall();
-       exception = e;
-       longjmp(handler->loc, 1);
-}
-
-
-/*
- * Called from trap.c when a SIGINT is received.  (If the user specifies
- * that SIGINT is to be trapped or ignored using the trap builtin, then
- * this routine is not called.)  Suppressint is nonzero when interrupts
- * are held using the INTOFF macro.  The call to _exit is necessary because
- * there is a short period after a fork before the signal handlers are
- * set to the appropriate value for the child.  (The test for iflag is
- * just defensive programming.)
- */
-
-static void
-onint(void) {
-       sigset_t mysigset;
-
-       if (suppressint) {
-               intpending++;
-               return;
-       }
-       intpending = 0;
-       sigemptyset(&mysigset);
-       sigprocmask(SIG_SETMASK, &mysigset, NULL);
-       if (rootshell && iflag)
-               exraise(EXINT);
-       else {
-               signal(SIGINT, SIG_DFL);
-               raise(SIGINT);
-       }
-       /* NOTREACHED */
-}
-
-
-static char *commandname;       /* currently executing command */
-
-/*
- * Exverror is called to raise the error exception.  If the first argument
- * is not NULL then error prints an error message using printf style
- * formatting.  It then raises the error exception.
- */
-static void
-exverror(int cond, const char *msg, va_list ap)
-{
-       CLEAR_PENDING_INT;
-       INTOFF;
-
-#ifdef DEBUG
-       if (msg)
-               TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
-       else
-               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
-#endif
-       if (msg) {
-               if (commandname)
-                       out2fmt("%s: ", commandname);
-               vfprintf(stderr, msg, ap);
-               out2c('\n');
-       }
-       exraise(cond);
-       /* NOTREACHED */
-}
-
-
-static void 
-error(const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(EXERROR, msg, ap);
-       /* NOTREACHED */
-       va_end(ap);
-}
-
-
-static void
-exerror(int cond, const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(cond, msg, ap);
-       /* NOTREACHED */
-       va_end(ap);
-}
-
-
-
-/*
- * Table of error messages.
- */
-
-struct errname {
-       short errcode;          /* error number */
-       char  action;           /* operation which encountered the error */
-};
-
-/*
- * Types of operations (passed to the errmsg routine).
- */
-
-#define E_OPEN 01       /* opening a file */
-#define E_CREAT 02      /* creating a file */
-#define E_EXEC 04       /* executing a program */
-
-#define ALL (E_OPEN|E_CREAT|E_EXEC)
-
-static const struct errname errormsg[] = {
-       { EINTR,        ALL     },
-       { EACCES,       ALL     },
-       { EIO,          ALL     },
-       { ENOENT,       E_OPEN  },
-       { ENOENT,       E_CREAT },
-       { ENOENT,       E_EXEC  },
-       { ENOTDIR,      E_OPEN  },
-       { ENOTDIR,      E_CREAT },
-       { ENOTDIR,      E_EXEC  },
-       { EISDIR,       ALL     },
-       { EEXIST,       E_CREAT },
-#ifdef EMFILE
-       { EMFILE,       ALL     },
-#endif
-       { ENFILE,       ALL     },
-       { ENOSPC,       ALL     },
-#ifdef EDQUOT
-       { EDQUOT,       ALL     },
-#endif
-#ifdef ENOSR
-       { ENOSR,        ALL     },
-#endif
-       { ENXIO,        ALL     },
-       { EROFS,        ALL     },
-       { ETXTBSY,      ALL     },
-#ifdef EAGAIN
-       { EAGAIN,       E_EXEC  },
-#endif
-       { ENOMEM,       ALL     },
-#ifdef ENOLINK
-       { ENOLINK,      ALL     },
-#endif
-#ifdef EMULTIHOP
-       { EMULTIHOP,    ALL     },
-#endif
-#ifdef ECOMM
-       { ECOMM,        ALL     },
-#endif
-#ifdef ESTALE
-       { ESTALE,       ALL     },
-#endif
-#ifdef ETIMEDOUT
-       { ETIMEDOUT,    ALL     },
-#endif
-#ifdef ELOOP
-       { ELOOP,        ALL     },
-#endif
-       { E2BIG,        E_EXEC  },
-#ifdef ELIBACC
-       { ELIBACC,      E_EXEC  },
-#endif
-};
-
-#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
-
-/*
- * Return a string describing an error.  The returned string may be a
- * pointer to a static buffer that will be overwritten on the next call.
- * Action describes the operation that got the error.
- */
-
-static const char *
-errmsg(int e, int action)
-{
-       struct errname const *ep;
-       static char buf[12];
-
-       for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
-               if (ep->errcode == e && (ep->action & action) != 0)
-                       return strerror(e);
-       }
-
-       snprintf(buf, sizeof buf, "error %d", e);
-       return buf;
-}
-
-
-#ifdef ASH_OPTIMIZE_FOR_SIZE
-static void
-__inton() {
-       if (--suppressint == 0 && intpending) {
-               onint();
-       }
-}
-static void forceinton (void) {
-       suppressint = 0;
-       if (intpending)
-               onint();
-}
-#endif
-
-/* flags in argument to evaltree */
-#define EV_EXIT 01              /* exit after evaluating tree */
-#define EV_TESTED 02            /* exit status is checked; ignore -e flag */
-#define EV_BACKCMD 04           /* command executing within back quotes */
-
-static int evalskip;                    /* set if we are skipping commands */
-static int skipcount;           /* number of levels to skip */
-static int loopnest;            /* current loop nesting level */
-static int funcnest;                    /* depth of function calls */
-
-
-static struct strlist *cmdenviron;      /* environment for builtin command */
-static int exitstatus;                  /* exit status of last command */
-static int oexitstatus;         /* saved exit status */
-
-static void evalsubshell (const union node *, int);
-static void expredir (union node *);
-static void prehash (union node *);
-static void eprintlist (struct strlist *);
-
-static union node *parsecmd(int);
-/*
- * Called to reset things after an exception.
- */
-
-/*
- * The eval commmand.
- */
-static void evalstring (char *, int);
-
-static int
-evalcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *p;
-       char *concat;
-       char **ap;
-
-       if (argc > 1) {
-               p = argv[1];
-               if (argc > 2) {
-                       STARTSTACKSTR(concat);
-                       ap = argv + 2;
-                       for (;;) {
-                               while (*p)
-                                       STPUTC(*p++, concat);
-                               if ((p = *ap++) == NULL)
-                                       break;
-                               STPUTC(' ', concat);
-                       }
-                       STPUTC('\0', concat);
-                       p = grabstackstr(concat);
-               }
-               evalstring(p, EV_TESTED);
-       }
-       return exitstatus;
-}
-
-/*
- * Execute a command or commands contained in a string.
- */
-
-static void evaltree (union node *, int);
-static void setinputstring (char *);
-static void popfile (void);
-static void setstackmark(struct stackmark *mark);
-static void popstackmark(struct stackmark *mark);
-
-
-static void
-evalstring(char *s, int flag)
-{
-       union node *n;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       setinputstring(s);
-       while ((n = parsecmd(0)) != NEOF) {
-               evaltree(n, flag);
-               popstackmark(&smark);
-       }
-       popfile();
-       popstackmark(&smark);
-}
-
-static struct builtincmd *find_builtin (const char *);
-static void expandarg (union node *, struct arglist *, int);
-static void calcsize (const union node *);
-static union node *copynode (const union node *);
-
-/*
- * Make a copy of a parse tree.
- */
-
-static int     funcblocksize;           /* size of structures in function */
-static int     funcstringsize;          /* size of strings in node */
-static pointer funcblock;              /* block to allocate function from */
-static char   *funcstring;              /* block to allocate strings from */
-
-
-static inline union node *
-copyfunc(union node *n)
-{
-       if (n == NULL)
-               return NULL;
-       funcblocksize = 0;
-       funcstringsize = 0;
-       calcsize(n);
-       funcblock = ckmalloc(funcblocksize + funcstringsize);
-       funcstring = (char *) funcblock + funcblocksize;
-       return copynode(n);
-}
-
-/*
- * Free a parse tree.
- */
-
-static void
-freefunc(union node *n)
-{
-       if (n)
-               ckfree(n);
-}
-
-
-/*
- * Add a new command entry, replacing any existing command entry for
- * the same name.
- */
-
-static inline void
-addcmdentry(char *name, struct cmdentry *entry)
-{
-       struct tblentry *cmdp;
-
-       INTOFF;
-       cmdp = cmdlookup(name, 1);
-       if (cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
-       }
-       cmdp->cmdtype = entry->cmdtype;
-       cmdp->param = entry->u;
-       INTON;
-}
-
-static inline void
-evalloop(const union node *n, int flags)
-{
-       int status;
-
-       loopnest++;
-       status = 0;
-       for (;;) {
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip) {
-skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
-                               evalskip = 0;
-                               continue;
-                       }
-                       if (evalskip == SKIPBREAK && --skipcount <= 0)
-                               evalskip = 0;
-                       break;
-               }
-               if (n->type == NWHILE) {
-                       if (exitstatus != 0)
-                               break;
-               } else {
-                       if (exitstatus == 0)
-                               break;
-               }
-               evaltree(n->nbinary.ch2, flags & EV_TESTED);
-               status = exitstatus;
-               if (evalskip)
-                       goto skipping;
-       }
-       loopnest--;
-       exitstatus = status;
-}
-
-static void
-evalfor(const union node *n, int flags)
-{
-       struct arglist arglist;
-       union node *argp;
-       struct strlist *sp;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
-               oexitstatus = exitstatus;
-               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
-               if (evalskip)
-                       goto out;
-       }
-       *arglist.lastp = NULL;
-
-       exitstatus = 0;
-       loopnest++;
-       for (sp = arglist.list ; sp ; sp = sp->next) {
-               setvar(n->nfor.var, sp->text, 0);
-               evaltree(n->nfor.body, flags & EV_TESTED);
-               if (evalskip) {
-                       if (evalskip == SKIPCONT && --skipcount <= 0) {
-                               evalskip = 0;
-                               continue;
-                       }
-                       if (evalskip == SKIPBREAK && --skipcount <= 0)
-                               evalskip = 0;
-                       break;
-               }
-       }
-       loopnest--;
-out:
-       popstackmark(&smark);
-}
-
-static inline void
-evalcase(const union node *n, int flags)
-{
-       union node *cp;
-       union node *patp;
-       struct arglist arglist;
-       struct stackmark smark;
-
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       oexitstatus = exitstatus;
-       expandarg(n->ncase.expr, &arglist, EXP_TILDE);
-       for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
-               for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
-                       if (casematch(patp, arglist.list->text)) {
-                               if (evalskip == 0) {
-                                       evaltree(cp->nclist.body, flags);
-                               }
-                               goto out;
-                       }
-               }
-       }
-out:
-       popstackmark(&smark);
-}
-
-/*
- * Evaluate a pipeline.  All the processes in the pipeline are children
- * of the process creating the pipeline.  (This differs from some versions
- * of the shell, which make the last process in a pipeline the parent
- * of all the rest.)
- */
-
-static inline void
-evalpipe(n)
-       union node *n;
-{
-       struct job *jp;
-       struct nodelist *lp;
-       int pipelen;
-       int prevfd;
-       int pip[2];
-
-       TRACE(("evalpipe(0x%lx) called\n", (long)n));
-       pipelen = 0;
-       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
-               pipelen++;
-       INTOFF;
-       jp = makejob(n, pipelen);
-       prevfd = -1;
-       for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-               prehash(lp->n);
-               pip[1] = -1;
-               if (lp->next) {
-                       if (pipe(pip) < 0) {
-                               close(prevfd);
-                               error("Pipe call failed");
-                       }
-               }
-               if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
-                       INTON;
-                       if (prevfd > 0) {
-                               close(0);
-                               dup_as_newfd(prevfd, 0);
-                               close(prevfd);
-                               if (pip[0] == 0) {
-                                       pip[0] = -1;
-                               }
-                       }
-                       if (pip[1] >= 0) {
-                               if (pip[0] >= 0) {
-                                       close(pip[0]);
-                               }
-                               if (pip[1] != 1) {
-                                       close(1);
-                                       dup_as_newfd(pip[1], 1);
-                                       close(pip[1]);
-                               }
-                       }
-                       evaltree(lp->n, EV_EXIT);
-               }
-               if (prevfd >= 0)
-                       close(prevfd);
-               prevfd = pip[0];
-               close(pip[1]);
-       }
-       INTON;
-       if (n->npipe.backgnd == 0) {
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
-               INTON;
-       }
-}
-
-static void find_command (const char *, struct cmdentry *, int, const char *);
-
-static int
-isassignment(const char *word) {
-       if (!is_name(*word)) {
-               return 0;
-       }
-       do {
-               word++;
-       } while (is_in_name(*word));
-       return *word == '=';
-}
-
-
-static void
-evalcommand(union node *cmd, int flags)
-{
-       struct stackmark smark;
-       union node *argp;
-       struct arglist arglist;
-       struct arglist varlist;
-       char **argv;
-       int argc;
-       char **envp;
-       struct strlist *sp;
-       int mode;
-       struct cmdentry cmdentry;
-       struct job *jp;
-       char *volatile savecmdname;
-       volatile struct shparam saveparam;
-       struct localvar *volatile savelocalvars;
-       volatile int e;
-       char *lastarg;
-       const char *path;
-       const struct builtincmd *firstbltin;
-       struct jmploc *volatile savehandler;
-       struct jmploc jmploc;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &argv;
-       (void) &argc;
-       (void) &lastarg;
-       (void) &flags;
-#endif
-
-       /* First expand the arguments. */
-       TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
-       setstackmark(&smark);
-       arglist.lastp = &arglist.list;
-       varlist.lastp = &varlist.list;
-       arglist.list = 0;
-       oexitstatus = exitstatus;
-       exitstatus = 0;
-       path = pathval();
-       for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
-               expandarg(argp, &varlist, EXP_VARTILDE);
-       }
-       for (
-               argp = cmd->ncmd.args; argp && !arglist.list;
-               argp = argp->narg.next
-       ) {
-               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-       }
-       if (argp) {
-               struct builtincmd *bcmd;
-               int pseudovarflag;
-               bcmd = find_builtin(arglist.list->text);
-               pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
-               for (; argp; argp = argp->narg.next) {
-                       if (pseudovarflag && isassignment(argp->narg.text)) {
-                               expandarg(argp, &arglist, EXP_VARTILDE);
-                               continue;
-                       }
-                       expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-               }
-       }
-       *arglist.lastp = NULL;
-       *varlist.lastp = NULL;
-       expredir(cmd->ncmd.redirect);
-       argc = 0;
-       for (sp = arglist.list ; sp ; sp = sp->next)
-               argc++;
-       argv = stalloc(sizeof (char *) * (argc + 1));
-
-       for (sp = arglist.list ; sp ; sp = sp->next) {
-               TRACE(("evalcommand arg: %s\n", sp->text));
-               *argv++ = sp->text;
-       }
-       *argv = NULL;
-       lastarg = NULL;
-       if (iflag && funcnest == 0 && argc > 0)
-               lastarg = argv[-1];
-       argv -= argc;
-
-       /* Print the command if xflag is set. */
-       if (xflag) {
-               out2c('+');
-               eprintlist(varlist.list);
-               eprintlist(arglist.list);
-               out2c('\n');
-       }
-
-       /* Now locate the command. */
-       if (argc == 0) {
-               cmdentry.cmdtype = CMDBUILTIN;
-               firstbltin = cmdentry.u.cmd = BLTINCMD;
-       } else {
-               const char *oldpath;
-               int findflag = DO_ERR;
-               int oldfindflag;
-
-               /*
-                * Modify the command lookup path, if a PATH= assignment
-                * is present
-                */
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       if (varequal(sp->text, defpathvar)) {
-                               path = sp->text + 5;
-                               findflag |= DO_BRUTE;
-                       }
-               oldpath = path;
-               oldfindflag = findflag;
-               firstbltin = 0;
-               for(;;) {
-                       find_command(argv[0], &cmdentry, findflag, path);
-                       if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
-                               exitstatus = 127;
-                               goto out;
-                       }
-                       /* implement bltin and command here */
-                       if (cmdentry.cmdtype != CMDBUILTIN) {
-                               break;
-                       }
-                       if (!firstbltin) {
-                               firstbltin = cmdentry.u.cmd;
-                       }
-                       if (cmdentry.u.cmd == BLTINCMD) {
-                               for(;;) {
-                                       struct builtincmd *bcmd;
-
-                                       argv++;
-                                       if (--argc == 0)
-                                               goto found;
-                                       if (!(bcmd = find_builtin(*argv))) {
-                                               out2fmt("%s: not found\n", *argv);
-                                               exitstatus = 127;
-                                               goto out;
-                                       }
-                                       cmdentry.u.cmd = bcmd;
-                                       if (bcmd != BLTINCMD)
-                                               break;
-                               }
-                       }
-                       if (cmdentry.u.cmd == find_builtin("command")) {
-                               argv++;
-                               if (--argc == 0) {
-                                       goto found;
-                               }
-                               if (*argv[0] == '-') {
-                                       if (!equal(argv[0], "-p")) {
-                                               argv--;
-                                               argc++;
-                                               break;
-                                       }
-                                       argv++;
-                                       if (--argc == 0) {
-                                               goto found;
-                                       }
-                                       path = defpath;
-                                       findflag |= DO_BRUTE;
-                               } else {
-                                       path = oldpath;
-                                       findflag = oldfindflag;
-                               }
-                               findflag |= DO_NOFUN;
-                               continue;
-                       }
-found:
-                       break;
-               }
-       }
-
-       /* Fork off a child process if necessary. */
-       if (cmd->ncmd.backgnd
-        || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
-       ) {
-               jp = makejob(cmd, 1);
-               mode = cmd->ncmd.backgnd;
-               if (forkshell(jp, cmd, mode) != 0)
-                       goto parent;    /* at end of routine */
-               flags |= EV_EXIT;
-       }
-
-       /* This is the child process if a fork occurred. */
-       /* Execute the command. */
-       if (cmdentry.cmdtype == CMDFUNCTION) {
-#ifdef DEBUG
-               trputs("Shell function:  ");  trargs(argv);
-#endif
-               exitstatus = oexitstatus;
-               redirect(cmd->ncmd.redirect, REDIR_PUSH);
-               saveparam = shellparam;
-               shellparam.malloc = 0;
-               shellparam.nparam = argc - 1;
-               shellparam.p = argv + 1;
-               INTOFF;
-               savelocalvars = localvars;
-               localvars = NULL;
-               INTON;
-               if (setjmp(jmploc.loc)) {
-                       if (exception == EXSHELLPROC) {
-                               freeparam((volatile struct shparam *)
-                                   &saveparam);
-                       } else {
-                               saveparam.optind = shellparam.optind;
-                               saveparam.optoff = shellparam.optoff;
-                               freeparam(&shellparam);
-                               shellparam = saveparam;
-                       }
-                       poplocalvars();
-                       localvars = savelocalvars;
-                       handler = savehandler;
-                       longjmp(handler->loc, 1);
-               }
-               savehandler = handler;
-               handler = &jmploc;
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       mklocal(sp->text);
-               funcnest++;
-               evaltree(cmdentry.u.func, flags & EV_TESTED);
-               funcnest--;
-               INTOFF;
-               poplocalvars();
-               localvars = savelocalvars;
-               saveparam.optind = shellparam.optind;
-               saveparam.optoff = shellparam.optoff;
-               freeparam(&shellparam);
-               shellparam = saveparam;
-               handler = savehandler;
-               popredir();
-               INTON;
-               if (evalskip == SKIPFUNC) {
-                       evalskip = 0;
-                       skipcount = 0;
-               }
-               if (flags & EV_EXIT)
-                       exitshell(exitstatus);
-       } else if (cmdentry.cmdtype == CMDBUILTIN) {
-#ifdef DEBUG
-               trputs("builtin command:  ");  trargs(argv);
-#endif
-               mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-               redirect(cmd->ncmd.redirect, mode);
-               savecmdname = commandname;
-               if (IS_BUILTIN_SPECIAL(firstbltin)) {
-                       listsetvar(varlist.list);
-               } else {
-                       cmdenviron = varlist.list;
-               }
-               e = -1;
-               if (setjmp(jmploc.loc)) {
-                       e = exception;
-                       exitstatus = (e == EXINT)? SIGINT+128 : 2;
-                       goto cmddone;
-               }
-               savehandler = handler;
-               handler = &jmploc;
-               commandname = argv[0];
-               argptr = argv + 1;
-               optptr = NULL;                  /* initialize nextopt */
-               exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
-               flushall();
-cmddone:
-               cmdenviron = NULL;
-               if (e != EXSHELLPROC) {
-                       commandname = savecmdname;
-                       if (flags & EV_EXIT)
-                               exitshell(exitstatus);
-               }
-               handler = savehandler;
-               if (e != -1) {
-                       if ((e != EXERROR && e != EXEXEC)
-                          || cmdentry.u.cmd == BLTINCMD
-                          || cmdentry.u.cmd == DOTCMD
-                          || cmdentry.u.cmd == EVALCMD
-                          || cmdentry.u.cmd == EXECCMD)
-                               exraise(e);
-                       FORCEINTON;
-               }
-               if (cmdentry.u.cmd != EXECCMD)
-                       popredir();
-       } else {
-#ifdef DEBUG
-               trputs("normal command:  ");  trargs(argv);
-#endif
-               redirect(cmd->ncmd.redirect, 0);
-               clearredir();
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
-               envp = environment();
-               shellexec(argv, envp, path, cmdentry.u.index);
-       }
-       goto out;
-
-parent: /* parent process gets here (if we forked) */
-       if (mode == 0) {        /* argument to fork */
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               INTON;
-       }
-
-out:
-       if (lastarg)
-               setvar("_", lastarg, 0);
-       popstackmark(&smark);
-}
-
-/*
- * Evaluate a parse tree.  The value is left in the global variable
- * exitstatus.
- */
-static void
-evaltree(n, flags)
-       union node *n;
-       int flags;
-{
-       int checkexit = 0;
-       if (n == NULL) {
-               TRACE(("evaltree(NULL) called\n"));
-               goto out;
-       }
-       TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
-       switch (n->type) {
-       case NSEMI:
-               evaltree(n->nbinary.ch1, flags & EV_TESTED);
-               if (evalskip)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NAND:
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus != 0)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NOR:
-               evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus == 0)
-                       goto out;
-               evaltree(n->nbinary.ch2, flags);
-               break;
-       case NREDIR:
-               expredir(n->nredir.redirect);
-               redirect(n->nredir.redirect, REDIR_PUSH);
-               evaltree(n->nredir.n, flags);
-               popredir();
-               break;
-       case NSUBSHELL:
-               evalsubshell(n, flags);
-               break;
-       case NBACKGND:
-               evalsubshell(n, flags);
-               break;
-       case NIF: {
-               evaltree(n->nif.test, EV_TESTED);
-               if (evalskip)
-                       goto out;
-               if (exitstatus == 0)
-                       evaltree(n->nif.ifpart, flags);
-               else if (n->nif.elsepart)
-                       evaltree(n->nif.elsepart, flags);
-               else
-                       exitstatus = 0;
-               break;
-       }
-       case NWHILE:
-       case NUNTIL:
-               evalloop(n, flags);
-               break;
-       case NFOR:
-               evalfor(n, flags);
-               break;
-       case NCASE:
-               evalcase(n, flags);
-               break;
-       case NDEFUN: {
-               struct builtincmd *bcmd;
-               struct cmdentry entry;
-               if (
-                       (bcmd = find_builtin(n->narg.text)) &&
-                       IS_BUILTIN_SPECIAL(bcmd)
-               ) {
-                       out2fmt("%s is a special built-in\n", n->narg.text);
-                       exitstatus = 1;
-                       break;
-               }
-               entry.cmdtype = CMDFUNCTION;
-               entry.u.func = copyfunc(n->narg.next);
-               addcmdentry(n->narg.text, &entry);
-               exitstatus = 0;
-               break;
-       }
-       case NNOT:
-               evaltree(n->nnot.com, EV_TESTED);
-               exitstatus = !exitstatus;
-               break;
-
-       case NPIPE:
-               evalpipe(n);
-               checkexit = 1;
-               break;
-       case NCMD:
-               evalcommand(n, flags);
-               checkexit = 1;
-               break;
-#ifdef DEBUG
-       default:
-               printf("Node type = %d\n", n->type);
-               break;
-#endif
-       }
-out:
-       if (pendingsigs)
-               dotrap();
-       if (
-               flags & EV_EXIT ||
-               (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
-       )
-               exitshell(exitstatus);
-}
-
-/*
- * Kick off a subshell to evaluate a tree.
- */
-
-static void
-evalsubshell(const union node *n, int flags)
-{
-       struct job *jp;
-       int backgnd = (n->type == NBACKGND);
-
-       expredir(n->nredir.redirect);
-       jp = makejob(n, 1);
-       if (forkshell(jp, n, backgnd) == 0) {
-               if (backgnd)
-                       flags &=~ EV_TESTED;
-               redirect(n->nredir.redirect, 0);
-               evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
-       }
-       if (! backgnd) {
-               INTOFF;
-               exitstatus = waitforjob(jp);
-               INTON;
-       }
-}
-
-/*
- * Compute the names of the files in a redirection list.
- */
-
-static void fixredir(union node *n, const char *text, int err);
-
-static void
-expredir(union node *n)
-{
-       union node *redir;
-
-       for (redir = n ; redir ; redir = redir->nfile.next) {
-               struct arglist fn;
-               fn.lastp = &fn.list;
-               oexitstatus = exitstatus;
-               switch (redir->type) {
-               case NFROMTO:
-               case NFROM:
-               case NTO:
-               case NAPPEND:
-               case NTOOV:
-                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
-                       redir->nfile.expfname = fn.list->text;
-                       break;
-               case NFROMFD:
-               case NTOFD:
-                       if (redir->ndup.vname) {
-                               expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
-                               fixredir(redir, fn.list->text, 1);
-                       }
-                       break;
-               }
-       }
-}
-
-
-/*
- * Execute a command inside back quotes.  If it's a builtin command, we
- * want to save its output in a block obtained from malloc.  Otherwise
- * we fork off a subprocess and get the output of the command via a pipe.
- * Should be called with interrupts off.
- */
-
-static void
-evalbackcmd(union node *n, struct backcmd *result)
-{
-       int pip[2];
-       struct job *jp;
-       struct stackmark smark;         /* unnecessary */
-
-       setstackmark(&smark);
-       result->fd = -1;
-       result->buf = NULL;
-       result->nleft = 0;
-       result->jp = NULL;
-       if (n == NULL) {
-               exitstatus = 0;
-               goto out;
-       }
-       exitstatus = 0;
-       if (pipe(pip) < 0)
-               error("Pipe call failed");
-       jp = makejob(n, 1);
-       if (forkshell(jp, n, FORK_NOJOB) == 0) {
-               FORCEINTON;
-               close(pip[0]);
-               if (pip[1] != 1) {
-                       close(1);
-                       dup_as_newfd(pip[1], 1);
-                       close(pip[1]);
-               }
-               eflag = 0;
-               evaltree(n, EV_EXIT);
-       }
-       close(pip[1]);
-       result->fd = pip[0];
-       result->jp = jp;
-out:
-       popstackmark(&smark);
-       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
-               result->fd, result->buf, result->nleft, result->jp));
-}
-
-
-/*
- * Execute a simple command.
- */
-
-/*
- * Search for a command.  This is called before we fork so that the
- * location of the command will be available in the parent as well as
- * the child.  The check for "goodname" is an overly conservative
- * check that the name will not be subject to expansion.
- */
-
-static void
-prehash(n)
-       union node *n;
-{
-       struct cmdentry entry;
-
-       if (n->type == NCMD && n->ncmd.args)
-               if (goodname(n->ncmd.args->narg.text))
-                       find_command(n->ncmd.args->narg.text, &entry, 0,
-                                    pathval());
-}
-
-
-/*
- * Builtin commands.  Builtin commands whose functions are closely
- * tied to evaluation are implemented here.
- */
-
-/*
- * No command given, or a bltin command with no arguments.  Set the
- * specified variables.
- */
-
-int
-bltincmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       /*
-        * Preserve exitstatus of a previous possible redirection
-        * as POSIX mandates
-        */
-       return exitstatus;
-}
-
-
-/*
- * Handle break and continue commands.  Break, continue, and return are
- * all handled by setting the evalskip flag.  The evaluation routines
- * above all check this flag, and if it is set they start skipping
- * commands rather than executing them.  The variable skipcount is
- * the number of loops to break/continue, or the number of function
- * levels to return.  (The latter is always 1.)  It should probably
- * be an error to break out of more loops than exist, but it isn't
- * in the standard shell so we don't make it one here.
- */
-
-static int
-breakcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int n = argc > 1 ? number(argv[1]) : 1;
-
-       if (n > loopnest)
-               n = loopnest;
-       if (n > 0) {
-               evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
-               skipcount = n;
-       }
-       return 0;
-}
-
-
-/*
- * The return command.
- */
-
-static int
-returncmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int ret = argc > 1 ? number(argv[1]) : oexitstatus;
-
-       if (funcnest) {
-               evalskip = SKIPFUNC;
-               skipcount = 1;
-               return ret;
-       }
-       else {
-               /* Do what ksh does; skip the rest of the file */
-               evalskip = SKIPFILE;
-               skipcount = 1;
-               return ret;
-       }
-}
-
-
-#ifndef BB_TRUE_FALSE
-static int
-false_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       return 1;
-}
-
-
-static int
-true_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       return 0;
-}
-#endif
-
-/*
- * Controls whether the shell is interactive or not.
- */
-
-static void setsignal(int signo);
-static void chkmail(int silent);
-
-
-static void
-setinteractive(int on)
-{
-       static int is_interactive;
-       static int do_banner=0;
-
-       if (on == is_interactive)
-               return;
-       setsignal(SIGINT);
-       setsignal(SIGQUIT);
-       setsignal(SIGTERM);
-       chkmail(1);
-       is_interactive = on;
-       if (do_banner==0 && is_interactive) {
-               /* Looks like they want an interactive shell */
-               printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
-               printf( "Enter 'help' for a list of built-in commands.\n\n");
-               do_banner=1;
-       }
-}
-
-static void
-optschanged(void)
-{
-       setinteractive(iflag);
-       setjobctl(mflag);
-}
-
-
-static int
-execcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc > 1) {
-               struct strlist *sp;
-
-               iflag = 0;              /* exit on error */
-               mflag = 0;
-               optschanged();
-               for (sp = cmdenviron; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
-               shellexec(argv + 1, environment(), pathval(), 0);
-       }
-       return 0;
-}
-
-static void
-eprintlist(struct strlist *sp)
-{
-       for (; sp; sp = sp->next) {
-               out2fmt(" %s",sp->text);
-       }
-}
-
-/*
- * Exec a program.  Never returns.  If you change this routine, you may
- * have to change the find_command routine as well.
- */
-
-static const char *pathopt;     /* set by padvance */
-
-static void
-shellexec(argv, envp, path, idx)
-       char **argv, **envp;
-       const char *path;
-       int idx;
-{
-       char *cmdname;
-       int e;
-
-       if (strchr(argv[0], '/') != NULL) {
-               tryexec(argv[0], argv, envp);
-               e = errno;
-       } else {
-               e = ENOENT;
-               while ((cmdname = padvance(&path, argv[0])) != NULL) {
-                       if (--idx < 0 && pathopt == NULL) {
-                               tryexec(cmdname, argv, envp);
-                               if (errno != ENOENT && errno != ENOTDIR)
-                                       e = errno;
-                       }
-                       stunalloc(cmdname);
-               }
-       }
-
-       /* Map to POSIX errors */
-       switch (e) {
-       case EACCES:
-               exerrno = 126;
-               break;
-       case ENOENT:
-               exerrno = 127;
-               break;
-       default:
-               exerrno = 2;
-               break;
-       }
-       exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
-       /* NOTREACHED */
-}
-
-/*
- * Clear traps on a fork.
- */
-static void
-clear_traps(void) {
-       char **tp;
-
-       for (tp = trap ; tp < &trap[NSIG] ; tp++) {
-               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
-                       INTOFF;
-                       ckfree(*tp);
-                       *tp = NULL;
-                       if (tp != &trap[0])
-                               setsignal(tp - trap);
-                       INTON;
-               }
-       }
-}
-
-
-static void
-initshellproc(void) {
-
-#ifdef ASH_ALIAS
-      /* from alias.c: */
-      {
-             rmaliases();
-      }
-#endif
-      /* from eval.c: */
-      {
-             exitstatus = 0;
-      }
-
-      /* from exec.c: */
-      {
-             deletefuncs();
-      }
-
-      /* from jobs.c: */
-      {
-             backgndpid = -1;
-#ifdef JOBS
-             jobctl = 0;
-#endif
-      }
-
-      /* from options.c: */
-      {
-             int i;
-
-             for (i = 0; i < NOPTS; i++)
-                     optent_val(i) = 0;
-             optschanged();
-
-      }
-
-      /* from redir.c: */
-      {
-             clearredir();
-      }
-
-      /* from trap.c: */
-      {
-             char *sm;
-
-             clear_traps();
-             for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
-                     if (*sm == S_IGN)
-                             *sm = S_HARD_IGN;
-             }
-      }
-
-      /* from var.c: */
-      {
-             shprocvar();
-      }
-}
-
-static int preadbuffer(void);
-static void pushfile (void);
-
-/*
- * Read a character from the script, returning PEOF on end of file.
- * Nul characters in the input are silently discarded.
- */
-
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define pgetc_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
-static int
-pgetc(void)
-{
-       return pgetc_macro();
-}
-#else
-static int
-pgetc_macro(void)
-{
-       return --parsenleft >= 0? *parsenextc++ : preadbuffer();
-}
-
-static inline int
-pgetc(void)
-{
-       return pgetc_macro();
-}
-#endif
-
-
-/*
- * Undo the last call to pgetc.  Only one character may be pushed back.
- * PEOF may be pushed back.
- */
-
-static void
-pungetc() {
-       parsenleft++;
-       parsenextc--;
-}
-
-
-static void
-popfile(void) {
-       struct parsefile *pf = parsefile;
-
-       INTOFF;
-       if (pf->fd >= 0)
-               close(pf->fd);
-       if (pf->buf)
-               ckfree(pf->buf);
-       while (pf->strpush)
-               popstring();
-       parsefile = pf->prev;
-       ckfree(pf);
-       parsenleft = parsefile->nleft;
-       parselleft = parsefile->lleft;
-       parsenextc = parsefile->nextc;
-       plinno = parsefile->linno;
-       INTON;
-}
-
-
-/*
- * Return to top level.
- */
-
-static void
-popallfiles(void) {
-       while (parsefile != &basepf)
-               popfile();
-}
-
-/*
- * Close the file(s) that the shell is reading commands from.  Called
- * after a fork is done.
- */
-
-static void
-closescript() {
-       popallfiles();
-       if (parsefile->fd > 0) {
-               close(parsefile->fd);
-               parsefile->fd = 0;
-       }
-}
-
-
-/*
- * Like setinputfile, but takes an open file descriptor.  Call this with
- * interrupts off.
- */
-
-static void
-setinputfd(fd, push)
-       int fd, push;
-{
-       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-       if (push) {
-               pushfile();
-               parsefile->buf = 0;
-       } else {
-               closescript();
-               while (parsefile->strpush)
-                       popstring();
-       }
-       parsefile->fd = fd;
-       if (parsefile->buf == NULL)
-               parsefile->buf = ckmalloc(BUFSIZ);
-       parselleft = parsenleft = 0;
-       plinno = 1;
-}
-
-
-/*
- * Set the input to take input from a file.  If push is set, push the
- * old input onto the stack first.
- */
-
-static void
-setinputfile(const char *fname, int push)
-{
-       int fd;
-       int myfileno2;
-
-       INTOFF;
-       if ((fd = open(fname, O_RDONLY)) < 0)
-               error("Can't open %s", fname);
-       if (fd < 10) {
-               myfileno2 = dup_as_newfd(fd, 10);
-               close(fd);
-               if (myfileno2 < 0)
-                       error("Out of file descriptors");
-               fd = myfileno2;
-       }
-       setinputfd(fd, push);
-       INTON;
-}
-
-
-static void
-tryexec(char *cmd, char **argv, char **envp)
-{
-       int e;
-
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name = cmd;
-       char** argv_l=argv;
-       int argc_l;
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       name = get_last_path_component(name);
-#endif
-       argv_l=envp;
-       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
-               putenv(*argv_l);
-       argv_l=argv;
-       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
-       optind = 1;
-       run_applet_by_name(name, argc_l, argv);
-#endif
-       execve(cmd, argv, envp);
-       e = errno;
-       if (e == ENOEXEC) {
-               INTOFF;
-               initshellproc();
-               setinputfile(cmd, 0);
-               commandname = arg0 = savestr(argv[0]);
-               setparam(argv + 1);
-               exraise(EXSHELLPROC);
-       }
-       errno = e;
-}
-
-static char *commandtext (const union node *);
-
-/*
- * Do a path search.  The variable path (passed by reference) should be
- * set to the start of the path before the first call; padvance will update
- * this value as it proceeds.  Successive calls to padvance will return
- * the possible path expansions in sequence.  If an option (indicated by
- * a percent sign) appears in the path entry then the global variable
- * pathopt will be set to point to it; otherwise pathopt will be set to
- * NULL.
- */
-
-static const char *pathopt;
-
-static void growstackblock(void);
-
-
-static char *
-padvance(const char **path, const char *name)
-{
-       const char *p;
-       char *q;
-       const char *start;
-       int len;
-
-       if (*path == NULL)
-               return NULL;
-       start = *path;
-       for (p = start ; *p && *p != ':' && *p != '%' ; p++);
-       len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
-       while (stackblocksize() < len)
-               growstackblock();
-       q = stackblock();
-       if (p != start) {
-               memcpy(q, start, p - start);
-               q += p - start;
-               *q++ = '/';
-       }
-       strcpy(q, name);
-       pathopt = NULL;
-       if (*p == '%') {
-               pathopt = ++p;
-               while (*p && *p != ':')  p++;
-       }
-       if (*p == ':')
-               *path = p + 1;
-       else
-               *path = NULL;
-       return stalloc(len);
-}
-
-/*
- * Wrapper around strcmp for qsort/bsearch/...
- */
-static int
-pstrcmp(const void *a, const void *b)
-{
-       return strcmp((const char *) a, *(const char *const *) b);
-}
-
-/*
- * Find a keyword is in a sorted array.
- */
-
-static const char *const *
-findkwd(const char *s)
-{
-       return  bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
-                       sizeof(const char *), pstrcmp);
-}
-
-
-/*** Command hashing code ***/
-
-
-static int
-hashcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-       int c;
-       int verbose;
-       struct cmdentry entry;
-       char *name;
-#ifdef ASH_ALIAS
-       const struct alias *ap;
-#endif
-
-       verbose = 0;
-       while ((c = nextopt("rvV")) != '\0') {
-               if (c == 'r') {
-                       clearcmdentry(0);
-                       return 0;
-               } else if (c == 'v' || c == 'V') {
-                       verbose = c;
-               }
-       }
-       if (*argptr == NULL) {
-               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                               if (cmdp->cmdtype != CMDBUILTIN) {
-                                       printentry(cmdp, verbose);
-                               }
-                       }
-               }
-               return 0;
-       }
-       c = 0;
-       while ((name = *argptr++) != NULL) {
-               if ((cmdp = cmdlookup(name, 0)) != NULL
-                && (cmdp->cmdtype == CMDNORMAL
-                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
-                       delete_cmd_entry();
-#ifdef ASH_ALIAS
-       /* Then look at the aliases */
-               if ((ap = lookupalias(name, 0)) != NULL) {
-                       if (verbose=='v')
-                               printf("%s is an alias for %s\n", name, ap->val);
-                       else
-                               printalias(ap);
-                       continue;
-               }
-#endif
-                       /* First look at the keywords */
-               if (findkwd(name)!=0) {
-                       if (verbose=='v')
-                               printf("%s is a shell keyword\n", name);
-                       else
-                               printf(snlfmt, name);
-                       continue;
-               }
-
-               find_command(name, &entry, DO_ERR, pathval());
-               if (entry.cmdtype == CMDUNKNOWN) c = 1;
-               else if (verbose) {
-                       cmdp = cmdlookup(name, 0);
-                       if (cmdp) printentry(cmdp, verbose=='v');
-                       flushall();
-               }
-       }
-       return c;
-}
-
-static void
-printentry(cmdp, verbose)
-       struct tblentry *cmdp;
-       int verbose;
-       {
-       int idx;
-       const char *path;
-       char *name;
-
-       printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
-       if (cmdp->cmdtype == CMDNORMAL) {
-               idx = cmdp->param.index;
-               path = pathval();
-               do {
-                       name = padvance(&path, cmdp->cmdname);
-                       stunalloc(name);
-               } while (--idx >= 0);
-               if(verbose)
-                       out1str(name);
-       } else if (cmdp->cmdtype == CMDBUILTIN) {
-               if(verbose)
-                       out1str("a shell builtin");
-       } else if (cmdp->cmdtype == CMDFUNCTION) {
-               if (verbose) {
-                       INTOFF;
-                       out1str("a function\n");
-                       name = commandtext(cmdp->param.func);
-                       printf("%s() {\n %s\n}", cmdp->cmdname, name);
-                       ckfree(name);
-                       INTON;
-               }
-#ifdef DEBUG
-       } else {
-               error("internal error: cmdtype %d", cmdp->cmdtype);
-#endif
-       }
-       printf(snlfmt, cmdp->rehash ? "*" : nullstr);
-}
-
-
-
-/*** List the available builtins ***/
-
-
-static int helpcmd(int argc, char** argv)
-{
-       int col, i;
-
-       printf("\nBuilt-in commands:\n-------------------\n");
-       for (col=0, i=0; i < NUMBUILTINS; i++) {
-               col += printf("%c%s", ((col == 0) ? '\t' : ' '),
-                               builtincmds[i].name+1);
-               if (col > 60) {
-                       printf("\n");
-                       col = 0;
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       {
-               extern const struct BB_applet applets[];
-               extern const size_t NUM_APPLETS;
-
-               for (i=0; i < NUM_APPLETS; i++) {
-
-                       col += printf("%c%s", ((col == 0) ? '\t' : ' '),
-                                       applets[i].name);
-                       if (col > 60) {
-                               printf("\n");
-                               col = 0;
-                       }
-               }
-       }
-#endif
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/*
- * Resolve a command name.  If you change this routine, you may have to
- * change the shellexec routine as well.
- */
-
-static int prefix (const char *, const char *);
-
-static void
-find_command(const char *name, struct cmdentry *entry, int act, const char *path)
-{
-       struct tblentry *cmdp;
-       int idx;
-       int prev;
-       char *fullname;
-       struct stat statb;
-       int e;
-       int bltin;
-       int firstchange;
-       int updatetbl;
-       int regular;
-       struct builtincmd *bcmd;
-
-       /* If name contains a slash, don't use the hash table */
-       if (strchr(name, '/') != NULL) {
-               if (act & DO_ABS) {
-                       while (stat(name, &statb) < 0) {
-                               if (errno != ENOENT && errno != ENOTDIR)
-                                       e = errno;
-                               entry->cmdtype = CMDUNKNOWN;
-                               entry->u.index = -1;
-                               return;
-                       }
-                       entry->cmdtype = CMDNORMAL;
-                       entry->u.index = -1;
-                       return;
-               }
-               entry->cmdtype = CMDNORMAL;
-               entry->u.index = 0;
-               return;
-       }
-
-       updatetbl = 1;
-       if (act & DO_BRUTE) {
-               firstchange = path_change(path, &bltin);
-       } else {
-               bltin = builtinloc;
-               firstchange = 9999;
-       }
-
-       /* If name is in the table, and not invalidated by cd, we're done */
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
-               if (cmdp->cmdtype == CMDFUNCTION) {
-                       if (act & DO_NOFUN) {
-                               updatetbl = 0;
-                       } else {
-                               goto success;
-                       }
-               } else if (act & DO_BRUTE) {
-                       if ((cmdp->cmdtype == CMDNORMAL &&
-                            cmdp->param.index >= firstchange) ||
-                           (cmdp->cmdtype == CMDBUILTIN &&
-                            ((builtinloc < 0 && bltin >= 0) ?
-                             bltin : builtinloc) >= firstchange)) {
-                               /* need to recompute the entry */
-                       } else {
-                               goto success;
-                       }
-               } else {
-                       goto success;
-               }
-       }
-
-       bcmd = find_builtin(name);
-       regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
-
-       if (regular) {
-               if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
-                       goto success;
-               }
-       } else if (act & DO_BRUTE) {
-               if (firstchange == 0) {
-                       updatetbl = 0;
-               }
-       }
-
-       /* If %builtin not in path, check for builtin next */
-       if (regular || (bltin < 0 && bcmd)) {
-builtin:
-               if (!updatetbl) {
-                       entry->cmdtype = CMDBUILTIN;
-                       entry->u.cmd = bcmd;
-                       return;
-               }
-               INTOFF;
-               cmdp = cmdlookup(name, 1);
-               cmdp->cmdtype = CMDBUILTIN;
-               cmdp->param.cmd = bcmd;
-               INTON;
-               goto success;
-       }
-
-       /* We have to search path. */
-       prev = -1;              /* where to start */
-       if (cmdp && cmdp->rehash) {     /* doing a rehash */
-               if (cmdp->cmdtype == CMDBUILTIN)
-                       prev = builtinloc;
-               else
-                       prev = cmdp->param.index;
-       }
-
-       e = ENOENT;
-       idx = -1;
-loop:
-       while ((fullname = padvance(&path, name)) != NULL) {
-               stunalloc(fullname);
-               idx++;
-               if (idx >= firstchange) {
-                       updatetbl = 0;
-               }
-               if (pathopt) {
-                       if (prefix("builtin", pathopt)) {
-                               if ((bcmd = find_builtin(name))) {
-                                       goto builtin;
-                               }
-                               continue;
-                       } else if (!(act & DO_NOFUN) &&
-                                  prefix("func", pathopt)) {
-                               /* handled below */
-                       } else {
-                               continue;       /* ignore unimplemented options */
-                       }
-               }
-               /* if rehash, don't redo absolute path names */
-               if (fullname[0] == '/' && idx <= prev &&
-                   idx < firstchange) {
-                       if (idx < prev)
-                               continue;
-                       TRACE(("searchexec \"%s\": no change\n", name));
-                       goto success;
-               }
-               while (stat(fullname, &statb) < 0) {
-                       if (errno != ENOENT && errno != ENOTDIR)
-                               e = errno;
-                       goto loop;
-               }
-               e = EACCES;     /* if we fail, this will be the error */
-               if (!S_ISREG(statb.st_mode))
-                       continue;
-               if (pathopt) {          /* this is a %func directory */
-                       stalloc(strlen(fullname) + 1);
-                       readcmdfile(fullname);
-                       if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
-                               error("%s not defined in %s", name, fullname);
-                       stunalloc(fullname);
-                       goto success;
-               }
-               TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
-               /* If we aren't called with DO_BRUTE and cmdp is set, it must
-                  be a function and we're being called with DO_NOFUN */
-               if (!updatetbl) {
-                       entry->cmdtype = CMDNORMAL;
-                       entry->u.index = idx;
-                       return;
-               }
-               INTOFF;
-               cmdp = cmdlookup(name, 1);
-               cmdp->cmdtype = CMDNORMAL;
-               cmdp->param.index = idx;
-               INTON;
-               goto success;
-       }
-
-       /* We failed.  If there was an entry for this command, delete it */
-       if (cmdp && updatetbl)
-               delete_cmd_entry();
-       if (act & DO_ERR)
-               out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
-       entry->cmdtype = CMDUNKNOWN;
-       return;
-
-success:
-       cmdp->rehash = 0;
-       entry->cmdtype = cmdp->cmdtype;
-       entry->u = cmdp->param;
-}
-
-
-
-/*
- * Search the table of builtin commands.
- */
-
-static int
-bstrcmp(const void *name, const void *b)
-{
-       return strcmp((const char *)name, (*(const char *const *) b)+1);
-}
-
-static struct builtincmd *
-find_builtin(const char *name)
-{
-       struct builtincmd *bp;
-
-       bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
-               bstrcmp
-       );
-       return bp;
-}
-
-
-/*
- * Called when a cd is done.  Marks all commands so the next time they
- * are executed they will be rehashed.
- */
-
-static void
-hashcd(void) {
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-               for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                       if (cmdp->cmdtype == CMDNORMAL
-                        || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
-                               cmdp->rehash = 1;
-               }
-       }
-}
-
-
-
-/*
- * Called before PATH is changed.  The argument is the new value of PATH;
- * pathval() still returns the old value at this point.  Called with
- * interrupts off.
- */
-
-static void
-changepath(const char *newval)
-{
-       int firstchange;
-       int bltin;
-
-       firstchange = path_change(newval, &bltin);
-       if (builtinloc < 0 && bltin >= 0)
-               builtinloc = bltin;             /* zap builtins */
-       clearcmdentry(firstchange);
-       builtinloc = bltin;
-}
-
-
-/*
- * Clear out command entries.  The argument specifies the first entry in
- * PATH which has changed.
- */
-
-static void
-clearcmdentry(firstchange)
-       int firstchange;
-{
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INTOFF;
-       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if ((cmdp->cmdtype == CMDNORMAL &&
-                            cmdp->param.index >= firstchange)
-                        || (cmdp->cmdtype == CMDBUILTIN &&
-                            builtinloc >= firstchange)) {
-                               *pp = cmdp->next;
-                               ckfree(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-
-/*
- * Delete all functions.
- */
-
-static void
-deletefuncs(void) {
-       struct tblentry **tblp;
-       struct tblentry **pp;
-       struct tblentry *cmdp;
-
-       INTOFF;
-       for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
-               pp = tblp;
-               while ((cmdp = *pp) != NULL) {
-                       if (cmdp->cmdtype == CMDFUNCTION) {
-                               *pp = cmdp->next;
-                               freefunc(cmdp->param.func);
-                               ckfree(cmdp);
-                       } else {
-                               pp = &cmdp->next;
-                       }
-               }
-       }
-       INTON;
-}
-
-
-
-/*
- * Locate a command in the command hash table.  If "add" is nonzero,
- * add the command to the table if it is not already present.  The
- * variable "lastcmdentry" is set to point to the address of the link
- * pointing to the entry, so that delete_cmd_entry can delete the
- * entry.
- */
-
-static struct tblentry **lastcmdentry;
-
-static struct tblentry *
-cmdlookup(const char *name, int add)
-{
-       int hashval;
-       const char *p;
-       struct tblentry *cmdp;
-       struct tblentry **pp;
-
-       p = name;
-       hashval = *p << 4;
-       while (*p)
-               hashval += *p++;
-       hashval &= 0x7FFF;
-       pp = &cmdtable[hashval % CMDTABLESIZE];
-       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-               if (equal(cmdp->cmdname, name))
-                       break;
-               pp = &cmdp->next;
-       }
-       if (add && cmdp == NULL) {
-               INTOFF;
-               cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
-                                       + strlen(name) + 1);
-               cmdp->next = NULL;
-               cmdp->cmdtype = CMDUNKNOWN;
-               cmdp->rehash = 0;
-               strcpy(cmdp->cmdname, name);
-               INTON;
-       }
-       lastcmdentry = pp;
-       return cmdp;
-}
-
-/*
- * Delete the command entry returned on the last lookup.
- */
-
-static void
-delete_cmd_entry() {
-       struct tblentry *cmdp;
-
-       INTOFF;
-       cmdp = *lastcmdentry;
-       *lastcmdentry = cmdp->next;
-       ckfree(cmdp);
-       INTON;
-}
-
-
-
-
-
-static const short nodesize[26] = {
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct ncmd)),
-      ALIGN(sizeof (struct npipe)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nredir)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nif)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nbinary)),
-      ALIGN(sizeof (struct nfor)),
-      ALIGN(sizeof (struct ncase)),
-      ALIGN(sizeof (struct nclist)),
-      ALIGN(sizeof (struct narg)),
-      ALIGN(sizeof (struct narg)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct nfile)),
-      ALIGN(sizeof (struct ndup)),
-      ALIGN(sizeof (struct ndup)),
-      ALIGN(sizeof (struct nhere)),
-      ALIGN(sizeof (struct nhere)),
-      ALIGN(sizeof (struct nnot)),
-};
-
-
-
-/*
- * Delete a function if it exists.
- */
-
-static void
-unsetfunc(char *name)
-{
-       struct tblentry *cmdp;
-
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
-               delete_cmd_entry();
-       }
-}
-
-
-/*
- * Locate and print what a word is...
- */
-
-static int
-typecmd(int argc, char **argv)
-{
-       int i;
-       int err = 0;
-       char *argv_a[2];
-
-       argv_a[1] = 0;
-
-       for (i = 1; i < argc; i++) {
-               argv_a[0] = argv[i];
-               argptr = argv_a;
-               optptr = "v";
-               err |= hashcmd(argc, argv);
-       }
-       return err;
-}
-
-#ifdef ASH_CMDCMD
-static int
-commandcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int c;
-       int default_path = 0;
-       int verify_only = 0;
-       int verbose_verify_only = 0;
-
-       while ((c = nextopt("pvV")) != '\0')
-               switch (c) {
-               case 'p':
-                       default_path = 1;
-                       break;
-               case 'v':
-                       verify_only = 1;
-                       break;
-               case 'V':
-                       verbose_verify_only = 1;
-                       break;
-               }
-
-       if (default_path + verify_only + verbose_verify_only > 1 ||
-           !*argptr) {
-                       out2str(
-                               "command [-p] command [arg ...]\n"
-                               "command {-v|-V} command\n");
-                       return EX_USAGE;
-       }
-
-       if (verify_only || verbose_verify_only) {
-               char *argv_a[2];
-
-               argv_a[1] = 0;
-               argv_a[0] = *argptr;
-               argptr = argv_a;
-               optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
-               return hashcmd(argc, argv);
-       }
-
-       return 0;
-}
-#endif
-
-static int
-path_change(newval, bltin)
-       const char *newval;
-       int *bltin;
-{
-       const char *old, *new;
-       int idx;
-       int firstchange;
-
-       old = pathval();
-       new = newval;
-       firstchange = 9999;     /* assume no change */
-       idx = 0;
-       *bltin = -1;
-       for (;;) {
-               if (*old != *new) {
-                       firstchange = idx;
-                       if ((*old == '\0' && *new == ':')
-                        || (*old == ':' && *new == '\0'))
-                               firstchange++;
-                       old = new;      /* ignore subsequent differences */
-               }
-               if (*new == '\0')
-                       break;
-               if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
-                       *bltin = idx;
-               if (*new == ':') {
-                       idx++;
-               }
-               new++, old++;
-       }
-       if (builtinloc >= 0 && *bltin < 0)
-               firstchange = 0;
-       return firstchange;
-}
-/*
- * Routines to expand arguments to commands.  We have to deal with
- * backquotes, shell variables, and file metacharacters.
- */
-/*
- * _rmescape() flags
- */
-#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
-#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
-
-/*
- * Structure specifying which parts of the string should be searched
- * for IFS characters.
- */
-
-struct ifsregion {
-       struct ifsregion *next; /* next region in list */
-       int begoff;             /* offset of start of region */
-       int endoff;             /* offset of end of region */
-       int nulonly;            /* search for nul bytes only */
-};
-
-
-static char *expdest;                   /* output of current string */
-static struct nodelist *argbackq;      /* list of back quote expressions */
-static struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
-static struct ifsregion *ifslastp;     /* last struct in list */
-static struct arglist exparg;          /* holds expanded arg list */
-
-static void argstr (char *, int);
-static char *exptilde (char *, int);
-static void expbackq (union node *, int, int);
-static int subevalvar (char *, char *, int, int, int, int, int);
-static int varisset (char *, int);
-static void strtodest (const char *, const char *, int);
-static void varvalue (char *, int, int);
-static void recordregion (int, int, int);
-static void removerecordregions (int);
-static void ifsbreakup (char *, struct arglist *);
-static void ifsfree (void);
-static void expandmeta (struct strlist *, int);
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
-#if !defined(GLOB_BROKEN)
-static void addglob (const glob_t *);
-#endif
-#endif
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-static void expmeta (char *, char *);
-#endif
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-static struct strlist *expsort (struct strlist *);
-static struct strlist *msort (struct strlist *, int);
-#endif
-static int patmatch (char *, char *, int);
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-static int patmatch2 (char *, char *, int);
-#else
-static int pmatch (char *, char *, int);
-#define patmatch2 patmatch
-#endif
-static char *cvtnum (int, char *);
-
-/*
- * Expand shell variables and backquotes inside a here document.
- */
-
-/* arg: the document, fd: where to write the expanded version */
-static inline void
-expandhere(union node *arg, int fd)
-{
-       herefd = fd;
-       expandarg(arg, (struct arglist *)NULL, 0);
-       xwrite(fd, stackblock(), expdest - stackblock());
-}
-
-
-/*
- * Perform variable substitution and command substitution on an argument,
- * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
- * perform splitting and file name expansion.  When arglist is NULL, perform
- * here document expansion.
- */
-
-static void
-expandarg(arg, arglist, flag)
-       union node *arg;
-       struct arglist *arglist;
-       int flag;
-{
-       struct strlist *sp;
-       char *p;
-
-       argbackq = arg->narg.backquote;
-       STARTSTACKSTR(expdest);
-       ifsfirst.next = NULL;
-       ifslastp = NULL;
-       argstr(arg->narg.text, flag);
-       if (arglist == NULL) {
-               return;                 /* here document expanded */
-       }
-       STPUTC('\0', expdest);
-       p = grabstackstr(expdest);
-       exparg.lastp = &exparg.list;
-       /*
-        * TODO - EXP_REDIR
-        */
-       if (flag & EXP_FULL) {
-               ifsbreakup(p, &exparg);
-               *exparg.lastp = NULL;
-               exparg.lastp = &exparg.list;
-               expandmeta(exparg.list, flag);
-       } else {
-               if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
-                       rmescapes(p);
-               sp = (struct strlist *)stalloc(sizeof (struct strlist));
-               sp->text = p;
-               *exparg.lastp = sp;
-               exparg.lastp = &sp->next;
-       }
-       ifsfree();
-       *exparg.lastp = NULL;
-       if (exparg.list) {
-               *arglist->lastp = exparg.list;
-               arglist->lastp = exparg.lastp;
-       }
-}
-
-
-/*
- * Expand a variable, and return a pointer to the next character in the
- * input string.
- */
-
-static inline char *
-evalvar(p, flag)
-       char *p;
-       int flag;
-{
-       int subtype;
-       int varflags;
-       char *var;
-       const char *val;
-       int patloc;
-       int c;
-       int set;
-       int special;
-       int startloc;
-       int varlen;
-       int easy;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-
-       varflags = *p++;
-       subtype = varflags & VSTYPE;
-       var = p;
-       special = 0;
-       if (! is_name(*p))
-               special = 1;
-       p = strchr(p, '=') + 1;
-again: /* jump here after setting a variable with ${var=text} */
-       if (special) {
-               set = varisset(var, varflags & VSNUL);
-               val = NULL;
-       } else {
-               val = lookupvar(var);
-               if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
-                       val = NULL;
-                       set = 0;
-               } else
-                       set = 1;
-       }
-       varlen = 0;
-       startloc = expdest - stackblock();
-       if (set && subtype != VSPLUS) {
-               /* insert the value of the variable */
-               if (special) {
-                       varvalue(var, varflags & VSQUOTE, flag);
-                       if (subtype == VSLENGTH) {
-                               varlen = expdest - stackblock() - startloc;
-                               STADJUST(-varlen, expdest);
-                       }
-               } else {
-                       if (subtype == VSLENGTH) {
-                               varlen = strlen(val);
-                       } else {
-                               strtodest(
-                                       val,
-                                       varflags & VSQUOTE ?
-                                               DQSYNTAX : BASESYNTAX,
-                                       quotes
-                               );
-                       }
-               }
-       }
-
-       if (subtype == VSPLUS)
-               set = ! set;
-
-       easy = ((varflags & VSQUOTE) == 0 ||
-               (*var == '@' && shellparam.nparam != 1));
-
-
-       switch (subtype) {
-       case VSLENGTH:
-               expdest = cvtnum(varlen, expdest);
-               goto record;
-
-       case VSNORMAL:
-               if (!easy)
-                       break;
-record:
-               recordregion(startloc, expdest - stackblock(),
-                            varflags & VSQUOTE);
-               break;
-
-       case VSPLUS:
-       case VSMINUS:
-               if (!set) {
-                       argstr(p, flag);
-                       break;
-               }
-               if (easy)
-                       goto record;
-               break;
-
-       case VSTRIMLEFT:
-       case VSTRIMLEFTMAX:
-       case VSTRIMRIGHT:
-       case VSTRIMRIGHTMAX:
-               if (!set)
-                       break;
-               /*
-                * Terminate the string and start recording the pattern
-                * right after it
-                */
-               STPUTC('\0', expdest);
-               patloc = expdest - stackblock();
-               if (subevalvar(p, NULL, patloc, subtype,
-                              startloc, varflags, quotes) == 0) {
-                       int amount = (expdest - stackblock() - patloc) + 1;
-                       STADJUST(-amount, expdest);
-               }
-               /* Remove any recorded regions beyond start of variable */
-               removerecordregions(startloc);
-               goto record;
-
-       case VSASSIGN:
-       case VSQUESTION:
-               if (!set) {
-                       if (subevalvar(p, var, 0, subtype, startloc,
-                                      varflags, quotes)) {
-                               varflags &= ~VSNUL;
-                               /*
-                                * Remove any recorded regions beyond
-                                * start of variable
-                                */
-                               removerecordregions(startloc);
-                               goto again;
-                       }
-                       break;
-               }
-               if (easy)
-                       goto record;
-               break;
-
-#ifdef DEBUG
-       default:
-               abort();
-#endif
-       }
-
-       if (subtype != VSNORMAL) {      /* skip to end of alternative */
-               int nesting = 1;
-               for (;;) {
-                       if ((c = *p++) == CTLESC)
-                               p++;
-                       else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
-                               if (set)
-                                       argbackq = argbackq->next;
-                       } else if (c == CTLVAR) {
-                               if ((*p++ & VSTYPE) != VSNORMAL)
-                                       nesting++;
-                       } else if (c == CTLENDVAR) {
-                               if (--nesting == 0)
-                                       break;
-                       }
-               }
-       }
-       return p;
-}
-
-
-/*
- * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
- * characters to allow for further processing.  Otherwise treat
- * $@ like $* since no splitting will be performed.
- */
-
-static void
-argstr(p, flag)
-       char *p;
-       int flag;
-{
-       char c;
-       int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
-       int firsteq = 1;
-
-       if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
-               p = exptilde(p, flag);
-       for (;;) {
-               switch (c = *p++) {
-               case '\0':
-               case CTLENDVAR: /* ??? */
-                       goto breakloop;
-               case CTLQUOTEMARK:
-                       /* "$@" syntax adherence hack */
-                       if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
-                               break;
-                       if ((flag & EXP_FULL) != 0)
-                               STPUTC(c, expdest);
-                       break;
-               case CTLESC:
-                       if (quotes)
-                               STPUTC(c, expdest);
-                       c = *p++;
-                       STPUTC(c, expdest);
-                       break;
-               case CTLVAR:
-                       p = evalvar(p, flag);
-                       break;
-               case CTLBACKQ:
-               case CTLBACKQ|CTLQUOTE:
-                       expbackq(argbackq->n, c & CTLQUOTE, flag);
-                       argbackq = argbackq->next;
-                       break;
-#ifdef ASH_MATH_SUPPORT
-               case CTLENDARI:
-                       expari(flag);
-                       break;
-#endif
-               case ':':
-               case '=':
-                       /*
-                        * sort of a hack - expand tildes in variable
-                        * assignments (after the first '=' and after ':'s).
-                        */
-                       STPUTC(c, expdest);
-                       if (flag & EXP_VARTILDE && *p == '~') {
-                               if (c == '=') {
-                                       if (firsteq)
-                                               firsteq = 0;
-                                       else
-                                               break;
-                               }
-                               p = exptilde(p, flag);
-                       }
-                       break;
-               default:
-                       STPUTC(c, expdest);
-               }
-       }
-breakloop:;
-       return;
-}
-
-static char *
-exptilde(p, flag)
-       char *p;
-       int flag;
-{
-       char c, *startp = p;
-       struct passwd *pw;
-       const char *home;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-
-       while ((c = *p) != '\0') {
-               switch(c) {
-               case CTLESC:
-                       return (startp);
-               case CTLQUOTEMARK:
-                       return (startp);
-               case ':':
-                       if (flag & EXP_VARTILDE)
-                               goto done;
-                       break;
-               case '/':
-                       goto done;
-               }
-               p++;
-       }
-done:
-       *p = '\0';
-       if (*(startp+1) == '\0') {
-               if ((home = lookupvar("HOME")) == NULL)
-                       goto lose;
-       } else {
-               if ((pw = getpwnam(startp+1)) == NULL)
-                       goto lose;
-               home = pw->pw_dir;
-       }
-       if (*home == '\0')
-               goto lose;
-       *p = c;
-       strtodest(home, SQSYNTAX, quotes);
-       return (p);
-lose:
-       *p = c;
-       return (startp);
-}
-
-
-static void
-removerecordregions(int endoff)
-{
-       if (ifslastp == NULL)
-               return;
-
-       if (ifsfirst.endoff > endoff) {
-               while (ifsfirst.next != NULL) {
-                       struct ifsregion *ifsp;
-                       INTOFF;
-                       ifsp = ifsfirst.next->next;
-                       ckfree(ifsfirst.next);
-                       ifsfirst.next = ifsp;
-                       INTON;
-               }
-               if (ifsfirst.begoff > endoff)
-                       ifslastp = NULL;
-               else {
-                       ifslastp = &ifsfirst;
-                       ifsfirst.endoff = endoff;
-               }
-               return;
-       }
-
-       ifslastp = &ifsfirst;
-       while (ifslastp->next && ifslastp->next->begoff < endoff)
-               ifslastp=ifslastp->next;
-       while (ifslastp->next != NULL) {
-               struct ifsregion *ifsp;
-               INTOFF;
-               ifsp = ifslastp->next->next;
-               ckfree(ifslastp->next);
-               ifslastp->next = ifsp;
-               INTON;
-       }
-       if (ifslastp->endoff > endoff)
-               ifslastp->endoff = endoff;
-}
-
-
-#ifdef ASH_MATH_SUPPORT
-/*
- * Expand arithmetic expression.  Backup to start of expression,
- * evaluate, place result in (backed up) result, adjust string position.
- */
-static void
-expari(int flag)
-{
-       char *p, *start;
-       int errcode;
-       int result;
-       int begoff;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-       int quoted;
-
-       /*      ifsfree(); */
-
-       /*
-        * This routine is slightly over-complicated for
-        * efficiency.  First we make sure there is
-        * enough space for the result, which may be bigger
-        * than the expression if we add exponentation.  Next we
-        * scan backwards looking for the start of arithmetic.  If the
-        * next previous character is a CTLESC character, then we
-        * have to rescan starting from the beginning since CTLESC
-        * characters have to be processed left to right.
-        */
-       CHECKSTRSPACE(10, expdest);
-       USTPUTC('\0', expdest);
-       start = stackblock();
-       p = expdest - 1;
-       while (*p != CTLARI && p >= start)
-               --p;
-       if (*p != CTLARI)
-               error("missing CTLARI (shouldn't happen)");
-       if (p > start && *(p-1) == CTLESC)
-               for (p = start; *p != CTLARI; p++)
-                       if (*p == CTLESC)
-                               p++;
-
-       if (p[1] == '"')
-               quoted=1;
-       else
-               quoted=0;
-       begoff = p - start;
-       removerecordregions(begoff);
-       if (quotes)
-               rmescapes(p+2);
-       result = arith(p+2, &errcode);
-       if (errcode < 0) {
-               if(errcode == -2)
-                       error("divide by zero");
-               else
-                       error("syntax error: \"%s\"\n", p+2);
-       }
-       snprintf(p, 12, "%d", result);
-
-       while (*p++)
-               ;
-
-       if (quoted == 0)
-               recordregion(begoff, p - 1 - start, 0);
-       result = expdest - p + 1;
-       STADJUST(-result, expdest);
-}
-#endif
-
-/*
- * Expand stuff in backwards quotes.
- */
-
-static void
-expbackq(cmd, quoted, flag)
-       union node *cmd;
-       int quoted;
-       int flag;
-{
-       volatile struct backcmd in;
-       int i;
-       char buf[128];
-       char *p;
-       char *dest = expdest;
-       volatile struct ifsregion saveifs;
-       struct ifsregion *volatile savelastp;
-       struct nodelist *volatile saveargbackq;
-       char lastc;
-       int startloc = dest - stackblock();
-       char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
-       volatile int saveherefd;
-       int quotes = flag & (EXP_FULL | EXP_CASE);
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
-       int ex;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &dest;
-       (void) &syntax;
-#endif
-
-       in.fd = -1;
-       in.buf = 0;
-       in.jp = 0;
-
-       INTOFF;
-       saveifs = ifsfirst;
-       savelastp = ifslastp;
-       saveargbackq = argbackq;
-       saveherefd = herefd;
-       herefd = -1;
-       if ((ex = setjmp(jmploc.loc))) {
-               goto err1;
-       }
-       savehandler = handler;
-       handler = &jmploc;
-       INTON;
-       p = grabstackstr(dest);
-       evalbackcmd(cmd, (struct backcmd *) &in);
-       ungrabstackstr(p, dest);
-err1:
-       INTOFF;
-       ifsfirst = saveifs;
-       ifslastp = savelastp;
-       argbackq = saveargbackq;
-       herefd = saveherefd;
-       if (ex) {
-               goto err2;
-       }
-
-       p = in.buf;
-       lastc = '\0';
-       for (;;) {
-               if (--in.nleft < 0) {
-                       if (in.fd < 0)
-                               break;
-                       i = safe_read(in.fd, buf, sizeof buf);
-                       TRACE(("expbackq: read returns %d\n", i));
-                       if (i <= 0)
-                               break;
-                       p = buf;
-                       in.nleft = i - 1;
-               }
-               lastc = *p++;
-               if (lastc != '\0') {
-                       if (quotes && syntax[(int)lastc] == CCTL)
-                               STPUTC(CTLESC, dest);
-                       STPUTC(lastc, dest);
-               }
-       }
-
-       /* Eat all trailing newlines */
-       for (; dest > stackblock() && dest[-1] == '\n';)
-               STUNPUTC(dest);
-
-err2:
-       if (in.fd >= 0)
-               close(in.fd);
-       if (in.buf)
-               ckfree(in.buf);
-       if (in.jp)
-               exitstatus = waitforjob(in.jp);
-       handler = savehandler;
-       if (ex) {
-               longjmp(handler->loc, 1);
-       }
-       if (quoted == 0)
-               recordregion(startloc, dest - stackblock(), 0);
-       TRACE(("evalbackq: size=%d: \"%.*s\"\n",
-               (dest - stackblock()) - startloc,
-               (dest - stackblock()) - startloc,
-               stackblock() + startloc));
-       expdest = dest;
-       INTON;
-}
-
-static int
-subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
-       char *p;
-       char *str;
-       int strloc;
-       int subtype;
-       int startloc;
-       int varflags;
-       int quotes;
-{
-       char *startp;
-       char *loc = NULL;
-       char *q;
-       int c = 0;
-       int saveherefd = herefd;
-       struct nodelist *saveargbackq = argbackq;
-       int amount;
-
-       herefd = -1;
-       argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
-       STACKSTRNUL(expdest);
-       herefd = saveherefd;
-       argbackq = saveargbackq;
-       startp = stackblock() + startloc;
-       if (str == NULL)
-           str = stackblock() + strloc;
-
-       switch (subtype) {
-       case VSASSIGN:
-               setvar(str, startp, 0);
-               amount = startp - expdest;
-               STADJUST(amount, expdest);
-               varflags &= ~VSNUL;
-               if (c != 0)
-                       *loc = c;
-               return 1;
-
-       case VSQUESTION:
-               if (*p != CTLENDVAR) {
-                       out2fmt(snlfmt, startp);
-                       error((char *)NULL);
-               }
-               error("%.*s: parameter %snot set", p - str - 1,
-                     str, (varflags & VSNUL) ? "null or "
-                                             : nullstr);
-               /* NOTREACHED */
-
-       case VSTRIMLEFT:
-               for (loc = startp; loc < str; loc++) {
-                       c = *loc;
-                       *loc = '\0';
-                       if (patmatch2(str, startp, quotes))
-                               goto recordleft;
-                       *loc = c;
-                       if (quotes && *loc == CTLESC)
-                               loc++;
-               }
-               return 0;
-
-       case VSTRIMLEFTMAX:
-               for (loc = str - 1; loc >= startp;) {
-                       c = *loc;
-                       *loc = '\0';
-                       if (patmatch2(str, startp, quotes))
-                               goto recordleft;
-                       *loc = c;
-                       loc--;
-                       if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-                               for (q = startp; q < loc; q++)
-                                       if (*q == CTLESC)
-                                               q++;
-                               if (q > loc)
-                                       loc--;
-                       }
-               }
-               return 0;
-
-       case VSTRIMRIGHT:
-               for (loc = str - 1; loc >= startp;) {
-                       if (patmatch2(str, loc, quotes))
-                               goto recordright;
-                       loc--;
-                       if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-                               for (q = startp; q < loc; q++)
-                                       if (*q == CTLESC)
-                                               q++;
-                               if (q > loc)
-                                       loc--;
-                       }
-               }
-               return 0;
-
-       case VSTRIMRIGHTMAX:
-               for (loc = startp; loc < str - 1; loc++) {
-                       if (patmatch2(str, loc, quotes))
-                               goto recordright;
-                       if (quotes && *loc == CTLESC)
-                               loc++;
-               }
-               return 0;
-
-#ifdef DEBUG
-       default:
-               abort();
-#endif
-       }
-
-recordleft:
-       *loc = c;
-       amount = ((str - 1) - (loc - startp)) - expdest;
-       STADJUST(amount, expdest);
-       while (loc != str - 1)
-               *startp++ = *loc++;
-       return 1;
-
-recordright:
-       amount = loc - expdest;
-       STADJUST(amount, expdest);
-       STPUTC('\0', expdest);
-       STADJUST(-1, expdest);
-       return 1;
-}
-
-
-/*
- * Test whether a specialized variable is set.
- */
-
-static int
-varisset(name, nulok)
-       char *name;
-       int nulok;
-{
-       if (*name == '!')
-               return backgndpid != -1;
-       else if (*name == '@' || *name == '*') {
-               if (*shellparam.p == NULL)
-                       return 0;
-
-               if (nulok) {
-                       char **av;
-
-                       for (av = shellparam.p; *av; av++)
-                               if (**av != '\0')
-                                       return 1;
-                       return 0;
-               }
-       } else if (is_digit(*name)) {
-               char *ap;
-               int num = atoi(name);
-
-               if (num > shellparam.nparam)
-                       return 0;
-
-               if (num == 0)
-                       ap = arg0;
-               else
-                       ap = shellparam.p[num - 1];
-
-               if (nulok && (ap == NULL || *ap == '\0'))
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Put a string on the stack.
- */
-
-static void
-strtodest(p, syntax, quotes)
-       const char *p;
-       const char *syntax;
-       int quotes;
-{
-       while (*p) {
-               if (quotes && syntax[(int) *p] == CCTL)
-                       STPUTC(CTLESC, expdest);
-               STPUTC(*p++, expdest);
-       }
-}
-
-/*
- * Add the value of a specialized variable to the stack string.
- */
-
-static void
-varvalue(name, quoted, flags)
-       char *name;
-       int quoted;
-       int flags;
-{
-       int num;
-       char *p;
-       int i;
-       int sep;
-       int sepq = 0;
-       char **ap;
-       char const *syntax;
-       int allow_split = flags & EXP_FULL;
-       int quotes = flags & (EXP_FULL | EXP_CASE);
-
-       syntax = quoted ? DQSYNTAX : BASESYNTAX;
-       switch (*name) {
-       case '$':
-               num = rootpid;
-               goto numvar;
-       case '?':
-               num = oexitstatus;
-               goto numvar;
-       case '#':
-               num = shellparam.nparam;
-               goto numvar;
-       case '!':
-               num = backgndpid;
-numvar:
-               expdest = cvtnum(num, expdest);
-               break;
-       case '-':
-               for (i = 0 ; i < NOPTS ; i++) {
-                       if (optent_val(i))
-                               STPUTC(optent_letter(optlist[i]), expdest);
-               }
-               break;
-       case '@':
-               if (allow_split && quoted) {
-                       sep = 1 << CHAR_BIT;
-                       goto param;
-               }
-               /* fall through */
-       case '*':
-               sep = ifsset() ? ifsval()[0] : ' ';
-               if (quotes) {
-                       sepq = syntax[(int) sep] == CCTL;
-               }
-param:
-               for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
-                       strtodest(p, syntax, quotes);
-                       if (*ap && sep) {
-                               if (sepq)
-                                       STPUTC(CTLESC, expdest);
-                               STPUTC(sep, expdest);
-                       }
-               }
-               break;
-       case '0':
-               strtodest(arg0, syntax, quotes);
-               break;
-       default:
-               num = atoi(name);
-               if (num > 0 && num <= shellparam.nparam) {
-                       strtodest(shellparam.p[num - 1], syntax, quotes);
-               }
-               break;
-       }
-}
-
-
-/*
- * Record the fact that we have to scan this region of the
- * string for IFS characters.
- */
-
-static void
-recordregion(start, end, nulonly)
-       int start;
-       int end;
-       int nulonly;
-{
-       struct ifsregion *ifsp;
-
-       if (ifslastp == NULL) {
-               ifsp = &ifsfirst;
-       } else {
-               INTOFF;
-               ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
-               ifsp->next = NULL;
-               ifslastp->next = ifsp;
-               INTON;
-       }
-       ifslastp = ifsp;
-       ifslastp->begoff = start;
-       ifslastp->endoff = end;
-       ifslastp->nulonly = nulonly;
-}
-
-
-
-/*
- * Break the argument string into pieces based upon IFS and add the
- * strings to the argument list.  The regions of the string to be
- * searched for IFS characters have been stored by recordregion.
- */
-static void
-ifsbreakup(string, arglist)
-       char *string;
-       struct arglist *arglist;
-       {
-       struct ifsregion *ifsp;
-       struct strlist *sp;
-       char *start;
-       char *p;
-       char *q;
-       const char *ifs, *realifs;
-       int ifsspc;
-       int nulonly;
-
-
-       start = string;
-       ifsspc = 0;
-       nulonly = 0;
-       realifs = ifsset() ? ifsval() : defifs;
-       if (ifslastp != NULL) {
-               ifsp = &ifsfirst;
-               do {
-                       p = string + ifsp->begoff;
-                       nulonly = ifsp->nulonly;
-                       ifs = nulonly ? nullstr : realifs;
-                       ifsspc = 0;
-                       while (p < string + ifsp->endoff) {
-                               q = p;
-                               if (*p == CTLESC)
-                                       p++;
-                               if (strchr(ifs, *p)) {
-                                       if (!nulonly)
-                                               ifsspc = (strchr(defifs, *p) != NULL);
-                                       /* Ignore IFS whitespace at start */
-                                       if (q == start && ifsspc) {
-                                               p++;
-                                               start = p;
-                                               continue;
-                                       }
-                                       *q = '\0';
-                                       sp = (struct strlist *)stalloc(sizeof *sp);
-                                       sp->text = start;
-                                       *arglist->lastp = sp;
-                                       arglist->lastp = &sp->next;
-                                       p++;
-                                       if (!nulonly) {
-                                               for (;;) {
-                                                       if (p >= string + ifsp->endoff) {
-                                                               break;
-                                                       }
-                                                       q = p;
-                                                       if (*p == CTLESC)
-                                                               p++;
-                                                       if (strchr(ifs, *p) == NULL ) {
-                                                               p = q;
-                                                               break;
-                                                       } else if (strchr(defifs, *p) == NULL) {
-                                                               if (ifsspc) {
-                                                                       p++;
-                                                                       ifsspc = 0;
-                                                               } else {
-                                                                       p = q;
-                                                                       break;
-                                                               }
-                                                       } else
-                                                               p++;
-                                               }
-                                       }
-                                       start = p;
-                               } else
-                                       p++;
-                       }
-               } while ((ifsp = ifsp->next) != NULL);
-               if (!(*start || (!ifsspc && start > string && nulonly))) {
-                       return;
-               }
-       }
-
-       sp = (struct strlist *)stalloc(sizeof *sp);
-       sp->text = start;
-       *arglist->lastp = sp;
-       arglist->lastp = &sp->next;
-}
-
-static void
-ifsfree()
-{
-       while (ifsfirst.next != NULL) {
-               struct ifsregion *ifsp;
-               INTOFF;
-               ifsp = ifsfirst.next->next;
-               ckfree(ifsfirst.next);
-               ifsfirst.next = ifsp;
-               INTON;
-       }
-       ifslastp = NULL;
-       ifsfirst.next = NULL;
-}
-
-/*
- * Add a file name to the list.
- */
-
-static void
-addfname(const char *name)
-{
-       char *p;
-       struct strlist *sp;
-
-       p = sstrdup(name);
-       sp = (struct strlist *)stalloc(sizeof *sp);
-       sp->text = p;
-       *exparg.lastp = sp;
-       exparg.lastp = &sp->next;
-}
-
-/*
- * Expand shell metacharacters.  At this point, the only control characters
- * should be escapes.  The results are stored in the list exparg.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
-static void
-expandmeta(str, flag)
-       struct strlist *str;
-       int flag;
-{
-       const char *p;
-       glob_t pglob;
-       /* TODO - EXP_REDIR */
-
-       while (str) {
-               if (fflag)
-                       goto nometa;
-               p = preglob(str->text);
-               INTOFF;
-               switch (glob(p, 0, 0, &pglob)) {
-               case 0:
-                       if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
-                               goto nometa2;
-                       addglob(&pglob);
-                       globfree(&pglob);
-                       INTON;
-                       break;
-               case GLOB_NOMATCH:
-nometa2:
-                       globfree(&pglob);
-                       INTON;
-nometa:
-                       *exparg.lastp = str;
-                       rmescapes(str->text);
-                       exparg.lastp = &str->next;
-                       break;
-               default:        /* GLOB_NOSPACE */
-                       error("Out of space");
-               }
-               str = str->next;
-       }
-}
-
-
-/*
- * Add the result of glob(3) to the list.
- */
-
-static void
-addglob(pglob)
-       const glob_t *pglob;
-{
-       char **p = pglob->gl_pathv;
-
-       do {
-               addfname(*p);
-       } while (*++p);
-}
-
-
-#else   /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
-static char *expdir;
-
-
-static void
-expandmeta(str, flag)
-       struct strlist *str;
-       int flag;
-{
-       char *p;
-       struct strlist **savelastp;
-       struct strlist *sp;
-       char c;
-       /* TODO - EXP_REDIR */
-
-       while (str) {
-               if (fflag)
-                       goto nometa;
-               p = str->text;
-               for (;;) {                      /* fast check for meta chars */
-                       if ((c = *p++) == '\0')
-                               goto nometa;
-                       if (c == '*' || c == '?' || c == '[' || c == '!')
-                               break;
-               }
-               savelastp = exparg.lastp;
-               INTOFF;
-               if (expdir == NULL) {
-                       int i = strlen(str->text);
-                       expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
-               }
-
-               expmeta(expdir, str->text);
-               ckfree(expdir);
-               expdir = NULL;
-               INTON;
-               if (exparg.lastp == savelastp) {
-                       /*
-                        * no matches
-                        */
-nometa:
-                       *exparg.lastp = str;
-                       rmescapes(str->text);
-                       exparg.lastp = &str->next;
-               } else {
-                       *exparg.lastp = NULL;
-                       *savelastp = sp = expsort(*savelastp);
-                       while (sp->next != NULL)
-                               sp = sp->next;
-                       exparg.lastp = &sp->next;
-               }
-               str = str->next;
-       }
-}
-
-
-/*
- * Do metacharacter (i.e. *, ?, [...]) expansion.
- */
-
-static void
-expmeta(enddir, name)
-       char *enddir;
-       char *name;
-       {
-       char *p;
-       const char *cp;
-       char *q;
-       char *start;
-       char *endname;
-       int metaflag;
-       struct stat statb;
-       DIR *dirp;
-       struct dirent *dp;
-       int atend;
-       int matchdot;
-
-       metaflag = 0;
-       start = name;
-       for (p = name ; ; p++) {
-               if (*p == '*' || *p == '?')
-                       metaflag = 1;
-               else if (*p == '[') {
-                       q = p + 1;
-                       if (*q == '!')
-                               q++;
-                       for (;;) {
-                               while (*q == CTLQUOTEMARK)
-                                       q++;
-                               if (*q == CTLESC)
-                                       q++;
-                               if (*q == '/' || *q == '\0')
-                                       break;
-                               if (*++q == ']') {
-                                       metaflag = 1;
-                                       break;
-                               }
-                       }
-               } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
-                       metaflag = 1;
-               } else if (*p == '\0')
-                       break;
-               else if (*p == CTLQUOTEMARK)
-                       continue;
-               else if (*p == CTLESC)
-                       p++;
-               if (*p == '/') {
-                       if (metaflag)
-                               break;
-                       start = p + 1;
-               }
-       }
-       if (metaflag == 0) {    /* we've reached the end of the file name */
-               if (enddir != expdir)
-                       metaflag++;
-               for (p = name ; ; p++) {
-                       if (*p == CTLQUOTEMARK)
-                               continue;
-                       if (*p == CTLESC)
-                               p++;
-                       *enddir++ = *p;
-                       if (*p == '\0')
-                               break;
-               }
-               if (metaflag == 0 || lstat(expdir, &statb) >= 0)
-                       addfname(expdir);
-               return;
-       }
-       endname = p;
-       if (start != name) {
-               p = name;
-               while (p < start) {
-                       while (*p == CTLQUOTEMARK)
-                               p++;
-                       if (*p == CTLESC)
-                               p++;
-                       *enddir++ = *p++;
-               }
-       }
-       if (enddir == expdir) {
-               cp = ".";
-       } else if (enddir == expdir + 1 && *expdir == '/') {
-               cp = "/";
-       } else {
-               cp = expdir;
-               enddir[-1] = '\0';
-       }
-       if ((dirp = opendir(cp)) == NULL)
-               return;
-       if (enddir != expdir)
-               enddir[-1] = '/';
-       if (*endname == 0) {
-               atend = 1;
-       } else {
-               atend = 0;
-               *endname++ = '\0';
-       }
-       matchdot = 0;
-       p = start;
-       while (*p == CTLQUOTEMARK)
-               p++;
-       if (*p == CTLESC)
-               p++;
-       if (*p == '.')
-               matchdot++;
-       while (! int_pending() && (dp = readdir(dirp)) != NULL) {
-               if (dp->d_name[0] == '.' && ! matchdot)
-                       continue;
-               if (patmatch(start, dp->d_name, 0)) {
-                       if (atend) {
-                               strcpy(enddir, dp->d_name);
-                               addfname(expdir);
-                       } else {
-                               for (p = enddir, cp = dp->d_name;
-                                    (*p++ = *cp++) != '\0';)
-                                       continue;
-                               p[-1] = '/';
-                               expmeta(p, endname);
-                       }
-               }
-       }
-       closedir(dirp);
-       if (! atend)
-               endname[-1] = '/';
-}
-#endif  /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
-
-
-
-#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
-/*
- * Sort the results of file name expansion.  It calculates the number of
- * strings to sort and then calls msort (short for merge sort) to do the
- * work.
- */
-
-static struct strlist *
-expsort(str)
-       struct strlist *str;
-       {
-       int len;
-       struct strlist *sp;
-
-       len = 0;
-       for (sp = str ; sp ; sp = sp->next)
-               len++;
-       return msort(str, len);
-}
-
-
-static struct strlist *
-msort(list, len)
-       struct strlist *list;
-       int len;
-{
-       struct strlist *p, *q = NULL;
-       struct strlist **lpp;
-       int half;
-       int n;
-
-       if (len <= 1)
-               return list;
-       half = len >> 1;
-       p = list;
-       for (n = half ; --n >= 0 ; ) {
-               q = p;
-               p = p->next;
-       }
-       q->next = NULL;                 /* terminate first half of list */
-       q = msort(list, half);          /* sort first half of list */
-       p = msort(p, len - half);               /* sort second half */
-       lpp = &list;
-       for (;;) {
-               if (strcmp(p->text, q->text) < 0) {
-                       *lpp = p;
-                       lpp = &p->next;
-                       if ((p = *lpp) == NULL) {
-                               *lpp = q;
-                               break;
-                       }
-               } else {
-                       *lpp = q;
-                       lpp = &q->next;
-                       if ((q = *lpp) == NULL) {
-                               *lpp = p;
-                               break;
-                       }
-               }
-       }
-       return list;
-}
-#endif
-
-
-
-/*
- * Returns true if the pattern matches the string.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-/* squoted: string might have quote chars */
-static int
-patmatch(char *pattern, char *string, int squoted)
-{
-       const char *p;
-       char *q;
-
-       p = preglob(pattern);
-       q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
-
-       return !fnmatch(p, q, 0);
-}
-
-
-static int
-patmatch2(char *pattern, char *string, int squoted)
-{
-       char *p;
-       int res;
-
-       sstrnleft--;
-       p = grabstackstr(expdest);
-       res = patmatch(pattern, string, squoted);
-       ungrabstackstr(p, expdest);
-       return res;
-}
-#else
-static int
-patmatch(char *pattern, char *string, int squoted) {
-       return pmatch(pattern, string, squoted);
-}
-
-
-static int
-pmatch(char *pattern, char *string, int squoted)
-{
-       char *p, *q;
-       char c;
-
-       p = pattern;
-       q = string;
-       for (;;) {
-               switch (c = *p++) {
-               case '\0':
-                       goto breakloop;
-               case CTLESC:
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ != *p++)
-                               return 0;
-                       break;
-               case CTLQUOTEMARK:
-                       continue;
-               case '?':
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ == '\0')
-                               return 0;
-                       break;
-               case '*':
-                       c = *p;
-                       while (c == CTLQUOTEMARK || c == '*')
-                               c = *++p;
-                       if (c != CTLESC &&  c != CTLQUOTEMARK &&
-                           c != '?' && c != '*' && c != '[') {
-                               while (*q != c) {
-                                       if (squoted && *q == CTLESC &&
-                                           q[1] == c)
-                                               break;
-                                       if (*q == '\0')
-                                               return 0;
-                                       if (squoted && *q == CTLESC)
-                                               q++;
-                                       q++;
-                               }
-                       }
-                       do {
-                               if (pmatch(p, q, squoted))
-                                       return 1;
-                               if (squoted && *q == CTLESC)
-                                       q++;
-                       } while (*q++ != '\0');
-                       return 0;
-               case '[': {
-                       char *endp;
-                       int invert, found;
-                       char chr;
-
-                       endp = p;
-                       if (*endp == '!')
-                               endp++;
-                       for (;;) {
-                               while (*endp == CTLQUOTEMARK)
-                                       endp++;
-                               if (*endp == '\0')
-                                       goto dft;               /* no matching ] */
-                               if (*endp == CTLESC)
-                                       endp++;
-                               if (*++endp == ']')
-                                       break;
-                       }
-                       invert = 0;
-                       if (*p == '!') {
-                               invert++;
-                               p++;
-                       }
-                       found = 0;
-                       chr = *q++;
-                       if (squoted && chr == CTLESC)
-                               chr = *q++;
-                       if (chr == '\0')
-                               return 0;
-                       c = *p++;
-                       do {
-                               if (c == CTLQUOTEMARK)
-                                       continue;
-                               if (c == CTLESC)
-                                       c = *p++;
-                               if (*p == '-' && p[1] != ']') {
-                                       p++;
-                                       while (*p == CTLQUOTEMARK)
-                                               p++;
-                                       if (*p == CTLESC)
-                                               p++;
-                                       if (chr >= c && chr <= *p)
-                                               found = 1;
-                                       p++;
-                               } else {
-                                       if (chr == c)
-                                               found = 1;
-                               }
-                       } while ((c = *p++) != ']');
-                       if (found == invert)
-                               return 0;
-                       break;
-               }
-dft:            default:
-                       if (squoted && *q == CTLESC)
-                               q++;
-                       if (*q++ != c)
-                               return 0;
-                       break;
-               }
-       }
-breakloop:
-       if (*q != '\0')
-               return 0;
-       return 1;
-}
-#endif
-
-
-
-/*
- * Remove any CTLESC characters from a string.
- */
-
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-static char *
-_rmescapes(char *str, int flag)
-{
-       char *p, *q, *r;
-       static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
-
-       p = strpbrk(str, qchars);
-       if (!p) {
-               return str;
-       }
-       q = p;
-       r = str;
-       if (flag & RMESCAPE_ALLOC) {
-               size_t len = p - str;
-               q = r = stalloc(strlen(p) + len + 1);
-               if (len > 0) {
-                       memcpy(q, str, len);
-                       q += len;
-               }
-       }
-       while (*p) {
-               if (*p == CTLQUOTEMARK) {
-                       p++;
-                       continue;
-               }
-               if (*p == CTLESC) {
-                       p++;
-                       if (flag & RMESCAPE_GLOB && *p != '/') {
-                               *q++ = '\\';
-                       }
-               }
-               *q++ = *p++;
-       }
-       *q = '\0';
-       return r;
-}
-#else
-static void
-rmescapes(str)
-       char *str;
-{
-       char *p, *q;
-
-       p = str;
-       while (*p != CTLESC && *p != CTLQUOTEMARK) {
-               if (*p++ == '\0')
-                       return;
-       }
-       q = p;
-       while (*p) {
-               if (*p == CTLQUOTEMARK) {
-                       p++;
-                       continue;
-               }
-               if (*p == CTLESC)
-                       p++;
-               *q++ = *p++;
-       }
-       *q = '\0';
-}
-#endif
-
-
-
-/*
- * See if a pattern matches in a case statement.
- */
-
-static int
-casematch(union node *pattern, const char *val)
-{
-       struct stackmark smark;
-       int result;
-       char *p;
-
-       setstackmark(&smark);
-       argbackq = pattern->narg.backquote;
-       STARTSTACKSTR(expdest);
-       ifslastp = NULL;
-       argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
-       STPUTC('\0', expdest);
-       p = grabstackstr(expdest);
-       result = patmatch(p, (char *)val, 0);
-       popstackmark(&smark);
-       return result;
-}
-
-/*
- * Our own itoa().
- */
-
-static char *
-cvtnum(num, buf)
-       int num;
-       char *buf;
-       {
-       int len;
-
-       CHECKSTRSPACE(32, buf);
-       len = sprintf(buf, "%d", num);
-       STADJUST(len, buf);
-       return buf;
-}
-/*
- * Editline and history functions (and glue).
- */
-static int histcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       error("not compiled with history support");
-       /* NOTREACHED */
-}
-
-
-struct redirtab {
-       struct redirtab *next;
-       short renamed[10]; /* Current ash support only 0-9 descriptors */
-       /* char on arm (and others) can't be negative */
-};
-
-static struct redirtab *redirlist;
-
-extern char **environ;
-
-
-
-/*
- * Initialization code.
- */
-
-static void
-init(void) {
-
-      /* from cd.c: */
-      {
-             setpwd(0, 0);
-      }
-
-      /* from input.c: */
-      {
-             basepf.nextc = basepf.buf = basebuf;
-      }
-
-      /* from var.c: */
-      {
-             char **envp;
-             char ppid[32];
-
-             initvar();
-             for (envp = environ ; *envp ; envp++) {
-                     if (strchr(*envp, '=')) {
-                             setvareq(*envp, VEXPORT|VTEXTFIXED);
-                     }
-             }
-
-             snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
-             setvar("PPID", ppid, 0);
-      }
-}
-
-
-
-/*
- * This routine is called when an error or an interrupt occurs in an
- * interactive shell and control is returned to the main command loop.
- */
-
-/* 1 == check for aliases, 2 == also check for assignments */
-static int checkalias;  /* also used in no alias mode for check assignments */
-
-static void
-reset(void) {
-
-      /* from eval.c: */
-      {
-             evalskip = 0;
-             loopnest = 0;
-             funcnest = 0;
-      }
-
-      /* from input.c: */
-      {
-             if (exception != EXSHELLPROC)
-                     parselleft = parsenleft = 0;      /* clear input buffer */
-             popallfiles();
-      }
-
-      /* from parser.c: */
-      {
-             tokpushback = 0;
-             checkkwd = 0;
-             checkalias = 0;
-      }
-
-      /* from redir.c: */
-      {
-             while (redirlist)
-                     popredir();
-      }
-
-}
-
-
-
-/*
- * This file implements the input routines used by the parser.
- */
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-static const char * cmdedit_prompt;
-static inline void putprompt(const char *s) {
-    cmdedit_prompt = s;
-}
-#else
-static inline void putprompt(const char *s) {
-    out2str(s);
-}
-#endif
-
-#define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
-
-
-
-/*
- * Same as pgetc(), but ignores PEOA.
- */
-
-#ifdef ASH_ALIAS
-static int
-pgetc2()
-{
-       int c;
-       do {
-               c = pgetc_macro();
-       } while (c == PEOA);
-       return c;
-}
-#else
-static inline int pgetc2() { return pgetc_macro(); }
-#endif
-
-/*
- * Read a line from the script.
- */
-
-static inline char *
-pfgets(char *line, int len)
-{
-       char *p = line;
-       int nleft = len;
-       int c;
-
-       while (--nleft > 0) {
-               c = pgetc2();
-               if (c == PEOF) {
-                       if (p == line)
-                               return NULL;
-                       break;
-               }
-               *p++ = c;
-               if (c == '\n')
-                       break;
-       }
-       *p = '\0';
-       return line;
-}
-
-static inline int
-preadfd(void)
-{
-    int nr;
-    char *buf =  parsefile->buf;
-    parsenextc = buf;
-
-retry:
-#ifdef BB_FEATURE_COMMAND_EDITING
-       {
-           if (!iflag || parsefile->fd)
-                   nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
-           else {
-                   nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
-           }
-       }
-#else
-       nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
-#endif
-
-       if (nr < 0) {
-               if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
-                       int flags = fcntl(0, F_GETFL, 0);
-                       if (flags >= 0 && flags & O_NONBLOCK) {
-                               flags &=~ O_NONBLOCK;
-                               if (fcntl(0, F_SETFL, flags) >= 0) {
-                                       out2str("sh: turning off NDELAY mode\n");
-                                       goto retry;
-                               }
-                       }
-               }
-       }
-       return nr;
-}
-
-static void
-popstring(void)
-{
-       struct strpush *sp = parsefile->strpush;
-
-       INTOFF;
-#ifdef ASH_ALIAS
-       if (sp->ap) {
-               if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
-                       if (!checkalias) {
-                               checkalias = 1;
-                       }
-               }
-               if (sp->string != sp->ap->val) {
-                       ckfree(sp->string);
-               }
-
-               sp->ap->flag &= ~ALIASINUSE;
-               if (sp->ap->flag & ALIASDEAD) {
-                       unalias(sp->ap->name);
-               }
-       }
-#endif
-       parsenextc = sp->prevstring;
-       parsenleft = sp->prevnleft;
-/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
-       parsefile->strpush = sp->prev;
-       if (sp != &(parsefile->basestrpush))
-               ckfree(sp);
-       INTON;
-}
-
-
-/*
- * Refill the input buffer and return the next input character:
- *
- * 1) If a string was pushed back on the input, pop it;
- * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
- *    from a string so we can't refill the buffer, return EOF.
- * 3) If the is more stuff in this buffer, use it else call read to fill it.
- * 4) Process input up to the next newline, deleting nul characters.
- */
-
-static int
-preadbuffer(void)
-{
-       char *p, *q;
-       int more;
-       char savec;
-
-       while (parsefile->strpush) {
-#ifdef ASH_ALIAS
-               if (parsenleft == -1 && parsefile->strpush->ap &&
-                       parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
-                       return PEOA;
-               }
-#endif
-               popstring();
-               if (--parsenleft >= 0)
-                       return (*parsenextc++);
-       }
-       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
-               return PEOF;
-       flushall();
-
-again:
-       if (parselleft <= 0) {
-               if ((parselleft = preadfd()) <= 0) {
-                       parselleft = parsenleft = EOF_NLEFT;
-                       return PEOF;
-               }
-       }
-
-       q = p = parsenextc;
-
-       /* delete nul characters */
-       for (more = 1; more;) {
-               switch (*p) {
-               case '\0':
-                       p++;    /* Skip nul */
-                       goto check;
-
-
-               case '\n':
-                       parsenleft = q - parsenextc;
-                       more = 0; /* Stop processing here */
-                       break;
-               }
-
-               *q++ = *p++;
-check:
-               if (--parselleft <= 0 && more) {
-                       parsenleft = q - parsenextc - 1;
-                       if (parsenleft < 0)
-                               goto again;
-                       more = 0;
-               }
-       }
-
-       savec = *q;
-       *q = '\0';
-
-       if (vflag) {
-               out2str(parsenextc);
-       }
-
-       *q = savec;
-
-       return *parsenextc++;
-}
-
-
-/*
- * Push a string back onto the input at this current parsefile level.
- * We handle aliases this way.
- */
-static void
-pushstring(char *s, int len, void *ap)
-{
-       struct strpush *sp;
-
-       INTOFF;
-/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
-       if (parsefile->strpush) {
-               sp = ckmalloc(sizeof (struct strpush));
-               sp->prev = parsefile->strpush;
-               parsefile->strpush = sp;
-       } else
-               sp = parsefile->strpush = &(parsefile->basestrpush);
-       sp->prevstring = parsenextc;
-       sp->prevnleft = parsenleft;
-#ifdef ASH_ALIAS
-       sp->ap = (struct alias *)ap;
-       if (ap) {
-               ((struct alias *)ap)->flag |= ALIASINUSE;
-               sp->string = s;
-       }
-#endif
-       parsenextc = s;
-       parsenleft = len;
-       INTON;
-}
-
-
-/*
- * Like setinputfile, but takes input from a string.
- */
-
-static void
-setinputstring(char *string)
-{
-       INTOFF;
-       pushfile();
-       parsenextc = string;
-       parsenleft = strlen(string);
-       parsefile->buf = NULL;
-       plinno = 1;
-       INTON;
-}
-
-
-
-/*
- * To handle the "." command, a stack of input files is used.  Pushfile
- * adds a new entry to the stack and popfile restores the previous level.
- */
-
-static void
-pushfile(void) {
-       struct parsefile *pf;
-
-       parsefile->nleft = parsenleft;
-       parsefile->lleft = parselleft;
-       parsefile->nextc = parsenextc;
-       parsefile->linno = plinno;
-       pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
-       pf->prev = parsefile;
-       pf->fd = -1;
-       pf->strpush = NULL;
-       pf->basestrpush.prev = NULL;
-       parsefile = pf;
-}
-
-#ifdef JOBS
-static void restartjob (struct job *);
-#endif
-static void freejob (struct job *);
-static struct job *getjob (const char *);
-static int dowait (int, struct job *);
-static void waitonint(int);
-
-
-/*
- * We keep track of whether or not fd0 has been redirected.  This is for
- * background commands, where we want to redirect fd0 to /dev/null only
- * if it hasn't already been redirected.
-*/
-static int fd0_redirected = 0;
-
-/* Return true if fd 0 has already been redirected at least once.  */
-static inline int
-fd0_redirected_p () {
-       return fd0_redirected != 0;
-}
-
-static void dupredirect (const union node *, int, int fd1dup);
-
-#ifdef JOBS
-/*
- * Turn job control on and off.
- *
- * Note:  This code assumes that the third arg to ioctl is a character
- * pointer, which is true on Berkeley systems but not System V.  Since
- * System V doesn't have job control yet, this isn't a problem now.
- */
-
-
-
-static void setjobctl(int enable)
-{
-#ifdef OLD_TTY_DRIVER
-       int ldisc;
-#endif
-
-       if (enable == jobctl || rootshell == 0)
-               return;
-       if (enable) {
-               do { /* while we are in the background */
-#ifdef OLD_TTY_DRIVER
-                       if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
-#else
-                       initialpgrp = tcgetpgrp(2);
-                       if (initialpgrp < 0) {
-#endif
-                               out2str("sh: can't access tty; job control turned off\n");
-                               mflag = 0;
-                               return;
-                       }
-                       if (initialpgrp == -1)
-                               initialpgrp = getpgrp();
-                       else if (initialpgrp != getpgrp()) {
-                               killpg(initialpgrp, SIGTTIN);
-                               continue;
-                       }
-               } while (0);
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
-                       out2str("sh: need new tty driver to run job control; job control turned off\n");
-                       mflag = 0;
-                       return;
-               }
-#endif
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-               setpgid(0, rootpid);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *)&rootpid);
-#else
-               tcsetpgrp(2, rootpid);
-#endif
-       } else { /* turning job control off */
-               setpgid(0, initialpgrp);
-#ifdef OLD_TTY_DRIVER
-               ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
-#else
-               tcsetpgrp(2, initialpgrp);
-#endif
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-       }
-       jobctl = enable;
-}
-#endif
-
-
-#ifdef JOBS
-static int
-killcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int signo = -1;
-       int list = 0;
-       int i;
-       pid_t pid;
-       struct job *jp;
-
-       if (argc <= 1) {
-usage:
-               error(
-"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
-"kill -l [exitstatus]"
-               );
-       }
-
-       if (*argv[1] == '-') {
-               signo = decode_signal(argv[1] + 1, 1);
-               if (signo < 0) {
-                       int c;
-
-                       while ((c = nextopt("ls:")) != '\0')
-                               switch (c) {
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 's':
-                                       signo = decode_signal(optionarg, 1);
-                                       if (signo < 0) {
-                                               error(
-                                                       "invalid signal number or name: %s",
-                                                       optionarg
-                                               );
-                                       }
-                                       break;
-#ifdef DEBUG
-                               default:
-                                       error(
-       "nextopt returned character code 0%o", c);
-#endif
-                       }
-               } else
-                       argptr++;
-       }
-
-       if (!list && signo < 0)
-               signo = SIGTERM;
-
-       if ((signo < 0 || !*argptr) ^ list) {
-               goto usage;
-       }
-
-       if (list) {
-               const char *name;
-
-               if (!*argptr) {
-                       out1str("0\n");
-                       for (i = 1; i < NSIG; i++) {
-                               name = u_signal_names(0, &i, 1);
-                               if(name)
-                                       printf(snlfmt, name);
-                       }
-                       return 0;
-               }
-               name = u_signal_names(*argptr, &signo, -1);
-               if (name)
-                       printf(snlfmt, name);
-               else
-                       error("invalid signal number or exit status: %s",
-                             *argptr);
-               return 0;
-       }
-
-       do {
-               if (**argptr == '%') {
-                       jp = getjob(*argptr);
-                       if (jp->jobctl == 0)
-                               error("job %s not created under job control",
-                                     *argptr);
-                       pid = -jp->ps[0].pid;
-               } else
-                       pid = atoi(*argptr);
-               if (kill(pid, signo) != 0)
-                       error("%s: %m", *argptr);
-       } while (*++argptr);
-
-       return 0;
-}
-
-static int
-fgcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *jp;
-       int pgrp;
-       int status;
-
-       jp = getjob(argv[1]);
-       if (jp->jobctl == 0)
-               error("job not created under job control");
-       pgrp = jp->ps[0].pid;
-#ifdef OLD_TTY_DRIVER
-       ioctl(2, TIOCSPGRP, (char *)&pgrp);
-#else
-       tcsetpgrp(2, pgrp);
-#endif
-       restartjob(jp);
-       INTOFF;
-       status = waitforjob(jp);
-       INTON;
-       return status;
-}
-
-
-static int
-bgcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *jp;
-
-       do {
-               jp = getjob(*++argv);
-               if (jp->jobctl == 0)
-                       error("job not created under job control");
-               restartjob(jp);
-       } while (--argc > 1);
-       return 0;
-}
-
-
-static void
-restartjob(jp)
-       struct job *jp;
-{
-       struct procstat *ps;
-       int i;
-
-       if (jp->state == JOBDONE)
-               return;
-       INTOFF;
-       killpg(jp->ps[0].pid, SIGCONT);
-       for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
-               if (WIFSTOPPED(ps->status)) {
-                       ps->status = -1;
-                       jp->state = 0;
-               }
-       }
-       INTON;
-}
-#endif
-
-static void showjobs(int change);
-
-
-static int
-jobscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       showjobs(0);
-       return 0;
-}
-
-
-/*
- * Print a list of jobs.  If "change" is nonzero, only print jobs whose
- * statuses have changed since the last call to showjobs.
- *
- * If the shell is interrupted in the process of creating a job, the
- * result may be a job structure containing zero processes.  Such structures
- * will be freed here.
- */
-
-static void
-showjobs(change)
-       int change;
-{
-       int jobno;
-       int procno;
-       int i;
-       struct job *jp;
-       struct procstat *ps;
-       int col;
-       char s[64];
-
-       TRACE(("showjobs(%d) called\n", change));
-       while (dowait(0, (struct job *)NULL) > 0);
-       for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
-               if (! jp->used)
-                       continue;
-               if (jp->nprocs == 0) {
-                       freejob(jp);
-                       continue;
-               }
-               if (change && ! jp->changed)
-                       continue;
-               procno = jp->nprocs;
-               for (ps = jp->ps ; ; ps++) {    /* for each process */
-                       if (ps == jp->ps)
-                               snprintf(s, 64, "[%d] %ld ", jobno,
-                                   (long)ps->pid);
-                       else
-                               snprintf(s, 64, "    %ld ",
-                                   (long)ps->pid);
-                       out1str(s);
-                       col = strlen(s);
-                       s[0] = '\0';
-                       if (ps->status == -1) {
-                               /* don't print anything */
-                       } else if (WIFEXITED(ps->status)) {
-                               snprintf(s, 64, "Exit %d",
-                                      WEXITSTATUS(ps->status));
-                       } else {
-#ifdef JOBS
-                               if (WIFSTOPPED(ps->status))
-                                       i = WSTOPSIG(ps->status);
-                               else /* WIFSIGNALED(ps->status) */
-#endif
-                                       i = WTERMSIG(ps->status);
-                               if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
-                                       strcpy(s, sys_siglist[i & 0x7F]);
-                               else
-                                       snprintf(s, 64, "Signal %d", i & 0x7F);
-                               if (WCOREDUMP(ps->status))
-                                       strcat(s, " (core dumped)");
-                       }
-                       out1str(s);
-                       col += strlen(s);
-                       printf(
-                               "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
-                               ps->cmd
-                       );
-                       if (--procno <= 0)
-                               break;
-               }
-               jp->changed = 0;
-               if (jp->state == JOBDONE) {
-                       freejob(jp);
-               }
-       }
-}
-
-
-/*
- * Mark a job structure as unused.
- */
-
-static void
-freejob(struct job *jp)
-{
-       const struct procstat *ps;
-       int i;
-
-       INTOFF;
-       for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
-               if (ps->cmd != nullstr)
-                       ckfree(ps->cmd);
-       }
-       if (jp->ps != &jp->ps0)
-               ckfree(jp->ps);
-       jp->used = 0;
-#ifdef JOBS
-       if (curjob == jp - jobtab + 1)
-               curjob = 0;
-#endif
-       INTON;
-}
-
-
-
-static int
-waitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct job *job;
-       int status, retval;
-       struct job *jp;
-
-       if (--argc > 0) {
-start:
-               job = getjob(*++argv);
-       } else {
-               job = NULL;
-       }
-       for (;;) {      /* loop until process terminated or stopped */
-               if (job != NULL) {
-                       if (job->state) {
-                               status = job->ps[job->nprocs - 1].status;
-                               if (! iflag)
-                                       freejob(job);
-                               if (--argc) {
-                                       goto start;
-                               }
-                               if (WIFEXITED(status))
-                                       retval = WEXITSTATUS(status);
-#ifdef JOBS
-                               else if (WIFSTOPPED(status))
-                                       retval = WSTOPSIG(status) + 128;
-#endif
-                               else {
-                                       /* XXX: limits number of signals */
-                                       retval = WTERMSIG(status) + 128;
-                               }
-                               return retval;
-                       }
-               } else {
-                       for (jp = jobtab ; ; jp++) {
-                               if (jp >= jobtab + njobs) {     /* no running procs */
-                                       return 0;
-                               }
-                               if (jp->used && jp->state == 0)
-                                       break;
-                       }
-               }
-               if (dowait(2, 0) < 0 && errno == EINTR) {
-                       return 129;
-               }
-       }
-}
-
-
-
-/*
- * Convert a job name to a job structure.
- */
-
-static struct job *
-getjob(const char *name)
-{
-       int jobno;
-       struct job *jp;
-       int pid;
-       int i;
-
-       if (name == NULL) {
-#ifdef JOBS
-currentjob:
-               if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
-                       error("No current job");
-               return &jobtab[jobno - 1];
-#else
-               error("No current job");
-#endif
-       } else if (name[0] == '%') {
-               if (is_digit(name[1])) {
-                       jobno = number(name + 1);
-                       if (jobno > 0 && jobno <= njobs
-                        && jobtab[jobno - 1].used != 0)
-                               return &jobtab[jobno - 1];
-#ifdef JOBS
-               } else if (name[1] == '%' && name[2] == '\0') {
-                       goto currentjob;
-#endif
-               } else {
-                       struct job *found = NULL;
-                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                               if (jp->used && jp->nprocs > 0
-                                && prefix(name + 1, jp->ps[0].cmd)) {
-                                       if (found)
-                                               error("%s: ambiguous", name);
-                                       found = jp;
-                               }
-                       }
-                       if (found)
-                               return found;
-               }
-       } else if (is_number(name, &pid)) {
-               for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                       if (jp->used && jp->nprocs > 0
-                        && jp->ps[jp->nprocs - 1].pid == pid)
-                               return jp;
-               }
-       }
-       error("No such job: %s", name);
-       /* NOTREACHED */
-}
-
-
-
-/*
- * Return a new job structure,
- */
-
-static struct job *
-makejob(const union node *node, int nprocs)
-{
-       int i;
-       struct job *jp;
-
-       for (i = njobs, jp = jobtab ; ; jp++) {
-               if (--i < 0) {
-                       INTOFF;
-                       if (njobs == 0) {
-                               jobtab = ckmalloc(4 * sizeof jobtab[0]);
-                       } else {
-                               jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
-                               memcpy(jp, jobtab, njobs * sizeof jp[0]);
-                               /* Relocate `ps' pointers */
-                               for (i = 0; i < njobs; i++)
-                                       if (jp[i].ps == &jobtab[i].ps0)
-                                               jp[i].ps = &jp[i].ps0;
-                               ckfree(jobtab);
-                               jobtab = jp;
-                       }
-                       jp = jobtab + njobs;
-                       for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
-                       INTON;
-                       break;
-               }
-               if (jp->used == 0)
-                       break;
-       }
-       INTOFF;
-       jp->state = 0;
-       jp->used = 1;
-       jp->changed = 0;
-       jp->nprocs = 0;
-#ifdef JOBS
-       jp->jobctl = jobctl;
-#endif
-       if (nprocs > 1) {
-               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
-       } else {
-               jp->ps = &jp->ps0;
-       }
-       INTON;
-       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
-           jp - jobtab + 1));
-       return jp;
-}
-
-
-/*
- * Fork of a subshell.  If we are doing job control, give the subshell its
- * own process group.  Jp is a job structure that the job is to be added to.
- * N is the command that will be evaluated by the child.  Both jp and n may
- * be NULL.  The mode parameter can be one of the following:
- *      FORK_FG - Fork off a foreground process.
- *      FORK_BG - Fork off a background process.
- *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
- *                   process group even if job control is on.
- *
- * When job control is turned off, background processes have their standard
- * input redirected to /dev/null (except for the second and later processes
- * in a pipeline).
- */
-
-
-
-static int
-forkshell(struct job *jp, const union node *n, int mode)
-{
-       int pid;
-#ifdef JOBS
-       int pgrp;
-#endif
-       const char *devnull = _PATH_DEVNULL;
-       const char *nullerr = "Can't open %s";
-
-       TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
-           mode));
-       INTOFF;
-       pid = fork();
-       if (pid == -1) {
-               TRACE(("Fork failed, errno=%d\n", errno));
-               INTON;
-               error("Cannot fork");
-       }
-       if (pid == 0) {
-               struct job *p;
-               int wasroot;
-               int i;
-
-               TRACE(("Child shell %d\n", getpid()));
-               wasroot = rootshell;
-               rootshell = 0;
-               closescript();
-               INTON;
-               clear_traps();
-#ifdef JOBS
-               jobctl = 0;             /* do job control only in root shell */
-               if (wasroot && mode != FORK_NOJOB && mflag) {
-                       if (jp == NULL || jp->nprocs == 0)
-                               pgrp = getpid();
-                       else
-                               pgrp = jp->ps[0].pid;
-                       setpgid(0, pgrp);
-                       if (mode == FORK_FG) {
-                               /*** this causes superfluous TIOCSPGRPS ***/
-#ifdef OLD_TTY_DRIVER
-                               if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
-                                       error("TIOCSPGRP failed, errno=%d", errno);
-#else
-                               if (tcsetpgrp(2, pgrp) < 0)
-                                       error("tcsetpgrp failed, errno=%d", errno);
-#endif
-                       }
-                       setsignal(SIGTSTP);
-                       setsignal(SIGTTOU);
-               } else if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(devnull, O_RDONLY) != 0)
-                                       error(nullerr, devnull);
-                       }
-               }
-#else
-               if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(devnull, O_RDONLY) != 0)
-                                       error(nullerr, devnull);
-                       }
-               }
-#endif
-               for (i = njobs, p = jobtab ; --i >= 0 ; p++)
-                       if (p->used)
-                               freejob(p);
-               if (wasroot && iflag) {
-                       setsignal(SIGINT);
-                       setsignal(SIGQUIT);
-                       setsignal(SIGTERM);
-               }
-               return pid;
-       }
-#ifdef JOBS
-       if (rootshell && mode != FORK_NOJOB && mflag) {
-               if (jp == NULL || jp->nprocs == 0)
-                       pgrp = pid;
-               else
-                       pgrp = jp->ps[0].pid;
-               setpgid(pid, pgrp);
-       }
-#endif
-       if (mode == FORK_BG)
-               backgndpid = pid;               /* set $! */
-       if (jp) {
-               struct procstat *ps = &jp->ps[jp->nprocs++];
-               ps->pid = pid;
-               ps->status = -1;
-               ps->cmd = nullstr;
-               if (iflag && rootshell && n)
-                       ps->cmd = commandtext(n);
-       }
-       INTON;
-       TRACE(("In parent shell:  child = %d\n", pid));
-       return pid;
-}
-
-
-
-/*
- * Wait for job to finish.
- *
- * Under job control we have the problem that while a child process is
- * running interrupts generated by the user are sent to the child but not
- * to the shell.  This means that an infinite loop started by an inter-
- * active user may be hard to kill.  With job control turned off, an
- * interactive user may place an interactive program inside a loop.  If
- * the interactive program catches interrupts, the user doesn't want
- * these interrupts to also abort the loop.  The approach we take here
- * is to have the shell ignore interrupt signals while waiting for a
- * forground process to terminate, and then send itself an interrupt
- * signal if the child process was terminated by an interrupt signal.
- * Unfortunately, some programs want to do a bit of cleanup and then
- * exit on interrupt; unless these processes terminate themselves by
- * sending a signal to themselves (instead of calling exit) they will
- * confuse this approach.
- */
-
-static int
-waitforjob(struct job *jp)
-{
-#ifdef JOBS
-       int mypgrp = getpgrp();
-#endif
-       int status;
-       int st;
-       struct sigaction act, oact;
-
-       INTOFF;
-       intreceived = 0;
-#ifdef JOBS
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, 0, &act);
-               act.sa_handler = waitonint;
-               sigaction(SIGINT, &act, &oact);
-       }
-       TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
-       while (jp->state == 0) {
-               dowait(1, jp);
-       }
-#ifdef JOBS
-       if (!jobctl) {
-#else
-       if (!iflag) {
-#endif
-               sigaction(SIGINT, &oact, 0);
-               if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
-       }
-#ifdef JOBS
-       if (jp->jobctl) {
-#ifdef OLD_TTY_DRIVER
-               if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
-                       error("TIOCSPGRP failed, errno=%d\n", errno);
-#else
-               if (tcsetpgrp(2, mypgrp) < 0)
-                       error("tcsetpgrp failed, errno=%d\n", errno);
-#endif
-       }
-       if (jp->state == JOBSTOPPED)
-               curjob = jp - jobtab + 1;
-#endif
-       status = jp->ps[jp->nprocs - 1].status;
-       /* convert to 8 bits */
-       if (WIFEXITED(status))
-               st = WEXITSTATUS(status);
-#ifdef JOBS
-       else if (WIFSTOPPED(status))
-               st = WSTOPSIG(status) + 128;
-#endif
-       else
-               st = WTERMSIG(status) + 128;
-#ifdef JOBS
-       if (jp->jobctl) {
-               /*
-                * This is truly gross.
-                * If we're doing job control, then we did a TIOCSPGRP which
-                * caused us (the shell) to no longer be in the controlling
-                * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
-                * intuit from the subprocess exit status whether a SIGINT
-                * occured, and if so interrupt ourselves.  Yuck.  - mycroft
-                */
-               if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
-                       raise(SIGINT);
-       }
-       if (jp->state == JOBDONE)
-
-#endif
-               freejob(jp);
-       INTON;
-       return st;
-}
-
-
-
-/*
- * Wait for a process to terminate.
- */
-
-/*
- * Do a wait system call.  If job control is compiled in, we accept
- * stopped processes.  If block is zero, we return a value of zero
- * rather than blocking.
- *
- * System V doesn't have a non-blocking wait system call.  It does
- * have a SIGCLD signal that is sent to a process when one of it's
- * children dies.  The obvious way to use SIGCLD would be to install
- * a handler for SIGCLD which simply bumped a counter when a SIGCLD
- * was received, and have waitproc bump another counter when it got
- * the status of a process.  Waitproc would then know that a wait
- * system call would not block if the two counters were different.
- * This approach doesn't work because if a process has children that
- * have not been waited for, System V will send it a SIGCLD when it
- * installs a signal handler for SIGCLD.  What this means is that when
- * a child exits, the shell will be sent SIGCLD signals continuously
- * until is runs out of stack space, unless it does a wait call before
- * restoring the signal handler.  The code below takes advantage of
- * this (mis)feature by installing a signal handler for SIGCLD and
- * then checking to see whether it was called.  If there are any
- * children to be waited for, it will be.
- *
- */
-
-static inline int
-waitproc(int block, int *status)
-{
-       int flags;
-
-       flags = 0;
-#ifdef JOBS
-       if (jobctl)
-               flags |= WUNTRACED;
-#endif
-       if (block == 0)
-               flags |= WNOHANG;
-       return wait3(status, flags, (struct rusage *)NULL);
-}
-
-static int
-dowait(int block, struct job *job)
-{
-       int pid;
-       int status;
-       struct procstat *sp;
-       struct job *jp;
-       struct job *thisjob;
-       int done;
-       int stopped;
-       int core;
-       int sig;
-
-       TRACE(("dowait(%d) called\n", block));
-       do {
-               pid = waitproc(block, &status);
-               TRACE(("wait returns %d, status=%d\n", pid, status));
-       } while (!(block & 2) && pid == -1 && errno == EINTR);
-       if (pid <= 0)
-               return pid;
-       INTOFF;
-       thisjob = NULL;
-       for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
-               if (jp->used) {
-                       done = 1;
-                       stopped = 1;
-                       for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
-                               if (sp->pid == -1)
-                                       continue;
-                               if (sp->pid == pid) {
-                                       TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
-                                       sp->status = status;
-                                       thisjob = jp;
-                               }
-                               if (sp->status == -1)
-                                       stopped = 0;
-                               else if (WIFSTOPPED(sp->status))
-                                       done = 0;
-                       }
-                       if (stopped) {          /* stopped or done */
-                               int state = done? JOBDONE : JOBSTOPPED;
-                               if (jp->state != state) {
-                                       TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
-                                       jp->state = state;
-#ifdef JOBS
-                                       if (done && curjob == jp - jobtab + 1)
-                                               curjob = 0;             /* no current job */
-#endif
-                               }
-                       }
-               }
-       }
-       INTON;
-       if (! rootshell || ! iflag || (job && thisjob == job)) {
-               core = WCOREDUMP(status);
-#ifdef JOBS
-               if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
-               else
-#endif
-               if (WIFEXITED(status)) sig = 0;
-               else sig = WTERMSIG(status);
-
-               if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
-                       if (thisjob != job)
-                               out2fmt("%d: ", pid);
-#ifdef JOBS
-                       if (sig == SIGTSTP && rootshell && iflag)
-                               out2fmt("%%%ld ",
-                                   (long)(job - jobtab + 1));
-#endif
-                       if (sig < NSIG && sys_siglist[sig])
-                               out2str(sys_siglist[sig]);
-                       else
-                               out2fmt("Signal %d", sig);
-                       if (core)
-                               out2str(" - core dumped");
-                       out2c('\n');
-               } else {
-                       TRACE(("Not printing status: status=%d, sig=%d\n",
-                              status, sig));
-               }
-       } else {
-               TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
-               if (thisjob)
-                       thisjob->changed = 1;
-       }
-       return pid;
-}
-
-
-
-
-/*
- * return 1 if there are stopped jobs, otherwise 0
- */
-static int
-stoppedjobs(void)
-{
-       int jobno;
-       struct job *jp;
-
-       if (job_warning)
-               return (0);
-       for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
-               if (jp->used == 0)
-                       continue;
-               if (jp->state == JOBSTOPPED) {
-                       out2str("You have stopped jobs.\n");
-                       job_warning = 2;
-                       return (1);
-               }
-       }
-
-       return (0);
-}
-
-/*
- * Return a string identifying a command (to be printed by the
- * jobs command.
- */
-
-static char *cmdnextc;
-static int cmdnleft;
-#define MAXCMDTEXT      200
-
-static void
-cmdputs(const char *s)
-{
-       const char *p;
-       char *q;
-       char c;
-       int subtype = 0;
-
-       if (cmdnleft <= 0)
-               return;
-       p = s;
-       q = cmdnextc;
-       while ((c = *p++) != '\0') {
-               if (c == CTLESC)
-                       *q++ = *p++;
-               else if (c == CTLVAR) {
-                       *q++ = '$';
-                       if (--cmdnleft > 0)
-                               *q++ = '{';
-                       subtype = *p++;
-               } else if (c == '=' && subtype != 0) {
-                       *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
-                       subtype = 0;
-               } else if (c == CTLENDVAR) {
-                       *q++ = '}';
-               } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
-                       cmdnleft++;             /* ignore it */
-               else
-                       *q++ = c;
-               if (--cmdnleft <= 0) {
-                       *q++ = '.';
-                       *q++ = '.';
-                       *q++ = '.';
-                       break;
-               }
-       }
-       cmdnextc = q;
-}
-
-
-static void
-cmdtxt(const union node *n)
-{
-       union node *np;
-       struct nodelist *lp;
-       const char *p;
-       int i;
-       char s[2];
-
-       if (n == NULL)
-               return;
-       switch (n->type) {
-       case NSEMI:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NAND:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" && ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NOR:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" || ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NPIPE:
-               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-                       cmdtxt(lp->n);
-                       if (lp->next)
-                               cmdputs(" | ");
-               }
-               break;
-       case NSUBSHELL:
-               cmdputs("(");
-               cmdtxt(n->nredir.n);
-               cmdputs(")");
-               break;
-       case NREDIR:
-       case NBACKGND:
-               cmdtxt(n->nredir.n);
-               break;
-       case NIF:
-               cmdputs("if ");
-               cmdtxt(n->nif.test);
-               cmdputs("; then ");
-               cmdtxt(n->nif.ifpart);
-               cmdputs("...");
-               break;
-       case NWHILE:
-               cmdputs("while ");
-               goto until;
-       case NUNTIL:
-               cmdputs("until ");
-until:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; do ");
-               cmdtxt(n->nbinary.ch2);
-               cmdputs("; done");
-               break;
-       case NFOR:
-               cmdputs("for ");
-               cmdputs(n->nfor.var);
-               cmdputs(" in ...");
-               break;
-       case NCASE:
-               cmdputs("case ");
-               cmdputs(n->ncase.expr->narg.text);
-               cmdputs(" in ...");
-               break;
-       case NDEFUN:
-               cmdputs(n->narg.text);
-               cmdputs("() ...");
-               break;
-       case NCMD:
-               for (np = n->ncmd.args ; np ; np = np->narg.next) {
-                       cmdtxt(np);
-                       if (np->narg.next)
-                               cmdputs(spcstr);
-               }
-               for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
-                       cmdputs(spcstr);
-                       cmdtxt(np);
-               }
-               break;
-       case NARG:
-               cmdputs(n->narg.text);
-               break;
-       case NTO:
-               p = ">";  i = 1;  goto redir;
-       case NAPPEND:
-               p = ">>";  i = 1;  goto redir;
-       case NTOFD:
-               p = ">&";  i = 1;  goto redir;
-       case NTOOV:
-               p = ">|";  i = 1;  goto redir;
-       case NFROM:
-               p = "<";  i = 0;  goto redir;
-       case NFROMFD:
-               p = "<&";  i = 0;  goto redir;
-       case NFROMTO:
-               p = "<>";  i = 0;  goto redir;
-redir:
-               if (n->nfile.fd != i) {
-                       s[0] = n->nfile.fd + '0';
-                       s[1] = '\0';
-                       cmdputs(s);
-               }
-               cmdputs(p);
-               if (n->type == NTOFD || n->type == NFROMFD) {
-                       s[0] = n->ndup.dupfd + '0';
-                       s[1] = '\0';
-                       cmdputs(s);
-               } else {
-                       cmdtxt(n->nfile.fname);
-               }
-               break;
-       case NHERE:
-       case NXHERE:
-               cmdputs("<<...");
-               break;
-       default:
-               cmdputs("???");
-               break;
-       }
-}
-
-
-static char *
-commandtext(const union node *n)
-{
-       char *name;
-
-       cmdnextc = name = ckmalloc(MAXCMDTEXT);
-       cmdnleft = MAXCMDTEXT - 4;
-       cmdtxt(n);
-       *cmdnextc = '\0';
-       return name;
-}
-
-
-static void waitonint(int sig) {
-       intreceived = 1;
-       return;
-}
-/*
- * Routines to check for mail.  (Perhaps make part of main.c?)
- */
-
-
-#define MAXMBOXES 10
-
-
-static int nmboxes;                     /* number of mailboxes */
-static time_t mailtime[MAXMBOXES];      /* times of mailboxes */
-
-
-
-/*
- * Print appropriate message(s) if mail has arrived.  If the argument is
- * nozero, then the value of MAIL has changed, so we just update the
- * values.
- */
-
-static void
-chkmail(int silent)
-{
-       int i;
-       const char *mpath;
-       char *p;
-       char *q;
-       struct stackmark smark;
-       struct stat statb;
-
-       if (silent)
-               nmboxes = 10;
-       if (nmboxes == 0)
-               return;
-       setstackmark(&smark);
-       mpath = mpathset()? mpathval() : mailval();
-       for (i = 0 ; i < nmboxes ; i++) {
-               p = padvance(&mpath, nullstr);
-               if (p == NULL)
-                       break;
-               if (*p == '\0')
-                       continue;
-               for (q = p ; *q ; q++);
-#ifdef DEBUG
-               if (q[-1] != '/')
-                       abort();
-#endif
-               q[-1] = '\0';                   /* delete trailing '/' */
-               if (stat(p, &statb) < 0)
-                       statb.st_size = 0;
-               if (statb.st_size > mailtime[i] && ! silent) {
-                       out2fmt(snlfmt,
-                               pathopt? pathopt : "you have mail");
-               }
-               mailtime[i] = statb.st_size;
-       }
-       nmboxes = i;
-       popstackmark(&smark);
-}
-
-#define PROFILE 0
-
-#if PROFILE
-static short profile_buf[16384];
-extern int etext();
-#endif
-
-static void read_profile (const char *);
-static void cmdloop (int);
-static void options (int);
-static void setoption (int, int);
-static void procargs (int, char **);
-
-
-/*
- * Main routine.  We initialize things, parse the arguments, execute
- * profiles if we're a login shell, and then call cmdloop to execute
- * commands.  The setjmp call sets up the location to jump to when an
- * exception occurs.  When an exception occurs the variable "state"
- * is used to figure out how far we had gotten.
- */
-
-int
-ash_main(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct jmploc jmploc;
-       struct stackmark smark;
-       volatile int state;
-       const char *shinit;
-
-       BLTINCMD = find_builtin("builtin");
-       EXECCMD = find_builtin("exec");
-       EVALCMD = find_builtin("eval");
-
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       unsetenv("PS1");
-       unsetenv("PS2");
-#endif
-
-#if PROFILE
-       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
-#endif
-#if defined(linux) || defined(__GNU__)
-       signal(SIGCHLD, SIG_DFL);
-#endif
-       state = 0;
-       if (setjmp(jmploc.loc)) {
-               INTOFF;
-               /*
-                * When a shell procedure is executed, we raise the
-                * exception EXSHELLPROC to clean up before executing
-                * the shell procedure.
-                */
-               switch (exception) {
-               case EXSHELLPROC:
-                       rootpid = getpid();
-                       rootshell = 1;
-                       minusc = NULL;
-                       state = 3;
-                       break;
-
-               case EXEXEC:
-                       exitstatus = exerrno;
-                       break;
-
-               case EXERROR:
-                       exitstatus = 2;
-                       break;
-
-               default:
-                       break;
-               }
-
-               if (exception != EXSHELLPROC) {
-                   if (state == 0 || iflag == 0 || ! rootshell)
-                           exitshell(exitstatus);
-               }
-               reset();
-               if (exception == EXINT) {
-                       out2c('\n');
-               }
-               popstackmark(&smark);
-               FORCEINTON;                             /* enable interrupts */
-               if (state == 1)
-                       goto state1;
-               else if (state == 2)
-                       goto state2;
-               else if (state == 3)
-                       goto state3;
-               else
-                       goto state4;
-       }
-       handler = &jmploc;
-#ifdef DEBUG
-       opentrace();
-       trputs("Shell args:  ");  trargs(argv);
-#endif
-       rootpid = getpid();
-       rootshell = 1;
-       init();
-       setstackmark(&smark);
-       procargs(argc, argv);
-       if (argv[0] && argv[0][0] == '-') {
-               state = 1;
-               read_profile("/etc/profile");
-state1:
-               state = 2;
-               read_profile(".profile");
-       }
-state2:
-       state = 3;
-#ifndef linux
-       if (getuid() == geteuid() && getgid() == getegid()) {
-#endif
-               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
-                       state = 3;
-                       read_profile(shinit);
-               }
-#ifndef linux
-       }
-#endif
-state3:
-       state = 4;
-       if (sflag == 0 || minusc) {
-               static int sigs[] =  {
-                   SIGINT, SIGQUIT, SIGHUP,
-#ifdef SIGTSTP
-                   SIGTSTP,
-#endif
-                   SIGPIPE
-               };
-#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
-               int i;
-
-               for (i = 0; i < SIGSSIZE; i++)
-                   setsignal(sigs[i]);
-       }
-
-       if (minusc)
-               evalstring(minusc, 0);
-
-       if (sflag || minusc == NULL) {
-state4: /* XXX ??? - why isn't this before the "if" statement */
-               cmdloop(1);
-       }
-#if PROFILE
-       monitor(0);
-#endif
-       exitshell(exitstatus);
-       /* NOTREACHED */
-}
-
-
-/*
- * Read and execute commands.  "Top" is nonzero for the top level command
- * loop; it turns on prompting if the shell is interactive.
- */
-
-static void
-cmdloop(int top)
-{
-       union node *n;
-       struct stackmark smark;
-       int inter;
-       int numeof = 0;
-
-       TRACE(("cmdloop(%d) called\n", top));
-       setstackmark(&smark);
-       for (;;) {
-               if (pendingsigs)
-                       dotrap();
-               inter = 0;
-               if (iflag && top) {
-                       inter++;
-                       showjobs(1);
-                       chkmail(0);
-                       flushall();
-               }
-               n = parsecmd(inter);
-               /* showtree(n); DEBUG */
-               if (n == NEOF) {
-                       if (!top || numeof >= 50)
-                               break;
-                       if (!stoppedjobs()) {
-                               if (!Iflag)
-                                       break;
-                               out2str("\nUse \"exit\" to leave shell.\n");
-                       }
-                       numeof++;
-               } else if (n != NULL && nflag == 0) {
-                       job_warning = (job_warning == 2) ? 1 : 0;
-                       numeof = 0;
-                       evaltree(n, 0);
-               }
-               popstackmark(&smark);
-               setstackmark(&smark);
-               if (evalskip == SKIPFILE) {
-                       evalskip = 0;
-                       break;
-               }
-       }
-       popstackmark(&smark);
-}
-
-
-
-/*
- * Read /etc/profile or .profile.  Return on error.
- */
-
-static void
-read_profile(name)
-       const char *name;
-{
-       int fd;
-       int xflag_set = 0;
-       int vflag_set = 0;
-
-       INTOFF;
-       if ((fd = open(name, O_RDONLY)) >= 0)
-               setinputfd(fd, 1);
-       INTON;
-       if (fd < 0)
-               return;
-       /* -q turns off -x and -v just when executing init files */
-       if (qflag)  {
-           if (xflag)
-                   xflag = 0, xflag_set = 1;
-           if (vflag)
-                   vflag = 0, vflag_set = 1;
-       }
-       cmdloop(0);
-       if (qflag)  {
-           if (xflag_set)
-                   xflag = 1;
-           if (vflag_set)
-                   vflag = 1;
-       }
-       popfile();
-}
-
-
-
-/*
- * Read a file containing shell functions.
- */
-
-static void
-readcmdfile(const char *name)
-{
-       int fd;
-
-       INTOFF;
-       if ((fd = open(name, O_RDONLY)) >= 0)
-               setinputfd(fd, 1);
-       else
-               error("Can't open %s", name);
-       INTON;
-       cmdloop(0);
-       popfile();
-}
-
-
-
-/*
- * Take commands from a file.  To be compatable we should do a path
- * search for the file, which is necessary to find sub-commands.
- */
-
-
-static inline char *
-find_dot_file(mybasename)
-       char *mybasename;
-{
-       char *fullname;
-       const char *path = pathval();
-       struct stat statb;
-
-       /* don't try this for absolute or relative paths */
-       if (strchr(mybasename, '/'))
-               return mybasename;
-
-       while ((fullname = padvance(&path, mybasename)) != NULL) {
-               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
-                       /*
-                        * Don't bother freeing here, since it will
-                        * be freed by the caller.
-                        */
-                       return fullname;
-               }
-               stunalloc(fullname);
-       }
-
-       /* not found in the PATH */
-       error("%s: not found", mybasename);
-       /* NOTREACHED */
-}
-
-static int
-dotcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct strlist *sp;
-       exitstatus = 0;
-
-       for (sp = cmdenviron; sp ; sp = sp->next)
-               setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
-
-       if (argc >= 2) {                /* That's what SVR2 does */
-               char *fullname;
-               struct stackmark smark;
-
-               setstackmark(&smark);
-               fullname = find_dot_file(argv[1]);
-               setinputfile(fullname, 1);
-               commandname = fullname;
-               cmdloop(0);
-               popfile();
-               popstackmark(&smark);
-       }
-       return exitstatus;
-}
-
-
-static int
-exitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (stoppedjobs())
-               return 0;
-       if (argc > 1)
-               exitstatus = number(argv[1]);
-       else
-               exitstatus = oexitstatus;
-       exitshell(exitstatus);
-       /* NOTREACHED */
-}
-
-static pointer
-stalloc(int nbytes)
-{
-       char *p;
-
-       nbytes = ALIGN(nbytes);
-       if (nbytes > stacknleft) {
-               int blocksize;
-               struct stack_block *sp;
-
-               blocksize = nbytes;
-               if (blocksize < MINSIZE)
-                       blocksize = MINSIZE;
-               INTOFF;
-               sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
-               sp->prev = stackp;
-               stacknxt = sp->space;
-               stacknleft = blocksize;
-               stackp = sp;
-               INTON;
-       }
-       p = stacknxt;
-       stacknxt += nbytes;
-       stacknleft -= nbytes;
-       return p;
-}
-
-
-static void
-stunalloc(pointer p)
-{
-#ifdef DEBUG
-       if (p == NULL) {                /*DEBUG */
-               write(2, "stunalloc\n", 10);
-               abort();
-       }
-#endif
-       if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
-               p = stackp->space;
-       }
-       stacknleft += stacknxt - (char *)p;
-       stacknxt = p;
-}
-
-
-static void
-setstackmark(struct stackmark *mark)
-{
-       mark->stackp = stackp;
-       mark->stacknxt = stacknxt;
-       mark->stacknleft = stacknleft;
-       mark->marknext = markp;
-       markp = mark;
-}
-
-
-static void
-popstackmark(struct stackmark *mark)
-{
-       struct stack_block *sp;
-
-       INTOFF;
-       markp = mark->marknext;
-       while (stackp != mark->stackp) {
-               sp = stackp;
-               stackp = sp->prev;
-               ckfree(sp);
-       }
-       stacknxt = mark->stacknxt;
-       stacknleft = mark->stacknleft;
-       INTON;
-}
-
-
-/*
- * When the parser reads in a string, it wants to stick the string on the
- * stack and only adjust the stack pointer when it knows how big the
- * string is.  Stackblock (defined in stack.h) returns a pointer to a block
- * of space on top of the stack and stackblocklen returns the length of
- * this block.  Growstackblock will grow this space by at least one byte,
- * possibly moving it (like realloc).  Grabstackblock actually allocates the
- * part of the block that has been used.
- */
-
-static void
-growstackblock(void) {
-       char *p;
-       int newlen = ALIGN(stacknleft * 2 + 100);
-       char *oldspace = stacknxt;
-       int oldlen = stacknleft;
-       struct stack_block *sp;
-       struct stack_block *oldstackp;
-
-       if (stacknxt == stackp->space && stackp != &stackbase) {
-               INTOFF;
-               oldstackp = stackp;
-               sp = stackp;
-               stackp = sp->prev;
-               sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
-               sp->prev = stackp;
-               stackp = sp;
-               stacknxt = sp->space;
-               stacknleft = newlen;
-               {
-                 /* Stack marks pointing to the start of the old block
-                  * must be relocated to point to the new block
-                  */
-                 struct stackmark *xmark;
-                 xmark = markp;
-                 while (xmark != NULL && xmark->stackp == oldstackp) {
-                   xmark->stackp = stackp;
-                   xmark->stacknxt = stacknxt;
-                   xmark->stacknleft = stacknleft;
-                   xmark = xmark->marknext;
-                 }
-               }
-               INTON;
-       } else {
-               p = stalloc(newlen);
-               memcpy(p, oldspace, oldlen);
-               stacknxt = p;                   /* free the space */
-               stacknleft += newlen;           /* we just allocated */
-       }
-}
-
-
-
-static inline void
-grabstackblock(int len)
-{
-       len = ALIGN(len);
-       stacknxt += len;
-       stacknleft -= len;
-}
-
-
-
-/*
- * The following routines are somewhat easier to use that the above.
- * The user declares a variable of type STACKSTR, which may be declared
- * to be a register.  The macro STARTSTACKSTR initializes things.  Then
- * the user uses the macro STPUTC to add characters to the string.  In
- * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
- * grown as necessary.  When the user is done, she can just leave the
- * string there and refer to it using stackblock().  Or she can allocate
- * the space for it using grabstackstr().  If it is necessary to allow
- * someone else to use the stack temporarily and then continue to grow
- * the string, the user should use grabstack to allocate the space, and
- * then call ungrabstr(p) to return to the previous mode of operation.
- *
- * USTPUTC is like STPUTC except that it doesn't check for overflow.
- * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
- * is space for at least one character.
- */
-
-
-static char *
-growstackstr(void) {
-       int len = stackblocksize();
-       if (herefd >= 0 && len >= 1024) {
-               xwrite(herefd, stackblock(), len);
-               sstrnleft = len - 1;
-               return stackblock();
-       }
-       growstackblock();
-       sstrnleft = stackblocksize() - len - 1;
-       return stackblock() + len;
-}
-
-
-/*
- * Called from CHECKSTRSPACE.
- */
-
-static char *
-makestrspace(size_t newlen) {
-       int len = stackblocksize() - sstrnleft;
-       do {
-               growstackblock();
-               sstrnleft = stackblocksize() - len;
-       } while (sstrnleft < newlen);
-       return stackblock() + len;
-}
-
-
-
-static void
-ungrabstackstr(char *s, char *p)
-{
-       stacknleft += stacknxt - s;
-       stacknxt = s;
-       sstrnleft = stacknleft - (p - s);
-}
-/*
- * Miscelaneous builtins.
- */
-
-
-#undef rflag
-
-//#ifdef __GLIBC__
-static mode_t getmode(const void *, mode_t);
-static void *setmode(const char *);
-//#endif
-
-#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
-typedef long rlim_t;
-#endif
-
-
-
-/*
- * The read builtin.  The -e option causes backslashes to escape the
- * following character.
- *
- * This uses unbuffered input, which may be avoidable in some cases.
- */
-
-static int
-readcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **ap;
-       int backslash;
-       char c;
-       int rflag;
-       char *prompt;
-       const char *ifs;
-       char *p;
-       int startword;
-       int status;
-       int i;
-
-       rflag = 0;
-       prompt = NULL;
-       while ((i = nextopt("p:r")) != '\0') {
-               if (i == 'p')
-                       prompt = optionarg;
-               else
-                       rflag = 1;
-       }
-       if (prompt && isatty(0)) {
-               putprompt(prompt);
-               flushall();
-       }
-       if (*(ap = argptr) == NULL)
-               error("arg count");
-       if ((ifs = bltinlookup("IFS")) == NULL)
-               ifs = defifs;
-       status = 0;
-       startword = 1;
-       backslash = 0;
-       STARTSTACKSTR(p);
-       for (;;) {
-               if (read(0, &c, 1) != 1) {
-                       status = 1;
-                       break;
-               }
-               if (c == '\0')
-                       continue;
-               if (backslash) {
-                       backslash = 0;
-                       if (c != '\n')
-                               STPUTC(c, p);
-                       continue;
-               }
-               if (!rflag && c == '\\') {
-                       backslash++;
-                       continue;
-               }
-               if (c == '\n')
-                       break;
-               if (startword && *ifs == ' ' && strchr(ifs, c)) {
-                       continue;
-               }
-               startword = 0;
-               if (backslash && c == '\\') {
-                       if (read(0, &c, 1) != 1) {
-                               status = 1;
-                               break;
-                       }
-                       STPUTC(c, p);
-               } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
-                       STACKSTRNUL(p);
-                       setvar(*ap, stackblock(), 0);
-                       ap++;
-                       startword = 1;
-                       STARTSTACKSTR(p);
-               } else {
-                       STPUTC(c, p);
-               }
-       }
-       STACKSTRNUL(p);
-       /* Remove trailing blanks */
-       while (stackblock() <= --p && strchr(ifs, *p) != NULL)
-               *p = '\0';
-       setvar(*ap, stackblock(), 0);
-       while (*++ap != NULL)
-               setvar(*ap, nullstr, 0);
-       return status;
-}
-
-
-
-static int
-umaskcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *ap;
-       int mask;
-       int i;
-       int symbolic_mode = 0;
-
-       while (nextopt("S") != '\0') {
-               symbolic_mode = 1;
-       }
-
-       INTOFF;
-       mask = umask(0);
-       umask(mask);
-       INTON;
-
-       if ((ap = *argptr) == NULL) {
-               if (symbolic_mode) {
-                       char u[4], g[4], o[4];
-
-                       i = 0;
-                       if ((mask & S_IRUSR) == 0)
-                               u[i++] = 'r';
-                       if ((mask & S_IWUSR) == 0)
-                               u[i++] = 'w';
-                       if ((mask & S_IXUSR) == 0)
-                               u[i++] = 'x';
-                       u[i] = '\0';
-
-                       i = 0;
-                       if ((mask & S_IRGRP) == 0)
-                               g[i++] = 'r';
-                       if ((mask & S_IWGRP) == 0)
-                               g[i++] = 'w';
-                       if ((mask & S_IXGRP) == 0)
-                               g[i++] = 'x';
-                       g[i] = '\0';
-
-                       i = 0;
-                       if ((mask & S_IROTH) == 0)
-                               o[i++] = 'r';
-                       if ((mask & S_IWOTH) == 0)
-                               o[i++] = 'w';
-                       if ((mask & S_IXOTH) == 0)
-                               o[i++] = 'x';
-                       o[i] = '\0';
-
-                       printf("u=%s,g=%s,o=%s\n", u, g, o);
-               } else {
-                       printf("%.4o\n", mask);
-               }
-       } else {
-               if (is_digit((unsigned char)*ap)) {
-                       mask = 0;
-                       do {
-                               if (*ap >= '8' || *ap < '0')
-                                       error("Illegal number: %s", argv[1]);
-                               mask = (mask << 3) + (*ap - '0');
-                       } while (*++ap != '\0');
-                       umask(mask);
-               } else {
-                       void *set;
-
-                       INTOFF;
-                       if ((set = setmode(ap)) != 0) {
-                               mask = getmode(set, ~mask & 0777);
-                               ckfree(set);
-                       }
-                       INTON;
-                       if (!set)
-                               error("Illegal mode: %s", ap);
-
-                       umask(~mask & 0777);
-               }
-       }
-       return 0;
-}
-
-/*
- * ulimit builtin
- *
- * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
- * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
- * ash by J.T. Conklin.
- *
- * Public domain.
- */
-
-struct limits {
-       const char *name;
-       int     cmd;
-       int     factor; /* multiply by to get rlim_{cur,max} values */
-       char    option;
-};
-
-static const struct limits limits[] = {
-#ifdef RLIMIT_CPU
-       { "time(seconds)",              RLIMIT_CPU,        1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
-       { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
-#endif
-#ifdef RLIMIT_DATA
-       { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
-       { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
-#endif
-#ifdef  RLIMIT_CORE
-       { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
-#endif
-#ifdef RLIMIT_RSS
-       { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
-#endif
-#ifdef RLIMIT_MEMLOCK
-       { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_NPROC
-       { "process(processes)",         RLIMIT_NPROC,      1, 'p' },
-#endif
-#ifdef RLIMIT_NOFILE
-       { "nofiles(descriptors)",       RLIMIT_NOFILE,     1, 'n' },
-#endif
-#ifdef RLIMIT_VMEM
-       { "vmemory(kbytes)",            RLIMIT_VMEM,    1024, 'v' },
-#endif
-#ifdef RLIMIT_SWAP
-       { "swap(kbytes)",               RLIMIT_SWAP,    1024, 'w' },
-#endif
-       { (char *) 0,                   0,                 0,  '\0' }
-};
-
-static int
-ulimitcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int     c;
-       rlim_t val = 0;
-       enum { SOFT = 0x1, HARD = 0x2 }
-                       how = SOFT | HARD;
-       const struct limits     *l;
-       int             set, all = 0;
-       int             optc, what;
-       struct rlimit   limit;
-
-       what = 'f';
-       while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
-               switch (optc) {
-               case 'H':
-                       how = HARD;
-                       break;
-               case 'S':
-                       how = SOFT;
-                       break;
-               case 'a':
-                       all = 1;
-                       break;
-               default:
-                       what = optc;
-               }
-
-       for (l = limits; l->name && l->option != what; l++)
-               ;
-       if (!l->name)
-               error("internal error (%c)", what);
-
-       set = *argptr ? 1 : 0;
-       if (set) {
-               char *p = *argptr;
-
-               if (all || argptr[1])
-                       error("too many arguments");
-               if (strcmp(p, "unlimited") == 0)
-                       val = RLIM_INFINITY;
-               else {
-                       val = (rlim_t) 0;
-
-                       while ((c = *p++) >= '0' && c <= '9')
-                       {
-                               val = (val * 10) + (long)(c - '0');
-                               if (val < (rlim_t) 0)
-                                       break;
-                       }
-                       if (c)
-                               error("bad number");
-                       val *= l->factor;
-               }
-       }
-       if (all) {
-               for (l = limits; l->name; l++) {
-                       getrlimit(l->cmd, &limit);
-                       if (how & SOFT)
-                               val = limit.rlim_cur;
-                       else if (how & HARD)
-                               val = limit.rlim_max;
-
-                       printf("%-20s ", l->name);
-                       if (val == RLIM_INFINITY)
-                               printf("unlimited\n");
-                       else
-                       {
-                               val /= l->factor;
-                               printf("%lld\n", (long long) val);
-                       }
-               }
-               return 0;
-       }
-
-       getrlimit(l->cmd, &limit);
-       if (set) {
-               if (how & HARD)
-                       limit.rlim_max = val;
-               if (how & SOFT)
-                       limit.rlim_cur = val;
-               if (setrlimit(l->cmd, &limit) < 0)
-                       error("error setting limit (%m)");
-       } else {
-               if (how & SOFT)
-                       val = limit.rlim_cur;
-               else if (how & HARD)
-                       val = limit.rlim_max;
-
-               if (val == RLIM_INFINITY)
-                       printf("unlimited\n");
-               else
-               {
-                       val /= l->factor;
-                       printf("%lld\n", (long long) val);
-               }
-       }
-       return 0;
-}
-/*
- * prefix -- see if pfx is a prefix of string.
- */
-
-static int
-prefix(char const *pfx, char const *string)
-{
-       while (*pfx) {
-               if (*pfx++ != *string++)
-                       return 0;
-       }
-       return 1;
-}
-
-/*
- * Return true if s is a string of digits, and save munber in intptr
- * nagative is bad
- */
-
-static int
-is_number(const char *p, int *intptr)
-{
-       int ret = 0;
-
-       do {
-               if (! is_digit(*p))
-                       return 0;
-               ret *= 10;
-               ret += digit_val(*p);
-               p++;
-       } while (*p != '\0');
-
-       *intptr = ret;
-       return 1;
-}
-
-/*
- * Convert a string of digits to an integer, printing an error message on
- * failure.
- */
-
-static int
-number(const char *s)
-{
-       int i;
-       if (! is_number(s, &i))
-               error("Illegal number: %s", s);
-       return i;
-}
-
-/*
- * Produce a possibly single quoted string suitable as input to the shell.
- * The return string is allocated on the stack.
- */
-
-static char *
-single_quote(const char *s) {
-       char *p;
-
-       STARTSTACKSTR(p);
-
-       do {
-               char *q = p;
-               size_t len1, len1p, len2, len2p;
-
-               len1 = strcspn(s, "'");
-               len2 = strspn(s + len1, "'");
-
-               len1p = len1 ? len1 + 2 : len1;
-               switch (len2) {
-               case 0:
-                       len2p = 0;
-                       break;
-               case 1:
-                       len2p = 2;
-                       break;
-               default:
-                       len2p = len2 + 2;
-               }
-
-               CHECKSTRSPACE(len1p + len2p + 1, p);
-
-               if (len1) {
-                       *p = '\'';
-                       q = p + 1 + len1;
-                       memcpy(p + 1, s, len1);
-                       *q++ = '\'';
-                       s += len1;
-               }
-
-               switch (len2) {
-               case 0:
-                       break;
-               case 1:
-                       *q++ = '\\';
-                       *q = '\'';
-                       s++;
-                       break;
-               default:
-                       *q = '"';
-                       q += 1 + len2;
-                       memcpy(q + 1, s, len2);
-                       *q = '"';
-                       s += len2;
-               }
-
-               STADJUST(len1p + len2p, p);
-       } while (*s);
-
-       USTPUTC(0, p);
-
-       return grabstackstr(p);
-}
-
-/*
- * Like strdup but works with the ash stack.
- */
-
-static char *
-sstrdup(const char *p)
-{
-       size_t len = strlen(p) + 1;
-       return memcpy(stalloc(len), p, len);
-}
-
-
-/*
- * Routine for dealing with parsed shell commands.
- */
-
-
-static void sizenodelist (const struct nodelist *);
-static struct nodelist *copynodelist (const struct nodelist *);
-static char *nodesavestr (const char *);
-
-static void
-calcsize(const union node *n)
-{
-      if (n == NULL)
-           return;
-      funcblocksize += nodesize[n->type];
-      switch (n->type) {
-      case NSEMI:
-      case NAND:
-      case NOR:
-      case NWHILE:
-      case NUNTIL:
-           calcsize(n->nbinary.ch2);
-           calcsize(n->nbinary.ch1);
-           break;
-      case NCMD:
-           calcsize(n->ncmd.redirect);
-           calcsize(n->ncmd.args);
-           calcsize(n->ncmd.assign);
-           break;
-      case NPIPE:
-           sizenodelist(n->npipe.cmdlist);
-           break;
-      case NREDIR:
-      case NBACKGND:
-      case NSUBSHELL:
-           calcsize(n->nredir.redirect);
-           calcsize(n->nredir.n);
-           break;
-      case NIF:
-           calcsize(n->nif.elsepart);
-           calcsize(n->nif.ifpart);
-           calcsize(n->nif.test);
-           break;
-      case NFOR:
-           funcstringsize += strlen(n->nfor.var) + 1;
-           calcsize(n->nfor.body);
-           calcsize(n->nfor.args);
-           break;
-      case NCASE:
-           calcsize(n->ncase.cases);
-           calcsize(n->ncase.expr);
-           break;
-      case NCLIST:
-           calcsize(n->nclist.body);
-           calcsize(n->nclist.pattern);
-           calcsize(n->nclist.next);
-           break;
-      case NDEFUN:
-      case NARG:
-           sizenodelist(n->narg.backquote);
-           funcstringsize += strlen(n->narg.text) + 1;
-           calcsize(n->narg.next);
-           break;
-      case NTO:
-      case NFROM:
-      case NFROMTO:
-      case NAPPEND:
-      case NTOOV:
-           calcsize(n->nfile.fname);
-           calcsize(n->nfile.next);
-           break;
-      case NTOFD:
-      case NFROMFD:
-           calcsize(n->ndup.vname);
-           calcsize(n->ndup.next);
-           break;
-      case NHERE:
-      case NXHERE:
-           calcsize(n->nhere.doc);
-           calcsize(n->nhere.next);
-           break;
-      case NNOT:
-           calcsize(n->nnot.com);
-           break;
-      };
-}
-
-static void
-sizenodelist(const struct nodelist *lp)
-{
-       while (lp) {
-               funcblocksize += ALIGN(sizeof(struct nodelist));
-               calcsize(lp->n);
-               lp = lp->next;
-       }
-}
-
-
-static union node *
-copynode(const union node *n)
-{
-      union node *new;
-
-      if (n == NULL)
-           return NULL;
-      new = funcblock;
-      funcblock = (char *) funcblock + nodesize[n->type];
-      switch (n->type) {
-      case NSEMI:
-      case NAND:
-      case NOR:
-      case NWHILE:
-      case NUNTIL:
-           new->nbinary.ch2 = copynode(n->nbinary.ch2);
-           new->nbinary.ch1 = copynode(n->nbinary.ch1);
-           break;
-      case NCMD:
-           new->ncmd.redirect = copynode(n->ncmd.redirect);
-           new->ncmd.args = copynode(n->ncmd.args);
-           new->ncmd.assign = copynode(n->ncmd.assign);
-           new->ncmd.backgnd = n->ncmd.backgnd;
-           break;
-      case NPIPE:
-           new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
-           new->npipe.backgnd = n->npipe.backgnd;
-           break;
-      case NREDIR:
-      case NBACKGND:
-      case NSUBSHELL:
-           new->nredir.redirect = copynode(n->nredir.redirect);
-           new->nredir.n = copynode(n->nredir.n);
-           break;
-      case NIF:
-           new->nif.elsepart = copynode(n->nif.elsepart);
-           new->nif.ifpart = copynode(n->nif.ifpart);
-           new->nif.test = copynode(n->nif.test);
-           break;
-      case NFOR:
-           new->nfor.var = nodesavestr(n->nfor.var);
-           new->nfor.body = copynode(n->nfor.body);
-           new->nfor.args = copynode(n->nfor.args);
-           break;
-      case NCASE:
-           new->ncase.cases = copynode(n->ncase.cases);
-           new->ncase.expr = copynode(n->ncase.expr);
-           break;
-      case NCLIST:
-           new->nclist.body = copynode(n->nclist.body);
-           new->nclist.pattern = copynode(n->nclist.pattern);
-           new->nclist.next = copynode(n->nclist.next);
-           break;
-      case NDEFUN:
-      case NARG:
-           new->narg.backquote = copynodelist(n->narg.backquote);
-           new->narg.text = nodesavestr(n->narg.text);
-           new->narg.next = copynode(n->narg.next);
-           break;
-      case NTO:
-      case NFROM:
-      case NFROMTO:
-      case NAPPEND:
-      case NTOOV:
-           new->nfile.fname = copynode(n->nfile.fname);
-           new->nfile.fd = n->nfile.fd;
-           new->nfile.next = copynode(n->nfile.next);
-           break;
-      case NTOFD:
-      case NFROMFD:
-           new->ndup.vname = copynode(n->ndup.vname);
-           new->ndup.dupfd = n->ndup.dupfd;
-           new->ndup.fd = n->ndup.fd;
-           new->ndup.next = copynode(n->ndup.next);
-           break;
-      case NHERE:
-      case NXHERE:
-           new->nhere.doc = copynode(n->nhere.doc);
-           new->nhere.fd = n->nhere.fd;
-           new->nhere.next = copynode(n->nhere.next);
-           break;
-      case NNOT:
-           new->nnot.com = copynode(n->nnot.com);
-           break;
-      };
-      new->type = n->type;
-      return new;
-}
-
-
-static struct nodelist *
-copynodelist(const struct nodelist *lp)
-{
-       struct nodelist *start;
-       struct nodelist **lpp;
-
-       lpp = &start;
-       while (lp) {
-               *lpp = funcblock;
-               funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
-               (*lpp)->n = copynode(lp->n);
-               lp = lp->next;
-               lpp = &(*lpp)->next;
-       }
-       *lpp = NULL;
-       return start;
-}
-
-
-static char *
-nodesavestr(const char *s)
-{
-       const char *p = s;
-       char *q = funcstring;
-       char   *rtn = funcstring;
-
-       while ((*q++ = *p++) != '\0')
-               continue;
-       funcstring = q;
-       return rtn;
-}
-
-#ifdef ASH_GETOPTS
-static int getopts (char *, char *, char **, int *, int *);
-#endif
-
-
-/*
- * Process the shell command line arguments.
- */
-
-static void
-procargs(argc, argv)
-       int argc;
-       char **argv;
-{
-       int i;
-
-       argptr = argv;
-       if (argc > 0)
-               argptr++;
-       for (i = 0; i < NOPTS; i++)
-               optent_val(i) = 2;
-       options(1);
-       if (*argptr == NULL && minusc == NULL)
-               sflag = 1;
-       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
-               iflag = 1;
-       if (mflag == 2)
-               mflag = iflag;
-       for (i = 0; i < NOPTS; i++)
-               if (optent_val(i) == 2)
-                       optent_val(i) = 0;
-       arg0 = argv[0];
-       if (sflag == 0 && minusc == NULL) {
-               commandname = argv[0];
-               arg0 = *argptr++;
-               setinputfile(arg0, 0);
-               commandname = arg0;
-       }
-       /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
-       if (argptr && minusc && *argptr)
-               arg0 = *argptr++;
-
-       shellparam.p = argptr;
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
-       while (*argptr) {
-               shellparam.nparam++;
-               argptr++;
-       }
-       optschanged();
-}
-
-
-
-/*
- * Process shell options.  The global variable argptr contains a pointer
- * to the argument list; we advance it past the options.
- */
-
-static inline void
-minus_o(const char *name, int val)
-{
-       int i;
-
-       if (name == NULL) {
-               out1str("Current option settings\n");
-               for (i = 0; i < NOPTS; i++)
-                       printf("%-16s%s\n", optent_name(optlist[i]),
-                               optent_val(i) ? "on" : "off");
-       } else {
-               for (i = 0; i < NOPTS; i++)
-                       if (equal(name, optent_name(optlist[i]))) {
-                               setoption(optent_letter(optlist[i]), val);
-                               return;
-                       }
-               error("Illegal option -o %s", name);
-       }
-}
-
-
-static void
-options(int cmdline)
-{
-       char *p;
-       int val;
-       int c;
-
-       if (cmdline)
-               minusc = NULL;
-       while ((p = *argptr) != NULL) {
-               argptr++;
-               if ((c = *p++) == '-') {
-                       val = 1;
-                       if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
-                               if (!cmdline) {
-                                       /* "-" means turn off -x and -v */
-                                       if (p[0] == '\0')
-                                               xflag = vflag = 0;
-                                       /* "--" means reset params */
-                                       else if (*argptr == NULL)
-                                               setparam(argptr);
-                               }
-                               break;    /* "-" or  "--" terminates options */
-                       }
-               } else if (c == '+') {
-                       val = 0;
-               } else {
-                       argptr--;
-                       break;
-               }
-               while ((c = *p++) != '\0') {
-                       if (c == 'c' && cmdline) {
-                               char *q;
-#ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
-                               if (*p == '\0')
-#endif
-                                       q = *argptr++;
-                               if (q == NULL || minusc != NULL)
-                                       error("Bad -c option");
-                               minusc = q;
-#ifdef NOHACK
-                               break;
-#endif
-                       } else if (c == 'o') {
-                               minus_o(*argptr, val);
-                               if (*argptr)
-                                       argptr++;
-                       } else {
-                               setoption(c, val);
-                       }
-               }
-       }
-}
-
-
-static void
-setoption(int flag, int val)
-{
-       int i;
-
-       for (i = 0; i < NOPTS; i++)
-               if (optent_letter(optlist[i]) == flag) {
-                       optent_val(i) = val;
-                       if (val) {
-                               /* #%$ hack for ksh semantics */
-                               if (flag == 'V')
-                                       Eflag = 0;
-                               else if (flag == 'E')
-                                       Vflag = 0;
-                       }
-                       return;
-               }
-       error("Illegal option -%c", flag);
-       /* NOTREACHED */
-}
-
-
-
-/*
- * Set the shell parameters.
- */
-
-static void
-setparam(char **argv)
-{
-       char **newparam;
-       char **ap;
-       int nparam;
-
-       for (nparam = 0 ; argv[nparam] ; nparam++);
-       ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
-       while (*argv) {
-               *ap++ = savestr(*argv++);
-       }
-       *ap = NULL;
-       freeparam(&shellparam);
-       shellparam.malloc = 1;
-       shellparam.nparam = nparam;
-       shellparam.p = newparam;
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-}
-
-
-/*
- * Free the list of positional parameters.
- */
-
-static void
-freeparam(volatile struct shparam *param)
-{
-       char **ap;
-
-       if (param->malloc) {
-               for (ap = param->p ; *ap ; ap++)
-                       ckfree(*ap);
-               ckfree(param->p);
-       }
-}
-
-
-
-/*
- * The shift builtin command.
- */
-
-static int
-shiftcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       int n;
-       char **ap1, **ap2;
-
-       n = 1;
-       if (argc > 1)
-               n = number(argv[1]);
-       if (n > shellparam.nparam)
-               error("can't shift that many");
-       INTOFF;
-       shellparam.nparam -= n;
-       for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
-               if (shellparam.malloc)
-                       ckfree(*ap1);
-       }
-       ap2 = shellparam.p;
-       while ((*ap2++ = *ap1++) != NULL);
-       shellparam.optind = 1;
-       shellparam.optoff = -1;
-       INTON;
-       return 0;
-}
-
-
-
-/*
- * The set command builtin.
- */
-
-static int
-setcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc == 1)
-               return showvarscmd(argc, argv);
-       INTOFF;
-       options(0);
-       optschanged();
-       if (*argptr != NULL) {
-               setparam(argptr);
-       }
-       INTON;
-       return 0;
-}
-
-
-static void
-getoptsreset(const char *value)
-{
-       shellparam.optind = number(value);
-       shellparam.optoff = -1;
-}
-
-#ifdef BB_LOCALE_SUPPORT
-static void change_lc_all(const char *value)
-{
-       if(value != 0 && *value != 0)
-               setlocale(LC_ALL, value);
-}
-
-static void change_lc_ctype(const char *value)
-{
-       if(value != 0 && *value != 0)
-               setlocale(LC_CTYPE, value);
-}
-
-#endif
-
-#ifdef ASH_GETOPTS
-/*
- * The getopts builtin.  Shellparam.optnext points to the next argument
- * to be processed.  Shellparam.optptr points to the next character to
- * be processed in the current argument.  If shellparam.optnext is NULL,
- * then it's the first time getopts has been called.
- */
-
-static int
-getoptscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **optbase;
-
-       if (argc < 3)
-               error("Usage: getopts optstring var [arg]");
-       else if (argc == 3) {
-               optbase = shellparam.p;
-               if (shellparam.optind > shellparam.nparam + 1) {
-                       shellparam.optind = 1;
-                       shellparam.optoff = -1;
-               }
-       }
-       else {
-               optbase = &argv[3];
-               if (shellparam.optind > argc - 2) {
-                       shellparam.optind = 1;
-                       shellparam.optoff = -1;
-               }
-       }
-
-       return getopts(argv[1], argv[2], optbase, &shellparam.optind,
-                      &shellparam.optoff);
-}
-
-/*
- * Safe version of setvar, returns 1 on success 0 on failure.
- */
-
-static int
-setvarsafe(name, val, flags)
-       const char *name, *val;
-       int flags;
-{
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler = handler;
-       int err = 0;
-#ifdef __GNUC__
-       (void) &err;
-#endif
-
-       if (setjmp(jmploc.loc))
-               err = 1;
-       else {
-               handler = &jmploc;
-               setvar(name, val, flags);
-       }
-       handler = savehandler;
-       return err;
-}
-
-static int
-getopts(optstr, optvar, optfirst, myoptind, optoff)
-       char *optstr;
-       char *optvar;
-       char **optfirst;
-       int *myoptind;
-       int *optoff;
-{
-       char *p, *q;
-       char c = '?';
-       int done = 0;
-       int err = 0;
-       char s[10];
-       char **optnext = optfirst + *myoptind - 1;
-
-       if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
-           strlen(*(optnext - 1)) < *optoff)
-               p = NULL;
-       else
-               p = *(optnext - 1) + *optoff;
-       if (p == NULL || *p == '\0') {
-               /* Current word is done, advance */
-               if (optnext == NULL)
-                       return 1;
-               p = *optnext;
-               if (p == NULL || *p != '-' || *++p == '\0') {
-atend:
-                       *myoptind = optnext - optfirst + 1;
-                       p = NULL;
-                       done = 1;
-                       goto out;
-               }
-               optnext++;
-               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
-                       goto atend;
-       }
-
-       c = *p++;
-       for (q = optstr; *q != c; ) {
-               if (*q == '\0') {
-                       if (optstr[0] == ':') {
-                               s[0] = c;
-                               s[1] = '\0';
-                               err |= setvarsafe("OPTARG", s, 0);
-                       }
-                       else {
-                               out2fmt("Illegal option -%c\n", c);
-                               (void) unsetvar("OPTARG");
-                       }
-                       c = '?';
-                       goto bad;
-               }
-               if (*++q == ':')
-                       q++;
-       }
-
-       if (*++q == ':') {
-               if (*p == '\0' && (p = *optnext) == NULL) {
-                       if (optstr[0] == ':') {
-                               s[0] = c;
-                               s[1] = '\0';
-                               err |= setvarsafe("OPTARG", s, 0);
-                               c = ':';
-                       }
-                       else {
-                               out2fmt("No arg for -%c option\n", c);
-                               (void) unsetvar("OPTARG");
-                               c = '?';
-                       }
-                       goto bad;
-               }
-
-               if (p == *optnext)
-                       optnext++;
-               setvarsafe("OPTARG", p, 0);
-               p = NULL;
-       }
-       else
-               setvarsafe("OPTARG", "", 0);
-       *myoptind = optnext - optfirst + 1;
-       goto out;
-
-bad:
-       *myoptind = 1;
-       p = NULL;
-out:
-       *optoff = p ? p - *(optnext - 1) : -1;
-       snprintf(s, sizeof(s), "%d", *myoptind);
-       err |= setvarsafe("OPTIND", s, VNOFUNC);
-       s[0] = c;
-       s[1] = '\0';
-       err |= setvarsafe(optvar, s, 0);
-       if (err) {
-               *myoptind = 1;
-               *optoff = -1;
-               exraise(EXERROR);
-       }
-       return done;
-}
-#endif
-
-/*
- * XXX - should get rid of.  have all builtins use getopt(3).  the
- * library getopt must have the BSD extension static variable "optreset"
- * otherwise it can't be used within the shell safely.
- *
- * Standard option processing (a la getopt) for builtin routines.  The
- * only argument that is passed to nextopt is the option string; the
- * other arguments are unnecessary.  It return the character, or '\0' on
- * end of input.
- */
-
-static int
-nextopt(const char *optstring)
-{
-       char *p;
-       const char *q;
-       char c;
-
-       if ((p = optptr) == NULL || *p == '\0') {
-               p = *argptr;
-               if (p == NULL || *p != '-' || *++p == '\0')
-                       return '\0';
-               argptr++;
-               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
-                       return '\0';
-       }
-       c = *p++;
-       for (q = optstring ; *q != c ; ) {
-               if (*q == '\0')
-                       error("Illegal option -%c", c);
-               if (*++q == ':')
-                       q++;
-       }
-       if (*++q == ':') {
-               if (*p == '\0' && (p = *argptr++) == NULL)
-                       error("No arg for -%c option", c);
-               optionarg = p;
-               p = NULL;
-       }
-       optptr = p;
-       return c;
-}
-
-static void
-flushall() {
-       INTOFF;
-       fflush(stdout);
-       INTON;
-}
-
-
-static void
-out2fmt(const char *fmt, ...)
-{
-       va_list ap;
-       va_start(ap, fmt);
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-}
-
-/*
- * Version of write which resumes after a signal is caught.
- */
-
-static int
-xwrite(int fd, const char *buf, int nbytes)
-{
-       int ntry;
-       int i;
-       int n;
-
-       n = nbytes;
-       ntry = 0;
-       for (;;) {
-               i = write(fd, buf, n);
-               if (i > 0) {
-                       if ((n -= i) <= 0)
-                               return nbytes;
-                       buf += i;
-                       ntry = 0;
-               } else if (i == 0) {
-                       if (++ntry > 10)
-                               return nbytes - n;
-               } else if (errno != EINTR) {
-                       return -1;
-               }
-       }
-}
-
-
-/*
- * Shell command parser.
- */
-
-#define EOFMARKLEN 79
-
-
-
-struct heredoc {
-       struct heredoc *next;   /* next here document in list */
-       union node *here;               /* redirection node */
-       char *eofmark;          /* string indicating end of input */
-       int striptabs;          /* if set, strip leading tabs */
-};
-
-static struct heredoc *heredoclist;     /* list of here documents to read */
-static int parsebackquote;              /* nonzero if we are inside backquotes */
-static int doprompt;                    /* if set, prompt the user */
-static int needprompt;                  /* true if interactive and at start of line */
-static int lasttoken;                   /* last token read */
-
-static char *wordtext;                  /* text of last word returned by readtoken */
-
-static struct nodelist *backquotelist;
-static union node *redirnode;
-static struct heredoc *heredoc;
-static int quoteflag;                   /* set if (part of) last token was quoted */
-static int startlinno;                  /* line # where last token started */
-
-
-static union node *list (int);
-static union node *andor (void);
-static union node *pipeline (void);
-static union node *command (void);
-static union node *simplecmd (void);
-static void parsefname (void);
-static void parseheredoc (void);
-static int peektoken (void);
-static int readtoken (void);
-static int xxreadtoken (void);
-static int readtoken1 (int, char const *, char *, int);
-static int noexpand (char *);
-static void synexpect (int) __attribute__((noreturn));
-static void synerror (const char *) __attribute__((noreturn));
-static void setprompt (int);
-
-
-/*
- * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
- * valid parse tree indicating a blank line.)
- */
-
-static union node *
-parsecmd(int interact)
-{
-       int t;
-
-       tokpushback = 0;
-       doprompt = interact;
-       if (doprompt)
-               setprompt(1);
-       else
-               setprompt(0);
-       needprompt = 0;
-       t = readtoken();
-       if (t == TEOF)
-               return NEOF;
-       if (t == TNL)
-               return NULL;
-       tokpushback++;
-       return list(1);
-}
-
-
-static union node *
-list(nlflag)
-       int nlflag;
-{
-       union node *n1, *n2, *n3;
-       int tok;
-
-       checkkwd = 2;
-       if (nlflag == 0 && tokendlist[peektoken()])
-               return NULL;
-       n1 = NULL;
-       for (;;) {
-               n2 = andor();
-               tok = readtoken();
-               if (tok == TBACKGND) {
-                       if (n2->type == NCMD || n2->type == NPIPE) {
-                               n2->ncmd.backgnd = 1;
-                       } else if (n2->type == NREDIR) {
-                               n2->type = NBACKGND;
-                       } else {
-                               n3 = (union node *)stalloc(sizeof (struct nredir));
-                               n3->type = NBACKGND;
-                               n3->nredir.n = n2;
-                               n3->nredir.redirect = NULL;
-                               n2 = n3;
-                       }
-               }
-               if (n1 == NULL) {
-                       n1 = n2;
-               }
-               else {
-                       n3 = (union node *)stalloc(sizeof (struct nbinary));
-                       n3->type = NSEMI;
-                       n3->nbinary.ch1 = n1;
-                       n3->nbinary.ch2 = n2;
-                       n1 = n3;
-               }
-               switch (tok) {
-               case TBACKGND:
-               case TSEMI:
-                       tok = readtoken();
-                       /* fall through */
-               case TNL:
-                       if (tok == TNL) {
-                               parseheredoc();
-                               if (nlflag)
-                                       return n1;
-                       } else {
-                               tokpushback++;
-                       }
-                       checkkwd = 2;
-                       if (tokendlist[peektoken()])
-                               return n1;
-                       break;
-               case TEOF:
-                       if (heredoclist)
-                               parseheredoc();
-                       else
-                               pungetc();              /* push back EOF on input */
-                       return n1;
-               default:
-                       if (nlflag)
-                               synexpect(-1);
-                       tokpushback++;
-                       return n1;
-               }
-       }
-}
-
-
-
-static union node *
-andor() {
-       union node *n1, *n2, *n3;
-       int t;
-
-       checkkwd = 1;
-       n1 = pipeline();
-       for (;;) {
-               if ((t = readtoken()) == TAND) {
-                       t = NAND;
-               } else if (t == TOR) {
-                       t = NOR;
-               } else {
-                       tokpushback++;
-                       return n1;
-               }
-               checkkwd = 2;
-               n2 = pipeline();
-               n3 = (union node *)stalloc(sizeof (struct nbinary));
-               n3->type = t;
-               n3->nbinary.ch1 = n1;
-               n3->nbinary.ch2 = n2;
-               n1 = n3;
-       }
-}
-
-
-
-static union node *
-pipeline() {
-       union node *n1, *n2, *pipenode;
-       struct nodelist *lp, *prev;
-       int negate;
-
-       negate = 0;
-       TRACE(("pipeline: entered\n"));
-       if (readtoken() == TNOT) {
-               negate = !negate;
-               checkkwd = 1;
-       } else
-               tokpushback++;
-       n1 = command();
-       if (readtoken() == TPIPE) {
-               pipenode = (union node *)stalloc(sizeof (struct npipe));
-               pipenode->type = NPIPE;
-               pipenode->npipe.backgnd = 0;
-               lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-               pipenode->npipe.cmdlist = lp;
-               lp->n = n1;
-               do {
-                       prev = lp;
-                       lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-                       checkkwd = 2;
-                       lp->n = command();
-                       prev->next = lp;
-               } while (readtoken() == TPIPE);
-               lp->next = NULL;
-               n1 = pipenode;
-       }
-       tokpushback++;
-       if (negate) {
-               n2 = (union node *)stalloc(sizeof (struct nnot));
-               n2->type = NNOT;
-               n2->nnot.com = n1;
-               return n2;
-       } else
-               return n1;
-}
-
-
-
-static union node *
-command() {
-       union node *n1, *n2;
-       union node *ap, **app;
-       union node *cp, **cpp;
-       union node *redir, **rpp;
-       int t;
-
-       redir = NULL;
-       n1 = NULL;
-       rpp = &redir;
-
-       /* Check for redirection which may precede command */
-       while (readtoken() == TREDIR) {
-               *rpp = n2 = redirnode;
-               rpp = &n2->nfile.next;
-               parsefname();
-       }
-       tokpushback++;
-
-       switch (readtoken()) {
-       case TIF:
-               n1 = (union node *)stalloc(sizeof (struct nif));
-               n1->type = NIF;
-               n1->nif.test = list(0);
-               if (readtoken() != TTHEN)
-                       synexpect(TTHEN);
-               n1->nif.ifpart = list(0);
-               n2 = n1;
-               while (readtoken() == TELIF) {
-                       n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
-                       n2 = n2->nif.elsepart;
-                       n2->type = NIF;
-                       n2->nif.test = list(0);
-                       if (readtoken() != TTHEN)
-                               synexpect(TTHEN);
-                       n2->nif.ifpart = list(0);
-               }
-               if (lasttoken == TELSE)
-                       n2->nif.elsepart = list(0);
-               else {
-                       n2->nif.elsepart = NULL;
-                       tokpushback++;
-               }
-               if (readtoken() != TFI)
-                       synexpect(TFI);
-               checkkwd = 1;
-               break;
-       case TWHILE:
-       case TUNTIL: {
-               int got;
-               n1 = (union node *)stalloc(sizeof (struct nbinary));
-               n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
-               n1->nbinary.ch1 = list(0);
-               if ((got=readtoken()) != TDO) {
-TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
-                       synexpect(TDO);
-               }
-               n1->nbinary.ch2 = list(0);
-               if (readtoken() != TDONE)
-                       synexpect(TDONE);
-               checkkwd = 1;
-               break;
-       }
-       case TFOR:
-               if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
-                       synerror("Bad for loop variable");
-               n1 = (union node *)stalloc(sizeof (struct nfor));
-               n1->type = NFOR;
-               n1->nfor.var = wordtext;
-               checkkwd = 1;
-               if (readtoken() == TIN) {
-                       app = &ap;
-                       while (readtoken() == TWORD) {
-                               n2 = (union node *)stalloc(sizeof (struct narg));
-                               n2->type = NARG;
-                               n2->narg.text = wordtext;
-                               n2->narg.backquote = backquotelist;
-                               *app = n2;
-                               app = &n2->narg.next;
-                       }
-                       *app = NULL;
-                       n1->nfor.args = ap;
-                       if (lasttoken != TNL && lasttoken != TSEMI)
-                               synexpect(-1);
-               } else {
-                       static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
-                                                                  '@', '=', '\0'};
-                       n2 = (union node *)stalloc(sizeof (struct narg));
-                       n2->type = NARG;
-                       n2->narg.text = argvars;
-                       n2->narg.backquote = NULL;
-                       n2->narg.next = NULL;
-                       n1->nfor.args = n2;
-                       /*
-                        * Newline or semicolon here is optional (but note
-                        * that the original Bourne shell only allowed NL).
-                        */
-                       if (lasttoken != TNL && lasttoken != TSEMI)
-                               tokpushback++;
-               }
-               checkkwd = 2;
-               if (readtoken() != TDO)
-                       synexpect(TDO);
-               n1->nfor.body = list(0);
-               if (readtoken() != TDONE)
-                       synexpect(TDONE);
-               checkkwd = 1;
-               break;
-       case TCASE:
-               n1 = (union node *)stalloc(sizeof (struct ncase));
-               n1->type = NCASE;
-               if (readtoken() != TWORD)
-                       synexpect(TWORD);
-               n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
-               n2->type = NARG;
-               n2->narg.text = wordtext;
-               n2->narg.backquote = backquotelist;
-               n2->narg.next = NULL;
-               do {
-                       checkkwd = 1;
-               } while (readtoken() == TNL);
-               if (lasttoken != TIN)
-                       synerror("expecting \"in\"");
-               cpp = &n1->ncase.cases;
-               checkkwd = 2, readtoken();
-               do {
-                       if (lasttoken == TLP)
-                               readtoken();
-                       *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
-                       cp->type = NCLIST;
-                       app = &cp->nclist.pattern;
-                       for (;;) {
-                               *app = ap = (union node *)stalloc(sizeof (struct narg));
-                               ap->type = NARG;
-                               ap->narg.text = wordtext;
-                               ap->narg.backquote = backquotelist;
-                               if (checkkwd = 2, readtoken() != TPIPE)
-                                       break;
-                               app = &ap->narg.next;
-                               readtoken();
-                       }
-                       ap->narg.next = NULL;
-                       if (lasttoken != TRP)
-                               synexpect(TRP);
-                       cp->nclist.body = list(0);
-
-                       checkkwd = 2;
-                       if ((t = readtoken()) != TESAC) {
-                               if (t != TENDCASE)
-                                       synexpect(TENDCASE);
-                               else
-                                       checkkwd = 2, readtoken();
-                       }
-                       cpp = &cp->nclist.next;
-               } while(lasttoken != TESAC);
-               *cpp = NULL;
-               checkkwd = 1;
-               break;
-       case TLP:
-               n1 = (union node *)stalloc(sizeof (struct nredir));
-               n1->type = NSUBSHELL;
-               n1->nredir.n = list(0);
-               n1->nredir.redirect = NULL;
-               if (readtoken() != TRP)
-                       synexpect(TRP);
-               checkkwd = 1;
-               break;
-       case TBEGIN:
-               n1 = list(0);
-               if (readtoken() != TEND)
-                       synexpect(TEND);
-               checkkwd = 1;
-               break;
-       /* Handle an empty command like other simple commands.  */
-       case TSEMI:
-       case TAND:
-       case TOR:
-       case TNL:
-       case TEOF:
-       case TRP:
-       case TBACKGND:
-               /*
-                * An empty command before a ; doesn't make much sense, and
-                * should certainly be disallowed in the case of `if ;'.
-                */
-               if (!redir)
-                       synexpect(-1);
-       case TWORD:
-               tokpushback++;
-               n1 = simplecmd();
-               return n1;
-       default:
-               synexpect(-1);
-               /* NOTREACHED */
-       }
-
-       /* Now check for redirection which may follow command */
-       while (readtoken() == TREDIR) {
-               *rpp = n2 = redirnode;
-               rpp = &n2->nfile.next;
-               parsefname();
-       }
-       tokpushback++;
-       *rpp = NULL;
-       if (redir) {
-               if (n1->type != NSUBSHELL) {
-                       n2 = (union node *)stalloc(sizeof (struct nredir));
-                       n2->type = NREDIR;
-                       n2->nredir.n = n1;
-                       n1 = n2;
-               }
-               n1->nredir.redirect = redir;
-       }
-
-       return n1;
-}
-
-
-static union node *
-simplecmd() {
-       union node *args, **app;
-       union node *n = NULL;
-       union node *vars, **vpp;
-       union node **rpp, *redir;
-
-       args = NULL;
-       app = &args;
-       vars = NULL;
-       vpp = &vars;
-       redir = NULL;
-       rpp = &redir;
-
-       checkalias = 2;
-       for (;;) {
-               switch (readtoken()) {
-               case TWORD:
-               case TASSIGN:
-                       n = (union node *)stalloc(sizeof (struct narg));
-                       n->type = NARG;
-                       n->narg.text = wordtext;
-                       n->narg.backquote = backquotelist;
-                       if (lasttoken == TWORD) {
-                               *app = n;
-                               app = &n->narg.next;
-                       } else {
-                               *vpp = n;
-                               vpp = &n->narg.next;
-                       }
-                       break;
-               case TREDIR:
-                       *rpp = n = redirnode;
-                       rpp = &n->nfile.next;
-                       parsefname();   /* read name of redirection file */
-                       break;
-               case TLP:
-                       if (
-                               args && app == &args->narg.next &&
-                               !vars && !redir
-                       ) {
-                               /* We have a function */
-                               if (readtoken() != TRP)
-                                       synexpect(TRP);
-                               n->type = NDEFUN;
-                               checkkwd = 2;
-                               n->narg.next = command();
-                               return n;
-                       }
-                       /* fall through */
-               default:
-                       tokpushback++;
-                       goto out;
-               }
-       }
-out:
-       *app = NULL;
-       *vpp = NULL;
-       *rpp = NULL;
-       n = (union node *)stalloc(sizeof (struct ncmd));
-       n->type = NCMD;
-       n->ncmd.backgnd = 0;
-       n->ncmd.args = args;
-       n->ncmd.assign = vars;
-       n->ncmd.redirect = redir;
-       return n;
-}
-
-static union node *
-makename(void) {
-       union node *n;
-
-       n = (union node *)stalloc(sizeof (struct narg));
-       n->type = NARG;
-       n->narg.next = NULL;
-       n->narg.text = wordtext;
-       n->narg.backquote = backquotelist;
-       return n;
-}
-
-static void fixredir(union node *n, const char *text, int err)
-{
-       TRACE(("Fix redir %s %d\n", text, err));
-       if (!err)
-               n->ndup.vname = NULL;
-
-       if (is_digit(text[0]) && text[1] == '\0')
-               n->ndup.dupfd = digit_val(text[0]);
-       else if (text[0] == '-' && text[1] == '\0')
-               n->ndup.dupfd = -1;
-       else {
-
-               if (err)
-                       synerror("Bad fd number");
-               else
-                       n->ndup.vname = makename();
-       }
-}
-
-
-static void
-parsefname(void) {
-       union node *n = redirnode;
-
-       if (readtoken() != TWORD)
-               synexpect(-1);
-       if (n->type == NHERE) {
-               struct heredoc *here = heredoc;
-               struct heredoc *p;
-               int i;
-
-               if (quoteflag == 0)
-                       n->type = NXHERE;
-               TRACE(("Here document %d\n", n->type));
-               if (here->striptabs) {
-                       while (*wordtext == '\t')
-                               wordtext++;
-               }
-               if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
-                       synerror("Illegal eof marker for << redirection");
-               rmescapes(wordtext);
-               here->eofmark = wordtext;
-               here->next = NULL;
-               if (heredoclist == NULL)
-                       heredoclist = here;
-               else {
-                       for (p = heredoclist ; p->next ; p = p->next);
-                       p->next = here;
-               }
-       } else if (n->type == NTOFD || n->type == NFROMFD) {
-               fixredir(n, wordtext, 0);
-       } else {
-               n->nfile.fname = makename();
-       }
-}
-
-
-/*
- * Input any here documents.
- */
-
-static void
-parseheredoc() {
-       struct heredoc *here;
-       union node *n;
-
-       while (heredoclist) {
-               here = heredoclist;
-               heredoclist = here->next;
-               if (needprompt) {
-                       setprompt(2);
-                       needprompt = 0;
-               }
-               readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
-                               here->eofmark, here->striptabs);
-               n = (union node *)stalloc(sizeof (struct narg));
-               n->narg.type = NARG;
-               n->narg.next = NULL;
-               n->narg.text = wordtext;
-               n->narg.backquote = backquotelist;
-               here->here->nhere.doc = n;
-       }
-}
-
-static int
-peektoken() {
-       int t;
-
-       t = readtoken();
-       tokpushback++;
-       return (t);
-}
-
-static int
-readtoken() {
-       int t;
-
-#ifdef ASH_ALIAS
-       int savecheckalias = checkalias;
-       int savecheckkwd = checkkwd;
-       struct alias *ap;
-#endif
-
-#ifdef DEBUG
-       int alreadyseen = tokpushback;
-#endif
-
-#ifdef ASH_ALIAS
-top:
-#endif
-
-       t = xxreadtoken();
-
-#ifdef ASH_ALIAS
-       checkalias = savecheckalias;
-#endif
-
-       if (checkkwd) {
-               /*
-                * eat newlines
-                */
-               if (checkkwd == 2) {
-                       checkkwd = 0;
-                       while (t == TNL) {
-                               parseheredoc();
-                               t = xxreadtoken();
-                       }
-               }
-               checkkwd = 0;
-               /*
-                * check for keywords
-                */
-               if (t == TWORD && !quoteflag)
-               {
-                       const char *const *pp;
-
-                       if ((pp = findkwd(wordtext))) {
-                               lasttoken = t = pp - parsekwd + KWDOFFSET;
-                               TRACE(("keyword %s recognized\n", tokname[t]));
-                               goto out;
-                       }
-               }
-       }
-
-
-       if (t != TWORD) {
-               if (t != TREDIR) {
-                       checkalias = 0;
-               }
-       } else if (checkalias == 2 && isassignment(wordtext)) {
-               lasttoken = t = TASSIGN;
-#ifdef ASH_ALIAS
-       } else if (checkalias) {
-               if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
-                       if (*ap->val) {
-                               pushstring(ap->val, strlen(ap->val), ap);
-                       }
-                       checkkwd = savecheckkwd;
-                       goto top;
-               }
-               checkalias = 0;
-#endif
-       }
-out:
-#ifdef DEBUG
-       if (!alreadyseen)
-           TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
-       else
-           TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
-#endif
-       return (t);
-}
-
-
-/*
- * Read the next input token.
- * If the token is a word, we set backquotelist to the list of cmds in
- *      backquotes.  We set quoteflag to true if any part of the word was
- *      quoted.
- * If the token is TREDIR, then we set redirnode to a structure containing
- *      the redirection.
- * In all cases, the variable startlinno is set to the number of the line
- *      on which the token starts.
- *
- * [Change comment:  here documents and internal procedures]
- * [Readtoken shouldn't have any arguments.  Perhaps we should make the
- *  word parsing code into a separate routine.  In this case, readtoken
- *  doesn't need to have any internal procedures, but parseword does.
- *  We could also make parseoperator in essence the main routine, and
- *  have parseword (readtoken1?) handle both words and redirection.]
- */
-
-#define RETURN(token)   return lasttoken = token
-
-static int
-xxreadtoken() {
-       int c;
-
-       if (tokpushback) {
-               tokpushback = 0;
-               return lasttoken;
-       }
-       if (needprompt) {
-               setprompt(2);
-               needprompt = 0;
-       }
-       startlinno = plinno;
-       for (;;) {      /* until token or start of word found */
-               c = pgetc_macro();
-               switch (c) {
-               case ' ': case '\t':
-#ifdef ASH_ALIAS
-               case PEOA:
-#endif
-                       continue;
-               case '#':
-                       while ((c = pgetc()) != '\n' && c != PEOF);
-                       pungetc();
-                       continue;
-               case '\\':
-                       if (pgetc() == '\n') {
-                               startlinno = ++plinno;
-                               if (doprompt)
-                                       setprompt(2);
-                               else
-                                       setprompt(0);
-                               continue;
-                       }
-                       pungetc();
-                       goto breakloop;
-               case '\n':
-                       plinno++;
-                       needprompt = doprompt;
-                       RETURN(TNL);
-               case PEOF:
-                       RETURN(TEOF);
-               case '&':
-                       if (pgetc() == '&')
-                               RETURN(TAND);
-                       pungetc();
-                       RETURN(TBACKGND);
-               case '|':
-                       if (pgetc() == '|')
-                               RETURN(TOR);
-                       pungetc();
-                       RETURN(TPIPE);
-               case ';':
-                       if (pgetc() == ';')
-                               RETURN(TENDCASE);
-                       pungetc();
-                       RETURN(TSEMI);
-               case '(':
-                       RETURN(TLP);
-               case ')':
-                       RETURN(TRP);
-               default:
-                       goto breakloop;
-               }
-       }
-breakloop:
-       return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
-#undef RETURN
-}
-
-
-
-/*
- * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
- * is not NULL, read a here document.  In the latter case, eofmark is the
- * word which marks the end of the document and striptabs is true if
- * leading tabs should be stripped from the document.  The argument firstc
- * is the first character of the input token or document.
- *
- * Because C does not have internal subroutines, I have simulated them
- * using goto's to implement the subroutine linkage.  The following macros
- * will run code that appears at the end of readtoken1.
- */
-
-#define CHECKEND()      {goto checkend; checkend_return:;}
-#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
-#define PARSESUB()      {goto parsesub; parsesub_return:;}
-#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
-#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
-#define PARSEARITH()    {goto parsearith; parsearith_return:;}
-
-static int
-readtoken1(firstc, syntax, eofmark, striptabs)
-       int firstc;
-       char const *syntax;
-       char *eofmark;
-       int striptabs;
-       {
-       int c = firstc;
-       char *out;
-       int len;
-       char line[EOFMARKLEN + 1];
-       struct nodelist *bqlist;
-       int quotef;
-       int dblquote;
-       int varnest;    /* levels of variables expansion */
-       int arinest;    /* levels of arithmetic expansion */
-       int parenlevel; /* levels of parens in arithmetic */
-       int dqvarnest;  /* levels of variables expansion within double quotes */
-       int oldstyle;
-       char const *prevsyntax; /* syntax before arithmetic */
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &out;
-       (void) &quotef;
-       (void) &dblquote;
-       (void) &varnest;
-       (void) &arinest;
-       (void) &parenlevel;
-       (void) &dqvarnest;
-       (void) &oldstyle;
-       (void) &prevsyntax;
-       (void) &syntax;
-#endif
-
-       startlinno = plinno;
-       dblquote = 0;
-       if (syntax == DQSYNTAX)
-               dblquote = 1;
-       quotef = 0;
-       bqlist = NULL;
-       varnest = 0;
-       arinest = 0;
-       parenlevel = 0;
-       dqvarnest = 0;
-
-       STARTSTACKSTR(out);
-       loop: { /* for each line, until end of word */
-               CHECKEND();     /* set c to PEOF if at end of here document */
-               for (;;) {      /* until end of line or end of word */
-                       CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
-                       switch(syntax[c]) {
-                       case CNL:       /* '\n' */
-                               if (syntax == BASESYNTAX)
-                                       goto endword;   /* exit outer loop */
-                               USTPUTC(c, out);
-                               plinno++;
-                               if (doprompt)
-                                       setprompt(2);
-                               else
-                                       setprompt(0);
-                               c = pgetc();
-                               goto loop;              /* continue outer loop */
-                       case CWORD:
-                               USTPUTC(c, out);
-                               break;
-                       case CCTL:
-                               if ((eofmark == NULL || dblquote) &&
-                                   dqvarnest == 0)
-                                       USTPUTC(CTLESC, out);
-                               USTPUTC(c, out);
-                               break;
-                       case CBACK:     /* backslash */
-                               c = pgetc2();
-                               if (c == PEOF) {
-                                       USTPUTC('\\', out);
-                                       pungetc();
-                               } else if (c == '\n') {
-                                       if (doprompt)
-                                               setprompt(2);
-                                       else
-                                               setprompt(0);
-                               } else {
-                                       if (dblquote && c != '\\' && c != '`' && c != '$'
-                                                        && (c != '"' || eofmark != NULL))
-                                               USTPUTC('\\', out);
-                                       if (SQSYNTAX[c] == CCTL)
-                                               USTPUTC(CTLESC, out);
-                                       else if (eofmark == NULL)
-                                               USTPUTC(CTLQUOTEMARK, out);
-                                       USTPUTC(c, out);
-                                       quotef++;
-                               }
-                               break;
-                       case CSQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = SQSYNTAX;
-                               break;
-                       case CDQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = DQSYNTAX;
-                               dblquote = 1;
-                               break;
-                       case CENDQUOTE:
-                               if (eofmark != NULL && arinest == 0 &&
-                                   varnest == 0) {
-                                       USTPUTC(c, out);
-                               } else {
-                                       if (arinest) {
-                                               syntax = ARISYNTAX;
-                                               dblquote = 0;
-                                       } else if (eofmark == NULL &&
-                                                  dqvarnest == 0) {
-                                               syntax = BASESYNTAX;
-                                               dblquote = 0;
-                                       }
-                                       quotef++;
-                               }
-                               break;
-                       case CVAR:      /* '$' */
-                               PARSESUB();             /* parse substitution */
-                               break;
-                       case CENDVAR:   /* '}' */
-                               if (varnest > 0) {
-                                       varnest--;
-                                       if (dqvarnest > 0) {
-                                               dqvarnest--;
-                                       }
-                                       USTPUTC(CTLENDVAR, out);
-                               } else {
-                                       USTPUTC(c, out);
-                               }
-                               break;
-#ifdef ASH_MATH_SUPPORT
-                       case CLP:       /* '(' in arithmetic */
-                               parenlevel++;
-                               USTPUTC(c, out);
-                               break;
-                       case CRP:       /* ')' in arithmetic */
-                               if (parenlevel > 0) {
-                                       USTPUTC(c, out);
-                                       --parenlevel;
-                               } else {
-                                       if (pgetc() == ')') {
-                                               if (--arinest == 0) {
-                                                       USTPUTC(CTLENDARI, out);
-                                                       syntax = prevsyntax;
-                                                       if (syntax == DQSYNTAX)
-                                                               dblquote = 1;
-                                                       else
-                                                               dblquote = 0;
-                                               } else
-                                                       USTPUTC(')', out);
-                                       } else {
-                                               /*
-                                                * unbalanced parens
-                                                *  (don't 2nd guess - no error)
-                                                */
-                                               pungetc();
-                                               USTPUTC(')', out);
-                                       }
-                               }
-                               break;
-#endif
-                       case CBQUOTE:   /* '`' */
-                               PARSEBACKQOLD();
-                               break;
-                       case CENDFILE:
-                               goto endword;           /* exit outer loop */
-                       case CIGN:
-                               break;
-                       default:
-                               if (varnest == 0)
-                                       goto endword;   /* exit outer loop */
-#ifdef ASH_ALIAS
-                               if (c != PEOA)
-#endif
-                                       USTPUTC(c, out);
-
-                       }
-                       c = pgetc_macro();
-               }
-       }
-endword:
-       if (syntax == ARISYNTAX)
-               synerror("Missing '))'");
-       if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
-               synerror("Unterminated quoted string");
-       if (varnest != 0) {
-               startlinno = plinno;
-               synerror("Missing '}'");
-       }
-       USTPUTC('\0', out);
-       len = out - stackblock();
-       out = stackblock();
-       if (eofmark == NULL) {
-               if ((c == '>' || c == '<')
-                && quotef == 0
-                && len <= 2
-                && (*out == '\0' || is_digit(*out))) {
-                       PARSEREDIR();
-                       return lasttoken = TREDIR;
-               } else {
-                       pungetc();
-               }
-       }
-       quoteflag = quotef;
-       backquotelist = bqlist;
-       grabstackblock(len);
-       wordtext = out;
-       return lasttoken = TWORD;
-/* end of readtoken routine */
-
-
-
-/*
- * Check to see whether we are at the end of the here document.  When this
- * is called, c is set to the first character of the next input line.  If
- * we are at the end of the here document, this routine sets the c to PEOF.
- */
-
-checkend: {
-       if (eofmark) {
-#ifdef ASH_ALIAS
-               if (c == PEOA) {
-                       c = pgetc2();
-               }
-#endif
-               if (striptabs) {
-                       while (c == '\t') {
-                               c = pgetc2();
-                       }
-               }
-               if (c == *eofmark) {
-                       if (pfgets(line, sizeof line) != NULL) {
-                               char *p, *q;
-
-                               p = line;
-                               for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
-                               if (*p == '\n' && *q == '\0') {
-                                       c = PEOF;
-                                       plinno++;
-                                       needprompt = doprompt;
-                               } else {
-                                       pushstring(line, strlen(line), NULL);
-                               }
-                       }
-               }
-       }
-       goto checkend_return;
-}
-
-
-/*
- * Parse a redirection operator.  The variable "out" points to a string
- * specifying the fd to be redirected.  The variable "c" contains the
- * first character of the redirection operator.
- */
-
-parseredir: {
-       char fd = *out;
-       union node *np;
-
-       np = (union node *)stalloc(sizeof (struct nfile));
-       if (c == '>') {
-               np->nfile.fd = 1;
-               c = pgetc();
-               if (c == '>')
-                       np->type = NAPPEND;
-               else if (c == '&')
-                       np->type = NTOFD;
-               else if (c == '|')
-                       np->type = NTOOV;
-               else {
-                       np->type = NTO;
-                       pungetc();
-               }
-       } else {        /* c == '<' */
-               np->nfile.fd = 0;
-               switch (c = pgetc()) {
-               case '<':
-                       if (sizeof (struct nfile) != sizeof (struct nhere)) {
-                               np = (union node *)stalloc(sizeof (struct nhere));
-                               np->nfile.fd = 0;
-                       }
-                       np->type = NHERE;
-                       heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
-                       heredoc->here = np;
-                       if ((c = pgetc()) == '-') {
-                               heredoc->striptabs = 1;
-                       } else {
-                               heredoc->striptabs = 0;
-                               pungetc();
-                       }
-                       break;
-
-               case '&':
-                       np->type = NFROMFD;
-                       break;
-
-               case '>':
-                       np->type = NFROMTO;
-                       break;
-
-               default:
-                       np->type = NFROM;
-                       pungetc();
-                       break;
-               }
-       }
-       if (fd != '\0')
-               np->nfile.fd = digit_val(fd);
-       redirnode = np;
-       goto parseredir_return;
-}
-
-
-/*
- * Parse a substitution.  At this point, we have read the dollar sign
- * and nothing else.
- */
-
-parsesub: {
-       int subtype;
-       int typeloc;
-       int flags;
-       char *p;
-       static const char types[] = "}-+?=";
-
-       c = pgetc();
-       if (
-               c <= PEOA  ||
-               (c != '(' && c != '{' && !is_name(c) && !is_special(c))
-       ) {
-               USTPUTC('$', out);
-               pungetc();
-       } else if (c == '(') {  /* $(command) or $((arith)) */
-               if (pgetc() == '(') {
-                       PARSEARITH();
-               } else {
-                       pungetc();
-                       PARSEBACKQNEW();
-               }
-       } else {
-               USTPUTC(CTLVAR, out);
-               typeloc = out - stackblock();
-               USTPUTC(VSNORMAL, out);
-               subtype = VSNORMAL;
-               if (c == '{') {
-                       c = pgetc();
-                       if (c == '#') {
-                               if ((c = pgetc()) == '}')
-                                       c = '#';
-                               else
-                                       subtype = VSLENGTH;
-                       }
-                       else
-                               subtype = 0;
-               }
-               if (c > PEOA && is_name(c)) {
-                       do {
-                               STPUTC(c, out);
-                               c = pgetc();
-                       } while (c > PEOA && is_in_name(c));
-               } else if (is_digit(c)) {
-                       do {
-                               USTPUTC(c, out);
-                               c = pgetc();
-                       } while (is_digit(c));
-               }
-               else if (is_special(c)) {
-                       USTPUTC(c, out);
-                       c = pgetc();
-               }
-               else
-badsub:                 synerror("Bad substitution");
-
-               STPUTC('=', out);
-               flags = 0;
-               if (subtype == 0) {
-                       switch (c) {
-                       case ':':
-                               flags = VSNUL;
-                               c = pgetc();
-                               /*FALLTHROUGH*/
-                       default:
-                               p = strchr(types, c);
-                               if (p == NULL)
-                                       goto badsub;
-                               subtype = p - types + VSNORMAL;
-                               break;
-                       case '%':
-                       case '#':
-                               {
-                                       int cc = c;
-                                       subtype = c == '#' ? VSTRIMLEFT :
-                                                            VSTRIMRIGHT;
-                                       c = pgetc();
-                                       if (c == cc)
-                                               subtype++;
-                                       else
-                                               pungetc();
-                                       break;
-                               }
-                       }
-               } else {
-                       pungetc();
-               }
-               if (dblquote || arinest)
-                       flags |= VSQUOTE;
-               *(stackblock() + typeloc) = subtype | flags;
-               if (subtype != VSNORMAL) {
-                       varnest++;
-                       if (dblquote) {
-                               dqvarnest++;
-                       }
-               }
-       }
-       goto parsesub_return;
-}
-
-
-/*
- * Called to parse command substitutions.  Newstyle is set if the command
- * is enclosed inside $(...); nlpp is a pointer to the head of the linked
- * list of commands (passed by reference), and savelen is the number of
- * characters on the top of the stack which must be preserved.
- */
-
-parsebackq: {
-       struct nodelist **nlpp;
-       int savepbq;
-       union node *n;
-       char *volatile str;
-       struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
-       int savelen;
-       int saveprompt;
-#ifdef __GNUC__
-       (void) &saveprompt;
-#endif
-
-       savepbq = parsebackquote;
-       if (setjmp(jmploc.loc)) {
-               if (str)
-                       ckfree(str);
-               parsebackquote = 0;
-               handler = savehandler;
-               longjmp(handler->loc, 1);
-       }
-       INTOFF;
-       str = NULL;
-       savelen = out - stackblock();
-       if (savelen > 0) {
-               str = ckmalloc(savelen);
-               memcpy(str, stackblock(), savelen);
-       }
-       savehandler = handler;
-       handler = &jmploc;
-       INTON;
-       if (oldstyle) {
-               /* We must read until the closing backquote, giving special
-                  treatment to some slashes, and then push the string and
-                  reread it as input, interpreting it normally.  */
-               char *pout;
-               int pc;
-               int psavelen;
-               char *pstr;
-
-
-               STARTSTACKSTR(pout);
-               for (;;) {
-                       if (needprompt) {
-                               setprompt(2);
-                               needprompt = 0;
-                       }
-                       switch (pc = pgetc()) {
-                       case '`':
-                               goto done;
-
-                       case '\\':
-                               if ((pc = pgetc()) == '\n') {
-                                       plinno++;
-                                       if (doprompt)
-                                               setprompt(2);
-                                       else
-                                               setprompt(0);
-                                       /*
-                                        * If eating a newline, avoid putting
-                                        * the newline into the new character
-                                        * stream (via the STPUTC after the
-                                        * switch).
-                                        */
-                                       continue;
-                               }
-                               if (pc != '\\' && pc != '`' && pc != '$'
-                                   && (!dblquote || pc != '"'))
-                                       STPUTC('\\', pout);
-                               if (pc > PEOA) {
-                                       break;
-                               }
-                               /* fall through */
-
-                       case PEOF:
-#ifdef ASH_ALIAS
-                       case PEOA:
-#endif
-                               startlinno = plinno;
-                               synerror("EOF in backquote substitution");
-
-                       case '\n':
-                               plinno++;
-                               needprompt = doprompt;
-                               break;
-
-                       default:
-                               break;
-                       }
-                       STPUTC(pc, pout);
-               }
-done:
-               STPUTC('\0', pout);
-               psavelen = pout - stackblock();
-               if (psavelen > 0) {
-                       pstr = grabstackstr(pout);
-                       setinputstring(pstr);
-               }
-       }
-       nlpp = &bqlist;
-       while (*nlpp)
-               nlpp = &(*nlpp)->next;
-       *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-       (*nlpp)->next = NULL;
-       parsebackquote = oldstyle;
-
-       if (oldstyle) {
-               saveprompt = doprompt;
-               doprompt = 0;
-       }
-
-       n = list(0);
-
-       if (oldstyle)
-               doprompt = saveprompt;
-       else {
-               if (readtoken() != TRP)
-                       synexpect(TRP);
-       }
-
-       (*nlpp)->n = n;
-       if (oldstyle) {
-               /*
-                * Start reading from old file again, ignoring any pushed back
-                * tokens left from the backquote parsing
-                */
-               popfile();
-               tokpushback = 0;
-       }
-       while (stackblocksize() <= savelen)
-               growstackblock();
-       STARTSTACKSTR(out);
-       if (str) {
-               memcpy(out, str, savelen);
-               STADJUST(savelen, out);
-               INTOFF;
-               ckfree(str);
-               str = NULL;
-               INTON;
-       }
-       parsebackquote = savepbq;
-       handler = savehandler;
-       if (arinest || dblquote)
-               USTPUTC(CTLBACKQ | CTLQUOTE, out);
-       else
-               USTPUTC(CTLBACKQ, out);
-       if (oldstyle)
-               goto parsebackq_oldreturn;
-       else
-               goto parsebackq_newreturn;
-}
-
-/*
- * Parse an arithmetic expansion (indicate start of one and set state)
- */
-parsearith: {
-
-       if (++arinest == 1) {
-               prevsyntax = syntax;
-               syntax = ARISYNTAX;
-               USTPUTC(CTLARI, out);
-               if (dblquote)
-                       USTPUTC('"',out);
-               else
-                       USTPUTC(' ',out);
-       } else {
-               /*
-                * we collapse embedded arithmetic expansion to
-                * parenthesis, which should be equivalent
-                */
-               USTPUTC('(', out);
-       }
-       goto parsearith_return;
-}
-
-} /* end of readtoken */
-
-
-/*
- * Returns true if the text contains nothing to expand (no dollar signs
- * or backquotes).
- */
-
-static int
-noexpand(text)
-       char *text;
-       {
-       char *p;
-       char c;
-
-       p = text;
-       while ((c = *p++) != '\0') {
-               if (c == CTLQUOTEMARK)
-                       continue;
-               if (c == CTLESC)
-                       p++;
-               else if (BASESYNTAX[(int)c] == CCTL)
-                       return 0;
-       }
-       return 1;
-}
-
-
-/*
- * Return true if the argument is a legal variable name (a letter or
- * underscore followed by zero or more letters, underscores, and digits).
- */
-
-static int
-goodname(const char *name)
-{
-       const char *p;
-
-       p = name;
-       if (! is_name(*p))
-               return 0;
-       while (*++p) {
-               if (! is_in_name(*p))
-                       return 0;
-       }
-       return 1;
-}
-
-
-/*
- * Called when an unexpected token is read during the parse.  The argument
- * is the token that is expected, or -1 if more than one type of token can
- * occur at this point.
- */
-
-static void
-synexpect(token)
-       int token;
-{
-       char msg[64];
-
-       if (token >= 0) {
-               snprintf(msg, 64, "%s unexpected (expecting %s)",
-                       tokname[lasttoken], tokname[token]);
-       } else {
-               snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
-       }
-       synerror(msg);
-       /* NOTREACHED */
-}
-
-
-static void
-synerror(const char *msg)
-{
-       if (commandname)
-               out2fmt("%s: %d: ", commandname, startlinno);
-       out2fmt("Syntax error: %s\n", msg);
-       error((char *)NULL);
-       /* NOTREACHED */
-}
-
-
-/*
- * called by editline -- any expansions to the prompt
- *    should be added here.
- */
-static void
-setprompt(int whichprompt)
-{
-    char *prompt;
-    switch (whichprompt) {
-       case 1:
-               prompt = ps1val();
-               break;
-       case 2:
-               prompt = ps2val();
-               break;
-       default:                /* 0 */
-               prompt = "";
-    }
-    putprompt(prompt);
-}
-
-
-/*
- * Code for dealing with input/output redirection.
- */
-
-#define EMPTY -2                /* marks an unused slot in redirtab */
-#ifndef PIPE_BUF
-# define PIPESIZE 4096          /* amount of buffering in a pipe */
-#else
-# define PIPESIZE PIPE_BUF
-#endif
-
-
-/*
- * Open a file in noclobber mode.
- * The code was copied from bash.
- */
-static inline int
-noclobberopen(const char *fname)
-{
-       int r, fd;
-       struct stat finfo, finfo2;
-
-       /*
-        * If the file exists and is a regular file, return an error
-        * immediately.
-        */
-       r = stat(fname, &finfo);
-       if (r == 0 && S_ISREG(finfo.st_mode)) {
-               errno = EEXIST;
-               return -1;
-       }
-
-       /*
-        * If the file was not present (r != 0), make sure we open it
-        * exclusively so that if it is created before we open it, our open
-        * will fail.  Make sure that we do not truncate an existing file.
-        * Note that we don't turn on O_EXCL unless the stat failed -- if the
-        * file was not a regular file, we leave O_EXCL off.
-        */
-       if (r != 0)
-               return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
-       fd = open(fname, O_WRONLY|O_CREAT, 0666);
-
-       /* If the open failed, return the file descriptor right away. */
-       if (fd < 0)
-               return fd;
-
-       /*
-        * OK, the open succeeded, but the file may have been changed from a
-        * non-regular file to a regular file between the stat and the open.
-        * We are assuming that the O_EXCL open handles the case where FILENAME
-        * did not exist and is symlinked to an existing file between the stat
-        * and open.
-        */
-
-       /*
-        * If we can open it and fstat the file descriptor, and neither check
-        * revealed that it was a regular file, and the file has not been
-        * replaced, return the file descriptor.
-        */
-        if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
-            finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
-               return fd;
-
-       /* The file has been replaced.  badness. */
-       close(fd);
-       errno = EEXIST;
-       return -1;
-}
-
-/*
- * Handle here documents.  Normally we fork off a process to write the
- * data to a pipe.  If the document is short, we can stuff the data in
- * the pipe without forking.
- */
-
-static inline int
-openhere(const union node *redir)
-{
-       int pip[2];
-       int len = 0;
-
-       if (pipe(pip) < 0)
-               error("Pipe call failed");
-       if (redir->type == NHERE) {
-               len = strlen(redir->nhere.doc->narg.text);
-               if (len <= PIPESIZE) {
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
-                       goto out;
-               }
-       }
-       if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
-               close(pip[0]);
-               signal(SIGINT, SIG_IGN);
-               signal(SIGQUIT, SIG_IGN);
-               signal(SIGHUP, SIG_IGN);
-#ifdef SIGTSTP
-               signal(SIGTSTP, SIG_IGN);
-#endif
-               signal(SIGPIPE, SIG_DFL);
-               if (redir->type == NHERE)
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
-               else
-                       expandhere(redir->nhere.doc, pip[1]);
-               _exit(0);
-       }
-out:
-       close(pip[1]);
-       return pip[0];
-}
-
-
-static inline int
-openredirect(const union node *redir)
-{
-       char *fname;
-       int f;
-
-       switch (redir->nfile.type) {
-       case NFROM:
-               fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDONLY)) < 0)
-                       goto eopen;
-               break;
-       case NFROMTO:
-               fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
-                       goto ecreate;
-               break;
-       case NTO:
-               /* Take care of noclobber mode. */
-               if (Cflag) {
-                       fname = redir->nfile.expfname;
-                       if ((f = noclobberopen(fname)) < 0)
-                               goto ecreate;
-                       break;
-               }
-       case NTOOV:
-               fname = redir->nfile.expfname;
-#ifdef O_CREAT
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
-                       goto ecreate;
-#else
-               if ((f = creat(fname, 0666)) < 0)
-                       goto ecreate;
-#endif
-               break;
-       case NAPPEND:
-               fname = redir->nfile.expfname;
-#ifdef O_APPEND
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
-                       goto ecreate;
-#else
-               if ((f = open(fname, O_WRONLY)) < 0
-                && (f = creat(fname, 0666)) < 0)
-                       goto ecreate;
-               lseek(f, (off_t)0, 2);
-#endif
-               break;
-       default:
-#ifdef DEBUG
-               abort();
-#endif
-               /* Fall through to eliminate warning. */
-       case NTOFD:
-       case NFROMFD:
-               f = -1;
-               break;
-       case NHERE:
-       case NXHERE:
-               f = openhere(redir);
-               break;
-       }
-
-       return f;
-ecreate:
-       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-eopen:
-       error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
-}
-
-
-/*
- * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
- * old file descriptors are stashed away so that the redirection can be
- * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
- * standard output, and the standard error if it becomes a duplicate of
- * stdout.
- */
-
-static void
-redirect(union node *redir, int flags)
-{
-       union node *n;
-       struct redirtab *sv = NULL;
-       int i;
-       int fd;
-       int newfd;
-       int try;
-       int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
-
-       if (flags & REDIR_PUSH) {
-               sv = ckmalloc(sizeof (struct redirtab));
-               for (i = 0 ; i < 10 ; i++)
-                       sv->renamed[i] = EMPTY;
-               sv->next = redirlist;
-               redirlist = sv;
-       }
-       for (n = redir ; n ; n = n->nfile.next) {
-               fd = n->nfile.fd;
-               try = 0;
-               if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
-                   n->ndup.dupfd == fd)
-                       continue; /* redirect from/to same file descriptor */
-
-               INTOFF;
-               newfd = openredirect(n);
-               if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
-                       if (newfd == fd) {
-                               try++;
-                       } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
-                               switch (errno) {
-                               case EBADF:
-                                       if (!try) {
-                                               dupredirect(n, newfd, fd1dup);
-                                               try++;
-                                               break;
-                                       }
-                                       /* FALLTHROUGH*/
-                               default:
-                                       if (newfd >= 0) {
-                                               close(newfd);
-                                       }
-                                       INTON;
-                                       error("%d: %m", fd);
-                                       /* NOTREACHED */
-                               }
-                       }
-                       if (!try) {
-                               close(fd);
-                               if (flags & REDIR_PUSH) {
-                                       sv->renamed[fd] = i;
-                               }
-                       }
-               } else if (fd != newfd) {
-                       close(fd);
-               }
-               if (fd == 0)
-                       fd0_redirected++;
-               if (!try)
-                       dupredirect(n, newfd, fd1dup);
-               INTON;
-       }
-}
-
-
-static void
-dupredirect(const union node *redir, int f, int fd1dup)
-{
-       int fd = redir->nfile.fd;
-
-       if(fd==1)
-               fd1dup = 0;
-       if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
-               if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
-                       if (redir->ndup.dupfd!=1 || fd1dup!=1)
-                               dup_as_newfd(redir->ndup.dupfd, fd);
-               }
-               return;
-       }
-
-       if (f != fd) {
-               dup_as_newfd(f, fd);
-               close(f);
-       }
-       return;
-}
-
-
-
-/*
- * Undo the effects of the last redirection.
- */
-
-static void
-popredir(void)
-{
-       struct redirtab *rp = redirlist;
-       int i;
-
-       INTOFF;
-       for (i = 0 ; i < 10 ; i++) {
-               if (rp->renamed[i] != EMPTY) {
-                       if (i == 0)
-                               fd0_redirected--;
-                       close(i);
-                       if (rp->renamed[i] >= 0) {
-                               dup_as_newfd(rp->renamed[i], i);
-                               close(rp->renamed[i]);
-                       }
-               }
-       }
-       redirlist = rp->next;
-       ckfree(rp);
-       INTON;
-}
-
-/*
- * Discard all saved file descriptors.
- */
-
-static void
-clearredir(void) {
-       struct redirtab *rp;
-       int i;
-
-       for (rp = redirlist ; rp ; rp = rp->next) {
-               for (i = 0 ; i < 10 ; i++) {
-                       if (rp->renamed[i] >= 0) {
-                               close(rp->renamed[i]);
-                       }
-                       rp->renamed[i] = EMPTY;
-               }
-       }
-}
-
-
-/*
- * Copy a file descriptor to be >= to.  Returns -1
- * if the source file descriptor is closed, EMPTY if there are no unused
- * file descriptors left.
- */
-
-static int
-dup_as_newfd(from, to)
-       int from;
-       int to;
-{
-       int newfd;
-
-       newfd = fcntl(from, F_DUPFD, to);
-       if (newfd < 0) {
-               if (errno == EMFILE)
-                       return EMPTY;
-               else
-                       error("%d: %m", from);
-       }
-       return newfd;
-}
-
-/*#ifdef __weak_alias
-__weak_alias(getmode,_getmode)
-__weak_alias(setmode,_setmode)
-#endif*/
-
-#ifndef S_ISTXT
-#if defined(__GLIBC__) && __GLIBC__ >= 2
-#define S_ISTXT __S_ISVTX
-#else
-#define S_ISTXT S_ISVTX
-#endif
-#endif
-
-#define SET_LEN 6               /* initial # of bitcmd struct to malloc */
-#define SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
-
-typedef struct bitcmd {
-       char    cmd;
-       char    cmd2;
-       mode_t  bits;
-} BITCMD;
-
-#define CMD2_CLR        0x01
-#define CMD2_SET        0x02
-#define CMD2_GBITS      0x04
-#define CMD2_OBITS      0x08
-#define CMD2_UBITS      0x10
-
-static BITCMD   *addcmd (BITCMD *, int, int, int, u_int);
-static void      compress_mode (BITCMD *);
-#ifdef SETMODE_DEBUG
-static void      dumpmode (BITCMD *);
-#endif
-
-/*
- * Given the old mode and an array of bitcmd structures, apply the operations
- * described in the bitcmd structures to the old mode, and return the new mode.
- * Note that there is no '=' command; a strict assignment is just a '-' (clear
- * bits) followed by a '+' (set bits).
- */
-static mode_t
-getmode(bbox, omode)
-       const void *bbox;
-       mode_t omode;
-{
-       const BITCMD *set;
-       mode_t clrval, newmode, value;
-
-       _DIAGASSERT(bbox != NULL);
-
-       set = (const BITCMD *)bbox;
-       newmode = omode;
-       for (value = 0;; set++)
-               switch(set->cmd) {
-               /*
-                * When copying the user, group or other bits around, we "know"
-                * where the bits are in the mode so that we can do shifts to
-                * copy them around.  If we don't use shifts, it gets real
-                * grundgy with lots of single bit checks and bit sets.
-                */
-               case 'u':
-                       value = (newmode & S_IRWXU) >> 6;
-                       goto common;
-
-               case 'g':
-                       value = (newmode & S_IRWXG) >> 3;
-                       goto common;
-
-               case 'o':
-                       value = newmode & S_IRWXO;
-common:                 if (set->cmd2 & CMD2_CLR) {
-                               clrval =
-                                   (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode &= ~((clrval<<6) & set->bits);
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode &= ~((clrval<<3) & set->bits);
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode &= ~(clrval & set->bits);
-                       }
-                       if (set->cmd2 & CMD2_SET) {
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode |= (value<<6) & set->bits;
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode |= (value<<3) & set->bits;
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode |= value & set->bits;
-                       }
-                       break;
-
-               case '+':
-                       newmode |= set->bits;
-                       break;
-
-               case '-':
-                       newmode &= ~set->bits;
-                       break;
-
-               case 'X':
-                       if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
-                               newmode |= set->bits;
-                       break;
-
-               case '\0':
-               default:
-#ifdef SETMODE_DEBUG
-                       (void)printf("getmode:%04o -> %04o\n", omode, newmode);
-#endif
-                       return (newmode);
-               }
-}
-
-#define ADDCMD(a, b, c, d) do {                                         \
-       if (set >= endset) {                                            \
-               BITCMD *newset;                                         \
-               setlen += SET_LEN_INCR;                                 \
-               newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
-               if (newset == NULL) {                                   \
-                       free(saveset);                                  \
-                       return (NULL);                                  \
-               }                                                       \
-               set = newset + (set - saveset);                         \
-               saveset = newset;                                       \
-               endset = newset + (setlen - 2);                         \
-       }                                                               \
-       set = addcmd(set, (a), (b), (c), (d));                          \
-} while (/*CONSTCOND*/0)
-
-#define STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
-
-static void *
-setmode(p)
-       const char *p;
-{
-       int perm, who;
-       char op, *ep;
-       BITCMD *set, *saveset, *endset;
-       sigset_t mysigset, sigoset;
-       mode_t mask;
-       int equalopdone = 0;    /* pacify gcc */
-       int permXbits, setlen;
-
-       if (!*p)
-               return (NULL);
-
-       /*
-        * Get a copy of the mask for the permissions that are mask relative.
-        * Flip the bits, we want what's not set.  Since it's possible that
-        * the caller is opening files inside a signal handler, protect them
-        * as best we can.
-        */
-       sigfillset(&mysigset);
-       (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
-       (void)umask(mask = umask(0));
-       mask = ~mask;
-       (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
-
-       setlen = SET_LEN + 2;
-
-       if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
-               return (NULL);
-       saveset = set;
-       endset = set + (setlen - 2);
-
-       /*
-        * If an absolute number, get it and return; disallow non-octal digits
-        * or illegal bits.
-        */
-       if (is_digit((unsigned char)*p)) {
-               perm = (mode_t)strtol(p, &ep, 8);
-               if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
-                       free(saveset);
-                       return (NULL);
-               }
-               ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
-               set->cmd = 0;
-               return (saveset);
-       }
-
-       /*
-        * Build list of structures to set/clear/copy bits as described by
-        * each clause of the symbolic mode.
-        */
-       for (;;) {
-               /* First, find out which bits might be modified. */
-               for (who = 0;; ++p) {
-                       switch (*p) {
-                       case 'a':
-                               who |= STANDARD_BITS;
-                               break;
-                       case 'u':
-                               who |= S_ISUID|S_IRWXU;
-                               break;
-                       case 'g':
-                               who |= S_ISGID|S_IRWXG;
-                               break;
-                       case 'o':
-                               who |= S_IRWXO;
-                               break;
-                       default:
-                               goto getop;
-                       }
-               }
-
-getop:          if ((op = *p++) != '+' && op != '-' && op != '=') {
-                       free(saveset);
-                       return (NULL);
-               }
-               if (op == '=')
-                       equalopdone = 0;
-
-               who &= ~S_ISTXT;
-               for (perm = 0, permXbits = 0;; ++p) {
-                       switch (*p) {
-                       case 'r':
-                               perm |= S_IRUSR|S_IRGRP|S_IROTH;
-                               break;
-                       case 's':
-                               /*
-                                * If specific bits where requested and
-                                * only "other" bits ignore set-id.
-                                */
-                               if (who == 0 || (who & ~S_IRWXO))
-                                       perm |= S_ISUID|S_ISGID;
-                               break;
-                       case 't':
-                               /*
-                                * If specific bits where requested and
-                                * only "other" bits ignore set-id.
-                                */
-                               if (who == 0 || (who & ~S_IRWXO)) {
-                                       who |= S_ISTXT;
-                                       perm |= S_ISTXT;
-                               }
-                               break;
-                       case 'w':
-                               perm |= S_IWUSR|S_IWGRP|S_IWOTH;
-                               break;
-                       case 'X':
-                               permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'x':
-                               perm |= S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'u':
-                       case 'g':
-                       case 'o':
-                               /*
-                                * When ever we hit 'u', 'g', or 'o', we have
-                                * to flush out any partial mode that we have,
-                                * and then do the copying of the mode bits.
-                                */
-                               if (perm) {
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (op == '=')
-                                       equalopdone = 1;
-                               if (op == '+' && permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               ADDCMD(*p, who, op, mask);
-                               break;
-
-                       default:
-                               /*
-                                * Add any permissions that we haven't already
-                                * done.
-                                */
-                               if (perm || (op == '=' && !equalopdone)) {
-                                       if (op == '=')
-                                               equalopdone = 1;
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               goto apply;
-                       }
-               }
-
-apply:          if (!*p)
-                       break;
-               if (*p != ',')
-                       goto getop;
-               ++p;
-       }
-       set->cmd = 0;
-#ifdef SETMODE_DEBUG
-       (void)printf("Before compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       compress_mode(saveset);
-#ifdef SETMODE_DEBUG
-       (void)printf("After compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       return (saveset);
-}
-
-static BITCMD *
-addcmd(set, op, who, oparg, mask)
-       BITCMD *set;
-       int oparg, who;
-       int op;
-       u_int mask;
-{
-
-       _DIAGASSERT(set != NULL);
-
-       switch (op) {
-       case '=':
-               set->cmd = '-';
-               set->bits = who ? who : STANDARD_BITS;
-               set++;
-
-               op = '+';
-               /* FALLTHROUGH */
-       case '+':
-       case '-':
-       case 'X':
-               set->cmd = op;
-               set->bits = (who ? who : mask) & oparg;
-               break;
-
-       case 'u':
-       case 'g':
-       case 'o':
-               set->cmd = op;
-               if (who) {
-                       set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
-                                   ((who & S_IRGRP) ? CMD2_GBITS : 0) |
-                                   ((who & S_IROTH) ? CMD2_OBITS : 0);
-                       set->bits = (mode_t)~0;
-               } else {
-                       set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
-                       set->bits = mask;
-               }
-
-               if (oparg == '+')
-                       set->cmd2 |= CMD2_SET;
-               else if (oparg == '-')
-                       set->cmd2 |= CMD2_CLR;
-               else if (oparg == '=')
-                       set->cmd2 |= CMD2_SET|CMD2_CLR;
-               break;
-       }
-       return (set + 1);
-}
-
-#ifdef SETMODE_DEBUG
-static void
-dumpmode(set)
-       BITCMD *set;
-{
-
-       _DIAGASSERT(set != NULL);
-
-       for (; set->cmd; ++set)
-               (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
-                   set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
-                   set->cmd2 & CMD2_CLR ? " CLR" : "",
-                   set->cmd2 & CMD2_SET ? " SET" : "",
-                   set->cmd2 & CMD2_UBITS ? " UBITS" : "",
-                   set->cmd2 & CMD2_GBITS ? " GBITS" : "",
-                   set->cmd2 & CMD2_OBITS ? " OBITS" : "");
-}
-#endif
-
-/*
- * Given an array of bitcmd structures, compress by compacting consecutive
- * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
- * 'g' and 'o' commands continue to be separate.  They could probably be
- * compacted, but it's not worth the effort.
- */
-static void
-compress_mode(set)
-       BITCMD *set;
-{
-       BITCMD *nset;
-       int setbits, clrbits, Xbits, op;
-
-       _DIAGASSERT(set != NULL);
-
-       for (nset = set;;) {
-               /* Copy over any 'u', 'g' and 'o' commands. */
-               while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
-                       *set++ = *nset++;
-                       if (!op)
-                               return;
-               }
-
-               for (setbits = clrbits = Xbits = 0;; nset++) {
-                       if ((op = nset->cmd) == '-') {
-                               clrbits |= nset->bits;
-                               setbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == '+') {
-                               setbits |= nset->bits;
-                               clrbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == 'X')
-                               Xbits |= nset->bits & ~setbits;
-                       else
-                               break;
-               }
-               if (clrbits) {
-                       set->cmd = '-';
-                       set->cmd2 = 0;
-                       set->bits = clrbits;
-                       set++;
-               }
-               if (setbits) {
-                       set->cmd = '+';
-                       set->cmd2 = 0;
-                       set->bits = setbits;
-                       set++;
-               }
-               if (Xbits) {
-                       set->cmd = 'X';
-                       set->cmd2 = 0;
-                       set->bits = Xbits;
-                       set++;
-               }
-       }
-}
-#ifdef DEBUG
-static void shtree (union node *, int, char *, FILE*);
-static void shcmd (union node *, FILE *);
-static void sharg (union node *, FILE *);
-static void indent (int, char *, FILE *);
-static void trstring (char *);
-
-
-static void
-showtree(n)
-       union node *n;
-{
-       trputs("showtree called\n");
-       shtree(n, 1, NULL, stdout);
-}
-
-
-static void
-shtree(n, ind, pfx, fp)
-       union node *n;
-       int ind;
-       char *pfx;
-       FILE *fp;
-{
-       struct nodelist *lp;
-       const char *s;
-
-       if (n == NULL)
-               return;
-
-       indent(ind, pfx, fp);
-       switch(n->type) {
-       case NSEMI:
-               s = "; ";
-               goto binop;
-       case NAND:
-               s = " && ";
-               goto binop;
-       case NOR:
-               s = " || ";
-binop:
-               shtree(n->nbinary.ch1, ind, NULL, fp);
-          /*    if (ind < 0) */
-                       fputs(s, fp);
-               shtree(n->nbinary.ch2, ind, NULL, fp);
-               break;
-       case NCMD:
-               shcmd(n, fp);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       case NPIPE:
-               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-                       shcmd(lp->n, fp);
-                       if (lp->next)
-                               fputs(" | ", fp);
-               }
-               if (n->npipe.backgnd)
-                       fputs(" &", fp);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       default:
-               fprintf(fp, "<node type %d>", n->type);
-               if (ind >= 0)
-                       putc('\n', fp);
-               break;
-       }
-}
-
-
-
-static void
-shcmd(cmd, fp)
-       union node *cmd;
-       FILE *fp;
-{
-       union node *np;
-       int first;
-       const char *s;
-       int dftfd;
-
-       first = 1;
-       for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
-               if (! first)
-                       putchar(' ');
-               sharg(np, fp);
-               first = 0;
-       }
-       for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
-               if (! first)
-                       putchar(' ');
-               switch (np->nfile.type) {
-                       case NTO:       s = ">";  dftfd = 1; break;
-                       case NAPPEND:   s = ">>"; dftfd = 1; break;
-                       case NTOFD:     s = ">&"; dftfd = 1; break;
-                       case NTOOV:     s = ">|"; dftfd = 1; break;
-                       case NFROM:     s = "<";  dftfd = 0; break;
-                       case NFROMFD:   s = "<&"; dftfd = 0; break;
-                       case NFROMTO:   s = "<>"; dftfd = 0; break;
-                       default:        s = "*error*"; dftfd = 0; break;
-               }
-               if (np->nfile.fd != dftfd)
-                       fprintf(fp, "%d", np->nfile.fd);
-               fputs(s, fp);
-               if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
-                       fprintf(fp, "%d", np->ndup.dupfd);
-               } else {
-                       sharg(np->nfile.fname, fp);
-               }
-               first = 0;
-       }
-}
-
-
-
-static void
-sharg(arg, fp)
-       union node *arg;
-       FILE *fp;
-       {
-       char *p;
-       struct nodelist *bqlist;
-       int subtype;
-
-       if (arg->type != NARG) {
-               printf("<node type %d>\n", arg->type);
-               fflush(stdout);
-               abort();
-       }
-       bqlist = arg->narg.backquote;
-       for (p = arg->narg.text ; *p ; p++) {
-               switch (*p) {
-               case CTLESC:
-                       putc(*++p, fp);
-                       break;
-               case CTLVAR:
-                       putc('$', fp);
-                       putc('{', fp);
-                       subtype = *++p;
-                       if (subtype == VSLENGTH)
-                               putc('#', fp);
-
-                       while (*p != '=')
-                               putc(*p++, fp);
-
-                       if (subtype & VSNUL)
-                               putc(':', fp);
-
-                       switch (subtype & VSTYPE) {
-                       case VSNORMAL:
-                               putc('}', fp);
-                               break;
-                       case VSMINUS:
-                               putc('-', fp);
-                               break;
-                       case VSPLUS:
-                               putc('+', fp);
-                               break;
-                       case VSQUESTION:
-                               putc('?', fp);
-                               break;
-                       case VSASSIGN:
-                               putc('=', fp);
-                               break;
-                       case VSTRIMLEFT:
-                               putc('#', fp);
-                               break;
-                       case VSTRIMLEFTMAX:
-                               putc('#', fp);
-                               putc('#', fp);
-                               break;
-                       case VSTRIMRIGHT:
-                               putc('%', fp);
-                               break;
-                       case VSTRIMRIGHTMAX:
-                               putc('%', fp);
-                               putc('%', fp);
-                               break;
-                       case VSLENGTH:
-                               break;
-                       default:
-                               printf("<subtype %d>", subtype);
-                       }
-                       break;
-               case CTLENDVAR:
-                    putc('}', fp);
-                    break;
-               case CTLBACKQ:
-               case CTLBACKQ|CTLQUOTE:
-                       putc('$', fp);
-                       putc('(', fp);
-                       shtree(bqlist->n, -1, NULL, fp);
-                       putc(')', fp);
-                       break;
-               default:
-                       putc(*p, fp);
-                       break;
-               }
-       }
-}
-
-
-static void
-indent(amount, pfx, fp)
-       int amount;
-       char *pfx;
-       FILE *fp;
-{
-       int i;
-
-       for (i = 0 ; i < amount ; i++) {
-               if (pfx && i == amount - 1)
-                       fputs(pfx, fp);
-               putc('\t', fp);
-       }
-}
-#endif
-
-
-
-/*
- * Debugging stuff.
- */
-
-
-#ifdef DEBUG
-FILE *tracefile;
-
-#if DEBUG == 2
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-
-
-static void
-trputc(c)
-       int c;
-{
-       if (tracefile == NULL)
-               return;
-       putc(c, tracefile);
-       if (c == '\n')
-               fflush(tracefile);
-}
-
-static void
-trace(const char *fmt, ...)
-{
-       va_list va;
-       va_start(va, fmt);
-       if (tracefile != NULL) {
-               (void) vfprintf(tracefile, fmt, va);
-               if (strchr(fmt, '\n'))
-                       (void) fflush(tracefile);
-       }
-       va_end(va);
-}
-
-
-static void
-trputs(s)
-       const char *s;
-{
-       if (tracefile == NULL)
-               return;
-       fputs(s, tracefile);
-       if (strchr(s, '\n'))
-               fflush(tracefile);
-}
-
-
-static void
-trstring(s)
-       char *s;
-{
-       char *p;
-       char c;
-
-       if (tracefile == NULL)
-               return;
-       putc('"', tracefile);
-       for (p = s ; *p ; p++) {
-               switch (*p) {
-               case '\n':  c = 'n';  goto backslash;
-               case '\t':  c = 't';  goto backslash;
-               case '\r':  c = 'r';  goto backslash;
-               case '"':  c = '"';  goto backslash;
-               case '\\':  c = '\\';  goto backslash;
-               case CTLESC:  c = 'e';  goto backslash;
-               case CTLVAR:  c = 'v';  goto backslash;
-               case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
-               case CTLBACKQ:  c = 'q';  goto backslash;
-               case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
-backslash:        putc('\\', tracefile);
-                       putc(c, tracefile);
-                       break;
-               default:
-                       if (*p >= ' ' && *p <= '~')
-                               putc(*p, tracefile);
-                       else {
-                               putc('\\', tracefile);
-                               putc(*p >> 6 & 03, tracefile);
-                               putc(*p >> 3 & 07, tracefile);
-                               putc(*p & 07, tracefile);
-                       }
-                       break;
-               }
-       }
-       putc('"', tracefile);
-}
-
-
-static void
-trargs(ap)
-       char **ap;
-{
-       if (tracefile == NULL)
-               return;
-       while (*ap) {
-               trstring(*ap++);
-               if (*ap)
-                       putc(' ', tracefile);
-               else
-                       putc('\n', tracefile);
-       }
-       fflush(tracefile);
-}
-
-
-static void
-opentrace() {
-       char s[100];
-#ifdef O_APPEND
-       int flags;
-#endif
-
-       if (!debug)
-               return;
-#ifdef not_this_way
-       {
-               char *p;
-               if ((p = getenv("HOME")) == NULL) {
-                       if (geteuid() == 0)
-                               p = "/";
-                       else
-                               p = "/tmp";
-               }
-               strcpy(s, p);
-               strcat(s, "/trace");
-       }
-#else
-       strcpy(s, "./trace");
-#endif /* not_this_way */
-       if ((tracefile = fopen(s, "a")) == NULL) {
-               fprintf(stderr, "Can't open %s\n", s);
-               return;
-       }
-#ifdef O_APPEND
-       if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
-               fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
-#endif
-       fputs("\nTracing started.\n", tracefile);
-       fflush(tracefile);
-}
-#endif /* DEBUG */
-
-
-/*
- * The trap builtin.
- */
-
-static int
-trapcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *action;
-       char **ap;
-       int signo;
-
-       if (argc <= 1) {
-               for (signo = 0 ; signo < NSIG ; signo++) {
-                       if (trap[signo] != NULL) {
-                               char *p;
-                               const char *sn;
-
-                               p = single_quote(trap[signo]);
-                               sn = sys_siglist[signo];
-                               if(sn==NULL)
-                                       sn = u_signal_names(0, &signo, 0);
-                               if(sn==NULL)
-                                       sn = "???";
-                               printf("trap -- %s %s\n", p, sn);
-                               stunalloc(p);
-                       }
-               }
-               return 0;
-       }
-       ap = argv + 1;
-       if (argc == 2)
-               action = NULL;
-       else
-               action = *ap++;
-       while (*ap) {
-               if ((signo = decode_signal(*ap, 0)) < 0)
-                       error("%s: bad trap", *ap);
-               INTOFF;
-               if (action) {
-                       if (action[0] == '-' && action[1] == '\0')
-                               action = NULL;
-                       else
-                               action = savestr(action);
-               }
-               if (trap[signo])
-                       ckfree(trap[signo]);
-               trap[signo] = action;
-               if (signo != 0)
-                       setsignal(signo);
-               INTON;
-               ap++;
-       }
-       return 0;
-}
-
-
-
-
-
-
-/*
- * Set the signal handler for the specified signal.  The routine figures
- * out what it should be set to.
- */
-
-static void
-setsignal(int signo)
-{
-       int action;
-       char *t;
-       struct sigaction act;
-
-       if ((t = trap[signo]) == NULL)
-               action = S_DFL;
-       else if (*t != '\0')
-               action = S_CATCH;
-       else
-               action = S_IGN;
-       if (rootshell && action == S_DFL) {
-               switch (signo) {
-               case SIGINT:
-                       if (iflag || minusc || sflag == 0)
-                               action = S_CATCH;
-                       break;
-               case SIGQUIT:
-#ifdef DEBUG
-                       {
-
-                       if (debug)
-                               break;
-                       }
-#endif
-                       /* FALLTHROUGH */
-               case SIGTERM:
-                       if (iflag)
-                               action = S_IGN;
-                       break;
-#ifdef JOBS
-               case SIGTSTP:
-               case SIGTTOU:
-                       if (mflag)
-                               action = S_IGN;
-                       break;
-#endif
-               }
-       }
-
-       t = &sigmode[signo - 1];
-       if (*t == 0) {
-               /*
-                * current setting unknown
-                */
-               if (sigaction(signo, 0, &act) == -1) {
-                       /*
-                        * Pretend it worked; maybe we should give a warning
-                        * here, but other shells don't. We don't alter
-                        * sigmode, so that we retry every time.
-                        */
-                       return;
-               }
-               if (act.sa_handler == SIG_IGN) {
-                       if (mflag && (signo == SIGTSTP ||
-                            signo == SIGTTIN || signo == SIGTTOU)) {
-                               *t = S_IGN;     /* don't hard ignore these */
-                       } else
-                               *t = S_HARD_IGN;
-               } else {
-                       *t = S_RESET;   /* force to be set */
-               }
-       }
-       if (*t == S_HARD_IGN || *t == action)
-               return;
-       switch (action) {
-       case S_CATCH:
-               act.sa_handler = onsig;
-               break;
-       case S_IGN:
-               act.sa_handler = SIG_IGN;
-               break;
-       default:
-               act.sa_handler = SIG_DFL;
-       }
-       *t = action;
-       act.sa_flags = 0;
-       sigemptyset(&act.sa_mask);
-       sigaction(signo, &act, 0);
-}
-
-/*
- * Ignore a signal.
- */
-
-static void
-ignoresig(signo)
-       int signo;
-{
-       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
-               signal(signo, SIG_IGN);
-       }
-       sigmode[signo - 1] = S_HARD_IGN;
-}
-
-
-/*
- * Signal handler.
- */
-
-static void
-onsig(int signo)
-{
-       if (signo == SIGINT && trap[SIGINT] == NULL) {
-               onint();
-               return;
-       }
-       gotsig[signo - 1] = 1;
-       pendingsigs++;
-}
-
-
-/*
- * Called to execute a trap.  Perhaps we should avoid entering new trap
- * handlers while we are executing a trap handler.
- */
-
-static void
-dotrap(void)
-{
-       int i;
-       int savestatus;
-
-       for (;;) {
-               for (i = 1 ; ; i++) {
-                       if (gotsig[i - 1])
-                               break;
-                       if (i >= NSIG - 1)
-                               goto done;
-               }
-               gotsig[i - 1] = 0;
-               savestatus=exitstatus;
-               evalstring(trap[i], 0);
-               exitstatus=savestatus;
-       }
-done:
-       pendingsigs = 0;
-}
-
-/*
- * Called to exit the shell.
- */
-
-static void
-exitshell(int status)
-{
-       struct jmploc loc1, loc2;
-       char *p;
-
-       TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
-       if (setjmp(loc1.loc)) {
-               goto l1;
-       }
-       if (setjmp(loc2.loc)) {
-               goto l2;
-       }
-       handler = &loc1;
-       if ((p = trap[0]) != NULL && *p != '\0') {
-               trap[0] = NULL;
-               evalstring(p, 0);
-       }
-l1:   handler = &loc2;                  /* probably unnecessary */
-       flushall();
-#ifdef JOBS
-       setjobctl(0);
-#endif
-l2:   _exit(status);
-       /* NOTREACHED */
-}
-
-static int decode_signal(const char *string, int minsig)
-{
-       int signo;
-       const char *name = u_signal_names(string, &signo, minsig);
-
-       return name ? signo : -1;
-}
-
-static struct var **hashvar (const char *);
-static void showvars (const char *, int, int);
-static struct var **findvar (struct var **, const char *);
-
-/*
- * Initialize the varable symbol tables and import the environment
- */
-
-/*
- * This routine initializes the builtin variables.  It is called when the
- * shell is initialized and again when a shell procedure is spawned.
- */
-
-static void
-initvar() {
-       const struct varinit *ip;
-       struct var *vp;
-       struct var **vpp;
-
-       for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
-               if ((vp->flags & VEXPORT) == 0) {
-                       vpp = hashvar(ip->text);
-                       vp->next = *vpp;
-                       *vpp = vp;
-                       vp->text = strdup(ip->text);
-                       vp->flags = ip->flags;
-                       vp->func = ip->func;
-               }
-       }
-       /*
-        * PS1 depends on uid
-        */
-       if ((vps1.flags & VEXPORT) == 0) {
-               vpp = hashvar("PS1=");
-               vps1.next = *vpp;
-               *vpp = &vps1;
-               vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
-               vps1.flags = VSTRFIXED|VTEXTFIXED;
-       }
-}
-
-/*
- * Set the value of a variable.  The flags argument is ored with the
- * flags of the variable.  If val is NULL, the variable is unset.
- */
-
-static void
-setvar(name, val, flags)
-       const char *name, *val;
-       int flags;
-{
-       const char *p;
-       int len;
-       int namelen;
-       char *nameeq;
-       int isbad;
-       int vallen = 0;
-
-       isbad = 0;
-       p = name;
-       if (! is_name(*p))
-               isbad = 1;
-       p++;
-       for (;;) {
-               if (! is_in_name(*p)) {
-                       if (*p == '\0' || *p == '=')
-                               break;
-                       isbad = 1;
-               }
-               p++;
-       }
-       namelen = p - name;
-       if (isbad)
-               error("%.*s: bad variable name", namelen, name);
-       len = namelen + 2;              /* 2 is space for '=' and '\0' */
-       if (val == NULL) {
-               flags |= VUNSET;
-       } else {
-               len += vallen = strlen(val);
-       }
-       INTOFF;
-       nameeq = ckmalloc(len);
-       memcpy(nameeq, name, namelen);
-       nameeq[namelen] = '=';
-       if (val) {
-               memcpy(nameeq + namelen + 1, val, vallen + 1);
-       } else {
-               nameeq[namelen + 1] = '\0';
-       }
-       setvareq(nameeq, flags);
-       INTON;
-}
-
-
-
-/*
- * Same as setvar except that the variable and value are passed in
- * the first argument as name=value.  Since the first argument will
- * be actually stored in the table, it should not be a string that
- * will go away.
- */
-
-static void
-setvareq(s, flags)
-       char *s;
-       int flags;
-{
-       struct var *vp, **vpp;
-
-       vpp = hashvar(s);
-       flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
-       if ((vp = *findvar(vpp, s))) {
-               if (vp->flags & VREADONLY) {
-                       size_t len = strchr(s, '=') - s;
-                       error("%.*s: is read only", len, s);
-               }
-               INTOFF;
-
-               if (vp->func && (flags & VNOFUNC) == 0)
-                       (*vp->func)(strchr(s, '=') + 1);
-
-               if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
-                       ckfree(vp->text);
-
-               vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
-               vp->flags |= flags;
-               vp->text = s;
-
-               /*
-                * We could roll this to a function, to handle it as
-                * a regular variable function callback, but why bother?
-                */
-               if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
-                       chkmail(1);
-               INTON;
-               return;
-       }
-       /* not found */
-       vp = ckmalloc(sizeof (*vp));
-       vp->flags = flags;
-       vp->text = s;
-       vp->next = *vpp;
-       vp->func = NULL;
-       *vpp = vp;
-}
-
-
-
-/*
- * Process a linked list of variable assignments.
- */
-
-static void
-listsetvar(mylist)
-       struct strlist *mylist;
-       {
-       struct strlist *lp;
-
-       INTOFF;
-       for (lp = mylist ; lp ; lp = lp->next) {
-               setvareq(savestr(lp->text), 0);
-       }
-       INTON;
-}
-
-
-
-/*
- * Find the value of a variable.  Returns NULL if not set.
- */
-
-static const char *
-lookupvar(name)
-       const char *name;
-       {
-       struct var *v;
-
-       if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
-               return strchr(v->text, '=') + 1;
-       }
-       return NULL;
-}
-
-
-
-/*
- * Search the environment of a builtin command.
- */
-
-static const char *
-bltinlookup(const char *name)
-{
-       const struct strlist *sp;
-
-       for (sp = cmdenviron ; sp ; sp = sp->next) {
-               if (varequal(sp->text, name))
-                       return strchr(sp->text, '=') + 1;
-       }
-       return lookupvar(name);
-}
-
-
-
-/*
- * Generate a list of exported variables.  This routine is used to construct
- * the third argument to execve when executing a program.
- */
-
-static char **
-environment() {
-       int nenv;
-       struct var **vpp;
-       struct var *vp;
-       char **env;
-       char **ep;
-
-       nenv = 0;
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next)
-                       if (vp->flags & VEXPORT)
-                               nenv++;
-       }
-       ep = env = stalloc((nenv + 1) * sizeof *env);
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next)
-                       if (vp->flags & VEXPORT)
-                               *ep++ = vp->text;
-       }
-       *ep = NULL;
-       return env;
-}
-
-
-/*
- * Called when a shell procedure is invoked to clear out nonexported
- * variables.  It is also necessary to reallocate variables of with
- * VSTACK set since these are currently allocated on the stack.
- */
-
-static void
-shprocvar(void) {
-       struct var **vpp;
-       struct var *vp, **prev;
-
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (prev = vpp ; (vp = *prev) != NULL ; ) {
-                       if ((vp->flags & VEXPORT) == 0) {
-                               *prev = vp->next;
-                               if ((vp->flags & VTEXTFIXED) == 0)
-                                       ckfree(vp->text);
-                               if ((vp->flags & VSTRFIXED) == 0)
-                                       ckfree(vp);
-                       } else {
-                               if (vp->flags & VSTACK) {
-                                       vp->text = savestr(vp->text);
-                                       vp->flags &=~ VSTACK;
-                               }
-                               prev = &vp->next;
-                       }
-               }
-       }
-       initvar();
-}
-
-
-
-/*
- * Command to list all variables which are set.  Currently this command
- * is invoked from the set command when the set command is called without
- * any variables.
- */
-
-static int
-showvarscmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       showvars(nullstr, VUNSET, VUNSET);
-       return 0;
-}
-
-
-
-/*
- * The export and readonly commands.
- */
-
-static int
-exportcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       struct var *vp;
-       char *name;
-       const char *p;
-       int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
-       int pflag;
-
-       listsetvar(cmdenviron);
-       pflag = (nextopt("p") == 'p');
-       if (argc > 1 && !pflag) {
-               while ((name = *argptr++) != NULL) {
-                       if ((p = strchr(name, '=')) != NULL) {
-                               p++;
-                       } else {
-                               if ((vp = *findvar(hashvar(name), name))) {
-                                       vp->flags |= flag;
-                                       goto found;
-                               }
-                       }
-                       setvar(name, p, flag);
-found:;
-               }
-       } else {
-               showvars(argv[0], flag, 0);
-       }
-       return 0;
-}
-
-
-/*
- * The "local" command.
- */
-
-/* funcnest nonzero if we are currently evaluating a function */
-
-static int
-localcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *name;
-
-       if (! funcnest)
-               error("Not in a function");
-       while ((name = *argptr++) != NULL) {
-               mklocal(name);
-       }
-       return 0;
-}
-
-
-/*
- * Make a variable a local variable.  When a variable is made local, it's
- * value and flags are saved in a localvar structure.  The saved values
- * will be restored when the shell function returns.  We handle the name
- * "-" as a special case.
- */
-
-static void
-mklocal(name)
-       char *name;
-       {
-       struct localvar *lvp;
-       struct var **vpp;
-       struct var *vp;
-
-       INTOFF;
-       lvp = ckmalloc(sizeof (struct localvar));
-       if (name[0] == '-' && name[1] == '\0') {
-               char *p;
-               p = ckmalloc(sizeof optet_vals);
-               lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
-               vp = NULL;
-       } else {
-               vpp = hashvar(name);
-               vp = *findvar(vpp, name);
-               if (vp == NULL) {
-                       if (strchr(name, '='))
-                               setvareq(savestr(name), VSTRFIXED);
-                       else
-                               setvar(name, NULL, VSTRFIXED);
-                       vp = *vpp;      /* the new variable */
-                       lvp->text = NULL;
-                       lvp->flags = VUNSET;
-               } else {
-                       lvp->text = vp->text;
-                       lvp->flags = vp->flags;
-                       vp->flags |= VSTRFIXED|VTEXTFIXED;
-                       if (strchr(name, '='))
-                               setvareq(savestr(name), 0);
-               }
-       }
-       lvp->vp = vp;
-       lvp->next = localvars;
-       localvars = lvp;
-       INTON;
-}
-
-
-/*
- * Called after a function returns.
- */
-
-static void
-poplocalvars() {
-       struct localvar *lvp;
-       struct var *vp;
-
-       while ((lvp = localvars) != NULL) {
-               localvars = lvp->next;
-               vp = lvp->vp;
-               if (vp == NULL) {       /* $- saved */
-                       memcpy(optet_vals, lvp->text, sizeof optet_vals);
-                       ckfree(lvp->text);
-               } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
-                       (void)unsetvar(vp->text);
-               } else {
-                       if ((vp->flags & VTEXTFIXED) == 0)
-                               ckfree(vp->text);
-                       vp->flags = lvp->flags;
-                       vp->text = lvp->text;
-               }
-               ckfree(lvp);
-       }
-}
-
-
-static int
-setvarcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       if (argc <= 2)
-               return unsetcmd(argc, argv);
-       else if (argc == 3)
-               setvar(argv[1], argv[2], 0);
-       else
-               error("List assignment not implemented");
-       return 0;
-}
-
-
-/*
- * The unset builtin command.  We unset the function before we unset the
- * variable to allow a function to be unset when there is a readonly variable
- * with the same name.
- */
-
-static int
-unsetcmd(argc, argv)
-       int argc;
-       char **argv;
-{
-       char **ap;
-       int i;
-       int flg_func = 0;
-       int flg_var = 0;
-       int ret = 0;
-
-       while ((i = nextopt("vf")) != '\0') {
-               if (i == 'f')
-                       flg_func = 1;
-               else
-                       flg_var = 1;
-       }
-       if (flg_func == 0 && flg_var == 0)
-               flg_var = 1;
-
-       for (ap = argptr; *ap ; ap++) {
-               if (flg_func)
-                       unsetfunc(*ap);
-               if (flg_var)
-                       ret |= unsetvar(*ap);
-       }
-       return ret;
-}
-
-
-/*
- * Unset the specified variable.
- */
-
-static int
-unsetvar(const char *s)
-{
-       struct var **vpp;
-       struct var *vp;
-
-       vpp = findvar(hashvar(s), s);
-       vp = *vpp;
-       if (vp) {
-               if (vp->flags & VREADONLY)
-                       return (1);
-               INTOFF;
-               if (*(strchr(vp->text, '=') + 1) != '\0')
-                       setvar(s, nullstr, 0);
-               vp->flags &= ~VEXPORT;
-               vp->flags |= VUNSET;
-               if ((vp->flags & VSTRFIXED) == 0) {
-                       if ((vp->flags & VTEXTFIXED) == 0)
-                               ckfree(vp->text);
-                       *vpp = vp->next;
-                       ckfree(vp);
-               }
-               INTON;
-               return (0);
-       }
-
-       return (0);
-}
-
-
-
-/*
- * Find the appropriate entry in the hash table from the name.
- */
-
-static struct var **
-hashvar(const char *p)
-{
-       unsigned int hashval;
-
-       hashval = ((unsigned char) *p) << 4;
-       while (*p && *p != '=')
-               hashval += (unsigned char) *p++;
-       return &vartab[hashval % VTABSIZE];
-}
-
-
-
-/*
- * Returns true if the two strings specify the same varable.  The first
- * variable name is terminated by '='; the second may be terminated by
- * either '=' or '\0'.
- */
-
-static int
-varequal(const char *p, const char *q)
-{
-       while (*p == *q++) {
-               if (*p++ == '=')
-                       return 1;
-       }
-       if (*p == '=' && *(q - 1) == '\0')
-               return 1;
-       return 0;
-}
-
-static void
-showvars(const char *myprefix, int mask, int xor)
-{
-       struct var **vpp;
-       struct var *vp;
-       const char *sep = myprefix == nullstr ? myprefix : spcstr;
-
-       for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-               for (vp = *vpp ; vp ; vp = vp->next) {
-                       if ((vp->flags & mask) ^ xor) {
-                               char *p;
-                               int len;
-
-                               p = strchr(vp->text, '=') + 1;
-                               len = p - vp->text;
-                               p = single_quote(p);
-
-                               printf("%s%s%.*s%s\n", myprefix, sep, len,
-                                       vp->text, p);
-                               stunalloc(p);
-                       }
-               }
-       }
-}
-
-static struct var **
-findvar(struct var **vpp, const char *name)
-{
-       for (; *vpp; vpp = &(*vpp)->next) {
-               if (varequal((*vpp)->text, name)) {
-                       break;
-               }
-       }
-       return vpp;
-}
-
-/*
- * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
- * This file contains code for the times builtin.
- * $Id: ash.c,v 1.17.2.3 2001/09/06 17:59:36 andersen Exp $
- */
-static int timescmd (int argc, char **argv)
-{
-       struct tms buf;
-       long int clk_tck = sysconf(_SC_CLK_TCK);
-
-       times(&buf);
-       printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
-              (int) (buf.tms_utime / clk_tck / 60),
-              ((double) buf.tms_utime) / clk_tck,
-              (int) (buf.tms_stime / clk_tck / 60),
-              ((double) buf.tms_stime) / clk_tck,
-              (int) (buf.tms_cutime / clk_tck / 60),
-              ((double) buf.tms_cutime) / clk_tck,
-              (int) (buf.tms_cstime / clk_tck / 60),
-              ((double) buf.tms_cstime) / clk_tck);
-       return 0;
-}
-
-#ifdef ASH_MATH_SUPPORT
-/* The let builtin.  */
-int letcmd(int argc, char **argv)
-{
-       int errcode;
-       long result=0;
-       if (argc == 2) {
-               char *tmp, *expression, p[13];
-               expression = strchr(argv[1], '=');
-               if (!expression) {
-                       /* Cannot use 'error()' here, or the return code
-                        * will be incorrect */
-                       out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
-                       return 0;
-               }
-               *expression = '\0';
-               tmp = ++expression;
-               result = arith(tmp, &errcode);
-               if (errcode < 0) {
-                       /* Cannot use 'error()' here, or the return code
-                        * will be incorrect */
-                       out2fmt("sh: let: ");
-                       if(errcode == -2)
-                               out2fmt("divide by zero");
-                       else
-                               out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
-                       return 0;
-               }
-               snprintf(p, 12, "%ld", result);
-               setvar(argv[1], savestr(p), 0);
-       } else if (argc >= 3)
-               synerror("invalid operand");
-       return !result;
-}
-#endif
-
-
-
-/*-
- * Copyright (c) 1989, 1991, 1993, 1994
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
- *
- * 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.
- */
diff --git a/busybox/shell/cmdedit.c b/busybox/shell/cmdedit.c
deleted file mode 100644 (file)
index 16ec2f8..0000000
+++ /dev/null
@@ -1,1521 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Termios command line History and Editting.
- *
- * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license.
- * Written by:   Vladimir Oleynik <dzo@simtreas.ru>
- *
- * Used ideas:
- *      Adam Rogoyski    <rogoyski@cs.utexas.edu>
- *      Dave Cinege      <dcinege@psychosis.com>
- *      Jakub Jelinek (c) 1995
- *      Erik Andersen    <andersee@debian.org> (Majorly adjusted for busybox)
- *
- * This code is 'as is' with no warranty.
- *
- *
- */
-
-/*
-   Usage and Known bugs:
-   Terminal key codes are not extensive, and more will probably
-   need to be added. This version was created on Debian GNU/Linux 2.x.
-   Delete, Backspace, Home, End, and the arrow keys were tested
-   to work in an Xterm and console. Ctrl-A also works as Home.
-   Ctrl-E also works as End.
-
-   Small bugs (simple effect):
-   - not true viewing if terminal size (x*y symbols) less
-     size (prompt + editor`s line + 2 symbols)
-   - not true viewing if length prompt less terminal width
- */
-
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <limits.h>
-
-#include "busybox.h"
-
-#ifdef BB_LOCALE_SUPPORT
-#define Isprint(c) isprint((c))
-#else
-#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
-#endif
-
-#ifndef TEST
-
-#define D(x)
-
-#else
-
-#define BB_FEATURE_COMMAND_EDITING
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-#define BB_FEATURE_CLEAN_UP
-
-#define D(x)  x
-
-#endif                                                 /* TEST */
-
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-#include <dirent.h>
-#include <sys/stat.h>
-#endif
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-
-#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION
-#undef  BB_FEATURE_COMMAND_USERNAME_COMPLETION
-#endif
-
-#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT)
-#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-#endif
-
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-#       ifndef TEST
-#               include "pwd_grp/pwd.h"
-#       else
-#               include <pwd.h>
-#       endif  /* TEST */
-#endif                                                 /* advanced FEATURES */
-
-
-
-struct history {
-       char *s;
-       struct history *p;
-       struct history *n;
-};
-
-/* Maximum length of the linked list for the command line history */
-static const int MAX_HISTORY = 15;
-
-/* First element in command line list */
-static struct history *his_front = NULL;
-
-/* Last element in command line list */
-static struct history *his_end = NULL;
-
-
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
-#define getTermSettings(fd,argp) tcgetattr(fd, argp);
-
-/* Current termio and the previous termio before starting sh */
-static struct termios initial_settings, new_settings;
-
-
-static
-volatile int cmdedit_termw = 80;       /* actual terminal width */
-static int history_counter = 0;        /* Number of commands in history list */
-static
-volatile int handlers_sets = 0;        /* Set next bites: */
-
-enum {
-       SET_ATEXIT = 1,         /* when atexit() has been called 
-                                  and get euid,uid,gid to fast compare */
-       SET_WCHG_HANDLERS = 2,  /* winchg signal handler */
-       SET_RESET_TERM = 4,     /* if the terminal needs to be reset upon exit */
-};
-
-
-static int cmdedit_x;          /* real x terminal position */
-static int cmdedit_y;          /* pseudoreal y terminal position */
-static int cmdedit_prmt_len;   /* lenght prompt without colores string */
-
-static int cursor;             /* required global for signal handler */
-static int len;                        /* --- "" - - "" - -"- --""-- --""--- */
-static char *command_ps;       /* --- "" - - "" - -"- --""-- --""--- */
-static
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       const
-#endif
-char *cmdedit_prompt;          /* --- "" - - "" - -"- --""-- --""--- */
-
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-static char *user_buf = "";
-static char *home_pwd_buf = "";
-static int my_euid;
-#endif
-
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-static char *hostname_buf = "";
-static int num_ok_lines = 1;
-#endif
-
-
-#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
-
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-static int my_euid;
-#endif
-
-static int my_uid;
-static int my_gid;
-
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-
-/* It seems that libc5 doesn't know what a sighandler_t is... */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-typedef void (*sighandler_t) (int);
-#endif
-
-static void cmdedit_setwidth(int w, int redraw_flg);
-
-static void win_changed(int nsig)
-{
-       struct winsize win = { 0, 0, 0, 0 };
-       static sighandler_t previous_SIGWINCH_handler;  /* for reset */
-
-       /*   emulate      || signal call */
-       if (nsig == -SIGWINCH || nsig == SIGWINCH) {
-               ioctl(0, TIOCGWINSZ, &win);
-               if (win.ws_col > 0) {
-                       cmdedit_setwidth(win.ws_col, nsig == SIGWINCH);
-               } 
-       }
-       /* Unix not all standart in recall signal */
-
-       if (nsig == -SIGWINCH)          /* save previous handler   */
-               previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
-       else if (nsig == SIGWINCH)      /* signaled called handler */
-               signal(SIGWINCH, win_changed);  /* set for next call       */
-       else                                            /* nsig == 0 */
-               /* set previous handler    */
-               signal(SIGWINCH, previous_SIGWINCH_handler);    /* reset    */
-}
-
-static void cmdedit_reset_term(void)
-{
-       if ((handlers_sets & SET_RESET_TERM) != 0) {
-/* sparc and other have broken termios support: use old termio handling. */
-               setTermSettings(fileno(stdin), (void *) &initial_settings);
-               handlers_sets &= ~SET_RESET_TERM;
-       }
-       if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
-               /* reset SIGWINCH handler to previous (default) */
-               win_changed(0);
-               handlers_sets &= ~SET_WCHG_HANDLERS;
-       }
-       fflush(stdout);
-#ifdef BB_FEATURE_CLEAN_UP
-       if (his_front) {
-               struct history *n;
-
-               while (his_front != his_end) {
-                       n = his_front->n;
-                       free(his_front->s);
-                       free(his_front);
-                       his_front = n;
-               }
-       }
-#endif
-}
-
-
-/* special for recount position for scroll and remove terminal margin effect */
-static void cmdedit_set_out_char(int next_char)
-{
-
-       int c = (int)((unsigned char) command_ps[cursor]);
-
-       if (c == 0)
-               c = ' ';        /* destroy end char? */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-       if (!Isprint(c)) {      /* Inverse put non-printable characters */
-               if (c >= 128)
-                       c -= 128;
-               if (c < ' ')
-                       c += '@';
-               if (c == 127)
-                       c = '?';
-               printf("\033[7m%c\033[0m", c);
-       } else
-#endif
-               putchar(c);
-       if (++cmdedit_x >= cmdedit_termw) {
-               /* terminal is scrolled down */
-               cmdedit_y++;
-               cmdedit_x = 0;
-
-               if (!next_char)
-                       next_char = ' ';
-               /* destroy "(auto)margin" */
-               putchar(next_char);
-               putchar('\b');
-       }
-       cursor++;
-}
-
-/* Move to end line. Bonus: rewrite line from cursor */
-static void input_end(void)
-{
-       while (cursor < len)
-               cmdedit_set_out_char(0);
-}
-
-/* Go to the next line */
-static void goto_new_line(void)
-{
-       input_end();
-       if (cmdedit_x)
-               putchar('\n');
-}
-
-
-static inline void out1str(const char *s)
-{
-       fputs(s, stdout);
-}
-static inline void beep(void)
-{
-       putchar('\007');
-}
-
-/* Move back one charactor */
-/* special for slow terminal */
-static void input_backward(int num)
-{
-       if (num > cursor)
-               num = cursor;
-       cursor -= num;          /* new cursor (in command, not terminal) */
-
-       if (cmdedit_x >= num) {         /* no to up line */
-               cmdedit_x -= num;
-               if (num < 4)
-                       while (num-- > 0)
-                               putchar('\b');
-
-               else
-                       printf("\033[%dD", num);
-       } else {
-               int count_y;
-
-               if (cmdedit_x) {
-                       putchar('\r');          /* back to first terminal pos.  */
-                       num -= cmdedit_x;       /* set previous backward        */
-               }
-               count_y = 1 + num / cmdedit_termw;
-               printf("\033[%dA", count_y);
-               cmdedit_y -= count_y;
-               /*  require  forward  after  uping   */
-               cmdedit_x = cmdedit_termw * count_y - num;
-               printf("\033[%dC", cmdedit_x);  /* set term cursor   */
-       }
-}
-
-static void put_prompt(void)
-{
-       out1str(cmdedit_prompt);
-       cmdedit_x = cmdedit_prmt_len;   /* count real x terminal position */
-       cursor = 0;
-       cmdedit_y = 0;                  /* new quasireal y */
-}
-
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-static void parse_prompt(const char *prmt_ptr)
-{
-       cmdedit_prompt = prmt_ptr;
-       cmdedit_prmt_len = strlen(prmt_ptr);
-       put_prompt();
-}
-#else
-static void parse_prompt(const char *prmt_ptr)
-{
-       int prmt_len = 0;
-       int sub_len = 0;
-       char  flg_not_length = '[';
-       char *prmt_mem_ptr = xcalloc(1, 1);
-       char *pwd_buf = xgetcwd(0);
-       char  buf2[PATH_MAX + 1];
-       char  buf[2];
-       char  c;
-       char *pbuf;
-
-       if (!pwd_buf) {
-               pwd_buf=(char *)unknown;
-       }
-
-       while (*prmt_ptr) {
-               pbuf    = buf;
-               pbuf[1] = 0;
-               c = *prmt_ptr++;
-               if (c == '\\') {
-                       const char *cp = prmt_ptr;
-                       int l;
-                       
-                       c = process_escape_sequence(&prmt_ptr);
-                       if(prmt_ptr==cp) {
-                         if (*cp == 0)
-                               break;
-                         c = *prmt_ptr++;
-                         switch (c) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'u':
-                               pbuf = user_buf;
-                               break;
-#endif 
-                         case 'h':
-                               pbuf = hostname_buf;
-                               if (*pbuf == 0) {
-                                       pbuf = xcalloc(256, 1);
-                                       if (gethostname(pbuf, 255) < 0) {
-                                               strcpy(pbuf, "?");
-                                       } else {
-                                               char *s = strchr(pbuf, '.');
-
-                                               if (s)
-                                                       *s = 0;
-                                       }
-                                       hostname_buf = pbuf;
-                               }
-                               break;
-                         case '$':
-                               c = my_euid == 0 ? '#' : '$';
-                               break;
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-                         case 'w':
-                               pbuf = pwd_buf;
-                               l = strlen(home_pwd_buf);
-                               if (home_pwd_buf[0] != 0 &&
-                                   strncmp(home_pwd_buf, pbuf, l) == 0 &&
-                                   (pbuf[l]=='/' || pbuf[l]=='\0') &&
-                                   strlen(pwd_buf+l)<PATH_MAX) {
-                                       pbuf = buf2;
-                                       *pbuf = '~';
-                                       strcpy(pbuf+1, pwd_buf+l);
-                                       }
-                               break;
-#endif 
-                         case 'W':
-                               pbuf = pwd_buf;
-                               cp = strrchr(pbuf,'/');
-                               if ( (cp != NULL) && (cp != pbuf) )
-                                       pbuf += (cp-pbuf)+1;
-                               break;
-                         case '!':
-                               snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
-                               break;
-                         case 'e': case 'E':     /* \e \E = \033 */
-                               c = '\033';
-                               break;
-                         case 'x': case 'X': 
-                               for (l = 0; l < 3;) {
-                                       int h;
-                                       buf2[l++] = *prmt_ptr;
-                                       buf2[l] = 0;
-                                       h = strtol(buf2, &pbuf, 16);
-                                       if (h > UCHAR_MAX || (pbuf - buf2) < l) {
-                                               l--;
-                                               break;
-                                       }
-                                       prmt_ptr++;
-                               }
-                               buf2[l] = 0;
-                               c = (char)strtol(buf2, 0, 16);
-                               if(c==0)
-                                       c = '?';
-                               pbuf = buf;
-                               break;
-                         case '[': case ']':
-                               if (c == flg_not_length) {
-                                       flg_not_length = flg_not_length == '[' ? ']' : '[';
-                                       continue;
-                               }
-                               break;
-                         }
-                       } 
-               }
-               if(pbuf == buf)
-                       *pbuf = c;
-               prmt_len += strlen(pbuf);
-               prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
-               if (flg_not_length == ']')
-                       sub_len++;
-       }
-       if(pwd_buf!=(char *)unknown)
-               free(pwd_buf);
-       cmdedit_prompt = prmt_mem_ptr;
-       cmdedit_prmt_len = prmt_len - sub_len;
-       put_prompt();
-}
-#endif
-
-
-/* draw promt, editor line, and clear tail */
-static void redraw(int y, int back_cursor)
-{
-       if (y > 0)                              /* up to start y */
-               printf("\033[%dA", y);
-       putchar('\r');
-       put_prompt();
-       input_end();                            /* rewrite */
-       printf("\033[J");                       /* destroy tail after cursor */
-       input_backward(back_cursor);
-}
-
-/* Delete the char in front of the cursor */
-static void input_delete(void)
-{
-       int j = cursor;
-
-       if (j == len)
-               return;
-
-       strcpy(command_ps + j, command_ps + j + 1);
-       len--;
-       input_end();                    /* rewtite new line */
-       cmdedit_set_out_char(0);        /* destroy end char */
-       input_backward(cursor - j);     /* back to old pos cursor */
-}
-
-/* Delete the char in back of the cursor */
-static void input_backspace(void)
-{
-       if (cursor > 0) {
-               input_backward(1);
-               input_delete();
-       }
-}
-
-
-/* Move forward one charactor */
-static void input_forward(void)
-{
-       if (cursor < len)
-               cmdedit_set_out_char(command_ps[cursor + 1]);
-}
-
-
-static void cmdedit_setwidth(int w, int redraw_flg)
-{
-       cmdedit_termw = cmdedit_prmt_len + 2;
-       if (w <= cmdedit_termw) {
-               cmdedit_termw = cmdedit_termw % w;
-       }
-       if (w > cmdedit_termw) {
-               cmdedit_termw = w;
-
-               if (redraw_flg) {
-                       /* new y for current cursor */
-                       int new_y = (cursor + cmdedit_prmt_len) / w;
-
-                       /* redraw */
-                       redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
-                       fflush(stdout);
-               }
-       } 
-}
-
-static void cmdedit_init(void)
-{
-       cmdedit_prmt_len = 0;
-       if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
-               /* emulate usage handler to set handler and call yours work */
-               win_changed(-SIGWINCH);
-               handlers_sets |= SET_WCHG_HANDLERS;
-       }
-
-       if ((handlers_sets & SET_ATEXIT) == 0) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-               struct passwd *entry;
-
-               my_euid = geteuid();
-               entry = getpwuid(my_euid);
-               if (entry) {
-                       user_buf = xstrdup(entry->pw_name);
-                       home_pwd_buf = xstrdup(entry->pw_dir);
-               }
-#endif
-
-#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
-
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
-               my_euid = geteuid();
-#endif
-               my_uid = getuid();
-               my_gid = getgid();
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-               handlers_sets |= SET_ATEXIT;
-               atexit(cmdedit_reset_term);     /* be sure to do this only once */
-       }
-}
-
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-
-static int is_execute(const struct stat *st)
-{
-       if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
-               (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
-               (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
-               (st->st_mode & S_IXOTH)) return TRUE;
-       return FALSE;
-}
-
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-
-static char **username_tab_completion(char *ud, int *num_matches)
-{
-       struct passwd *entry;
-       int userlen;
-       char *temp;
-
-
-       ud++;                           /* ~user/... to user/... */
-       userlen = strlen(ud);
-
-       if (num_matches == 0) {         /* "~/..." or "~user/..." */
-               char *sav_ud = ud - 1;
-               char *home = 0;
-
-               if (*ud == '/') {       /* "~/..."     */
-                       home = home_pwd_buf;
-               } else {
-                       /* "~user/..." */
-                       temp = strchr(ud, '/');
-                       *temp = 0;              /* ~user\0 */
-                       entry = getpwnam(ud);
-                       *temp = '/';            /* restore ~user/... */
-                       ud = temp;
-                       if (entry)
-                               home = entry->pw_dir;
-               }
-               if (home) {
-                       if ((userlen + strlen(home) + 1) < BUFSIZ) {
-                               char temp2[BUFSIZ];     /* argument size */
-
-                               /* /home/user/... */
-                               sprintf(temp2, "%s%s", home, ud);
-                               strcpy(sav_ud, temp2);
-                       }
-               }
-               return 0;       /* void, result save to argument :-) */
-       } else {
-               /* "~[^/]*" */
-               char **matches = (char **) NULL;
-               int nm = 0;
-
-               setpwent();
-
-               while ((entry = getpwent()) != NULL) {
-                       /* Null usernames should result in all users as possible completions. */
-                       if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
-
-                               temp = xmalloc(3 + strlen(entry->pw_name));
-                               sprintf(temp, "~%s/", entry->pw_name);
-                               matches = xrealloc(matches, (nm + 1) * sizeof(char *));
-
-                               matches[nm++] = temp;
-                       }
-               }
-
-               endpwent();
-               (*num_matches) = nm;
-               return (matches);
-       }
-}
-#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */
-
-enum {
-       FIND_EXE_ONLY = 0,
-       FIND_DIR_ONLY = 1,
-       FIND_FILE_ONLY = 2,
-};
-
-static int path_parse(char ***p, int flags)
-{
-       int npth;
-       char *tmp;
-       char *pth;
-
-       /* if not setenv PATH variable, to search cur dir "." */
-       if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 ||
-               /* PATH=<empty> or PATH=:<empty> */
-               *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
-               return 1;
-       }
-
-       tmp = pth;
-       npth = 0;
-
-       for (;;) {
-               npth++;                 /* count words is + 1 count ':' */
-               tmp = strchr(tmp, ':');
-               if (tmp) {
-                       if (*++tmp == 0)
-                               break;  /* :<empty> */
-               } else
-                       break;
-       }
-
-       *p = xmalloc(npth * sizeof(char *));
-
-       tmp = pth;
-       (*p)[0] = xstrdup(tmp);
-       npth = 1;                       /* count words is + 1 count ':' */
-
-       for (;;) {
-               tmp = strchr(tmp, ':');
-               if (tmp) {
-                       (*p)[0][(tmp - pth)] = 0;       /* ':' -> '\0' */
-                       if (*++tmp == 0)
-                               break;                  /* :<empty> */
-               } else
-                       break;
-               (*p)[npth++] = &(*p)[0][(tmp - pth)];   /* p[next]=p[0][&'\0'+1] */
-       }
-
-       return npth;
-}
-
-static char *add_quote_for_spec_chars(char *found)
-{
-       int l = 0;
-       char *s = xmalloc((strlen(found) + 1) * 2);
-
-       while (*found) {
-               if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
-                       s[l++] = '\\';
-               s[l++] = *found++;
-       }
-       s[l] = 0;
-       return s;
-}
-
-static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
-                                       int type)
-{
-
-       char **matches = 0;
-       DIR *dir;
-       struct dirent *next;
-       char dirbuf[BUFSIZ];
-       int nm = *num_matches;
-       struct stat st;
-       char *path1[1];
-       char **paths = path1;
-       int npaths;
-       int i;
-       char *found;
-       char *pfind = strrchr(command, '/');
-
-       path1[0] = ".";
-
-       if (pfind == NULL) {
-               /* no dir, if flags==EXE_ONLY - get paths, else "." */
-               npaths = path_parse(&paths, type);
-               pfind = command;
-       } else {
-               /* with dir */
-               /* save for change */
-               strcpy(dirbuf, command);
-               /* set dir only */
-               dirbuf[(pfind - command) + 1] = 0;
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               if (dirbuf[0] == '~')   /* ~/... or ~user/... */
-                       username_tab_completion(dirbuf, 0);
-#endif
-               /* "strip" dirname in command */
-               pfind++;
-
-               paths[0] = dirbuf;
-               npaths = 1;                             /* only 1 dir */
-       }
-
-       for (i = 0; i < npaths; i++) {
-
-               dir = opendir(paths[i]);
-               if (!dir)                       /* Don't print an error */
-                       continue;
-
-               while ((next = readdir(dir)) != NULL) {
-                       char *str_found = next->d_name;
-
-                       /* matched ? */
-                       if (strncmp(str_found, pfind, strlen(pfind)))
-                               continue;
-                       /* not see .name without .match */
-                       if (*str_found == '.' && *pfind == 0) {
-                               if (*paths[i] == '/' && paths[i][1] == 0
-                                       && str_found[1] == 0) str_found = "";   /* only "/" */
-                               else
-                                       continue;
-                       }
-                       found = concat_path_file(paths[i], str_found);
-                       /* hmm, remover in progress? */
-                       if (stat(found, &st) < 0) 
-                               goto cont;
-                       /* find with dirs ? */
-                       if (paths[i] != dirbuf)
-                               strcpy(found, next->d_name);    /* only name */
-                       if (S_ISDIR(st.st_mode)) {
-                               /* name is directory      */
-                               str_found = found;
-                               found = concat_path_file(found, "");
-                               free(str_found);
-                               str_found = add_quote_for_spec_chars(found);
-                       } else {
-                               /* not put found file if search only dirs for cd */
-                               if (type == FIND_DIR_ONLY) 
-                                       goto cont;
-                               str_found = add_quote_for_spec_chars(found);
-                               if (type == FIND_FILE_ONLY ||
-                                       (type == FIND_EXE_ONLY && is_execute(&st) == TRUE))
-                                       strcat(str_found, " ");
-                       }
-                       /* Add it to the list */
-                       matches = xrealloc(matches, (nm + 1) * sizeof(char *));
-
-                       matches[nm++] = str_found;
-cont:
-                       free(found);
-               }
-               closedir(dir);
-       }
-       if (paths != path1) {
-               free(paths[0]);                 /* allocated memory only in first member */
-               free(paths);
-       }
-       *num_matches = nm;
-       return (matches);
-}
-
-static int match_compare(const void *a, const void *b)
-{
-       return strcmp(*(char **) a, *(char **) b);
-}
-
-
-
-#define QUOT    (UCHAR_MAX+1)
-
-#define collapse_pos(is, in) { \
-       memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \
-       memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); }
-
-static int find_match(char *matchBuf, int *len_with_quotes)
-{
-       int i, j;
-       int command_mode;
-       int c, c2;
-       int int_buf[BUFSIZ + 1];
-       int pos_buf[BUFSIZ + 1];
-
-       /* set to integer dimension characters and own positions */
-       for (i = 0;; i++) {
-               int_buf[i] = (int) ((unsigned char) matchBuf[i]);
-               if (int_buf[i] == 0) {
-                       pos_buf[i] = -1;        /* indicator end line */
-                       break;
-               } else
-                       pos_buf[i] = i;
-       }
-
-       /* mask \+symbol and convert '\t' to ' ' */
-       for (i = j = 0; matchBuf[i]; i++, j++)
-               if (matchBuf[i] == '\\') {
-                       collapse_pos(j, j + 1);
-                       int_buf[j] |= QUOT;
-                       i++;
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-                       if (matchBuf[i] == '\t')        /* algorithm equivalent */
-                               int_buf[j] = ' ' | QUOT;
-#endif
-               }
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-               else if (matchBuf[i] == '\t')
-                       int_buf[j] = ' ';
-#endif
-
-       /* mask "symbols" or 'symbols' */
-       c2 = 0;
-       for (i = 0; int_buf[i]; i++) {
-               c = int_buf[i];
-               if (c == '\'' || c == '"') {
-                       if (c2 == 0)
-                               c2 = c;
-                       else {
-                               if (c == c2)
-                                       c2 = 0;
-                               else
-                                       int_buf[i] |= QUOT;
-                       }
-               } else if (c2 != 0 && c != '$')
-                       int_buf[i] |= QUOT;
-       }
-
-       /* skip commands with arguments if line have commands delimiters */
-       /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
-       for (i = 0; int_buf[i]; i++) {
-               c = int_buf[i];
-               c2 = int_buf[i + 1];
-               j = i ? int_buf[i - 1] : -1;
-               command_mode = 0;
-               if (c == ';' || c == '&' || c == '|') {
-                       command_mode = 1 + (c == c2);
-                       if (c == '&') {
-                               if (j == '>' || j == '<')
-                                       command_mode = 0;
-                       } else if (c == '|' && j == '>')
-                               command_mode = 0;
-               }
-               if (command_mode) {
-                       collapse_pos(0, i + command_mode);
-                       i = -1;                         /* hack incremet */
-               }
-       }
-       /* collapse `command...` */
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == '`') {
-                       for (j = i + 1; int_buf[j]; j++)
-                               if (int_buf[j] == '`') {
-                                       collapse_pos(i, j + 1);
-                                       j = 0;
-                                       break;
-                               }
-                       if (j) {
-                               /* not found close ` - command mode, collapse all previous */
-                               collapse_pos(0, i + 1);
-                               break;
-                       } else
-                               i--;                    /* hack incremet */
-               }
-
-       /* collapse (command...(command...)...) or {command...{command...}...} */
-       c = 0;                                          /* "recursive" level */
-       c2 = 0;
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == '(' || int_buf[i] == '{') {
-                       if (int_buf[i] == '(')
-                               c++;
-                       else
-                               c2++;
-                       collapse_pos(0, i + 1);
-                       i = -1;                         /* hack incremet */
-               }
-       for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
-               if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
-                       if (int_buf[i] == ')')
-                               c--;
-                       else
-                               c2--;
-                       collapse_pos(0, i + 1);
-                       i = -1;                         /* hack incremet */
-               }
-
-       /* skip first not quote space */
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] != ' ')
-                       break;
-       if (i)
-               collapse_pos(0, i);
-
-       /* set find mode for completion */
-       command_mode = FIND_EXE_ONLY;
-       for (i = 0; int_buf[i]; i++)
-               if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
-                       if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
-                               && matchBuf[pos_buf[0]]=='c'
-                               && matchBuf[pos_buf[1]]=='d' )
-                               command_mode = FIND_DIR_ONLY;
-                       else {
-                               command_mode = FIND_FILE_ONLY;
-                               break;
-                       }
-               }
-       /* "strlen" */
-       for (i = 0; int_buf[i]; i++);
-       /* find last word */
-       for (--i; i >= 0; i--) {
-               c = int_buf[i];
-               if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
-                       collapse_pos(0, i + 1);
-                       break;
-               }
-       }
-       /* skip first not quoted '\'' or '"' */
-       for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
-       /* collapse quote or unquote // or /~ */
-       while ((int_buf[i] & ~QUOT) == '/' && 
-                       ((int_buf[i + 1] & ~QUOT) == '/'
-                        || (int_buf[i + 1] & ~QUOT) == '~')) {
-               i++;
-       }
-
-       /* set only match and destroy quotes */
-       j = 0;
-       for (c = 0; pos_buf[i] >= 0; i++) {
-               matchBuf[c++] = matchBuf[pos_buf[i]];
-               j = pos_buf[i] + 1;
-       }
-       matchBuf[c] = 0;
-       /* old lenght matchBuf with quotes symbols */
-       *len_with_quotes = j ? j - pos_buf[0] : 0;
-
-       return command_mode;
-}
-
-
-static void input_tab(int *lastWasTab)
-{
-       /* Do TAB completion */
-       static int num_matches;
-       static char **matches;
-
-       if (lastWasTab == 0) {          /* free all memory */
-               if (matches) {
-                       while (num_matches > 0)
-                               free(matches[--num_matches]);
-                       free(matches);
-                       matches = (char **) NULL;
-               }
-               return;
-       }
-       if (*lastWasTab == FALSE) {
-
-               char *tmp;
-               int len_found;
-               char matchBuf[BUFSIZ];
-               int find_type;
-               int recalc_pos;
-
-               *lastWasTab = TRUE;             /* flop trigger */
-
-               /* Make a local copy of the string -- up
-                * to the position of the cursor */
-               tmp = strncpy(matchBuf, command_ps, cursor);
-               tmp[cursor] = 0;
-
-               find_type = find_match(matchBuf, &recalc_pos);
-
-               /* Free up any memory already allocated */
-               input_tab(0);
-
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
-               /* If the word starts with `~' and there is no slash in the word,
-                * then try completing this word as a username. */
-
-               if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
-                       matches = username_tab_completion(matchBuf, &num_matches);
-#endif
-               /* Try to match any executable in our path and everything
-                * in the current working directory that matches.  */
-               if (!matches)
-                       matches =
-                               exe_n_cwd_tab_completion(matchBuf,
-                                       &num_matches, find_type);
-               /* Remove duplicate found */
-               if(matches) {
-                       int i, j;
-                       /* bubble */
-                       for(i=0; i<(num_matches-1); i++)
-                               for(j=i+1; j<num_matches; j++)
-                                       if(matches[i]!=0 && matches[j]!=0 &&
-                                               strcmp(matches[i], matches[j])==0) {
-                                                       free(matches[j]);
-                                                       matches[j]=0;
-                                       }
-                       j=num_matches;
-                       num_matches = 0;
-                       for(i=0; i<j; i++)
-                               if(matches[i]) {
-                                       if(!strcmp(matches[i], "./"))
-                                               matches[i][1]=0;
-                                       else if(!strcmp(matches[i], "../"))
-                                               matches[i][2]=0;
-                                       matches[num_matches++]=matches[i];
-                               }
-               }
-               /* Did we find exactly one match? */
-               if (!matches || num_matches > 1) {
-                       char *tmp1;
-
-                       beep();
-                       if (!matches)
-                               return;         /* not found */
-                       /* sort */
-                       qsort(matches, num_matches, sizeof(char *), match_compare);
-
-                       /* find minimal match */
-                       tmp = xstrdup(matches[0]);
-                       for (tmp1 = tmp; *tmp1; tmp1++)
-                               for (len_found = 1; len_found < num_matches; len_found++)
-                                       if (matches[len_found][(tmp1 - tmp)] != *tmp1) {
-                                               *tmp1 = 0;
-                                               break;
-                                       }
-                       if (*tmp == 0) {        /* have unique */
-                               free(tmp);
-                               return;
-                       }
-               } else {                        /* one match */
-                       tmp = matches[0];
-                       /* for next completion current found */
-                       *lastWasTab = FALSE;
-               }
-
-               len_found = strlen(tmp);
-               /* have space to placed match? */
-               if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
-
-                       /* before word for match   */
-                       command_ps[cursor - recalc_pos] = 0;
-                       /* save   tail line        */
-                       strcpy(matchBuf, command_ps + cursor);
-                       /* add    match            */
-                       strcat(command_ps, tmp);
-                       /* add    tail             */
-                       strcat(command_ps, matchBuf);
-                       /* back to begin word for match    */
-                       input_backward(recalc_pos);
-                       /* new pos                         */
-                       recalc_pos = cursor + len_found;
-                       /* new len                         */
-                       len = strlen(command_ps);
-                       /* write out the matched command   */
-                       redraw(cmdedit_y, len - recalc_pos);
-               }
-               if (tmp != matches[0])
-                       free(tmp);
-       } else {
-               /* Ok -- the last char was a TAB.  Since they
-                * just hit TAB again, print a list of all the
-                * available choices... */
-               if (matches && num_matches > 0) {
-                       int i, col, l;
-                       int sav_cursor = cursor;        /* change goto_new_line() */
-
-                       /* Go to the next line */
-                       goto_new_line();
-                       for (i = 0, col = 0; i < num_matches; i++) {
-                               l = strlen(matches[i]);
-                               if (l < 14)
-                                       l = 14;
-                               printf("%-14s  ", matches[i]);
-                               if ((l += 2) > 16)
-                                       while (l % 16) {
-                                               putchar(' ');
-                                               l++;
-                                       }
-                               col += l;
-                               col -= (col / cmdedit_termw) * cmdedit_termw;
-                               if (col > 60 && matches[i + 1] != NULL) {
-                                       putchar('\n');
-                                       col = 0;
-                               }
-                       }
-                       /* Go to the next line and rewrite */
-                       putchar('\n');
-                       redraw(0, len - sav_cursor);
-               }
-       }
-}
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
-
-static void get_previous_history(struct history **hp, struct history *p)
-{
-       if ((*hp)->s)
-               free((*hp)->s);
-       (*hp)->s = xstrdup(command_ps);
-       *hp = p;
-}
-
-static inline void get_next_history(struct history **hp)
-{
-       get_previous_history(hp, (*hp)->n);
-}
-
-enum {
-       ESC = 27,
-       DEL = 127,
-};
-
-
-/*
- * This function is used to grab a character buffer
- * from the input file descriptor and allows you to
- * a string with full command editing (sortof like
- * a mini readline).
- *
- * The following standard commands are not implemented:
- * ESC-b -- Move back one word
- * ESC-f -- Move forward one word
- * ESC-d -- Delete back one word
- * ESC-h -- Delete forward one word
- * CTL-t -- Transpose two characters
- *
- * Furthermore, the "vi" command editing keys are not implemented.
- *
- */
-
-int cmdedit_read_input(char *prompt, char command[BUFSIZ])
-{
-
-       int break_out = 0;
-       int lastWasTab = FALSE;
-       unsigned char c = 0;
-       struct history *hp = his_end;
-
-       /* prepare before init handlers */
-       cmdedit_y = 0;  /* quasireal y, not true work if line > xt*yt */
-       len = 0;
-       command_ps = command;
-
-       getTermSettings(0, (void *) &initial_settings);
-       memcpy(&new_settings, &initial_settings, sizeof(struct termios));
-       new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
-       /* Turn off echoing and CTRL-C, so we can trap it */
-       new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
-#ifndef linux
-       /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-       new_settings.c_cc[VMIN] = 1;
-       new_settings.c_cc[VTIME] = 0;
-       /* Turn off CTRL-C, so we can trap it */
-#       ifndef _POSIX_VDISABLE
-#               define _POSIX_VDISABLE '\0'
-#       endif
-       new_settings.c_cc[VINTR] = _POSIX_VDISABLE;     
-#endif
-       command[0] = 0;
-
-       setTermSettings(0, (void *) &new_settings);
-       handlers_sets |= SET_RESET_TERM;
-
-       /* Now initialize things */
-       cmdedit_init();
-       /* Print out the command prompt */
-       parse_prompt(prompt);
-
-       while (1) {
-
-               fflush(stdout);                 /* buffered out to fast */
-
-               if (safe_read(0, &c, 1) < 1)
-                       /* if we can't read input then exit */
-                       goto prepare_to_die;
-
-               switch (c) {
-               case '\n':
-               case '\r':
-                       /* Enter */
-                       goto_new_line();
-                       break_out = 1;
-                       break;
-               case 1:
-                       /* Control-a -- Beginning of line */
-                       input_backward(cursor);
-                       break;
-               case 2:
-                       /* Control-b -- Move back one character */
-                       input_backward(1);
-                       break;
-               case 3:
-                       /* Control-c -- stop gathering input */
-                       goto_new_line();
-                       command[0] = 0;
-                       len = 0;
-                       lastWasTab = FALSE;
-                       put_prompt();
-                       break;
-               case 4:
-                       /* Control-d -- Delete one character, or exit
-                        * if the len=0 and no chars to delete */
-                       if (len == 0) {
-prepare_to_die:
-#if !defined(BB_ASH)
-                               printf("exit");
-                               goto_new_line();
-                               /* cmdedit_reset_term() called in atexit */
-                               exit(EXIT_SUCCESS);
-#else
-                               break_out = -1; /* for control stoped jobs */
-                               break;
-#endif
-                       } else {
-                               input_delete();
-                       }
-                       break;
-               case 5:
-                       /* Control-e -- End of line */
-                       input_end();
-                       break;
-               case 6:
-                       /* Control-f -- Move forward one character */
-                       input_forward();
-                       break;
-               case '\b':
-               case DEL:
-                       /* Control-h and DEL */
-                       input_backspace();
-                       break;
-               case '\t':
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-                       input_tab(&lastWasTab);
-#endif
-                       break;
-               case 14:
-                       /* Control-n -- Get next command in history */
-                       if (hp && hp->n && hp->n->s) {
-                               get_next_history(&hp);
-                               goto rewrite_line;
-                       } else {
-                               beep();
-                       }
-                       break;
-               case 16:
-                       /* Control-p -- Get previous command from history */
-                       if (hp && hp->p) {
-                               get_previous_history(&hp, hp->p);
-                               goto rewrite_line;
-                       } else {
-                               beep();
-                       }
-                       break;
-               case 21:
-                       /* Control-U -- Clear line before cursor */
-                       if (cursor) {
-                               strcpy(command, command + cursor);
-                               redraw(cmdedit_y, len -= cursor);
-                       }
-                       break;
-
-               case ESC:{
-                       /* escape sequence follows */
-                       if (safe_read(0, &c, 1) < 1)
-                               goto prepare_to_die;
-                       /* different vt100 emulations */
-                       if (c == '[' || c == 'O') {
-                               if (safe_read(0, &c, 1) < 1)
-                                       goto prepare_to_die;
-                       }
-                       switch (c) {
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
-                       case '\t':                      /* Alt-Tab */
-
-                               input_tab(&lastWasTab);
-                               break;
-#endif
-                       case 'A':
-                               /* Up Arrow -- Get previous command from history */
-                               if (hp && hp->p) {
-                                       get_previous_history(&hp, hp->p);
-                                       goto rewrite_line;
-                               } else {
-                                       beep();
-                               }
-                               break;
-                       case 'B':
-                               /* Down Arrow -- Get next command in history */
-                               if (hp && hp->n && hp->n->s) {
-                                       get_next_history(&hp);
-                                       goto rewrite_line;
-                               } else {
-                                       beep();
-                               }
-                               break;
-
-                               /* Rewrite the line with the selected history item */
-                         rewrite_line:
-                               /* change command */
-                               len = strlen(strcpy(command, hp->s));
-                               /* redraw and go to end line */
-                               redraw(cmdedit_y, 0);
-                               break;
-                       case 'C':
-                               /* Right Arrow -- Move forward one character */
-                               input_forward();
-                               break;
-                       case 'D':
-                               /* Left Arrow -- Move back one character */
-                               input_backward(1);
-                               break;
-                       case '3':
-                               /* Delete */
-                               input_delete();
-                               break;
-                       case '1':
-                       case 'H':
-                               /* Home (Ctrl-A) */
-                               input_backward(cursor);
-                               break;
-                       case '4':
-                       case 'F':
-                               /* End (Ctrl-E) */
-                               input_end();
-                               break;
-                       default:
-                               if (!(c >= '1' && c <= '9'))
-                                       c = 0;
-                               beep();
-                       }
-                       if (c >= '1' && c <= '9')
-                               do
-                                       if (safe_read(0, &c, 1) < 1)
-                                               goto prepare_to_die;
-                               while (c != '~');
-                       break;
-               }
-
-               default:        /* If it's regular input, do the normal thing */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-                       /* Control-V -- Add non-printable symbol */
-                       if (c == 22) {
-                               if (safe_read(0, &c, 1) < 1)
-                                       goto prepare_to_die;
-                               if (c == 0) {
-                                       beep();
-                                       break;
-                               }
-                       } else
-#endif
-                       if (!Isprint(c))        /* Skip non-printable characters */
-                               break;
-
-                       if (len >= (BUFSIZ - 2))        /* Need to leave space for enter */
-                               break;
-
-                       len++;
-
-                       if (cursor == (len - 1)) {      /* Append if at the end of the line */
-                               *(command + cursor) = c;
-                               *(command + cursor + 1) = 0;
-                               cmdedit_set_out_char(0);
-                       } else {                        /* Insert otherwise */
-                               int sc = cursor;
-
-                               memmove(command + sc + 1, command + sc, len - sc);
-                               *(command + sc) = c;
-                               sc++;
-                               /* rewrite from cursor */
-                               input_end();
-                               /* to prev x pos + 1 */
-                               input_backward(cursor - sc);
-                       }
-
-                       break;
-               }
-               if (break_out)                  /* Enter is the command terminator, no more input. */
-                       break;
-
-               if (c != '\t')
-                       lastWasTab = FALSE;
-       }
-
-       setTermSettings(0, (void *) &initial_settings);
-       handlers_sets &= ~SET_RESET_TERM;
-
-       /* Handle command history log */
-       if (len) {                                      /* no put empty line */
-
-               struct history *h = his_end;
-               char *ss;
-
-               ss = xstrdup(command);  /* duplicate */
-
-               if (h == 0) {
-                       /* No previous history -- this memory is never freed */
-                       h = his_front = xmalloc(sizeof(struct history));
-                       h->n = xmalloc(sizeof(struct history));
-
-                       h->p = NULL;
-                       h->s = ss;
-                       h->n->p = h;
-                       h->n->n = NULL;
-                       h->n->s = NULL;
-                       his_end = h->n;
-                       history_counter++;
-               } else {
-                       /* Add a new history command -- this memory is never freed */
-                       h->n = xmalloc(sizeof(struct history));
-
-                       h->n->p = h;
-                       h->n->n = NULL;
-                       h->n->s = NULL;
-                       h->s = ss;
-                       his_end = h->n;
-
-                       /* After max history, remove the oldest command */
-                       if (history_counter >= MAX_HISTORY) {
-
-                               struct history *p = his_front->n;
-
-                               p->p = NULL;
-                               free(his_front->s);
-                               free(his_front);
-                               his_front = p;
-                       } else {
-                               history_counter++;
-                       }
-               }
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-               num_ok_lines++;
-#endif
-       }
-       if(break_out>0) {
-       command[len++] = '\n';          /* set '\n' */
-       command[len] = 0;
-       }
-#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION)
-       input_tab(0);                           /* strong free */
-#endif
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-       free(cmdedit_prompt);
-#endif
-       cmdedit_reset_term();
-       return len;
-}
-
-
-
-#endif /* BB_FEATURE_COMMAND_EDITING */
-
-
-#ifdef TEST
-
-const char *applet_name = "debug stuff usage";
-const char *memory_exhausted = "Memory exhausted";
-
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-#include <locale.h>
-#endif
-
-int main(int argc, char **argv)
-{
-       char buff[BUFSIZ];
-       char *prompt =
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
-               "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
-\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
-\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
-#else
-               "% ";
-#endif
-
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-       setlocale(LC_ALL, "");
-#endif
-       while(1) {
-               int l;
-               cmdedit_read_input(prompt, buff);
-               l = strlen(buff);
-               if(l==0)
-                       break;
-               if(l > 0 && buff[l-1] == '\n')
-                       buff[l-1] = 0;
-               printf("*** cmdedit_read_input() returned line =%s=\n", buff);
-       }
-       printf("*** cmdedit_read_input() detect ^C\n");
-       return 0;
-}
-
-#endif /* TEST */
diff --git a/busybox/shell/cmdedit.h b/busybox/shell/cmdedit.h
deleted file mode 100644 (file)
index 8389357..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef CMDEDIT_H
-#define CMDEDIT_H
-
-int     cmdedit_read_input(char* promptStr, char* command);
-
-#endif /* CMDEDIT_H */
diff --git a/busybox/shell/hush.c b/busybox/shell/hush.c
deleted file mode 100644 (file)
index 0e619f8..0000000
+++ /dev/null
@@ -1,2692 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * sh.c -- a prototype Bourne shell grammar parser
- *      Intended to follow the original Thompson and Ritchie
- *      "small and simple is beautiful" philosophy, which
- *      incidentally is a good match to today's BusyBox.
- *
- * Copyright (C) 2000,2001  Larry Doolittle  <larry@doolittle.boa.org>
- *
- * Credits:
- *      The parser routines proper are all original material, first
- *      written Dec 2000 and Jan 2001 by Larry Doolittle.
- *      The execution engine, the builtins, and much of the underlying
- *      support has been adapted from busybox-0.49pre's lash,
- *      which is Copyright (C) 2000 by Lineo, Inc., and
- *      written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
- *      That, in turn, is based in part on ladsh.c, by Michael K. Johnson and
- *      Erik W. Troan, which they placed in the public domain.  I don't know
- *      how much of the Johnson/Troan code has survived the repeated rewrites.
- * Other credits:
- *      simple_itoa() was lifted from boa-0.93.15
- *      b_addchr() derived from similar w_addchar function in glibc-2.2
- *      setup_redirect(), redirect_opt_num(), and big chunks of main()
- *        and many builtins derived from contributions by Erik Andersen
- *      miscellaneous bugfixes from Matt Kraai
- *
- * There are two big (and related) architecture differences between
- * this parser and the lash parser.  One is that this version is
- * actually designed from the ground up to understand nearly all
- * of the Bourne grammar.  The second, consequential change is that
- * the parser and input reader have been turned inside out.  Now,
- * the parser is in control, and asks for input as needed.  The old
- * way had the input reader in control, and it asked for parsing to
- * take place as needed.  The new way makes it much easier to properly
- * handle the recursion implicit in the various substitutions, especially
- * across continuation lines.
- *
- * Bash grammar not implemented: (how many of these were in original sh?)
- *      $@ (those sure look like weird quoting rules)
- *      $_
- *      ! negation operator for pipes
- *      &> and >& redirection of stdout+stderr
- *      Brace Expansion
- *      Tilde Expansion
- *      fancy forms of Parameter Expansion
- *      aliases
- *      Arithmetic Expansion
- *      <(list) and >(list) Process Substitution
- *      reserved words: case, esac, select, function
- *      Here Documents ( << word )
- *      Functions
- * Major bugs:
- *      job handling woefully incomplete and buggy
- *      reserved word execution woefully incomplete and buggy
- * to-do:
- *      port selected bugfixes from post-0.49 busybox lash - done?
- *      finish implementing reserved words: for, while, until, do, done
- *      change { and } from special chars to reserved words
- *      builtins: break, continue, eval, return, set, trap, ulimit
- *      test magic exec
- *      handle children going into background
- *      clean up recognition of null pipes
- *      check setting of global_argc and global_argv
- *      control-C handling, probably with longjmp
- *      follow IFS rules more precisely, including update semantics
- *      figure out what to do with backslash-newline
- *      explain why we use signal instead of sigaction
- *      propagate syntax errors, die on resource errors?
- *      continuation lines, both explicit and implicit - done?
- *      memory leak finding and plugging - done?
- *      more testing, especially quoting rules and redirection
- *      document how quoting rules not precisely followed for variable assignments
- *      maybe change map[] to use 2-bit entries
- *      (eventually) remove all the printf's
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <ctype.h>     /* isalpha, isdigit */
-#include <unistd.h>    /* getpid */
-#include <stdlib.h>    /* getenv, atoi */
-#include <string.h>    /* strchr */
-#include <stdio.h>     /* popen etc. */
-#include <glob.h>      /* glob, of course */
-#include <stdarg.h>    /* va_list */
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>    /* should be pretty obvious */
-
-#include <sys/stat.h>  /* ulimit */
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-/* #include <dmalloc.h> */
-/* #define DEBUG_SHELL */
-
-#ifdef BB_VER
-#include "busybox.h"
-#include "cmdedit.h"
-#else
-#define applet_name "hush"
-#include "standalone.h"
-#define hush_main main
-#undef BB_FEATURE_SH_FANCY_PROMPT
-#endif
-
-typedef enum {
-       REDIRECT_INPUT     = 1,
-       REDIRECT_OVERWRITE = 2,
-       REDIRECT_APPEND    = 3,
-       REDIRECT_HEREIS    = 4,
-       REDIRECT_IO        = 5
-} redir_type;
-
-/* The descrip member of this structure is only used to make debugging
- * output pretty */
-struct {int mode; int default_fd; char *descrip;} redir_table[] = {
-       { 0,                         0, "()" },
-       { O_RDONLY,                  0, "<"  },
-       { O_CREAT|O_TRUNC|O_WRONLY,  1, ">"  },
-       { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
-       { O_RDONLY,                 -1, "<<" },
-       { O_RDWR,                    1, "<>" }
-};
-
-typedef enum {
-       PIPE_SEQ = 1,
-       PIPE_AND = 2,
-       PIPE_OR  = 3,
-       PIPE_BG  = 4,
-} pipe_style;
-
-/* might eventually control execution */
-typedef enum {
-       RES_NONE  = 0,
-       RES_IF    = 1,
-       RES_THEN  = 2,
-       RES_ELIF  = 3,
-       RES_ELSE  = 4,
-       RES_FI    = 5,
-       RES_FOR   = 6,
-       RES_WHILE = 7,
-       RES_UNTIL = 8,
-       RES_DO    = 9,
-       RES_DONE  = 10,
-       RES_XXXX  = 11,
-       RES_SNTX  = 12
-} reserved_style;
-#define FLAG_END   (1<<RES_NONE)
-#define FLAG_IF    (1<<RES_IF)
-#define FLAG_THEN  (1<<RES_THEN)
-#define FLAG_ELIF  (1<<RES_ELIF)
-#define FLAG_ELSE  (1<<RES_ELSE)
-#define FLAG_FI    (1<<RES_FI)
-#define FLAG_FOR   (1<<RES_FOR)
-#define FLAG_WHILE (1<<RES_WHILE)
-#define FLAG_UNTIL (1<<RES_UNTIL)
-#define FLAG_DO    (1<<RES_DO)
-#define FLAG_DONE  (1<<RES_DONE)
-#define FLAG_START (1<<RES_XXXX)
-
-/* This holds pointers to the various results of parsing */
-struct p_context {
-       struct child_prog *child;
-       struct pipe *list_head;
-       struct pipe *pipe;
-       struct redir_struct *pending_redirect;
-       reserved_style w;
-       int old_flag;                           /* for figuring out valid reserved words */
-       struct p_context *stack;
-       /* How about quoting status? */
-};
-
-struct redir_struct {
-       redir_type type;                        /* type of redirection */
-       int fd;                                         /* file descriptor being redirected */
-       int dup;                                        /* -1, or file descriptor being duplicated */
-       struct redir_struct *next;      /* pointer to the next redirect in the list */ 
-       glob_t word;                            /* *word.gl_pathv is the filename */
-};
-
-struct child_prog {
-       pid_t pid;                                      /* 0 if exited */
-       char **argv;                            /* program name and arguments */
-       struct pipe *group;                     /* if non-NULL, first in group or subshell */
-       int subshell;                           /* flag, non-zero if group must be forked */
-       struct redir_struct *redirects; /* I/O redirections */
-       glob_t glob_result;                     /* result of parameter globbing */
-       int is_stopped;                         /* is the program currently running? */
-       struct pipe *family;            /* pointer back to the child's parent pipe */
-};
-
-struct pipe {
-       int jobid;                                      /* job number */
-       int num_progs;                          /* total number of programs in job */
-       int running_progs;                      /* number of programs running */
-       char *text;                                     /* name of job */
-       char *cmdbuf;                           /* buffer various argv's point into */
-       pid_t pgrp;                                     /* process group ID for the job */
-       struct child_prog *progs;       /* array of commands in pipe */
-       struct pipe *next;                      /* to track background commands */
-       int stopped_progs;                      /* number of programs alive, but stopped */
-       int job_context;                        /* bitmask defining current context */
-       pipe_style followup;            /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
-       reserved_style r_mode;          /* supports if, for, while, until */
-};
-
-struct close_me {
-       int fd;
-       struct close_me *next;
-};
-
-struct variables {
-       char *name;
-       char *value;
-       int flg_export;
-       int flg_read_only;
-       struct variables *next;
-};
-
-/* globals, connect us to the outside world
- * the first three support $?, $#, and $1 */
-char **global_argv;
-unsigned int global_argc;
-unsigned int last_return_code;
-extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
-/* "globals" within this file */
-static char *ifs;
-static char map[256];
-static int fake_mode;
-static int interactive;
-static struct close_me *close_me_head;
-static const char *cwd;
-static struct pipe *job_list;
-static unsigned int last_bg_pid;
-static unsigned int last_jobid;
-static unsigned int shell_terminal;
-static char *PS1;
-static char *PS2;
-struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
-struct variables *top_vars = &shell_ver;
-
-
-#define B_CHUNK (100)
-#define B_NOSPAC 1
-
-typedef struct {
-       char *data;
-       int length;
-       int maxlen;
-       int quote;
-       int nonnull;
-} o_string;
-#define NULL_O_STRING {NULL,0,0,0,0}
-/* used for initialization:
-       o_string foo = NULL_O_STRING; */
-
-/* I can almost use ordinary FILE *.  Is open_memstream() universally
- * available?  Where is it documented? */
-struct in_str {
-       const char *p;
-       char peek_buf[2];
-       int __promptme;
-       int promptmode;
-       FILE *file;
-       int (*get) (struct in_str *);
-       int (*peek) (struct in_str *);
-};
-#define b_getch(input) ((input)->get(input))
-#define b_peek(input) ((input)->peek(input))
-
-#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
-
-struct built_in_command {
-       char *cmd;                                      /* name */
-       char *descr;                            /* description */
-       int (*function) (struct child_prog *);  /* function ptr */
-};
-
-/* belongs in busybox.h */
-static inline int max(int a, int b) {
-       return (a>b)?a:b;
-}
-
-/* This should be in utility.c */
-#ifdef DEBUG_SHELL
-static void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-}
-#else
-static inline void debug_printf(const char *format, ...) { }
-#endif
-#define final_printf debug_printf
-
-static void __syntax(char *file, int line) {
-       error_msg("syntax error %s:%d", file, line);
-}
-#define syntax() __syntax(__FILE__, __LINE__)
-
-/* Index of subroutines: */
-/*   function prototypes for builtins */
-static int builtin_cd(struct child_prog *child);
-static int builtin_env(struct child_prog *child);
-static int builtin_exec(struct child_prog *child);
-static int builtin_exit(struct child_prog *child);
-static int builtin_export(struct child_prog *child);
-static int builtin_fg_bg(struct child_prog *child);
-static int builtin_help(struct child_prog *child);
-static int builtin_jobs(struct child_prog *child);
-static int builtin_pwd(struct child_prog *child);
-static int builtin_read(struct child_prog *child);
-static int builtin_set(struct child_prog *child);
-static int builtin_shift(struct child_prog *child);
-static int builtin_source(struct child_prog *child);
-static int builtin_umask(struct child_prog *child);
-static int builtin_unset(struct child_prog *child);
-static int builtin_not_written(struct child_prog *child);
-/*   o_string manipulation: */
-static int b_check_space(o_string *o, int len);
-static int b_addchr(o_string *o, int ch);
-static void b_reset(o_string *o);
-static int b_addqchr(o_string *o, int ch, int quote);
-static int b_adduint(o_string *o, unsigned int i);
-/*  in_str manipulations: */
-static int static_get(struct in_str *i);
-static int static_peek(struct in_str *i);
-static int file_get(struct in_str *i);
-static int file_peek(struct in_str *i);
-static void setup_file_in_str(struct in_str *i, FILE *f);
-static void setup_string_in_str(struct in_str *i, const char *s);
-/*  close_me manipulations: */
-static void mark_open(int fd);
-static void mark_closed(int fd);
-static void close_all();
-/*  "run" the final data structures: */
-static char *indenter(int i);
-static int free_pipe_list(struct pipe *head, int indent);
-static int free_pipe(struct pipe *pi, int indent);
-/*  really run the final data structures: */
-static int setup_redirects(struct child_prog *prog, int squirrel[]);
-static int run_list_real(struct pipe *pi);
-static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
-static int run_pipe_real(struct pipe *pi);
-/*   extended glob support: */
-static int globhack(const char *src, int flags, glob_t *pglob);
-static int glob_needed(const char *s);
-static int xglob(o_string *dest, int flags, glob_t *pglob);
-/*   variable assignment: */
-static int is_assignment(const char *s);
-/*   data structure manipulation: */
-static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
-static void initialize_context(struct p_context *ctx);
-static int done_word(o_string *dest, struct p_context *ctx);
-static int done_command(struct p_context *ctx);
-static int done_pipe(struct p_context *ctx, pipe_style type);
-/*   primary string parsing: */
-static int redirect_dup_num(struct in_str *input);
-static int redirect_opt_num(o_string *o);
-static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
-static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
-static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src);
-static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
-static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
-static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
-/*   setup: */
-static int parse_stream_outer(struct in_str *inp);
-static int parse_string_outer(const char *s);
-static int parse_file_outer(FILE *f);
-/*   job management: */
-static int checkjobs(struct pipe* fg_pipe);
-static void insert_bg_job(struct pipe *pi);
-static void remove_bg_job(struct pipe *pi);
-/*     local variable support */
-static char *get_local_var(const char *var);
-static void  unset_local_var(const char *name);
-static int set_local_var(const char *s, int flg_export);
-
-/* Table of built-in functions.  They can be forked or not, depending on
- * context: within pipes, they fork.  As simple commands, they do not.
- * When used in non-forking context, they can change global variables
- * in the parent shell process.  If forked, of course they can not.
- * For example, 'unset foo | whatever' will parse and run, but foo will
- * still be set at the end. */
-static struct built_in_command bltins[] = {
-       {"bg", "Resume a job in the background", builtin_fg_bg},
-       {"break", "Exit for, while or until loop", builtin_not_written},
-       {"cd", "Change working directory", builtin_cd},
-       {"continue", "Continue for, while or until loop", builtin_not_written},
-       {"env", "Print all environment variables", builtin_env},
-       {"eval", "Construct and run shell command", builtin_not_written},
-       {"exec", "Exec command, replacing this shell with the exec'd process", 
-               builtin_exec},
-       {"exit", "Exit from shell()", builtin_exit},
-       {"export", "Set environment variable", builtin_export},
-       {"fg", "Bring job into the foreground", builtin_fg_bg},
-       {"jobs", "Lists the active jobs", builtin_jobs},
-       {"pwd", "Print current directory", builtin_pwd},
-       {"read", "Input environment variable", builtin_read},
-       {"return", "Return from a function", builtin_not_written},
-       {"set", "Set/unset shell local variables", builtin_set},
-       {"shift", "Shift positional parameters", builtin_shift},
-       {"trap", "Trap signals", builtin_not_written},
-       {"ulimit","Controls resource limits", builtin_not_written},
-       {"umask","Sets file creation mask", builtin_umask},
-       {"unset", "Unset environment variable", builtin_unset},
-       {".", "Source-in and run commands in a file", builtin_source},
-       {"help", "List shell built-in commands", builtin_help},
-       {NULL, NULL, NULL}
-};
-
-static const char *set_cwd(void)
-{
-       if(cwd==unknown)
-               cwd = NULL;     /* xgetcwd(arg) called free(arg) */
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       return cwd;
-}
-
-
-/* built-in 'cd <path>' handler */
-static int builtin_cd(struct child_prog *child)
-{
-       char *newdir;
-       if (child->argv[1] == NULL)
-               newdir = getenv("HOME");
-       else
-               newdir = child->argv[1];
-       if (chdir(newdir)) {
-               printf("cd: %s: %s\n", newdir, strerror(errno));
-               return EXIT_FAILURE;
-       }
-       set_cwd();
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'env' handler */
-static int builtin_env(struct child_prog *dummy)
-{
-       char **e = environ;
-       if (e == NULL) return EXIT_FAILURE;
-       for (; *e; e++) {
-               puts(*e);
-       }
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'exec' handler */
-static int builtin_exec(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               return EXIT_SUCCESS;   /* Really? */
-       child->argv++;
-       pseudo_exec(child);
-       /* never returns */
-}
-
-/* built-in 'exit' handler */
-static int builtin_exit(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               exit(last_return_code);
-       exit (atoi(child->argv[1]));
-}
-
-/* built-in 'export VAR=value' handler */
-static int builtin_export(struct child_prog *child)
-{
-       int res = 0;
-       char *name = child->argv[1];
-
-       if (name == NULL) {
-               return (builtin_env(child));
-       }
-
-       name = strdup(name);
-
-       if(name) {
-               char *value = strchr(name, '=');
-
-               if (!value) {
-                       char *tmp;
-                       /* They are exporting something without an =VALUE */
-
-                       value = get_local_var(name);
-                       if (value) {
-                               size_t ln = strlen(name);
-
-                               tmp = realloc(name, ln+strlen(value)+2);
-                               if(tmp==NULL)
-                                       res = -1;
-                               else {
-                                       sprintf(tmp+ln, "=%s", value);
-                                       name = tmp;
-                               }
-                       } else {
-                               /* bash does not return an error when trying to export
-                                * an undefined variable.  Do likewise. */
-                               res = 1;
-                       }
-               }
-       }
-       if (res<0)
-               perror_msg("export");
-       else if(res==0)
-               res = set_local_var(name, 1);
-       else
-               res = 0;
-       free(name);
-       return res;
-}
-
-/* built-in 'fg' and 'bg' handler */
-static int builtin_fg_bg(struct child_prog *child)
-{
-       int i, jobnum;
-       struct pipe *pi=NULL;
-
-       if (!interactive)
-               return EXIT_FAILURE;
-       /* If they gave us no args, assume they want the last backgrounded task */
-       if (!child->argv[1]) {
-               for (pi = job_list; pi; pi = pi->next) {
-                       if (pi->jobid == last_jobid) {
-                               break;
-                       }
-               }
-               if (!pi) {
-                       error_msg("%s: no current job", child->argv[0]);
-                       return EXIT_FAILURE;
-               }
-       } else {
-               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
-                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
-                       return EXIT_FAILURE;
-               }
-               for (pi = job_list; pi; pi = pi->next) {
-                       if (pi->jobid == jobnum) {
-                               break;
-                       }
-               }
-               if (!pi) {
-                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       if (*child->argv[0] == 'f') {
-               /* Put the job into the foreground.  */
-               tcsetpgrp(shell_terminal, pi->pgrp);
-       }
-
-       /* Restart the processes in the job */
-       for (i = 0; i < pi->num_progs; i++)
-               pi->progs[i].is_stopped = 0;
-
-       if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
-               if (i == ESRCH) {
-                       remove_bg_job(pi);
-               } else {
-                       perror_msg("kill (SIGCONT)");
-               }
-       }
-
-       pi->stopped_progs = 0;
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'help' handler */
-static int builtin_help(struct child_prog *dummy)
-{
-       struct built_in_command *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-       for (x = bltins; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'jobs' handler */
-static int builtin_jobs(struct child_prog *child)
-{
-       struct pipe *job;
-       char *status_string;
-
-       for (job = job_list; job; job = job->next) {
-               if (job->running_progs == job->stopped_progs)
-                       status_string = "Stopped";
-               else
-                       status_string = "Running";
-
-               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
-       }
-       return EXIT_SUCCESS;
-}
-
-
-/* built-in 'pwd' handler */
-static int builtin_pwd(struct child_prog *dummy)
-{
-       puts(set_cwd());
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'read VAR' handler */
-static int builtin_read(struct child_prog *child)
-{
-       int res;
-
-       if (child->argv[1]) {
-               char string[BUFSIZ];
-               char *var = 0;
-
-               string[0] = 0;  /* In case stdin has only EOF */
-               /* read string */
-               fgets(string, sizeof(string), stdin);
-               chomp(string);
-               var = malloc(strlen(child->argv[1])+strlen(string)+2);
-               if(var) {
-                       sprintf(var, "%s=%s", child->argv[1], string);
-                       res = set_local_var(var, 0);
-               } else
-                       res = -1;
-               if (res)
-                       fprintf(stderr, "read: %m\n");
-               free(var);      /* So not move up to avoid breaking errno */
-               return res;
-       } else {
-               do res=getchar(); while(res!='\n' && res!=EOF);
-               return 0;
-       }
-}
-
-/* built-in 'set VAR=value' handler */
-static int builtin_set(struct child_prog *child)
-{
-       char *temp = child->argv[1];
-       struct variables *e;
-
-       if (temp == NULL)
-               for(e = top_vars; e; e=e->next)
-                       printf("%s=%s\n", e->name, e->value);
-       else
-               set_local_var(temp, 0);
-
-               return EXIT_SUCCESS;
-}
-
-
-/* Built-in 'shift' handler */
-static int builtin_shift(struct child_prog *child)
-{
-       int n=1;
-       if (child->argv[1]) {
-               n=atoi(child->argv[1]);
-       }
-       if (n>=0 && n<global_argc) {
-               /* XXX This probably breaks $0 */
-               global_argc -= n;
-               global_argv += n;
-               return EXIT_SUCCESS;
-       } else {
-               return EXIT_FAILURE;
-       }
-}
-
-/* Built-in '.' handler (read-in and execute commands from file) */
-static int builtin_source(struct child_prog *child)
-{
-       FILE *input;
-       int status;
-
-       if (child->argv[1] == NULL)
-               return EXIT_FAILURE;
-
-       /* XXX search through $PATH is missing */
-       input = fopen(child->argv[1], "r");
-       if (!input) {
-               error_msg("Couldn't open file '%s'", child->argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       /* Now run the file */
-       /* XXX argv and argc are broken; need to save old global_argv
-        * (pointer only is OK!) on this stack frame,
-        * set global_argv=child->argv+1, recurse, and restore. */
-       mark_open(fileno(input));
-       status = parse_file_outer(input);
-       mark_closed(fileno(input));
-       fclose(input);
-       return (status);
-}
-
-static int builtin_umask(struct child_prog *child)
-{
-       mode_t new_umask;
-       const char *arg = child->argv[1];
-       char *end;
-       if (arg) {
-               new_umask=strtoul(arg, &end, 8);
-               if (*end!='\0' || end == arg) {
-                       return EXIT_FAILURE;
-               }
-       } else {
-               printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
-       }
-       umask(new_umask);
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'unset VAR' handler */
-static int builtin_unset(struct child_prog *child)
-{
-       /* bash returned already true */
-       unset_local_var(child->argv[1]);
-       return EXIT_SUCCESS;
-}
-
-static int builtin_not_written(struct child_prog *child)
-{
-       printf("builtin_%s not written\n",child->argv[0]);
-       return EXIT_FAILURE;
-}
-
-static int b_check_space(o_string *o, int len)
-{
-       /* It would be easy to drop a more restrictive policy
-        * in here, such as setting a maximum string length */
-       if (o->length + len > o->maxlen) {
-               char *old_data = o->data;
-               /* assert (data == NULL || o->maxlen != 0); */
-               o->maxlen += max(2*len, B_CHUNK);
-               o->data = realloc(o->data, 1 + o->maxlen);
-               if (o->data == NULL) {
-                       free(old_data);
-               }
-       }
-       return o->data == NULL;
-}
-
-static int b_addchr(o_string *o, int ch)
-{
-       debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
-       if (b_check_space(o, 1)) return B_NOSPAC;
-       o->data[o->length] = ch;
-       o->length++;
-       o->data[o->length] = '\0';
-       return 0;
-}
-
-static void b_reset(o_string *o)
-{
-       o->length = 0;
-       o->nonnull = 0;
-       if (o->data != NULL) *o->data = '\0';
-}
-
-static void b_free(o_string *o)
-{
-       b_reset(o);
-       if (o->data != NULL) free(o->data);
-       o->data = NULL;
-       o->maxlen = 0;
-}
-
-/* My analysis of quoting semantics tells me that state information
- * is associated with a destination, not a source.
- */
-static int b_addqchr(o_string *o, int ch, int quote)
-{
-       if (quote && strchr("*?[\\",ch)) {
-               int rc;
-               rc = b_addchr(o, '\\');
-               if (rc) return rc;
-       }
-       return b_addchr(o, ch);
-}
-
-/* belongs in utility.c */
-char *simple_itoa(unsigned int i)
-{
-       /* 21 digits plus null terminator, good for 64-bit or smaller ints */
-       static char local[22];
-       char *p = &local[21];
-       *p-- = '\0';
-       do {
-               *p-- = '0' + i % 10;
-               i /= 10;
-       } while (i > 0);
-       return p + 1;
-}
-
-static int b_adduint(o_string *o, unsigned int i)
-{
-       int r;
-       char *p = simple_itoa(i);
-       /* no escape checking necessary */
-       do r=b_addchr(o, *p++); while (r==0 && *p);
-       return r;
-}
-
-static int static_get(struct in_str *i)
-{
-       int ch=*i->p++;
-       if (ch=='\0') return EOF;
-       return ch;
-}
-
-static int static_peek(struct in_str *i)
-{
-       return *i->p;
-}
-
-static inline void cmdedit_set_initial_prompt(void)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       PS1 = NULL;
-#else
-       PS1 = getenv("PS1");
-       if(PS1==0)
-               PS1 = "\\w \\$ ";
-#endif 
-}
-
-static inline void setup_prompt_string(int promptmode, char **prompt_str)
-{
-       debug_printf("setup_prompt_string %d ",promptmode);
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       /* Set up the prompt */
-       if (promptmode == 1) {
-               if (PS1)
-                       free(PS1);
-               PS1=xmalloc(strlen(cwd)+4);
-               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
-               *prompt_str = PS1;
-       } else {
-               *prompt_str = PS2;
-       }
-#else
-       *prompt_str = (promptmode==1)? PS1 : PS2;
-#endif
-       debug_printf("result %s\n",*prompt_str);
-}
-
-static void get_user_input(struct in_str *i)
-{
-       char *prompt_str;
-       static char the_command[BUFSIZ];
-
-       setup_prompt_string(i->promptmode, &prompt_str);
-#ifdef BB_FEATURE_COMMAND_EDITING
-       /*
-        ** enable command line editing only while a command line
-        ** is actually being read; otherwise, we'll end up bequeathing
-        ** atexit() handlers and other unwanted stuff to our
-        ** child processes (rob@sysgo.de)
-        */
-       cmdedit_read_input(prompt_str, the_command);
-#else
-       fputs(prompt_str, stdout);
-       fflush(stdout);
-       the_command[0]=fgetc(i->file);
-       the_command[1]='\0';
-#endif
-       fflush(stdout);
-       i->p = the_command;
-}
-
-/* This is the magic location that prints prompts 
- * and gets data back from the user */
-static int file_get(struct in_str *i)
-{
-       int ch;
-
-       ch = 0;
-       /* If there is data waiting, eat it up */
-       if (i->p && *i->p) {
-               ch=*i->p++;
-       } else {
-               /* need to double check i->file because we might be doing something
-                * more complicated by now, like sourcing or substituting. */
-               if (i->__promptme && interactive && i->file == stdin) {
-                       while(! i->p || (interactive && strlen(i->p)==0) ) {
-                               get_user_input(i);
-                       }
-                       i->promptmode=2;
-                       i->__promptme = 0;
-                       if (i->p && *i->p) {
-                               ch=*i->p++;
-                       }
-               } else {
-                       ch = fgetc(i->file);
-               }
-
-               debug_printf("b_getch: got a %d\n", ch);
-       }
-       if (ch == '\n') i->__promptme=1;
-       return ch;
-}
-
-/* All the callers guarantee this routine will never be
- * used right after a newline, so prompting is not needed.
- */
-static int file_peek(struct in_str *i)
-{
-       if (i->p && *i->p) {
-               return *i->p;
-       } else {
-               i->peek_buf[0] = fgetc(i->file);
-               i->peek_buf[1] = '\0';
-               i->p = i->peek_buf;
-               debug_printf("b_peek: got a %d\n", *i->p);
-               return *i->p;
-       }
-}
-
-static void setup_file_in_str(struct in_str *i, FILE *f)
-{
-       i->peek = file_peek;
-       i->get = file_get;
-       i->__promptme=1;
-       i->promptmode=1;
-       i->file = f;
-       i->p = NULL;
-}
-
-static void setup_string_in_str(struct in_str *i, const char *s)
-{
-       i->peek = static_peek;
-       i->get = static_get;
-       i->__promptme=1;
-       i->promptmode=1;
-       i->p = s;
-}
-
-static void mark_open(int fd)
-{
-       struct close_me *new = xmalloc(sizeof(struct close_me));
-       new->fd = fd;
-       new->next = close_me_head;
-       close_me_head = new;
-}
-
-static void mark_closed(int fd)
-{
-       struct close_me *tmp;
-       if (close_me_head == NULL || close_me_head->fd != fd)
-               error_msg_and_die("corrupt close_me");
-       tmp = close_me_head;
-       close_me_head = close_me_head->next;
-       free(tmp);
-}
-
-static void close_all()
-{
-       struct close_me *c;
-       for (c=close_me_head; c; c=c->next) {
-               close(c->fd);
-       }
-       close_me_head = NULL;
-}
-
-/* squirrel != NULL means we squirrel away copies of stdin, stdout,
- * and stderr if they are redirected. */
-static int setup_redirects(struct child_prog *prog, int squirrel[])
-{
-       int openfd, mode;
-       struct redir_struct *redir;
-
-       for (redir=prog->redirects; redir; redir=redir->next) {
-               if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
-                       /* something went wrong in the parse.  Pretend it didn't happen */
-                       continue;
-               }
-               if (redir->dup == -1) {
-                       mode=redir_table[redir->type].mode;
-                       openfd = open(redir->word.gl_pathv[0], mode, 0666);
-                       if (openfd < 0) {
-                       /* this could get lost if stderr has been redirected, but
-                          bash and ash both lose it as well (though zsh doesn't!) */
-                               perror_msg("error opening %s", redir->word.gl_pathv[0]);
-                               return 1;
-                       }
-               } else {
-                       openfd = redir->dup;
-               }
-
-               if (openfd != redir->fd) {
-                       if (squirrel && redir->fd < 3) {
-                               squirrel[redir->fd] = dup(redir->fd);
-                       }
-                       if (openfd == -3) {
-                               close(openfd);
-                       } else {
-                               dup2(openfd, redir->fd);
-                               if (redir->dup == -1)
-                                       close (openfd);
-                       }
-               }
-       }
-       return 0;
-}
-
-static void restore_redirects(int squirrel[])
-{
-       int i, fd;
-       for (i=0; i<3; i++) {
-               fd = squirrel[i];
-               if (fd != -1) {
-                       /* No error checking.  I sure wouldn't know what
-                        * to do with an error if I found one! */
-                       dup2(fd, i);
-                       close(fd);
-               }
-       }
-}
-
-/* never returns */
-/* XXX no exit() here.  If you don't exec, use _exit instead.
- * The at_exit handlers apparently confuse the calling process,
- * in particular stdin handling.  Not sure why? */
-static void pseudo_exec(struct child_prog *child)
-{
-       int i, rcode;
-       struct built_in_command *x;
-       if (child->argv) {
-               for (i=0; is_assignment(child->argv[i]); i++) {
-                       debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
-                       putenv(strdup(child->argv[i]));
-               }
-               child->argv+=i;  /* XXX this hack isn't so horrible, since we are about
-                                       to exit, and therefore don't need to keep data
-                                       structures consistent for free() use. */
-               /* If a variable is assigned in a forest, and nobody listens,
-                * was it ever really set?
-                */
-               if (child->argv[0] == NULL) {
-                       _exit(EXIT_SUCCESS);
-               }
-
-               /*
-                * Check if the command matches any of the builtins.
-                * Depending on context, this might be redundant.  But it's
-                * easier to waste a few CPU cycles than it is to figure out
-                * if this is one of those cases.
-                */
-               for (x = bltins; x->cmd; x++) {
-                       if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                               debug_printf("builtin exec %s\n", child->argv[0]);
-                               rcode = x->function(child);
-                               fflush(stdout);
-                               _exit(rcode);
-                       }
-               }
-
-               /* Check if the command matches any busybox internal commands
-                * ("applets") here.  
-                * FIXME: This feature is not 100% safe, since
-                * BusyBox is not fully reentrant, so we have no guarantee the things
-                * from the .bss are still zeroed, or that things from .data are still
-                * at their defaults.  We could exec ourself from /proc/self/exe, but I
-                * really dislike relying on /proc for things.  We could exec ourself
-                * from global_argv[0], but if we are in a chroot, we may not be able
-                * to find ourself... */ 
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-               {
-                       int argc_l;
-                       char** argv_l=child->argv;
-                       char *name = child->argv[0];
-
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-                       /* Following discussions from November 2000 on the busybox mailing
-                        * list, the default configuration, (without
-                        * get_last_path_component()) lets the user force use of an
-                        * external command by specifying the full (with slashes) filename.
-                        * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets
-                        * _aways_ override external commands, so if you want to run
-                        * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
-                        * filesystem and is _not_ busybox.  Some systems may want this,
-                        * most do not.  */
-                       name = get_last_path_component(name);
-#endif
-                       /* Count argc for use in a second... */
-                       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
-                       optind = 1;
-                       debug_printf("running applet %s\n", name);
-                       run_applet_by_name(name, argc_l, child->argv);
-               }
-#endif
-               debug_printf("exec of %s\n",child->argv[0]);
-               execvp(child->argv[0],child->argv);
-               perror_msg("couldn't exec: %s",child->argv[0]);
-               _exit(1);
-       } else if (child->group) {
-               debug_printf("runtime nesting to group\n");
-               interactive=0;    /* crucial!!!! */
-               rcode = run_list_real(child->group);
-               /* OK to leak memory by not calling free_pipe_list,
-                * since this process is about to exit */
-               _exit(rcode);
-       } else {
-               /* Can happen.  See what bash does with ">foo" by itself. */
-               debug_printf("trying to pseudo_exec null command\n");
-               _exit(EXIT_SUCCESS);
-       }
-}
-
-static void insert_bg_job(struct pipe *pi)
-{
-       struct pipe *thejob;
-
-       /* Linear search for the ID of the job to use */
-       pi->jobid = 1;
-       for (thejob = job_list; thejob; thejob = thejob->next)
-               if (thejob->jobid >= pi->jobid)
-                       pi->jobid = thejob->jobid + 1;
-
-       /* add thejob to the list of running jobs */
-       if (!job_list) {
-               thejob = job_list = xmalloc(sizeof(*thejob));
-       } else {
-               for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
-               thejob->next = xmalloc(sizeof(*thejob));
-               thejob = thejob->next;
-       }
-
-       /* physically copy the struct job */
-       memcpy(thejob, pi, sizeof(struct pipe));
-       thejob->next = NULL;
-       thejob->running_progs = thejob->num_progs;
-       thejob->stopped_progs = 0;
-       thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
-
-       //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
-       {
-               char *bar=thejob->text;
-               char **foo=pi->progs[0].argv;
-               while(foo && *foo) {
-                       bar += sprintf(bar, "%s ", *foo++);
-               }
-       }
-
-       /* we don't wait for background thejobs to return -- append it 
-          to the list of backgrounded thejobs and leave it alone */
-       printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
-       last_bg_pid = thejob->progs[0].pid;
-       last_jobid = thejob->jobid;
-}
-
-/* remove a backgrounded job */
-static void remove_bg_job(struct pipe *pi)
-{
-       struct pipe *prev_pipe;
-
-       if (pi == job_list) {
-               job_list = pi->next;
-       } else {
-               prev_pipe = job_list;
-               while (prev_pipe->next != pi)
-                       prev_pipe = prev_pipe->next;
-               prev_pipe->next = pi->next;
-       }
-       if (job_list)
-               last_jobid = job_list->jobid;
-       else
-               last_jobid = 0;
-
-       pi->stopped_progs = 0;
-       free_pipe(pi, 0);
-       free(pi);
-}
-
-/* Checks to see if any processes have exited -- if they 
-   have, figure out why and see if a job has completed */
-static int checkjobs(struct pipe* fg_pipe)
-{
-       int attributes;
-       int status;
-       int prognum = 0;
-       struct pipe *pi;
-       pid_t childpid;
-
-       attributes = WUNTRACED;
-       if (fg_pipe==NULL) {
-               attributes |= WNOHANG;
-       }
-
-       while ((childpid = waitpid(-1, &status, attributes)) > 0) {
-               if (fg_pipe) {
-                       int i, rcode = 0;
-                       for (i=0; i < fg_pipe->num_progs; i++) {
-                               if (fg_pipe->progs[i].pid == childpid) {
-                                       if (i==fg_pipe->num_progs-1) 
-                                               rcode=WEXITSTATUS(status);
-                                       (fg_pipe->num_progs)--;
-                                       return(rcode);
-                               }
-                       }
-               }
-
-               for (pi = job_list; pi; pi = pi->next) {
-                       prognum = 0;
-                       while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
-                               prognum++;
-                       }
-                       if (prognum < pi->num_progs)
-                               break;
-               }
-
-               if(pi==NULL) {
-                       debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
-                       continue;
-               }
-
-               if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                       /* child exited */
-                       pi->running_progs--;
-                       pi->progs[prognum].pid = 0;
-
-                       if (!pi->running_progs) {
-                               printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
-                               remove_bg_job(pi);
-                       }
-               } else {
-                       /* child stopped */
-                       pi->stopped_progs++;
-                       pi->progs[prognum].is_stopped = 1;
-
-#if 0
-                       /* Printing this stuff is a pain, since it tends to
-                        * overwrite the prompt an inconveinient moments.  So
-                        * don't do that.  */
-                       if (pi->stopped_progs == pi->num_progs) {
-                               printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
-                       }
-#endif 
-               }
-       }
-
-       if (childpid == -1 && errno != ECHILD)
-               perror_msg("waitpid");
-
-       /* move the shell to the foreground */
-       //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
-       //      perror_msg("tcsetpgrp-2");
-       return -1;
-}
-
-/* Figure out our controlling tty, checking in order stderr,
- * stdin, and stdout.  If check_pgrp is set, also check that
- * we belong to the foreground process group associated with
- * that tty.  The value of shell_terminal is needed in order to call
- * tcsetpgrp(shell_terminal, ...); */
-void controlling_tty(int check_pgrp)
-{
-       pid_t curpgrp;
-
-       if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
-                       && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
-                       && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
-               goto shell_terminal_error;
-
-       if (check_pgrp && curpgrp != getpgid(0))
-               goto shell_terminal_error;
-
-       return;
-
-shell_terminal_error:
-               shell_terminal = -1;
-               return;
-}
-
-/* run_pipe_real() starts all the jobs, but doesn't wait for anything
- * to finish.  See checkjobs().
- *
- * return code is normally -1, when the caller has to wait for children
- * to finish to determine the exit status of the pipe.  If the pipe
- * is a simple builtin command, however, the action is done by the
- * time run_pipe_real returns, and the exit code is provided as the
- * return value.
- *
- * The input of the pipe is always stdin, the output is always
- * stdout.  The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
- * because it tries to avoid running the command substitution in
- * subshell, when that is in fact necessary.  The subshell process
- * now has its stdout directed to the input of the appropriate pipe,
- * so this routine is noticeably simpler.
- */
-static int run_pipe_real(struct pipe *pi)
-{
-       int i;
-       int nextin, nextout;
-       int pipefds[2];                         /* pipefds[0] is for reading */
-       struct child_prog *child;
-       struct built_in_command *x;
-
-       nextin = 0;
-       pi->pgrp = -1;
-
-       /* Check if this is a simple builtin (not part of a pipe).
-        * Builtins within pipes have to fork anyway, and are handled in
-        * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
-        */
-       if (pi->num_progs == 1) child = & (pi->progs[0]);
-       if (pi->num_progs == 1 && child->group && child->subshell == 0) {
-               int squirrel[] = {-1, -1, -1};
-               int rcode;
-               debug_printf("non-subshell grouping\n");
-               setup_redirects(child, squirrel);
-               /* XXX could we merge code with following builtin case,
-                * by creating a pseudo builtin that calls run_list_real? */
-               rcode = run_list_real(child->group);
-               restore_redirects(squirrel);
-               return rcode;
-       } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
-               for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
-               if (i!=0 && child->argv[i]==NULL) {
-                       /* assignments, but no command: set the local environment */
-                       for (i=0; child->argv[i]!=NULL; i++) {
-
-                               /* Ok, this case is tricky.  We have to decide if this is a
-                                * local variable, or an already exported variable.  If it is
-                                * already exported, we have to export the new value.  If it is
-                                * not exported, we need only set this as a local variable. 
-                                * This junk is all to decide whether or not to export this
-                                * variable. */
-                               int export_me=0;
-                               char *name, *value;
-                               name = xstrdup(child->argv[i]);
-                               debug_printf("Local environment set: %s\n", name);
-                               value = strchr(name, '=');
-                               if (value)
-                                       *value=0;
-                               if ( get_local_var(name)) {
-                                       export_me=1;
-                               }
-                               free(name);
-                               set_local_var(child->argv[i], export_me);
-                       }
-                       return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
-               }
-               for (x = bltins; x->cmd; x++) {
-                       if (strcmp(child->argv[i], x->cmd) == 0 ) {
-                               int squirrel[] = {-1, -1, -1};
-                               int rcode;
-                               if (x->function == builtin_exec && child->argv[i+1]==NULL) {
-                                       debug_printf("magic exec\n");
-                                       setup_redirects(child,NULL);
-                                       return EXIT_SUCCESS;
-                               }
-                               debug_printf("builtin inline %s\n", child->argv[0]);
-                               /* XXX setup_redirects acts on file descriptors, not FILEs.
-                                * This is perfect for work that comes after exec().
-                                * Is it really safe for inline use?  Experimentally,
-                                * things seem to work with glibc. */
-                               setup_redirects(child, squirrel);
-                               for (i=0; is_assignment(child->argv[i]); i++) {
-                                       putenv(strdup(child->argv[i]));
-                               }
-                               child->argv+=i;  /* XXX horrible hack */
-                               rcode = x->function(child);
-                               child->argv-=i;  /* XXX restore hack so free() can work right */
-                               restore_redirects(squirrel);
-                               return rcode;
-                       }
-               }
-       }
-
-       for (i = 0; i < pi->num_progs; i++) {
-               child = & (pi->progs[i]);
-
-               /* pipes are inserted between pairs of commands */
-               if ((i + 1) < pi->num_progs) {
-                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
-                       nextout = pipefds[1];
-               } else {
-                       nextout=1;
-                       pipefds[0] = -1;
-               }
-
-               /* XXX test for failed fork()? */
-               if (!(child->pid = fork())) {
-                       /* Set the handling for job control signals back to the default.  */
-                       signal(SIGINT, SIG_DFL);
-                       signal(SIGQUIT, SIG_DFL);
-                       signal(SIGTERM, SIG_DFL);
-                       signal(SIGTSTP, SIG_DFL);
-                       signal(SIGTTIN, SIG_DFL);
-                       signal(SIGTTOU, SIG_DFL);
-                       signal(SIGCHLD, SIG_DFL);
-                       
-                       close_all();
-
-                       if (nextin != 0) {
-                               dup2(nextin, 0);
-                               close(nextin);
-                       }
-                       if (nextout != 1) {
-                               dup2(nextout, 1);
-                               close(nextout);
-                       }
-                       if (pipefds[0]!=-1) {
-                               close(pipefds[0]);  /* opposite end of our output pipe */
-                       }
-
-                       /* Like bash, explicit redirects override pipes,
-                        * and the pipe fd is available for dup'ing. */
-                       setup_redirects(child,NULL);
-
-                       if (interactive && pi->followup!=PIPE_BG) {
-                               /* If we (the child) win the race, put ourselves in the process
-                                * group whose leader is the first process in this pipe. */
-                               if (pi->pgrp < 0) {
-                                       pi->pgrp = getpid();
-                               }
-                               if (setpgid(0, pi->pgrp) == 0) {
-                                       tcsetpgrp(2, pi->pgrp);
-                               }
-                       }
-
-                       pseudo_exec(child);
-               }
-               
-
-               /* put our child in the process group whose leader is the
-                  first process in this pipe */
-               if (pi->pgrp < 0) {
-                       pi->pgrp = child->pid;
-               }
-               /* Don't check for errors.  The child may be dead already,
-                * in which case setpgid returns error code EACCES. */
-               setpgid(child->pid, pi->pgrp);
-
-               if (nextin != 0)
-                       close(nextin);
-               if (nextout != 1)
-                       close(nextout);
-
-               /* If there isn't another process, nextin is garbage 
-                  but it doesn't matter */
-               nextin = pipefds[0];
-       }
-       return -1;
-}
-
-static int run_list_real(struct pipe *pi)
-{
-       int rcode=0;
-       int if_code=0, next_if_code=0;  /* need double-buffer to handle elif */
-       reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
-       for (;pi;pi=pi->next) {
-               rmode = pi->r_mode;
-               debug_printf("rmode=%d  if_code=%d  next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
-               if (rmode == skip_more_in_this_rmode) continue;
-               skip_more_in_this_rmode = RES_XXXX;
-               if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
-               if (rmode == RES_THEN &&  if_code) continue;
-               if (rmode == RES_ELSE && !if_code) continue;
-               if (rmode == RES_ELIF && !if_code) continue;
-               if (pi->num_progs == 0) continue;
-               rcode = run_pipe_real(pi);
-               debug_printf("run_pipe_real returned %d\n",rcode);
-               if (rcode!=-1) {
-                       /* We only ran a builtin: rcode was set by the return value
-                        * of run_pipe_real(), and we don't need to wait for anything. */
-               } else if (pi->followup==PIPE_BG) {
-                       /* XXX check bash's behavior with nontrivial pipes */
-                       /* XXX compute jobid */
-                       /* XXX what does bash do with attempts to background builtins? */
-                       insert_bg_job(pi);
-                       rcode = EXIT_SUCCESS;
-               } else {
-                       if (interactive) {
-                               /* move the new process group into the foreground */
-                               if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp-3");
-                               rcode = checkjobs(pi);
-                               /* move the shell to the foreground */
-                               if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp-4");
-                       } else {
-                               rcode = checkjobs(pi);
-                       }
-                       debug_printf("checkjobs returned %d\n",rcode);
-               }
-               last_return_code=rcode;
-               if ( rmode == RES_IF || rmode == RES_ELIF )
-                       next_if_code=rcode;  /* can be overwritten a number of times */
-               if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
-                    (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
-                       skip_more_in_this_rmode=rmode;
-               checkjobs(NULL);
-       }
-       return rcode;
-}
-
-/* broken, of course, but OK for testing */
-static char *indenter(int i)
-{
-       static char blanks[]="                                    ";
-       return &blanks[sizeof(blanks)-i-1];
-}
-
-/* return code is the exit status of the pipe */
-static int free_pipe(struct pipe *pi, int indent)
-{
-       char **p;
-       struct child_prog *child;
-       struct redir_struct *r, *rnext;
-       int a, i, ret_code=0;
-       char *ind = indenter(indent);
-
-       if (pi->stopped_progs > 0)
-               return ret_code;
-       final_printf("%s run pipe: (pid %d)\n",ind,getpid());
-       for (i=0; i<pi->num_progs; i++) {
-               child = &pi->progs[i];
-               final_printf("%s  command %d:\n",ind,i);
-               if (child->argv) {
-                       for (a=0,p=child->argv; *p; a++,p++) {
-                               final_printf("%s   argv[%d] = %s\n",ind,a,*p);
-                       }
-                       globfree(&child->glob_result);
-                       child->argv=NULL;
-               } else if (child->group) {
-                       final_printf("%s   begin group (subshell:%d)\n",ind, child->subshell);
-                       ret_code = free_pipe_list(child->group,indent+3);
-                       final_printf("%s   end group\n",ind);
-               } else {
-                       final_printf("%s   (nil)\n",ind);
-               }
-               for (r=child->redirects; r; r=rnext) {
-                       final_printf("%s   redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
-                       if (r->dup == -1) {
-                               /* guard against the case >$FOO, where foo is unset or blank */
-                               if (r->word.gl_pathv) {
-                                       final_printf(" %s\n", *r->word.gl_pathv);
-                                       globfree(&r->word);
-                               }
-                       } else {
-                               final_printf("&%d\n", r->dup);
-                       }
-                       rnext=r->next;
-                       free(r);
-               }
-               child->redirects=NULL;
-       }
-       free(pi->progs);   /* children are an array, they get freed all at once */
-       pi->progs=NULL;
-       return ret_code;
-}
-
-static int free_pipe_list(struct pipe *head, int indent)
-{
-       int rcode=0;   /* if list has no members */
-       struct pipe *pi, *next;
-       char *ind = indenter(indent);
-       for (pi=head; pi; pi=next) {
-               final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
-               rcode = free_pipe(pi, indent);
-               final_printf("%s pipe followup code %d\n", ind, pi->followup);
-               next=pi->next;
-               pi->next=NULL;
-               free(pi);
-       }
-       return rcode;   
-}
-
-/* Select which version we will use */
-static int run_list(struct pipe *pi)
-{
-       int rcode=0;
-       if (fake_mode==0) {
-               rcode = run_list_real(pi);
-       } 
-       /* free_pipe_list has the side effect of clearing memory
-        * In the long run that function can be merged with run_list_real,
-        * but doing that now would hobble the debugging effort. */
-       free_pipe_list(pi,0);
-       return rcode;
-}
-
-/* The API for glob is arguably broken.  This routine pushes a non-matching
- * string into the output structure, removing non-backslashed backslashes.
- * If someone can prove me wrong, by performing this function within the
- * original glob(3) api, feel free to rewrite this routine into oblivion.
- * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
- * XXX broken if the last character is '\\', check that before calling.
- */
-static int globhack(const char *src, int flags, glob_t *pglob)
-{
-       int cnt=0, pathc;
-       const char *s;
-       char *dest;
-       for (cnt=1, s=src; s && *s; s++) {
-               if (*s == '\\') s++;
-               cnt++;
-       }
-       dest = malloc(cnt);
-       if (!dest) return GLOB_NOSPACE;
-       if (!(flags & GLOB_APPEND)) {
-               pglob->gl_pathv=NULL;
-               pglob->gl_pathc=0;
-               pglob->gl_offs=0;
-               pglob->gl_offs=0;
-       }
-       pathc = ++pglob->gl_pathc;
-       pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
-       if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
-       pglob->gl_pathv[pathc-1]=dest;
-       pglob->gl_pathv[pathc]=NULL;
-       for (s=src; s && *s; s++, dest++) {
-               if (*s == '\\') s++;
-               *dest = *s;
-       }
-       *dest='\0';
-       return 0;
-}
-
-/* XXX broken if the last character is '\\', check that before calling */
-static int glob_needed(const char *s)
-{
-       for (; *s; s++) {
-               if (*s == '\\') s++;
-               if (strchr("*[?",*s)) return 1;
-       }
-       return 0;
-}
-
-#if 0
-static void globprint(glob_t *pglob)
-{
-       int i;
-       debug_printf("glob_t at %p:\n", pglob);
-       debug_printf("  gl_pathc=%d  gl_pathv=%p  gl_offs=%d  gl_flags=%d\n",
-               pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
-       for (i=0; i<pglob->gl_pathc; i++)
-               debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
-                       pglob->gl_pathv[i], pglob->gl_pathv[i]);
-}
-#endif
-
-static int xglob(o_string *dest, int flags, glob_t *pglob)
-{
-       int gr;
-
-       /* short-circuit for null word */
-       /* we can code this better when the debug_printf's are gone */
-       if (dest->length == 0) {
-               if (dest->nonnull) {
-                       /* bash man page calls this an "explicit" null */
-                       gr = globhack(dest->data, flags, pglob);
-                       debug_printf("globhack returned %d\n",gr);
-               } else {
-                       return 0;
-               }
-       } else if (glob_needed(dest->data)) {
-               gr = glob(dest->data, flags, NULL, pglob);
-               debug_printf("glob returned %d\n",gr);
-               if (gr == GLOB_NOMATCH) {
-                       /* quote removal, or more accurately, backslash removal */
-                       gr = globhack(dest->data, flags, pglob);
-                       debug_printf("globhack returned %d\n",gr);
-               }
-       } else {
-               gr = globhack(dest->data, flags, pglob);
-               debug_printf("globhack returned %d\n",gr);
-       }
-       if (gr == GLOB_NOSPACE)
-               error_msg_and_die("out of memory during glob");
-       if (gr != 0) { /* GLOB_ABORTED ? */
-               error_msg("glob(3) error %d",gr);
-       }
-       /* globprint(glob_target); */
-       return gr;
-}
-
-/* This is used to get/check local shell variables */
-static char *get_local_var(const char *s)
-{
-       struct variables *cur;
-
-       if (!s)
-               return NULL;
-       for (cur = top_vars; cur; cur=cur->next)
-               if(strcmp(cur->name, s)==0)
-                       return cur->value;
-       return NULL;
-}
-
-/* This is used to set local shell variables
-   flg_export==0 if only local (not exporting) variable
-   flg_export==1 if "new" exporting environ
-   flg_export>1  if current startup environ (not call putenv()) */
-static int set_local_var(const char *s, int flg_export)
-{
-       char *name, *value;
-       int result=0;
-       struct variables *cur;
-
-       name=strdup(s);
-
-       /* Assume when we enter this function that we are already in
-        * NAME=VALUE format.  So the first order of business is to
-        * split 's' on the '=' into 'name' and 'value' */ 
-       value = strchr(name, '=');
-       if (value==0 && ++value==0) {
-               free(name);
-               return -1;
-       }
-       *value++ = 0;
-
-       for(cur = top_vars; cur; cur = cur->next) {
-               if(strcmp(cur->name, name)==0)
-                       break;
-       }
-
-       if(cur) {
-               if(strcmp(cur->value, value)==0) {
-                       if(flg_export>0 && cur->flg_export==0)
-                               cur->flg_export=flg_export;
-                       else
-                               result++;
-               } else {
-                       if(cur->flg_read_only) {
-                               error_msg("%s: readonly variable", name);
-                               result = -1;
-                       } else {
-                               if(flg_export>0 || cur->flg_export>1)
-                                       cur->flg_export=1;
-                               free(cur->value);
-
-                               cur->value = strdup(value);
-                       }
-               }
-       } else {
-               cur = malloc(sizeof(struct variables));
-               if(!cur) {
-                       result = -1;
-               } else {
-                       cur->name = strdup(name);
-                       if(cur->name == 0) {
-                               free(cur);
-                               result = -1;
-                       } else {
-                               struct variables *bottom = top_vars;
-                               cur->value = strdup(value);
-                               cur->next = 0;
-                               cur->flg_export = flg_export;
-                               cur->flg_read_only = 0;
-                               while(bottom->next) bottom=bottom->next;
-                               bottom->next = cur;
-                       }
-               }
-       }
-
-       if(result==0 && cur->flg_export==1) {
-               *(value-1) = '=';
-               result = putenv(name);
-       } else {
-               free(name);
-               if(result>0)            /* equivalent to previous set */
-                       result = 0;
-       }
-       return result;
-}
-
-static void unset_local_var(const char *name)
-{
-       struct variables *cur;
-
-       if (name) {
-               for (cur = top_vars; cur; cur=cur->next) {
-                       if(strcmp(cur->name, name)==0)
-                               break;
-               }
-               if(cur!=0) {
-                       struct variables *next = top_vars;
-                       if(cur->flg_read_only) {
-                               error_msg("%s: readonly variable", name);
-                               return;
-                       } else {
-                               if(cur->flg_export)
-                                       unsetenv(cur->name);
-                               free(cur->name);
-                               free(cur->value);
-                               while (next->next != cur)
-                                       next = next->next;
-                               next->next = cur->next;
-                       }
-                       free(cur);
-               }
-       }
-}
-
-static int is_assignment(const char *s)
-{
-       if (s==NULL || !isalpha(*s)) return 0;
-       ++s;
-       while(isalnum(*s) || *s=='_') ++s;
-       return *s=='=';
-}
-
-/* the src parameter allows us to peek forward to a possible &n syntax
- * for file descriptor duplication, e.g., "2>&1".
- * Return code is 0 normally, 1 if a syntax error is detected in src.
- * Resource errors (in xmalloc) cause the process to exit */
-static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
-       struct in_str *input)
-{
-       struct child_prog *child=ctx->child;
-       struct redir_struct *redir = child->redirects;
-       struct redir_struct *last_redir=NULL;
-
-       /* Create a new redir_struct and drop it onto the end of the linked list */
-       while(redir) {
-               last_redir=redir;
-               redir=redir->next;
-       }
-       redir = xmalloc(sizeof(struct redir_struct));
-       redir->next=NULL;
-       redir->word.gl_pathv=NULL;
-       if (last_redir) {
-               last_redir->next=redir;
-       } else {
-               child->redirects=redir;
-       }
-
-       redir->type=style;
-       redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
-
-       debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
-
-       /* Check for a '2>&1' type redirect */ 
-       redir->dup = redirect_dup_num(input);
-       if (redir->dup == -2) return 1;  /* syntax error */
-       if (redir->dup != -1) {
-               /* Erik had a check here that the file descriptor in question
-                * is legit; I postpone that to "run time"
-                * A "-" representation of "close me" shows up as a -3 here */
-               debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
-       } else {
-               /* We do _not_ try to open the file that src points to,
-                * since we need to return and let src be expanded first.
-                * Set ctx->pending_redirect, so we know what to do at the
-                * end of the next parsed word.
-                */
-               ctx->pending_redirect = redir;
-       }
-       return 0;
-}
-
-struct pipe *new_pipe(void) {
-       struct pipe *pi;
-       pi = xmalloc(sizeof(struct pipe));
-       pi->num_progs = 0;
-       pi->progs = NULL;
-       pi->next = NULL;
-       pi->followup = 0;  /* invalid */
-       return pi;
-}
-
-static void initialize_context(struct p_context *ctx)
-{
-       ctx->pipe=NULL;
-       ctx->pending_redirect=NULL;
-       ctx->child=NULL;
-       ctx->list_head=new_pipe();
-       ctx->pipe=ctx->list_head;
-       ctx->w=RES_NONE;
-       ctx->stack=NULL;
-       done_command(ctx);   /* creates the memory for working child */
-}
-
-/* normal return is 0
- * if a reserved word is found, and processed, return 1
- * should handle if, then, elif, else, fi, for, while, until, do, done.
- * case, function, and select are obnoxious, save those for later.
- */
-int reserved_word(o_string *dest, struct p_context *ctx)
-{
-       struct reserved_combo {
-               char *literal;
-               int code;
-               long flag;
-       };
-       /* Mostly a list of accepted follow-up reserved words.
-        * FLAG_END means we are done with the sequence, and are ready
-        * to turn the compound list into a command.
-        * FLAG_START means the word must start a new compound list.
-        */
-       static struct reserved_combo reserved_list[] = {
-               { "if",    RES_IF,    FLAG_THEN | FLAG_START },
-               { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
-               { "elif",  RES_ELIF,  FLAG_THEN },
-               { "else",  RES_ELSE,  FLAG_FI   },
-               { "fi",    RES_FI,    FLAG_END  },
-               { "for",   RES_FOR,   FLAG_DO   | FLAG_START },
-               { "while", RES_WHILE, FLAG_DO   | FLAG_START },
-               { "until", RES_UNTIL, FLAG_DO   | FLAG_START },
-               { "do",    RES_DO,    FLAG_DONE },
-               { "done",  RES_DONE,  FLAG_END  }
-       };
-       struct reserved_combo *r;
-       for (r=reserved_list;
-#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
-               r<reserved_list+NRES; r++) {
-               if (strcmp(dest->data, r->literal) == 0) {
-                       debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
-                       if (r->flag & FLAG_START) {
-                               struct p_context *new = xmalloc(sizeof(struct p_context));
-                               debug_printf("push stack\n");
-                               *new = *ctx;   /* physical copy */
-                               initialize_context(ctx);
-                               ctx->stack=new;
-                       } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
-                               syntax();
-                               ctx->w = RES_SNTX;
-                               b_reset (dest);
-                               return 1;
-                       }
-                       ctx->w=r->code;
-                       ctx->old_flag = r->flag;
-                       if (ctx->old_flag & FLAG_END) {
-                               struct p_context *old;
-                               debug_printf("pop stack\n");
-                               old = ctx->stack;
-                               old->child->group = ctx->list_head;
-                               old->child->subshell = 0;
-                               *ctx = *old;   /* physical copy */
-                               free(old);
-                       }
-                       b_reset (dest);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/* normal return is 0.
- * Syntax or xglob errors return 1. */
-static int done_word(o_string *dest, struct p_context *ctx)
-{
-       struct child_prog *child=ctx->child;
-       glob_t *glob_target;
-       int gr, flags = 0;
-
-       debug_printf("done_word: %s %p\n", dest->data, child);
-       if (dest->length == 0 && !dest->nonnull) {
-               debug_printf("  true null, ignored\n");
-               return 0;
-       }
-       if (ctx->pending_redirect) {
-               glob_target = &ctx->pending_redirect->word;
-       } else {
-               if (child->group) {
-                       syntax();
-                       return 1;  /* syntax error, groups and arglists don't mix */
-               }
-               if (!child->argv) {
-                       debug_printf("checking %s for reserved-ness\n",dest->data);
-                       if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
-               }
-               glob_target = &child->glob_result;
-               if (child->argv) flags |= GLOB_APPEND;
-       }
-       gr = xglob(dest, flags, glob_target);
-       if (gr != 0) return 1;
-
-       b_reset(dest);
-       if (ctx->pending_redirect) {
-               ctx->pending_redirect=NULL;
-               if (glob_target->gl_pathc != 1) {
-                       error_msg("ambiguous redirect");
-                       return 1;
-               }
-       } else {
-               child->argv = glob_target->gl_pathv;
-       }
-       return 0;
-}
-
-/* The only possible error here is out of memory, in which case
- * xmalloc exits. */
-static int done_command(struct p_context *ctx)
-{
-       /* The child is really already in the pipe structure, so
-        * advance the pipe counter and make a new, null child.
-        * Only real trickiness here is that the uncommitted
-        * child structure, to which ctx->child points, is not
-        * counted in pi->num_progs. */
-       struct pipe *pi=ctx->pipe;
-       struct child_prog *prog=ctx->child;
-
-       if (prog && prog->group == NULL
-                && prog->argv == NULL
-                && prog->redirects == NULL) {
-               debug_printf("done_command: skipping null command\n");
-               return 0;
-       } else if (prog) {
-               pi->num_progs++;
-               debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
-       } else {
-               debug_printf("done_command: initializing\n");
-       }
-       pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
-
-       prog = pi->progs + pi->num_progs;
-       prog->redirects = NULL;
-       prog->argv = NULL;
-       prog->is_stopped = 0;
-       prog->group = NULL;
-       prog->glob_result.gl_pathv = NULL;
-       prog->family = pi;
-
-       ctx->child=prog;
-       /* but ctx->pipe and ctx->list_head remain unchanged */
-       return 0;
-}
-
-static int done_pipe(struct p_context *ctx, pipe_style type)
-{
-       struct pipe *new_p;
-       done_command(ctx);  /* implicit closure of previous command */
-       debug_printf("done_pipe, type %d\n", type);
-       ctx->pipe->followup = type;
-       ctx->pipe->r_mode = ctx->w;
-       new_p=new_pipe();
-       ctx->pipe->next = new_p;
-       ctx->pipe = new_p;
-       ctx->child = NULL;
-       done_command(ctx);  /* set up new pipe to accept commands */
-       return 0;
-}
-
-/* peek ahead in the in_str to find out if we have a "&n" construct,
- * as in "2>&1", that represents duplicating a file descriptor.
- * returns either -2 (syntax error), -1 (no &), or the number found.
- */
-static int redirect_dup_num(struct in_str *input)
-{
-       int ch, d=0, ok=0;
-       ch = b_peek(input);
-       if (ch != '&') return -1;
-
-       b_getch(input);  /* get the & */
-       ch=b_peek(input);
-       if (ch == '-') {
-               b_getch(input);
-               return -3;  /* "-" represents "close me" */
-       }
-       while (isdigit(ch)) {
-               d = d*10+(ch-'0');
-               ok=1;
-               b_getch(input);
-               ch = b_peek(input);
-       }
-       if (ok) return d;
-
-       error_msg("ambiguous redirect");
-       return -2;
-}
-
-/* If a redirect is immediately preceded by a number, that number is
- * supposed to tell which file descriptor to redirect.  This routine
- * looks for such preceding numbers.  In an ideal world this routine
- * needs to handle all the following classes of redirects...
- *     echo 2>foo     # redirects fd  2 to file "foo", nothing passed to echo
- *     echo 49>foo    # redirects fd 49 to file "foo", nothing passed to echo
- *     echo -2>foo    # redirects fd  1 to file "foo",    "-2" passed to echo
- *     echo 49x>foo   # redirects fd  1 to file "foo",   "49x" passed to echo
- * A -1 output from this program means no valid number was found, so the
- * caller should use the appropriate default for this redirection.
- */
-static int redirect_opt_num(o_string *o)
-{
-       int num;
-
-       if (o->length==0) return -1;
-       for(num=0; num<o->length; num++) {
-               if (!isdigit(*(o->data+num))) {
-                       return -1;
-               }
-       }
-       /* reuse num (and save an int) */
-       num=atoi(o->data);
-       b_reset(o);
-       return num;
-}
-
-FILE *generate_stream_from_list(struct pipe *head)
-{
-       FILE *pf;
-#if 1
-       int pid, channel[2];
-       if (pipe(channel)<0) perror_msg_and_die("pipe");
-       pid=fork();
-       if (pid<0) {
-               perror_msg_and_die("fork");
-       } else if (pid==0) {
-               close(channel[0]);
-               if (channel[1] != 1) {
-                       dup2(channel[1],1);
-                       close(channel[1]);
-               }
-#if 0
-#define SURROGATE "surrogate response"
-               write(1,SURROGATE,sizeof(SURROGATE));
-               _exit(run_list(head));
-#else
-               _exit(run_list_real(head));   /* leaks memory */
-#endif
-       }
-       debug_printf("forked child %d\n",pid);
-       close(channel[1]);
-       pf = fdopen(channel[0],"r");
-       debug_printf("pipe on FILE *%p\n",pf);
-#else
-       free_pipe_list(head,0);
-       pf=popen("echo surrogate response","r");
-       debug_printf("started fake pipe on FILE *%p\n",pf);
-#endif
-       return pf;
-}
-
-/* this version hacked for testing purposes */
-/* return code is exit status of the process that is run. */
-static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
-{
-       int retcode;
-       o_string result=NULL_O_STRING;
-       struct p_context inner;
-       FILE *p;
-       struct in_str pipe_str;
-       initialize_context(&inner);
-
-       /* recursion to generate command */
-       retcode = parse_stream(&result, &inner, input, subst_end);
-       if (retcode != 0) return retcode;  /* syntax error or EOF */
-       done_word(&result, &inner);
-       done_pipe(&inner, PIPE_SEQ);
-       b_free(&result);
-
-       p=generate_stream_from_list(inner.list_head);
-       if (p==NULL) return 1;
-       mark_open(fileno(p));
-       setup_file_in_str(&pipe_str, p);
-
-       /* now send results of command back into original context */
-       retcode = parse_stream(dest, ctx, &pipe_str, '\0');
-       /* XXX In case of a syntax error, should we try to kill the child?
-        * That would be tough to do right, so just read until EOF. */
-       if (retcode == 1) {
-               while (b_getch(&pipe_str)!=EOF) { /* discard */ };
-       }
-
-       debug_printf("done reading from pipe, pclose()ing\n");
-       /* This is the step that wait()s for the child.  Should be pretty
-        * safe, since we just read an EOF from its stdout.  We could try
-        * to better, by using wait(), and keeping track of background jobs
-        * at the same time.  That would be a lot of work, and contrary
-        * to the KISS philosophy of this program. */
-       mark_closed(fileno(p));
-       retcode=pclose(p);
-       free_pipe_list(inner.list_head,0);
-       debug_printf("pclosed, retcode=%d\n",retcode);
-       /* XXX this process fails to trim a single trailing newline */
-       return retcode;
-}
-
-static int parse_group(o_string *dest, struct p_context *ctx,
-       struct in_str *input, int ch)
-{
-       int rcode, endch=0;
-       struct p_context sub;
-       struct child_prog *child = ctx->child;
-       if (child->argv) {
-               syntax();
-               return 1;  /* syntax error, groups and arglists don't mix */
-       }
-       initialize_context(&sub);
-       switch(ch) {
-               case '(': endch=')'; child->subshell=1; break;
-               case '{': endch='}'; break;
-               default: syntax();   /* really logic error */
-       }
-       rcode=parse_stream(dest,&sub,input,endch);
-       done_word(dest,&sub); /* finish off the final word in the subcontext */
-       done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
-       child->group = sub.list_head;
-       return rcode;
-       /* child remains "open", available for possible redirects */
-}
-
-/* basically useful version until someone wants to get fancier,
- * see the bash man page under "Parameter Expansion" */
-static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src)
-{
-       const char *p=NULL;
-       if (src->data) { 
-               p = getenv(src->data);
-               if (!p) 
-                       p = get_local_var(src->data);
-       }
-       if (p) parse_string(dest, ctx, p);   /* recursion */
-       b_free(src);
-}
-
-/* return code: 0 for OK, 1 for syntax error */
-static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
-{
-       int i, advance=0;
-       o_string alt=NULL_O_STRING;
-       char sep[]=" ";
-       int ch = input->peek(input);  /* first character after the $ */
-       debug_printf("handle_dollar: ch=%c\n",ch);
-       if (isalpha(ch)) {
-               while(ch=b_peek(input),isalnum(ch) || ch=='_') {
-                       b_getch(input);
-                       b_addchr(&alt,ch);
-               }
-               lookup_param(dest, ctx, &alt);
-       } else if (isdigit(ch)) {
-               i = ch-'0';  /* XXX is $0 special? */
-               if (i<global_argc) {
-                       parse_string(dest, ctx, global_argv[i]); /* recursion */
-               }
-               advance = 1;
-       } else switch (ch) {
-               case '$':
-                       b_adduint(dest,getpid());
-                       advance = 1;
-                       break;
-               case '!':
-                       if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
-                       advance = 1;
-                       break;
-               case '?':
-                       b_adduint(dest,last_return_code);
-                       advance = 1;
-                       break;
-               case '#':
-                       b_adduint(dest,global_argc ? global_argc-1 : 0);
-                       advance = 1;
-                       break;
-               case '{':
-                       b_getch(input);
-                       /* XXX maybe someone will try to escape the '}' */
-                       while(ch=b_getch(input),ch!=EOF && ch!='}') {
-                               b_addchr(&alt,ch);
-                       }
-                       if (ch != '}') {
-                               syntax();
-                               return 1;
-                       }
-                       lookup_param(dest, ctx, &alt);
-                       break;
-               case '(':
-                       b_getch(input);
-                       process_command_subs(dest, ctx, input, ')');
-                       break;
-               case '*':
-                       sep[0]=ifs[0];
-                       for (i=1; i<global_argc; i++) {
-                               parse_string(dest, ctx, global_argv[i]);
-                               if (i+1 < global_argc) parse_string(dest, ctx, sep);
-                       }
-                       break;
-               case '@':
-               case '-':
-               case '_':
-                       /* still unhandled, but should be eventually */
-                       error_msg("unhandled syntax: $%c",ch);
-                       return 1;
-                       break;
-               default:
-                       b_addqchr(dest,'$',dest->quote);
-       }
-       /* Eat the character if the flag was set.  If the compiler
-        * is smart enough, we could substitute "b_getch(input);"
-        * for all the "advance = 1;" above, and also end up with
-        * a nice size-optimized program.  Hah!  That'll be the day.
-        */
-       if (advance) b_getch(input);
-       return 0;
-}
-
-int parse_string(o_string *dest, struct p_context *ctx, const char *src)
-{
-       struct in_str foo;
-       setup_string_in_str(&foo, src);
-       return parse_stream(dest, ctx, &foo, '\0');
-}
-
-/* return code is 0 for normal exit, 1 for syntax error */
-int parse_stream(o_string *dest, struct p_context *ctx,
-       struct in_str *input, int end_trigger)
-{
-       unsigned int ch, m;
-       int redir_fd;
-       redir_type redir_style;
-       int next;
-
-       /* Only double-quote state is handled in the state variable dest->quote.
-        * A single-quote triggers a bypass of the main loop until its mate is
-        * found.  When recursing, quote state is passed in via dest->quote. */
-
-       debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
-       while ((ch=b_getch(input))!=EOF) {
-               m = map[ch];
-               next = (ch == '\n') ? 0 : b_peek(input);
-               debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
-                       ch,ch,m,dest->quote);
-               if (m==0 || ((m==1 || m==2) && dest->quote)) {
-                       b_addqchr(dest, ch, dest->quote);
-               } else {
-                       if (m==2) {  /* unquoted IFS */
-                               done_word(dest, ctx);
-                               /* If we aren't performing a substitution, treat a newline as a
-                                * command separator.  */
-                               if (end_trigger != '\0' && ch=='\n')
-                                       done_pipe(ctx,PIPE_SEQ);
-                       }
-                       if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
-                               debug_printf("leaving parse_stream (triggered)\n");
-                               return 0;
-                       }
-#if 0
-                       if (ch=='\n') {
-                               /* Yahoo!  Time to run with it! */
-                               done_pipe(ctx,PIPE_SEQ);
-                               run_list(ctx->list_head);
-                               initialize_context(ctx);
-                       }
-#endif
-                       if (m!=2) switch (ch) {
-               case '#':
-                       if (dest->length == 0 && !dest->quote) {
-                               while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
-                       } else {
-                               b_addqchr(dest, ch, dest->quote);
-                       }
-                       break;
-               case '\\':
-                       if (next == EOF) {
-                               syntax();
-                               return 1;
-                       }
-                       b_addqchr(dest, '\\', dest->quote);
-                       b_addqchr(dest, b_getch(input), dest->quote);
-                       break;
-               case '$':
-                       if (handle_dollar(dest, ctx, input)!=0) return 1;
-                       break;
-               case '\'':
-                       dest->nonnull = 1;
-                       while(ch=b_getch(input),ch!=EOF && ch!='\'') {
-                               b_addchr(dest,ch);
-                       }
-                       if (ch==EOF) {
-                               syntax();
-                               return 1;
-                       }
-                       break;
-               case '"':
-                       dest->nonnull = 1;
-                       dest->quote = !dest->quote;
-                       break;
-               case '`':
-                       process_command_subs(dest, ctx, input, '`');
-                       break;
-               case '>':
-                       redir_fd = redirect_opt_num(dest);
-                       done_word(dest, ctx);
-                       redir_style=REDIRECT_OVERWRITE;
-                       if (next == '>') {
-                               redir_style=REDIRECT_APPEND;
-                               b_getch(input);
-                       } else if (next == '(') {
-                               syntax();   /* until we support >(list) Process Substitution */
-                               return 1;
-                       }
-                       setup_redirect(ctx, redir_fd, redir_style, input);
-                       break;
-               case '<':
-                       redir_fd = redirect_opt_num(dest);
-                       done_word(dest, ctx);
-                       redir_style=REDIRECT_INPUT;
-                       if (next == '<') {
-                               redir_style=REDIRECT_HEREIS;
-                               b_getch(input);
-                       } else if (next == '>') {
-                               redir_style=REDIRECT_IO;
-                               b_getch(input);
-                       } else if (next == '(') {
-                               syntax();   /* until we support <(list) Process Substitution */
-                               return 1;
-                       }
-                       setup_redirect(ctx, redir_fd, redir_style, input);
-                       break;
-               case ';':
-                       done_word(dest, ctx);
-                       done_pipe(ctx,PIPE_SEQ);
-                       break;
-               case '&':
-                       done_word(dest, ctx);
-                       if (next=='&') {
-                               b_getch(input);
-                               done_pipe(ctx,PIPE_AND);
-                       } else {
-                               done_pipe(ctx,PIPE_BG);
-                       }
-                       break;
-               case '|':
-                       done_word(dest, ctx);
-                       if (next=='|') {
-                               b_getch(input);
-                               done_pipe(ctx,PIPE_OR);
-                       } else {
-                               /* we could pick up a file descriptor choice here
-                                * with redirect_opt_num(), but bash doesn't do it.
-                                * "echo foo 2| cat" yields "foo 2". */
-                               done_command(ctx);
-                       }
-                       break;
-               case '(':
-               case '{':
-                       if (parse_group(dest, ctx, input, ch)!=0) return 1;
-                       break;
-               case ')':
-               case '}':
-                       syntax();   /* Proper use of this character caught by end_trigger */
-                       return 1;
-                       break;
-               default:
-                       syntax();   /* this is really an internal logic error */
-                       return 1;
-                       }
-               }
-       }
-       /* complain if quote?  No, maybe we just finished a command substitution
-        * that was quoted.  Example:
-        * $ echo "`cat foo` plus more" 
-        * and we just got the EOF generated by the subshell that ran "cat foo"
-        * The only real complaint is if we got an EOF when end_trigger != '\0',
-        * that is, we were really supposed to get end_trigger, and never got
-        * one before the EOF.  Can't use the standard "syntax error" return code,
-        * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
-       debug_printf("leaving parse_stream (EOF)\n");
-       if (end_trigger != '\0') return -1;
-       return 0;
-}
-
-void mapset(const unsigned char *set, int code)
-{
-       const unsigned char *s;
-       for (s=set; *s; s++) map[*s] = code;
-}
-
-void update_ifs_map(void)
-{
-       /* char *ifs and char map[256] are both globals. */
-       ifs = getenv("IFS");
-       if (ifs == NULL) ifs=" \t\n";
-       /* Precompute a list of 'flow through' behavior so it can be treated
-        * quickly up front.  Computation is necessary because of IFS.
-        * Special case handling of IFS == " \t\n" is not implemented.
-        * The map[] array only really needs two bits each, and on most machines
-        * that would be faster because of the reduced L1 cache footprint.
-        */
-       memset(map,0,sizeof(map)); /* most characters flow through always */
-       mapset("\\$'\"`", 3);      /* never flow through */
-       mapset("<>;&|(){}#", 1);   /* flow through if quoted */
-       mapset(ifs, 2);            /* also flow through if quoted */
-}
-
-/* most recursion does not come through here, the exeception is
- * from builtin_source() */
-int parse_stream_outer(struct in_str *inp)
-{
-
-       struct p_context ctx;
-       o_string temp=NULL_O_STRING;
-       int rcode;
-       do {
-               initialize_context(&ctx);
-               update_ifs_map();
-               inp->promptmode=1;
-               rcode = parse_stream(&temp, &ctx, inp, '\n');
-               done_word(&temp, &ctx);
-               done_pipe(&ctx,PIPE_SEQ);
-               run_list(ctx.list_head);
-               b_free(&temp);
-       } while (rcode != -1);   /* loop on syntax errors, return on EOF */
-       return 0;
-}
-
-static int parse_string_outer(const char *s)
-{
-       struct in_str input;
-       setup_string_in_str(&input, s);
-       return parse_stream_outer(&input);
-}
-
-static int parse_file_outer(FILE *f)
-{
-       int rcode;
-       struct in_str input;
-       setup_file_in_str(&input, f);
-       rcode = parse_stream_outer(&input);
-       return rcode;
-}
-
-/* Make sure we have a controlling tty.  If we get started under a job
- * aware app (like bash for example), make sure we are now in charge so
- * we don't fight over who gets the foreground */
-static void setup_job_control()
-{
-       static pid_t shell_pgrp;
-       /* Loop until we are in the foreground.  */
-       while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
-               kill (- shell_pgrp, SIGTTIN);
-
-       /* Ignore interactive and job-control signals.  */
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGTERM, SIG_IGN);
-       signal(SIGTSTP, SIG_IGN);
-       signal(SIGTTIN, SIG_IGN);
-       signal(SIGTTOU, SIG_IGN);
-       signal(SIGCHLD, SIG_IGN);
-
-       /* Put ourselves in our own process group.  */
-       setsid();
-       shell_pgrp = getpid ();
-       setpgid (shell_pgrp, shell_pgrp);
-
-       /* Grab control of the terminal.  */
-       tcsetpgrp(shell_terminal, shell_pgrp);
-}
-
-int hush_main(int argc, char **argv)
-{
-       int opt;
-       FILE *input;
-       char **e = environ;
-
-       /* XXX what should these be while sourcing /etc/profile? */
-       global_argc = argc;
-       global_argv = argv;
-       
-       /* (re?) initialize globals.  Sometimes hush_main() ends up calling
-        * hush_main(), therefore we cannot rely on the BSS to zero out this 
-        * stuff.  Reset these to 0 every time. */
-       ifs = NULL;
-       /* map[] is taken care of with call to update_ifs_map() */
-       fake_mode = 0;
-       interactive = 0;
-       close_me_head = NULL;
-       last_bg_pid = 0;
-       job_list = NULL;
-       last_jobid = 0;
-
-       /* Initialize some more globals to non-zero values */
-       set_cwd();
-#ifdef BB_FEATURE_COMMAND_EDITING
-       cmdedit_set_initial_prompt();
-#else
-       PS1 = NULL;
-#endif
-       PS2 = "> ";
-
-       /* initialize our shell local variables with the values 
-        * currently living in the environment */
-       if (e) {
-               for (; *e; e++)
-                       set_local_var(*e, 2);   /* without call putenv() */
-       }
-
-       last_return_code=EXIT_SUCCESS;
-
-
-       if (argv[0] && argv[0][0] == '-') {
-               debug_printf("\nsourcing /etc/profile\n");
-               if ((input = fopen("/etc/profile", "r")) != NULL) {
-                       mark_open(fileno(input));
-                       parse_file_outer(input);
-                       mark_closed(fileno(input));
-                       fclose(input);
-               }
-       }
-       input=stdin;
-       
-       while ((opt = getopt(argc, argv, "c:xif")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               {
-                                       global_argv = argv+optind;
-                                       global_argc = argc-optind;
-                                       opt = parse_string_outer(optarg);
-                                       goto final_return;
-                               }
-                               break;
-                       case 'i':
-                               interactive++;
-                               break;
-                       case 'f':
-                               fake_mode++;
-                               break;
-                       default:
-#ifndef BB_VER
-                               fprintf(stderr, "Usage: sh [FILE]...\n"
-                                               "   or: sh -c command [args]...\n\n");
-                               exit(EXIT_FAILURE);
-#else
-                               show_usage();
-#endif
-               }
-       }
-       /* A shell is interactive if the `-i' flag was given, or if all of
-        * the following conditions are met:
-        *        no -c command
-        *    no arguments remaining or the -s flag given
-        *    standard input is a terminal
-        *    standard output is a terminal
-        *    Refer to Posix.2, the description of the `sh' utility. */
-       if (argv[optind]==NULL && input==stdin &&
-                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
-               interactive++;
-       }
-
-       debug_printf("\ninteractive=%d\n", interactive);
-       if (interactive) {
-               /* Looks like they want an interactive shell */
-               fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
-               setup_job_control();
-       }
-       
-       if (argv[optind]==NULL) {
-               opt=parse_file_outer(stdin);
-               goto final_return;
-       }
-
-       debug_printf("\nrunning script '%s'\n", argv[optind]);
-       global_argv = argv+optind;
-       global_argc = argc-optind;
-       input = xfopen(argv[optind], "r");
-       opt = parse_file_outer(input);
-
-#ifdef BB_FEATURE_CLEAN_UP
-       fclose(input);
-       if (cwd && cwd != unknown)
-               free((char*)cwd);
-       {
-               struct variables *cur, *tmp;
-               for(cur = top_vars; cur; cur = tmp) {
-                       tmp = cur->next;
-                       if (!cur->flg_read_only) {
-                               free(cur->name);
-                               free(cur->value);
-                               free(cur);
-                       }
-               }
-       }
-#endif
-
-final_return:
-       return(opt?opt:last_return_code);
-}
diff --git a/busybox/shell/lash.c b/busybox/shell/lash.c
deleted file mode 100644 (file)
index b3f7cb6..0000000
+++ /dev/null
@@ -1,1638 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * lash -- the BusyBox Lame-Ass SHell
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
- * under the following liberal license: "We have placed this source code in the
- * public domain. Use it in any project, free or commercial."
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* This shell's parsing engine is officially at a dead-end.
- * Future work shell work should be done using hush.c
- */
-
-//For debugging/development on the shell only...
-//#define DEBUG_SHELL
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <termios.h>
-#include "busybox.h"
-#include "cmdedit.h"
-
-#ifdef BB_LOCALE_SUPPORT
-#include <locale.h>
-#endif
-
-#include <glob.h>
-#define expand_t       glob_t
-
-
-static const int MAX_READ = 128;       /* size of input buffer for `read' builtin */
-#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
-
-
-enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
-       REDIRECT_APPEND
-};
-
-static const unsigned int DEFAULT_CONTEXT=0x1;
-static const unsigned int IF_TRUE_CONTEXT=0x2;
-static const unsigned int IF_FALSE_CONTEXT=0x4;
-static const unsigned int THEN_EXP_CONTEXT=0x8;
-static const unsigned int ELSE_EXP_CONTEXT=0x10;
-
-
-struct jobset {
-       struct job *head;                       /* head of list of running jobs */
-       struct job *fg;                         /* current foreground job */
-};
-
-struct redir_struct {
-       enum redir_type type;   /* type of redirection */
-       int fd;                                         /* file descriptor being redirected */
-       char *filename;                         /* file to redirect fd to */
-};
-
-struct child_prog {
-       pid_t pid;                                      /* 0 if exited */
-       char **argv;                            /* program name and arguments */
-       int num_redirects;                      /* elements in redirection array */
-       struct redir_struct *redirects; /* I/O redirects */
-       int is_stopped;                         /* is the program currently running? */
-       struct job *family;                     /* pointer back to the child's parent job */
-};
-
-struct job {
-       int jobid;                                      /* job number */
-       int num_progs;                          /* total number of programs in job */
-       int running_progs;                      /* number of programs running */
-       char *text;                                     /* name of job */
-       char *cmdbuf;                           /* buffer various argv's point into */
-       pid_t pgrp;                                     /* process group ID for the job */
-       struct child_prog *progs;       /* array of programs in job */
-       struct job *next;                       /* to track background commands */
-       int stopped_progs;                      /* number of programs alive, but stopped */
-       unsigned int job_context;       /* bitmask defining current context */
-       struct jobset *job_list;
-};
-
-struct built_in_command {
-       char *cmd;                                      /* name */
-       char *descr;                            /* description */
-       int (*function) (struct child_prog *);  /* function ptr */
-};
-
-struct close_me {
-       int fd;
-       struct close_me *next;
-};
-
-/* function prototypes for builtins */
-static int builtin_cd(struct child_prog *cmd);
-static int builtin_exec(struct child_prog *cmd);
-static int builtin_exit(struct child_prog *cmd);
-static int builtin_fg_bg(struct child_prog *cmd);
-static int builtin_help(struct child_prog *cmd);
-static int builtin_jobs(struct child_prog *dummy);
-static int builtin_pwd(struct child_prog *dummy);
-static int builtin_export(struct child_prog *cmd);
-static int builtin_source(struct child_prog *cmd);
-static int builtin_unset(struct child_prog *cmd);
-static int builtin_read(struct child_prog *cmd);
-
-
-/* function prototypes for shell stuff */
-static void mark_open(int fd);
-static void mark_closed(int fd);
-static void close_all(void);
-static void checkjobs(struct jobset *job_list);
-static void remove_job(struct jobset *j_list, struct job *job);
-static int get_command(FILE * source, char *command);
-static int parse_command(char **command_ptr, struct job *job, int *inbg);
-static int run_command(struct job *newjob, int inbg, int outpipe[2]);
-static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
-static int busy_loop(FILE * input);
-
-
-/* Table of built-in functions (these are non-forking builtins, meaning they
- * can change global variables in the parent shell process but they will not
- * work with pipes and redirects; 'unset foo | whatever' will not work) */
-static struct built_in_command bltins[] = {
-       {"bg", "Resume a job in the background", builtin_fg_bg},
-       {"cd", "Change working directory", builtin_cd},
-       {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
-       {"exit", "Exit from shell()", builtin_exit},
-       {"fg", "Bring job into the foreground", builtin_fg_bg},
-       {"jobs", "Lists the active jobs", builtin_jobs},
-       {"export", "Set environment variable", builtin_export},
-       {"unset", "Unset environment variable", builtin_unset},
-       {"read", "Input environment variable", builtin_read},
-       {".", "Source-in and run commands in a file", builtin_source},
-       /* to do: add ulimit */
-       {NULL, NULL, NULL}
-};
-
-/* Table of forking built-in functions (things that fork cannot change global
- * variables in the parent process, such as the current working directory) */
-static struct built_in_command bltins_forking[] = {
-       {"pwd", "Print current directory", builtin_pwd},
-       {"help", "List shell built-in commands", builtin_help},
-       {NULL, NULL, NULL}
-};
-
-
-static int shell_context;  /* Type prompt trigger (PS1 or PS2) */
-
-
-/* Globals that are static to this file */
-static const char *cwd;
-static char *local_pending_command = NULL;
-static struct jobset job_list = { NULL, NULL };
-static int argc;
-static char **argv;
-static struct close_me *close_me_head;
-static int last_return_code;
-static int last_bg_pid;
-static unsigned int last_jobid;
-static int shell_terminal;
-static pid_t shell_pgrp;
-static char *PS1;
-static char *PS2 = "> ";
-
-
-#ifdef DEBUG_SHELL
-static inline void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-}
-#else
-static inline void debug_printf(const char *format, ...) { }
-#endif
-
-/*
-       Most builtins need access to the struct child_prog that has
-       their arguments, previously coded as cmd->progs[0].  That coding
-       can exhibit a bug, if the builtin is not the first command in
-       a pipeline: "echo foo | exec sort" will attempt to exec foo.
-
-builtin   previous use      notes
------- -----------------  ---------
-cd      cmd->progs[0]
-exec    cmd->progs[0]  squashed bug: didn't look for applets or forking builtins
-exit    cmd->progs[0]
-fg_bg   cmd->progs[0], job_list->head, job_list->fg
-help    0
-jobs    job_list->head
-pwd     0
-export  cmd->progs[0]
-source  cmd->progs[0]
-unset   cmd->progs[0]
-read    cmd->progs[0]
-
-I added "struct job *family;" to struct child_prog,
-and switched API to builtin_foo(struct child_prog *child);
-So   cmd->text        becomes  child->family->text
-     cmd->job_context  becomes  child->family->job_context
-     cmd->progs[0]    becomes  *child
-     job_list          becomes  child->family->job_list
- */
-
-/* built-in 'cd <path>' handler */
-static int builtin_cd(struct child_prog *child)
-{
-       char *newdir;
-
-       if (child->argv[1] == NULL)
-               newdir = getenv("HOME");
-       else
-               newdir = child->argv[1];
-       if (chdir(newdir)) {
-               printf("cd: %s: %m\n", newdir);
-               return EXIT_FAILURE;
-       }
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'exec' handler */
-static int builtin_exec(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               return EXIT_SUCCESS;   /* Really? */
-       child->argv++;
-       close_all();
-       pseudo_exec(child);
-       /* never returns */
-}
-
-/* built-in 'exit' handler */
-static int builtin_exit(struct child_prog *child)
-{
-       if (child->argv[1] == NULL)
-               exit(EXIT_SUCCESS);
-
-       exit (atoi(child->argv[1]));
-}
-
-/* built-in 'fg' and 'bg' handler */
-static int builtin_fg_bg(struct child_prog *child)
-{
-       int i, jobnum;
-       struct job *job=NULL;
-
-       /* If they gave us no args, assume they want the last backgrounded task */
-       if (!child->argv[1]) {
-               for (job = child->family->job_list->head; job; job = job->next) {
-                       if (job->jobid == last_jobid) {
-                               break;
-                       }
-               }
-               if (!job) {
-                       error_msg("%s: no current job", child->argv[0]);
-                       return EXIT_FAILURE;
-               }
-       } else {
-               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
-                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
-                       return EXIT_FAILURE;
-               }
-               for (job = child->family->job_list->head; job; job = job->next) {
-                       if (job->jobid == jobnum) {
-                               break;
-                       }
-               }
-               if (!job) {
-                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       if (*child->argv[0] == 'f') {
-               /* Put the job into the foreground.  */
-               tcsetpgrp(shell_terminal, job->pgrp);
-
-               child->family->job_list->fg = job;
-       }
-
-       /* Restart the processes in the job */
-       for (i = 0; i < job->num_progs; i++)
-               job->progs[i].is_stopped = 0;
-
-       job->stopped_progs = 0;
-
-       if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
-               if (i == ESRCH) {
-                       remove_job(&job_list, job);
-               } else {
-                       perror_msg("kill (SIGCONT)");
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'help' handler */
-static int builtin_help(struct child_prog *dummy)
-{
-       struct built_in_command *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-       for (x = bltins; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       for (x = bltins_forking; x->cmd; x++) {
-               if (x->descr==NULL)
-                       continue;
-               printf("%s\t%s\n", x->cmd, x->descr);
-       }
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'jobs' handler */
-static int builtin_jobs(struct child_prog *child)
-{
-       struct job *job;
-       char *status_string;
-
-       for (job = child->family->job_list->head; job; job = job->next) {
-               if (job->running_progs == job->stopped_progs)
-                       status_string = "Stopped";
-               else
-                       status_string = "Running";
-
-               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
-       }
-       return EXIT_SUCCESS;
-}
-
-
-/* built-in 'pwd' handler */
-static int builtin_pwd(struct child_prog *dummy)
-{
-       cwd = xgetcwd((char *)cwd);
-       if (!cwd)
-               cwd = unknown;
-       puts(cwd);
-       return EXIT_SUCCESS;
-}
-
-/* built-in 'export VAR=value' handler */
-static int builtin_export(struct child_prog *child)
-{
-       int res;
-       char *v = child->argv[1];
-
-       if (v == NULL) {
-               char **e;
-               for (e = environ; *e; e++) {
-                       puts(*e);
-               }
-               return 0;
-       }
-       res = putenv(v);
-       if (res)
-               fprintf(stderr, "export: %m\n");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (strncmp(v, "PS1=", 4)==0)
-               PS1 = getenv("PS1");
-#endif
-
-#ifdef BB_LOCALE_SUPPORT
-       if(strncmp(v, "LC_ALL=", 7)==0)
-               setlocale(LC_ALL, getenv("LC_ALL"));
-       if(strncmp(v, "LC_CTYPE=", 9)==0)
-               setlocale(LC_CTYPE, getenv("LC_CTYPE"));
-#endif
-
-       return (res);
-}
-
-/* built-in 'read VAR' handler */
-static int builtin_read(struct child_prog *child)
-{
-       int res = 0, len, newlen;
-       char *s;
-       char string[MAX_READ];
-
-       if (child->argv[1]) {
-               /* argument (VAR) given: put "VAR=" into buffer */
-               strcpy(string, child->argv[1]);
-               len = strlen(string);
-               string[len++] = '=';
-               string[len]   = '\0';
-               fgets(&string[len], sizeof(string) - len, stdin);       /* read string */
-               newlen = strlen(string);
-               if(newlen > len)
-                       string[--newlen] = '\0';        /* chomp trailing newline */
-               /*
-               ** string should now contain "VAR=<value>"
-               ** copy it (putenv() won't do that, so we must make sure
-               ** the string resides in a static buffer!)
-               */
-               res = -1;
-               if((s = strdup(string)))
-                       res = putenv(s);
-               if (res)
-                       fprintf(stderr, "read: %m\n");
-       }
-       else
-               fgets(string, sizeof(string), stdin);
-
-       return (res);
-}
-
-/* Built-in '.' handler (read-in and execute commands from file) */
-static int builtin_source(struct child_prog *child)
-{
-       FILE *input;
-       int status;
-       int fd;
-
-       if (child->argv[1] == NULL)
-               return EXIT_FAILURE;
-
-       input = fopen(child->argv[1], "r");
-       if (!input) {
-               printf( "Couldn't open file '%s'\n", child->argv[1]);
-               return EXIT_FAILURE;
-       }
-
-       fd=fileno(input);
-       mark_open(fd);
-       /* Now run the file */
-       status = busy_loop(input);
-       fclose(input);
-       mark_closed(fd);
-       return (status);
-}
-
-/* built-in 'unset VAR' handler */
-static int builtin_unset(struct child_prog *child)
-{
-       if (child->argv[1] == NULL) {
-               printf( "unset: parameter required.\n");
-               return EXIT_FAILURE;
-       }
-       unsetenv(child->argv[1]);
-       return EXIT_SUCCESS;
-}
-
-static void mark_open(int fd)
-{
-       struct close_me *new = xmalloc(sizeof(struct close_me));
-       new->fd = fd;
-       new->next = close_me_head;
-       close_me_head = new;
-}
-
-static void mark_closed(int fd)
-{
-       struct close_me *tmp;
-       if (close_me_head == NULL || close_me_head->fd != fd)
-               error_msg_and_die("corrupt close_me");
-       tmp = close_me_head;
-       close_me_head = close_me_head->next;
-       free(tmp);
-}
-
-static void close_all()
-{
-       struct close_me *c, *tmp;
-       for (c=close_me_head; c; c=tmp) {
-               close(c->fd);
-               tmp=c->next;
-               free(c);
-       }
-       close_me_head = NULL;
-}
-
-
-/* free up all memory from a job */
-static void free_job(struct job *cmd)
-{
-       int i;
-       struct jobset *keep;
-
-       for (i = 0; i < cmd->num_progs; i++) {
-               free(cmd->progs[i].argv);
-               if (cmd->progs[i].redirects)
-                       free(cmd->progs[i].redirects);
-       }
-       if (cmd->progs)
-               free(cmd->progs);
-       if (cmd->text)
-               free(cmd->text);
-       if (cmd->cmdbuf)
-               free(cmd->cmdbuf);
-       keep = cmd->job_list;
-       memset(cmd, 0, sizeof(struct job));
-       cmd->job_list = keep;
-}
-
-/* remove a job from a jobset */
-static void remove_job(struct jobset *j_list, struct job *job)
-{
-       struct job *prevjob;
-
-       free_job(job);
-       if (job == j_list->head) {
-               j_list->head = job->next;
-       } else {
-               prevjob = j_list->head;
-               while (prevjob->next != job)
-                       prevjob = prevjob->next;
-               prevjob->next = job->next;
-       }
-
-       if (j_list->head)
-               last_jobid = j_list->head->jobid;
-       else
-               last_jobid = 0;
-
-       free(job);
-}
-
-/* Checks to see if any background processes have exited -- if they 
-   have, figure out why and see if a job has completed */
-static void checkjobs(struct jobset *j_list)
-{
-       struct job *job;
-       pid_t childpid;
-       int status;
-       int prognum = 0;
-
-       while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
-               for (job = j_list->head; job; job = job->next) {
-                       prognum = 0;
-                       while (prognum < job->num_progs &&
-                                  job->progs[prognum].pid != childpid) prognum++;
-                       if (prognum < job->num_progs)
-                               break;
-               }
-
-               /* This happens on backticked commands */
-               if(job==NULL)
-                       return;
-
-               if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                       /* child exited */
-                       job->running_progs--;
-                       job->progs[prognum].pid = 0;
-
-                       if (!job->running_progs) {
-                               printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
-                               last_jobid=0;
-                               remove_job(j_list, job);
-                       }
-               } else {
-                       /* child stopped */
-                       job->stopped_progs++;
-                       job->progs[prognum].is_stopped = 1;
-
-#if 0
-                       /* Printing this stuff is a pain, since it tends to
-                        * overwrite the prompt an inconveinient moments.  So
-                        * don't do that.  */
-                       if (job->stopped_progs == job->num_progs) {
-                               printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
-                                          job->text);
-                       }
-#endif 
-               }
-       }
-
-       if (childpid == -1 && errno != ECHILD)
-               perror_msg("waitpid");
-}
-
-/* squirrel != NULL means we squirrel away copies of stdin, stdout,
- * and stderr if they are redirected. */
-static int setup_redirects(struct child_prog *prog, int squirrel[])
-{
-       int i;
-       int openfd;
-       int mode = O_RDONLY;
-       struct redir_struct *redir = prog->redirects;
-
-       for (i = 0; i < prog->num_redirects; i++, redir++) {
-               switch (redir->type) {
-               case REDIRECT_INPUT:
-                       mode = O_RDONLY;
-                       break;
-               case REDIRECT_OVERWRITE:
-                       mode = O_WRONLY | O_CREAT | O_TRUNC;
-                       break;
-               case REDIRECT_APPEND:
-                       mode = O_WRONLY | O_CREAT | O_APPEND;
-                       break;
-               }
-
-               openfd = open(redir->filename, mode, 0666);
-               if (openfd < 0) {
-                       /* this could get lost if stderr has been redirected, but
-                          bash and ash both lose it as well (though zsh doesn't!) */
-                       perror_msg("error opening %s", redir->filename);
-                       return 1;
-               }
-
-               if (openfd != redir->fd) {
-                       if (squirrel && redir->fd < 3) {
-                               squirrel[redir->fd] = dup(redir->fd);
-                       }
-                       dup2(openfd, redir->fd);
-                       close(openfd);
-               }
-       }
-
-       return 0;
-}
-
-static void restore_redirects(int squirrel[])
-{
-       int i, fd;
-       for (i=0; i<3; i++) {
-               fd = squirrel[i];
-               if (fd != -1) {
-                       /* No error checking.  I sure wouldn't know what
-                        * to do with an error if I found one! */
-                       dup2(fd, i);
-                       close(fd);
-               }
-       }
-}
-
-static inline void cmdedit_set_initial_prompt(void)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       PS1 = NULL;
-#else
-       PS1 = getenv("PS1");
-       if(PS1==0)
-               PS1 = "\\w \\$ ";
-#endif 
-}
-
-static inline void setup_prompt_string(char **prompt_str)
-{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
-       /* Set up the prompt */
-       if (shell_context == 0) {
-               if (PS1)
-                       free(PS1);
-               PS1=xmalloc(strlen(cwd)+4);
-               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
-               *prompt_str = PS1;
-       } else {
-               *prompt_str = PS2;
-       }
-#else
-       *prompt_str = (shell_context==0)? PS1 : PS2;
-#endif 
-}
-
-static int get_command(FILE * source, char *command)
-{
-       char *prompt_str;
-
-       if (source == NULL) {
-               if (local_pending_command) {
-                       /* a command specified (-c option): return it & mark it done */
-                       strcpy(command, local_pending_command);
-                       free(local_pending_command);
-                       local_pending_command = NULL;
-                       return 0;
-               }
-               return 1;
-       }
-
-       if (source == stdin) {
-               setup_prompt_string(&prompt_str);
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-               /*
-               ** enable command line editing only while a command line
-               ** is actually being read; otherwise, we'll end up bequeathing
-               ** atexit() handlers and other unwanted stuff to our
-               ** child processes (rob@sysgo.de)
-               */
-               cmdedit_read_input(prompt_str, command);
-               return 0;
-#else
-               fputs(prompt_str, stdout);
-#endif
-       }
-
-       if (!fgets(command, BUFSIZ - 2, source)) {
-               if (source == stdin)
-                       printf("\n");
-               return 1;
-       }
-
-       return 0;
-}
-
-static char* itoa(register int i)
-{
-       static char a[7]; /* Max 7 ints */
-       register char *b = a + sizeof(a) - 1;
-       int   sign = (i < 0);
-
-       if (sign)
-               i = -i;
-       *b = 0;
-       do
-       {
-               *--b = '0' + (i % 10);
-               i /= 10;
-       }
-       while (i);
-       if (sign)
-               *--b = '-';
-       return b;
-}
-
-char * strsep_space( char *string, int * ix)
-{
-       char *token, *begin;
-
-       begin = string;
-
-       /* Short circuit the trivial case */
-       if ( !string || ! string[*ix])
-               return NULL;
-
-       /* Find the end of the token. */
-       while( string && string[*ix] && !isspace(string[*ix]) ) {
-               (*ix)++;
-       }
-
-       /* Find the end of any whitespace trailing behind 
-        * the token and let that be part of the token */
-       while( string && string[*ix] && isspace(string[*ix]) ) {
-               (*ix)++;
-       }
-
-       if (! string && *ix==0) {
-               /* Nothing useful was found */
-               return NULL;
-       }
-
-       token = xmalloc(*ix+1);
-       token[*ix] = '\0';
-       strncpy(token, string,  *ix); 
-
-       return token;
-}
-
-static int expand_arguments(char *command)
-{
-       int total_length=0, length, i, retval, ix = 0;
-       expand_t expand_result;
-       char *tmpcmd, *cmd, *cmd_copy;
-       char *src, *dst, *var;
-       const char *out_of_space = "out of space during expansion";
-       int flags = GLOB_NOCHECK
-#ifdef GLOB_BRACE
-               | GLOB_BRACE
-#endif 
-#ifdef GLOB_TILDE
-               | GLOB_TILDE
-#endif 
-               ;
-
-       /* get rid of the terminating \n */
-       chomp(command);
-
-       /* Fix up escape sequences to be the Real Thing(tm) */
-       while( command && command[ix]) {
-               if (command[ix] == '\\') {
-                       const char *tmp = command+ix+1;
-                       command[ix] = process_escape_sequence(  &tmp );
-                       memmove(command+ix + 1, tmp, strlen(tmp)+1);
-               }
-               ix++;
-       }
-       /* Use glob and then fixup environment variables and such */
-
-       /* It turns out that glob is very stupid.  We have to feed it one word at a
-        * time since it can't cope with a full string.  Here we convert command
-        * (char*) into cmd (char**, one word per string) */
-
-       /* We need a clean copy, so strsep can mess up the copy while
-        * we write stuff into the original (in a minute) */
-       cmd = cmd_copy = strdup(command);
-       *command = '\0';
-       for (ix = 0, tmpcmd = cmd; 
-                       (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
-               if (*tmpcmd == '\0')
-                       break;
-               /* we need to trim() the result for glob! */
-               trim(tmpcmd);
-               retval = glob(tmpcmd, flags, NULL, &expand_result);
-               free(tmpcmd); /* Free mem allocated by strsep_space */
-               if (retval == GLOB_NOSPACE) {
-                       /* Mem may have been allocated... */
-                       globfree (&expand_result);
-                       error_msg(out_of_space);
-                       return FALSE;
-               } else if (retval != 0) {
-                       /* Some other error.  GLOB_NOMATCH shouldn't
-                        * happen because of the GLOB_NOCHECK flag in 
-                        * the glob call. */
-                       error_msg("syntax error");
-                       return FALSE;
-               } else {
-                       /* Convert from char** (one word per string) to a simple char*,
-                        * but don't overflow command which is BUFSIZ in length */
-                       for (i=0; i < expand_result.gl_pathc; i++) {
-                               length=strlen(expand_result.gl_pathv[i]);
-                               if (total_length+length+1 >= BUFSIZ) {
-                                       error_msg(out_of_space);
-                                       return FALSE;
-                               }
-                               strcat(command+total_length, " ");
-                               total_length+=1;
-                               strcat(command+total_length, expand_result.gl_pathv[i]);
-                               total_length+=length;
-                       }
-                       globfree (&expand_result);
-               }
-       }
-       free(cmd_copy);
-       trim(command);
-
-       /* Now do the shell variable substitutions which 
-        * wordexp can't do for us, namely $? and $! */
-       src = command;
-       while((dst = strchr(src,'$')) != NULL){
-               var = NULL;
-               switch(*(dst+1)) {
-                       case '?':
-                               var = itoa(last_return_code);
-                               break;
-                       case '!':
-                               if (last_bg_pid==-1)
-                                       *(var)='\0';
-                               else
-                                       var = itoa(last_bg_pid);
-                               break;
-                               /* Everything else like $$, $#, $[0-9], etc. should all be
-                                * expanded by wordexp(), so we can in theory skip that stuff
-                                * here, but just to be on the safe side (i.e., since uClibc
-                                * wordexp doesn't do this stuff yet), lets leave it in for
-                                * now. */
-                       case '$':
-                               var = itoa(getpid());
-                               break;
-                       case '#':
-                               var = itoa(argc-1);
-                               break;
-                       case '0':case '1':case '2':case '3':case '4':
-                       case '5':case '6':case '7':case '8':case '9':
-                               {
-                                       int ixx=*(dst + 1)-48;
-                                       if (ixx >= argc) {
-                                               var='\0';
-                                       } else {
-                                               var = argv[ixx];
-                                       }
-                               }
-                               break;
-
-               }
-               if (var) {
-                       /* a single character construction was found, and 
-                        * already handled in the case statement */
-                       src=dst+2;
-               } else {
-                       /* Looks like an environment variable */
-                       char delim_hold;
-                       int num_skip_chars=0;
-                       int dstlen = strlen(dst);
-                       /* Is this a ${foo} type variable? */
-                       if (dstlen >=2 && *(dst+1) == '{') {
-                               src=strchr(dst+1, '}');
-                               num_skip_chars=1;
-                       } else {
-                               src=dst+1;
-                               while(isalnum(*src) || *src=='_') src++;
-                       }
-                       if (src == NULL) {
-                               src = dst+dstlen;
-                       }
-                       delim_hold=*src;
-                       *src='\0';  /* temporary */
-                       var = getenv(dst + 1 + num_skip_chars);
-                       *src=delim_hold;
-                       src += num_skip_chars;
-               }
-               if (var == NULL) {
-                       /* Seems we got an un-expandable variable.  So delete it. */
-                       var = "";
-               }
-               {
-                       int subst_len = strlen(var);
-                       int trail_len = strlen(src);
-                       if (dst+subst_len+trail_len >= command+BUFSIZ) {
-                               error_msg(out_of_space);
-                               return FALSE;
-                       }
-                       /* Move stuff to the end of the string to accommodate
-                        * filling the created gap with the new stuff */
-                       memmove(dst+subst_len, src, trail_len+1);
-                       /* Now copy in the new stuff */
-                       memcpy(dst, var, subst_len);
-                       src = dst+subst_len;
-               }
-       }
-
-       return TRUE;
-}
-
-/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
-   line). If a valid command is found, command_ptr is set to point to
-   the beginning of the next command (if the original command had more 
-   then one job associated with it) or NULL if no more commands are 
-   present. */
-static int parse_command(char **command_ptr, struct job *job, int *inbg)
-{
-       char *command;
-       char *return_command = NULL;
-       char *src, *buf, *chptr;
-       int argc_l = 0;
-       int done = 0;
-       int argv_alloced;
-       int i, saw_quote = 0;
-       char quote = '\0';
-       int count;
-       struct child_prog *prog;
-
-       /* skip leading white space */
-       while (**command_ptr && isspace(**command_ptr))
-               (*command_ptr)++;
-
-       /* this handles empty lines or leading '#' characters */
-       if (!**command_ptr || (**command_ptr == '#')) {
-               job->num_progs=0;
-               return 0;
-       }
-
-       *inbg = 0;
-       job->num_progs = 1;
-       job->progs = xmalloc(sizeof(*job->progs));
-
-       /* We set the argv elements to point inside of this string. The 
-          memory is freed by free_job(). Allocate twice the original
-          length in case we need to quote every single character.
-
-          Getting clean memory relieves us of the task of NULL 
-          terminating things and makes the rest of this look a bit 
-          cleaner (though it is, admittedly, a tad less efficient) */
-       job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
-       job->text = NULL;
-
-       prog = job->progs;
-       prog->num_redirects = 0;
-       prog->redirects = NULL;
-       prog->is_stopped = 0;
-       prog->family = job;
-
-       argv_alloced = 5;
-       prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
-       prog->argv[0] = job->cmdbuf;
-
-       buf = command;
-       src = *command_ptr;
-       while (*src && !done) {
-               if (quote == *src) {
-                       quote = '\0';
-               } else if (quote) {
-                       if (*src == '\\') {
-                               src++;
-                               if (!*src) {
-                                       error_msg("character expected after \\");
-                                       free_job(job);
-                                       return 1;
-                               }
-
-                               /* in shell, "\'" should yield \' */
-                               if (*src != quote) {
-                                       *buf++ = '\\';
-                                       *buf++ = '\\';
-                               }
-                       } else if (*src == '*' || *src == '?' || *src == '[' ||
-                                          *src == ']') *buf++ = '\\';
-                       *buf++ = *src;
-               } else if (isspace(*src)) {
-                       if (*prog->argv[argc_l] || saw_quote) {
-                               buf++, argc_l++;
-                               /* +1 here leaves room for the NULL which ends argv */
-                               if ((argc_l + 1) == argv_alloced) {
-                                       argv_alloced += 5;
-                                       prog->argv = xrealloc(prog->argv,
-                                                                                 sizeof(*prog->argv) *
-                                                                                 argv_alloced);
-                               }
-                               prog->argv[argc_l] = buf;
-                               saw_quote = 0;
-                       }
-               } else
-                       switch (*src) {
-                       case '"':
-                       case '\'':
-                               quote = *src;
-                               saw_quote = 1;
-                               break;
-
-                       case '#':                       /* comment */
-                               if (*(src-1)== '$')
-                                       *buf++ = *src;
-                               else
-                                       done = 1;
-                               break;
-
-                       case '>':                       /* redirects */
-                       case '<':
-                               i = prog->num_redirects++;
-                               prog->redirects = xrealloc(prog->redirects,
-                                                                                         sizeof(*prog->redirects) *
-                                                                                         (i + 1));
-
-                               prog->redirects[i].fd = -1;
-                               if (buf != prog->argv[argc_l]) {
-                                       /* the stuff before this character may be the file number 
-                                          being redirected */
-                                       prog->redirects[i].fd =
-                                               strtol(prog->argv[argc_l], &chptr, 10);
-
-                                       if (*chptr && *prog->argv[argc_l]) {
-                                               buf++, argc_l++;
-                                               prog->argv[argc_l] = buf;
-                                       }
-                               }
-
-                               if (prog->redirects[i].fd == -1) {
-                                       if (*src == '>')
-                                               prog->redirects[i].fd = 1;
-                                       else
-                                               prog->redirects[i].fd = 0;
-                               }
-
-                               if (*src++ == '>') {
-                                       if (*src == '>')
-                                               prog->redirects[i].type =
-                                                       REDIRECT_APPEND, src++;
-                                       else
-                                               prog->redirects[i].type = REDIRECT_OVERWRITE;
-                               } else {
-                                       prog->redirects[i].type = REDIRECT_INPUT;
-                               }
-
-                               /* This isn't POSIX sh compliant. Oh well. */
-                               chptr = src;
-                               while (isspace(*chptr))
-                                       chptr++;
-
-                               if (!*chptr) {
-                                       error_msg("file name expected after %c", *(src-1));
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-
-                               prog->redirects[i].filename = buf;
-                               while (*chptr && !isspace(*chptr))
-                                       *buf++ = *chptr++;
-
-                               src = chptr - 1;        /* we src++ later */
-                               prog->argv[argc_l] = ++buf;
-                               break;
-
-                       case '|':                       /* pipe */
-                               /* finish this command */
-                               if (*prog->argv[argc_l] || saw_quote)
-                                       argc_l++;
-                               if (!argc_l) {
-                                       error_msg("empty command in pipe");
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-                               prog->argv[argc_l] = NULL;
-
-                               /* and start the next */
-                               job->num_progs++;
-                               job->progs = xrealloc(job->progs,
-                                                                         sizeof(*job->progs) * job->num_progs);
-                               prog = job->progs + (job->num_progs - 1);
-                               prog->num_redirects = 0;
-                               prog->redirects = NULL;
-                               prog->is_stopped = 0;
-                               prog->family = job;
-                               argc_l = 0;
-
-                               argv_alloced = 5;
-                               prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
-                               prog->argv[0] = ++buf;
-
-                               src++;
-                               while (*src && isspace(*src))
-                                       src++;
-
-                               if (!*src) {
-                                       error_msg("empty command in pipe");
-                                       free_job(job);
-                                       job->num_progs=0;
-                                       return 1;
-                               }
-                               src--;                  /* we'll ++ it at the end of the loop */
-
-                               break;
-
-                       case '&':                       /* background */
-                               *inbg = 1;
-                       case ';':                       /* multiple commands */
-                               done = 1;
-                               return_command = *command_ptr + (src - *command_ptr) + 1;
-                               break;
-
-                       case '\\':
-                               src++;
-                               if (!*src) {
-                                       error_msg("character expected after \\");
-                                       free_job(job);
-                                       return 1;
-                               }
-                               if (*src == '*' || *src == '[' || *src == ']'
-                                       || *src == '?') *buf++ = '\\';
-                               /* fallthrough */
-                       default:
-                               *buf++ = *src;
-                       }
-
-               src++;
-       }
-
-       if (*prog->argv[argc_l] || saw_quote) {
-               argc_l++;
-       }
-       if (!argc_l) {
-               free_job(job);
-               return 0;
-       }
-       prog->argv[argc_l] = NULL;
-
-       if (!return_command) {
-               job->text = xmalloc(strlen(*command_ptr) + 1);
-               strcpy(job->text, *command_ptr);
-       } else {
-               /* This leaves any trailing spaces, which is a bit sloppy */
-               count = return_command - *command_ptr;
-               job->text = xmalloc(count + 1);
-               strncpy(job->text, *command_ptr, count);
-               job->text[count] = '\0';
-       }
-
-       *command_ptr = return_command;
-       
-       return 0;
-}
-
-/* Run the child_prog, no matter what kind of command it uses.
- */
-static int pseudo_exec(struct child_prog *child)
-{
-       struct built_in_command *x;
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name;
-#endif
-
-       /* Check if the command matches any of the non-forking builtins.
-        * Depending on context, this might be redundant.  But it's
-        * easier to waste a few CPU cycles than it is to figure out
-        * if this is one of those cases.
-        */
-       for (x = bltins; x->cmd; x++) {
-               if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                       exit(x->function(child));
-               }
-       }
-
-       /* Check if the command matches any of the forking builtins. */
-       for (x = bltins_forking; x->cmd; x++) {
-               if (strcmp(child->argv[0], x->cmd) == 0) {
-                       applet_name=x->cmd;
-                       exit (x->function(child));
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       /* Check if the command matches any busybox internal
-        * commands ("applets") here.  Following discussions from
-        * November 2000 on busybox@opensource.lineo.com, don't use
-        * get_last_path_component().  This way explicit (with
-        * slashes) filenames will never be interpreted as an
-        * applet, just like with builtins.  This way the user can
-        * override an applet with an explicit filename reference.
-        * The only downside to this change is that an explicit
-        * /bin/foo invocation will fork and exec /bin/foo, even if
-        * /bin/foo is a symlink to busybox.
-        */
-       name = child->argv[0];
-
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
-        * if you run /bin/cat, it will use BusyBox cat even if 
-        * /bin/cat exists on the filesystem and is _not_ busybox.
-        * Some systems want this, others do not.  Choose wisely.  :-)
-        */
-       name = get_last_path_component(name);
-#endif
-
-       {
-           char** argv_l=child->argv;
-           int argc_l;
-           for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
-           optind = 1;
-           run_applet_by_name(name, argc_l, child->argv);
-       }
-#endif
-
-       execvp(child->argv[0], child->argv);
-       perror_msg_and_die("%s", child->argv[0]);
-}
-
-static void insert_job(struct job *newjob, int inbg)
-{
-       struct job *thejob;
-       struct jobset *j_list=newjob->job_list;
-
-       /* find the ID for thejob to use */
-       newjob->jobid = 1;
-       for (thejob = j_list->head; thejob; thejob = thejob->next)
-               if (thejob->jobid >= newjob->jobid)
-                       newjob->jobid = thejob->jobid + 1;
-
-       /* add thejob to the list of running jobs */
-       if (!j_list->head) {
-               thejob = j_list->head = xmalloc(sizeof(*thejob));
-       } else {
-               for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
-               thejob->next = xmalloc(sizeof(*thejob));
-               thejob = thejob->next;
-       }
-
-       *thejob = *newjob;   /* physically copy the struct job */
-       thejob->next = NULL;
-       thejob->running_progs = thejob->num_progs;
-       thejob->stopped_progs = 0;
-
-       if (inbg) {
-               /* we don't wait for background thejobs to return -- append it 
-                  to the list of backgrounded thejobs and leave it alone */
-               printf("[%d] %d\n", thejob->jobid,
-                          newjob->progs[newjob->num_progs - 1].pid);
-               last_jobid = newjob->jobid;
-               last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
-       } else {
-               newjob->job_list->fg = thejob;
-
-               /* move the new process group into the foreground */
-               /* suppress messages when run from /linuxrc mag@sysgo.de */
-               if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
-                       perror_msg("tcsetpgrp");
-       }
-}
-
-static int run_command(struct job *newjob, int inbg, int outpipe[2])
-{
-       /* struct job *thejob; */
-       int i;
-       int nextin, nextout;
-       int pipefds[2];                         /* pipefd[0] is for reading */
-       struct built_in_command *x;
-       struct child_prog *child;
-
-       nextin = 0, nextout = 1;
-       for (i = 0; i < newjob->num_progs; i++) {
-               child = & (newjob->progs[i]);
-
-               if ((i + 1) < newjob->num_progs) {
-                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
-                       nextout = pipefds[1];
-               } else {
-                       if (outpipe[1]!=-1) {
-                               nextout = outpipe[1];
-                       } else {
-                               nextout = 1;
-                       }
-               }
-
-
-               /* Check if the command matches any non-forking builtins,
-                * but only if this is a simple command.
-                * Non-forking builtins within pipes have to fork anyway,
-                * and are handled in pseudo_exec.  "echo foo | read bar"
-                * is doomed to failure, and doesn't work on bash, either.
-                */
-               if (newjob->num_progs == 1) {
-                       for (x = bltins; x->cmd; x++) {
-                               if (strcmp(child->argv[0], x->cmd) == 0 ) {
-                                       int squirrel[] = {-1, -1, -1};
-                                       int rcode;
-                                       setup_redirects(child, squirrel);
-                                       rcode = x->function(child);
-                                       restore_redirects(squirrel);
-                                       return rcode;
-                               }
-                       }
-               }
-
-               if (!(child->pid = fork())) {
-                       /* Set the handling for job control signals back to the default.  */
-                       signal(SIGINT, SIG_DFL);
-                       signal(SIGQUIT, SIG_DFL);
-                       signal(SIGTSTP, SIG_DFL);
-                       signal(SIGTTIN, SIG_DFL);
-                       signal(SIGTTOU, SIG_DFL);
-                       signal(SIGCHLD, SIG_DFL);
-
-                       close_all();
-
-                       if (outpipe[1]!=-1) {
-                               close(outpipe[0]);
-                       }
-                       if (nextin != 0) {
-                               dup2(nextin, 0);
-                               close(nextin);
-                       }
-
-                       if (nextout != 1) {
-                               dup2(nextout, 1);
-                               dup2(nextout, 2);  /* Really? */
-                               close(nextout);
-                               close(pipefds[0]);
-                       }
-
-                       /* explicit redirects override pipes */
-                       setup_redirects(child,NULL);
-
-                       pseudo_exec(child);
-               }
-               if (outpipe[1]!=-1) {
-                       close(outpipe[1]);
-               }
-
-               /* put our child in the process group whose leader is the
-                  first process in this pipe */
-               setpgid(child->pid, newjob->progs[0].pid);
-               if (nextin != 0)
-                       close(nextin);
-               if (nextout != 1)
-                       close(nextout);
-
-               /* If there isn't another process, nextin is garbage 
-                  but it doesn't matter */
-               nextin = pipefds[0];
-       }
-
-       newjob->pgrp = newjob->progs[0].pid;
-
-       insert_job(newjob, inbg);
-
-       return 0;
-}
-
-static int busy_loop(FILE * input)
-{
-       char *command;
-       char *next_command = NULL;
-       struct job newjob;
-       pid_t  parent_pgrp;
-       int i;
-       int inbg;
-       int status;
-       newjob.job_list = &job_list;
-       newjob.job_context = DEFAULT_CONTEXT;
-
-       /* save current owner of TTY so we can restore it on exit */
-       parent_pgrp = tcgetpgrp(shell_terminal);
-
-       command = (char *) xcalloc(BUFSIZ, sizeof(char));
-
-       while (1) {
-               if (!job_list.fg) {
-                       /* no job is in the foreground */
-
-                       /* see if any background processes have exited */
-                       checkjobs(&job_list);
-
-                       if (!next_command) {
-                               if (get_command(input, command))
-                                       break;
-                               next_command = command;
-                       }
-
-                       if (expand_arguments(next_command) == FALSE) {
-                               free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
-                               next_command = NULL;
-                               continue;
-                       }
-
-                       if (!parse_command(&next_command, &newjob, &inbg) &&
-                               newjob.num_progs) {
-                               int pipefds[2] = {-1,-1};
-                               debug_printf( "job=%p fed to run_command by busy_loop()'\n", 
-                                               &newjob);
-                               run_command(&newjob, inbg, pipefds);
-                       }
-                       else {
-                               free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
-                               next_command = NULL;
-                       }
-               } else {
-                       /* a job is running in the foreground; wait for it */
-                       i = 0;
-                       while (!job_list.fg->progs[i].pid ||
-                                  job_list.fg->progs[i].is_stopped == 1) i++;
-
-                       if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0)
-                               perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
-
-                       if (WIFEXITED(status) || WIFSIGNALED(status)) {
-                               /* the child exited */
-                               job_list.fg->running_progs--;
-                               job_list.fg->progs[i].pid = 0;
-
-                               last_return_code=WEXITSTATUS(status);
-
-                               if (!job_list.fg->running_progs) {
-                                       /* child exited */
-                                       remove_job(&job_list, job_list.fg);
-                                       job_list.fg = NULL;
-                               }
-                       } else {
-                               /* the child was stopped */
-                               job_list.fg->stopped_progs++;
-                               job_list.fg->progs[i].is_stopped = 1;
-
-                               if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
-                                       printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
-                                                  "Stopped", job_list.fg->text);
-                                       job_list.fg = NULL;
-                               }
-                       }
-
-                       if (!job_list.fg) {
-                               /* move the shell to the foreground */
-                               /* suppress messages when run from /linuxrc mag@sysgo.de */
-                               if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
-                                       perror_msg("tcsetpgrp"); 
-                       }
-               }
-       }
-       free(command);
-
-       /* return controlling TTY back to parent process group before exiting */
-       if (tcsetpgrp(shell_terminal, parent_pgrp))
-               perror_msg("tcsetpgrp");
-
-       /* return exit status if called with "-c" */
-       if (input == NULL && WIFEXITED(status))
-               return WEXITSTATUS(status);
-       
-       return 0;
-}
-
-
-#ifdef BB_FEATURE_CLEAN_UP
-void free_memory(void)
-{
-       if (cwd && cwd!=unknown) {
-               free((char*)cwd);
-       }
-       if (local_pending_command)
-               free(local_pending_command);
-
-       if (job_list.fg && !job_list.fg->running_progs) {
-               remove_job(&job_list, job_list.fg);
-       }
-}
-#endif
-
-/* Make sure we have a controlling tty.  If we get started under a job
- * aware app (like bash for example), make sure we are now in charge so
- * we don't fight over who gets the foreground */
-static void setup_job_control()
-{
-       int status;
-       
-       /* Loop until we are in the foreground.  */
-       while ((status = tcgetpgrp (shell_terminal)) >= 0) {
-               if (status == (shell_pgrp = getpgrp ())) {
-                       break;
-               }
-               kill (- shell_pgrp, SIGTTIN);
-       }
-
-       /* Ignore interactive and job-control signals.  */
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGTSTP, SIG_IGN);
-       signal(SIGTTIN, SIG_IGN);
-       signal(SIGTTOU, SIG_IGN);
-       signal(SIGCHLD, SIG_IGN);
-
-       /* Put ourselves in our own process group.  */
-       setsid();
-       shell_pgrp = getpid ();
-       setpgid (shell_pgrp, shell_pgrp);
-
-       /* Grab control of the terminal.  */
-       tcsetpgrp(shell_terminal, shell_pgrp);
-}
-
-int lash_main(int argc_l, char **argv_l)
-{
-       int opt, interactive=FALSE;
-       FILE *input = stdin;
-       argc = argc_l;
-       argv = argv_l;
-
-       /* These variables need re-initializing when recursing */
-       last_jobid = 0;
-       local_pending_command = NULL;
-       close_me_head = NULL;
-       job_list.head = NULL;
-       job_list.fg = NULL;
-       last_return_code=1;
-
-       if (argv[0] && argv[0][0] == '-') {
-               FILE *prof_input;
-               prof_input = fopen("/etc/profile", "r");
-               if (prof_input) {
-                       int tmp_fd = fileno(prof_input);
-                       mark_open(tmp_fd);      
-                       /* Now run the file */
-                       busy_loop(prof_input);
-                       fclose(prof_input);
-                       mark_closed(tmp_fd);
-               }
-       }
-
-       while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               input = NULL;
-                               if (local_pending_command != 0)
-                                       error_msg_and_die("multiple -c arguments");
-                               local_pending_command = xstrdup(argv[optind]);
-                               optind++;
-                               argv = argv+optind;
-                               break;
-                       case 'i':
-                               interactive = TRUE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       /* A shell is interactive if the `-i' flag was given, or if all of
-        * the following conditions are met:
-        *        no -c command
-        *    no arguments remaining or the -s flag given
-        *    standard input is a terminal
-        *    standard output is a terminal
-        *    Refer to Posix.2, the description of the `sh' utility. */
-       if (argv[optind]==NULL && input==stdin &&
-                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
-               interactive=TRUE;
-       }
-       setup_job_control();
-       if (interactive==TRUE) {
-               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
-               /* Looks like they want an interactive shell */
-               printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
-               printf( "Enter 'help' for a list of built-in commands.\n\n");
-       } else if (local_pending_command==NULL) {
-               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
-               input = xfopen(argv[optind], "r");
-               mark_open(fileno(input));  /* be lazy, never mark this closed */
-       }
-
-       /* initialize the cwd -- this is never freed...*/
-       cwd = xgetcwd(0);
-       if (!cwd)
-               cwd = unknown;
-
-#ifdef BB_FEATURE_CLEAN_UP
-       atexit(free_memory);
-#endif
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-       cmdedit_set_initial_prompt();
-#else
-       PS1 = NULL;
-#endif
-       
-       return (busy_loop(input));
-}
diff --git a/busybox/shell/msh.c b/busybox/shell/msh.c
deleted file mode 100644 (file)
index e16d6f3..0000000
+++ /dev/null
@@ -1,4868 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Minix shell port for busybox
- *
- * This version of the Minix shell was adapted for use in busybox
- * by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "cmdedit.h"
-#include "busybox.h"
-
-
-/* -------- sh.h -------- */
-/*
- * shell
- */
-
-#define        LINELIM 2100
-#define        NPUSH   8       /* limit to input nesting */
-
-#define        NOFILE  20      /* Number of open files */
-#define        NUFILE  10      /* Number of user-accessible files */
-#define        FDBASE  10      /* First file usable by Shell */
-
-/*
- * values returned by wait
- */
-#define        WAITSIG(s) ((s)&0177)
-#define        WAITVAL(s) (((s)>>8)&0377)
-#define        WAITCORE(s) (((s)&0200)!=0)
-
-/*
- * library and system defintions
- */
-typedef void xint;     /* base type of jmp_buf, for not broken compilers */
-
-/*
- * shell components
- */
-
-#define        QUOTE   0200
-
-#define        NOBLOCK ((struct op *)NULL)
-#define        NOWORD  ((char *)NULL)
-#define        NOWORDS ((char **)NULL)
-#define        NOPIPE  ((int *)NULL)
-
-/*
- * Description of a command or an operation on commands.
- * Might eventually use a union.
- */
-struct op {
-       int     type;   /* operation type, see below */
-       char    **words;        /* arguments to a command */
-       struct  ioword  **ioact;        /* IO actions (eg, < > >>) */
-       struct op *left;
-       struct op *right;
-       char    *str;   /* identifier for case and for */
-};
-
-#define        TCOM    1       /* command */
-#define        TPAREN  2       /* (c-list) */
-#define        TPIPE   3       /* a | b */
-#define        TLIST   4       /* a [&;] b */
-#define        TOR     5       /* || */
-#define        TAND    6       /* && */
-#define        TFOR    7
-#define        TDO     8
-#define        TCASE   9
-#define        TIF     10
-#define        TWHILE  11
-#define        TUNTIL  12
-#define        TELIF   13
-#define        TPAT    14      /* pattern in case */
-#define        TBRACE  15      /* {c-list} */
-#define        TASYNC  16      /* c & */
-
-/*
- * actions determining the environment of a process
- */
-#define        BIT(i)  (1<<(i))
-#define        FEXEC   BIT(0)  /* execute without forking */
-
-/*
- * flags to control evaluation of words
- */
-#define        DOSUB   1       /* interpret $, `, and quotes */
-#define        DOBLANK 2       /* perform blank interpretation */
-#define        DOGLOB  4       /* interpret [?* */
-#define        DOKEY   8       /* move words with `=' to 2nd arg. list */
-#define        DOTRIM  16      /* trim resulting string */
-
-#define        DOALL   (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
-
-static char    **dolv;
-static int     dolc;
-static int     exstat;
-static  char   gflg;
-static  int    interactive;    /* Is this an interactive shell */
-static  int    execflg;
-static  int    multiline;      /* \n changed to ; */
-static  struct op      *outtree;       /* result from parser */
-
-static xint    *failpt;
-static xint    *errpt;
-static struct brkcon   *brklist;
-static int     isbreak;
-static int newfile(char *s);
-static char *findeq(char *cp);
-static char *cclass(char *p, int sub);
-static void initarea(void);
-extern int msh_main(int argc, char **argv);
-
-
-struct brkcon {
-       jmp_buf brkpt;
-       struct  brkcon  *nextlev;
-} ;
-
-/*
- * redirection
- */
-struct ioword {
-       short   io_unit;        /* unit affected */
-       short   io_flag;        /* action (below) */
-       char    *io_name;       /* file name */
-};
-#define        IOREAD  1       /* < */
-#define        IOHERE  2       /* << (here file) */
-#define        IOWRITE 4       /* > */
-#define        IOCAT   8       /* >> */
-#define        IOXHERE 16      /* ${}, ` in << */
-#define        IODUP   32      /* >&digit */
-#define        IOCLOSE 64      /* >&- */
-
-#define        IODEFAULT (-1)  /* token for default IO unit */
-
-static struct  wdblock *wdlist;
-static struct  wdblock *iolist;
-
-/*
- * parsing & execution environment
- */
-static struct  env {
-       char    *linep;
-       struct  io      *iobase;
-       struct  io      *iop;
-       xint    *errpt;
-       int     iofd;
-       struct  env     *oenv;
-} e;
-
-/*
- * flags:
- * -e: quit on error
- * -k: look for name=value everywhere on command line
- * -n: no execution
- * -t: exit after reading and executing one command
- * -v: echo as read
- * -x: trace
- * -u: unset variables net diagnostic
- */
-static char    *flag;
-
-static char    *null;  /* null value for variable */
-static int     intr;   /* interrupt pending */
-
-static char    *trap[_NSIG+1];
-static char    ourtrap[_NSIG+1];
-static int     trapset;        /* trap pending */
-
-static int     heedint;        /* heed interrupt signals */
-
-static int     yynerrs;        /* yacc */
-
-static char    line[LINELIM];
-static char    *elinep;
-
-/*
- * other functions
- */
-static int (*inbuilt(char *s ))(void);
-
-static char *rexecve (char *c , char **v, char **envp );
-static char *space (int n );
-static char *strsave (char *s, int a );
-static char *evalstr (char *cp, int f );
-static char *putn (int n );
-static char *itoa (unsigned u, int n );
-static char *unquote (char *as );
-static struct var *lookup (char *n );
-static int rlookup (char *n );
-static struct wdblock *glob (char *cp, struct wdblock *wb );
-static int my_getc( int ec);
-static int subgetc (int ec, int quoted );
-static char **makenv (void);
-static char **eval (char **ap, int f );
-static int setstatus (int s );
-static int waitfor (int lastpid, int canintr );
-
-static void onintr (int s ); /* SIGINT handler */
-
-static int newenv (int f );
-static void quitenv (void);
-static void err (char *s );
-static int anys (char *s1, char *s2 );
-static int any (int c, char *s );
-static void next (int f );
-static void setdash (void);
-static void onecommand (void);
-static void runtrap (int i );
-static int gmatch (char *s, char *p );
-
-/*
- * error handling
- */
-static void leave (void); /* abort shell (or fail in subshell) */
-static void fail (void);        /* fail but return to process next command */
-static void warn (char *s );
-static void sig (int i );       /* default signal handler */
-
-
-
-/* -------- area stuff -------- */
-
-#define        REGSIZE         sizeof(struct region)
-#define GROWBY         256
-//#define      SHRINKBY   64
-#undef SHRINKBY
-#define FREE 32767
-#define BUSY 0
-#define        ALIGN (sizeof(int)-1)
-
-
-struct region {
-       struct  region *next;
-       int     area;
-};
-
-
-
-/* -------- grammar stuff -------- */
-typedef union {
-       char    *cp;
-       char    **wp;
-       int     i;
-       struct  op *o;
-} YYSTYPE;
-#define        WORD    256
-#define        LOGAND  257
-#define        LOGOR   258
-#define        BREAK   259
-#define        IF      260
-#define        THEN    261
-#define        ELSE    262
-#define        ELIF    263
-#define        FI      264
-#define        CASE    265
-#define        ESAC    266
-#define        FOR     267
-#define        WHILE   268
-#define        UNTIL   269
-#define        DO      270
-#define        DONE    271
-#define        IN      272
-#define        YYERRCODE 300
-
-/* flags to yylex */
-#define        CONTIN  01      /* skip new lines to complete command */
-
-#define        SYNTAXERR       zzerr()
-static struct op *pipeline(int cf );
-static struct op *andor(void);
-static struct op *c_list(void);
-static int synio(int cf );
-static void musthave (int c, int cf );
-static struct op *simple(void);
-static struct op *nested(int type, int mark );
-static struct op *command(int cf );
-static struct op *dogroup(int onlydone );
-static struct op *thenpart(void);
-static struct op *elsepart(void);
-static struct op *caselist(void);
-static struct op *casepart(void);
-static char **pattern(void);
-static char **wordlist(void);
-static struct op *list(struct op *t1, struct op *t2 );
-static struct op *block(int type, struct op *t1, struct op *t2, char **wp );
-static struct op *newtp(void);
-static struct op *namelist(struct op *t );
-static char **copyw(void);
-static void word(char *cp );
-static struct ioword **copyio(void);
-static struct ioword *io (int u, int f, char *cp );
-static void zzerr(void);
-static void yyerror(char *s );
-static int yylex(int cf );
-static int collect(int c, int c1 );
-static int dual(int c );
-static void diag(int ec );
-static char *tree(unsigned size );
-
-/* -------- var.h -------- */
-
-struct var {
-       char    *value;
-       char    *name;
-       struct  var     *next;
-       char    status;
-};
-#define        COPYV   1       /* flag to setval, suggesting copy */
-#define        RONLY   01      /* variable is read-only */
-#define        EXPORT  02      /* variable is to be exported */
-#define        GETCELL 04      /* name & value space was got with getcell */
-
-static struct  var     *vlist;         /* dictionary */
-
-static struct  var     *homedir;       /* home directory */
-static struct  var     *prompt;        /* main prompt */
-static struct  var     *cprompt;       /* continuation prompt */
-static struct  var     *path;          /* search path for commands */
-static struct  var     *shell;         /* shell to interpret command files */
-static struct  var     *ifs;           /* field separators */
-
-static int yyparse (void);
-static struct var *lookup (char *n );
-static void setval (struct var *vp, char *val );
-static void nameval (struct var *vp, char *val, char *name );
-static void export (struct var *vp );
-static void ronly (struct var *vp );
-static int isassign (char *s );
-static int checkname (char *cp );
-static int assign (char *s, int cf );
-static void putvlist (int f, int out );
-static int eqname (char *n1, char *n2 );
-
-static int execute (struct op *t, int *pin, int *pout, int act );
-
-/* -------- io.h -------- */
-/* io buffer */
-struct iobuf {
-  unsigned id;                         /* buffer id */
-  char buf[512];                       /* buffer */
-  char *bufp;                          /* pointer into buffer */
-  char *ebufp;                         /* pointer to end of buffer */
-};
-
-/* possible arguments to an IO function */
-struct ioarg {
-       char    *aword;
-       char    **awordlist;
-       int     afile;          /* file descriptor */
-       unsigned afid;          /* buffer id */
-       long    afpos;          /* file position */
-       struct iobuf *afbuf;    /* buffer for this file */
-};
-//static struct ioarg ioargstack[NPUSH];
-#define AFID_NOBUF     (~0)
-#define AFID_ID                0
-
-/* an input generator's state */
-struct io {
-       int     (*iofn)();
-       struct  ioarg   *argp;
-       int     peekc;
-       char    prev;           /* previous character read by readc() */
-       char    nlcount;        /* for `'s */
-       char    xchar;          /* for `'s */
-       char    task;           /* reason for pushed IO */
-};
-//static       struct  io      iostack[NPUSH];
-#define        XOTHER  0       /* none of the below */
-#define        XDOLL   1       /* expanding ${} */
-#define        XGRAVE  2       /* expanding `'s */
-#define        XIO     3       /* file IO */
-
-/* in substitution */
-#define        INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
-
-/*
- * input generators for IO structure
- */
-static int nlchar (struct ioarg *ap );
-static int strchar (struct ioarg *ap );
-static int qstrchar (struct ioarg *ap );
-static int filechar (struct ioarg *ap );
-static int herechar (struct ioarg *ap );
-static int linechar (struct ioarg *ap );
-static int gravechar (struct ioarg *ap, struct io *iop );
-static int qgravechar (struct ioarg *ap, struct io *iop );
-static int dolchar (struct ioarg *ap );
-static int wdchar (struct ioarg *ap );
-static void scraphere (void);
-static void freehere (int area );
-static void gethere (void);
-static void markhere (char *s, struct ioword *iop );
-static int herein (char *hname, int xdoll );
-static int run (struct ioarg *argp, int (*f)());
-
-/*
- * IO functions
- */
-static int eofc (void);
-static int readc (void);
-static void unget (int c );
-static void ioecho (int c );
-static void prs (char *s );
-static void prn (unsigned u );
-static void closef (int i );
-static void closeall (void);
-
-/*
- * IO control
- */
-static void pushio (struct ioarg *argp, int (*fn)());
-static int remap (int fd );
-static int openpipe (int *pv );
-static void closepipe (int *pv );
-static struct io *setbase (struct io *ip );
-
-static struct  ioarg   temparg;        /* temporary for PUSHIO */
-#define        PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
-#define        RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
-
-/* -------- word.h -------- */
-
-#define        NSTART  16      /* default number of words to allow for initially */
-
-struct wdblock {
-       short   w_bsize;
-       short   w_nword;
-       /* bounds are arbitrary */
-       char    *w_words[1];
-};
-
-static struct wdblock *addword (char *wd, struct wdblock *wb );
-static struct wdblock *newword (int nw );
-static char **getwords (struct wdblock *wb );
-
-/* -------- area.h -------- */
-
-/*
- * storage allocation
- */
-static char *getcell (unsigned nbytes );
-static void garbage (void);
-static void setarea (char *cp, int a );
-static int getarea (char *cp );
-static void freearea (int a );
-static void freecell (char *cp );
-static int     areanum;        /* current allocation area */
-
-#define        NEW(type) (type *)getcell(sizeof(type))
-#define        DELETE(obj)     freecell((char *)obj)
-
-
-/* -------- misc stuff -------- */
-
-static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked );
-static int iosetup (struct ioword *iop, int pipein, int pipeout );
-static void echo(char **wp );
-static struct op **find1case (struct op *t, char *w );
-static struct op *findcase (struct op *t, char *w );
-static void brkset(struct brkcon *bc );
-static int dolabel(void);
-static int dohelp(void);
-static int dochdir(struct op *t );
-static int doshift(struct op *t );
-static int dologin(struct op *t );
-static int doumask(struct op *t );
-static int doexec(struct op *t );
-static int dodot(struct op *t );
-static int dowait(struct op *t );
-static int doread(struct op *t );
-static int doeval(struct op *t );
-static int dotrap(struct op *t );
-static int getsig(char *s );
-static void setsig (int n, void (*f)());
-static int getn(char *as );
-static int dobreak(struct op *t );
-static int docontinue(struct op *t );
-static int brkcontin (char *cp, int val );
-static int doexit(struct op *t );
-static int doexport(struct op *t );
-static int doreadonly(struct op *t );
-static void rdexp (char **wp, void (*f)(), int key);
-static void badid(char *s );
-static int doset(struct op *t );
-static void varput (char *s, int out );
-static int dotimes(void);
-static int expand (char *cp, struct wdblock **wbp, int f );
-static char *blank(int f );
-static int dollar(int quoted );
-static int grave(int quoted );
-static void globname (char *we, char *pp );
-static char *generate (char *start1, char *end1, char *middle, char *end );
-static int anyspcl(struct wdblock *wb );
-static int xstrcmp (char *p1, char *p2 );
-static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *));
-static void glob1 (char *base, char *lim );
-static void glob2 (char *i, char *j );
-static void glob3 (char *i, char *j, char *k );
-static void readhere (char **name, char *s, int ec );
-static void pushio(struct ioarg *argp, int (*fn)());
-static int xxchar(struct ioarg *ap );
-
-struct here {
-       char    *h_tag;
-       int     h_dosub;
-       struct  ioword *h_iop;
-       struct  here    *h_next;
-};
-
-static char    *signame[] = {
-       "Signal 0",
-       "Hangup",
-       (char *)NULL,   /* interrupt */
-       "Quit",
-       "Illegal instruction",
-       "Trace/BPT trap",
-       "Abort",
-       "Bus error",
-       "Floating Point Exception",
-       "Killed",
-       "SIGUSR1",
-       "SIGSEGV",
-       "SIGUSR2",
-       (char *)NULL,   /* broken pipe */
-       "Alarm clock",
-       "Terminated",
-};
-#define        NSIGNAL (sizeof(signame)/sizeof(signame[0]))
-
-struct res {
-       char *r_name;
-       int       r_val;
-};
-static struct res restab[] = {
-    {"for",            FOR},
-    {"case",   CASE},
-    {"esac",   ESAC},
-    {"while",  WHILE},
-    {"do",             DO},
-    {"done",   DONE},
-    {"if",             IF},
-    {"in",             IN},
-    {"then",   THEN},
-    {"else",   ELSE},
-    {"elif",   ELIF},
-    {"until",  UNTIL},
-    {"fi",             FI},
-
-    {";;",             BREAK},
-    {"||",             LOGOR},
-    {"&&",             LOGAND},
-    {"{",              '{'},
-    {"}",              '}'},
-    {0,                0},
-};
-
-
-struct builtincmd {
-       const char *name;
-       int (*builtinfunc)();
-};
-static const struct    builtincmd      builtincmds[] = {
-    {".",              dodot},
-    {":",              dolabel},
-    {"break",  dobreak},
-    {"cd",             dochdir},
-    {"continue",docontinue},
-    {"eval",   doeval},
-    {"exec",   doexec},
-    {"exit",   doexit},
-    {"export", doexport},
-    {"help",   dohelp},
-    {"login",  dologin},
-    {"newgrp", dologin},
-    {"read",   doread},
-    {"readonly",doreadonly},
-    {"set",            doset},
-    {"shift",  doshift},
-    {"times",  dotimes},
-    {"trap",   dotrap},
-    {"umask",  doumask},
-    {"wait",   dowait},
-    {0,0}
-};
-
-/* Globals */
-extern char    **environ;      /* environment pointer */
-static char    **dolv;
-static int     dolc;
-static int     exstat;
-static char    gflg;
-static int     interactive;    /* Is this an interactive shell */
-static int     execflg;
-static int     multiline;      /* \n changed to ; */
-static struct  op      *outtree;       /* result from parser */
-static xint    *failpt;
-static xint    *errpt;
-static struct  brkcon  *brklist;
-static int     isbreak;
-static struct  wdblock *wdlist;
-static struct  wdblock *iolist;
-static char    *trap[_NSIG+1];
-static char    ourtrap[_NSIG+1];
-static int     trapset;        /* trap pending */
-static int     yynerrs;        /* yacc */
-static char    line[LINELIM];
-static struct  var     *vlist;         /* dictionary */
-static struct  var     *homedir;       /* home directory */
-static struct  var     *prompt;        /* main prompt */
-static struct  var     *cprompt;       /* continuation prompt */
-static struct  var     *path;          /* search path for commands */
-static struct  var     *shell;         /* shell to interpret command files */
-static struct  var     *ifs;           /* field separators */
-static struct  ioarg ioargstack[NPUSH];
-static struct  io      iostack[NPUSH];
-static int     areanum;        /* current allocation area */
-static int     intr;
-static int     inparse;
-static char    flags['z'-'a'+1];
-static char    *flag = flags-'a';
-static char    *elinep = line+sizeof(line)-5;
-static char    *null   = "";
-static int     heedint =1;
-static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL};
-static void (*qflag)(int) = SIG_IGN;
-static char    shellname[] = "/bin/sh";
-static char    search[] = ":/bin:/usr/bin";
-static int     startl;
-static int     peeksym;
-static int     nlseen;
-static int     iounit = IODEFAULT;
-static YYSTYPE yylval;
-static struct iobuf sharedbuf = {AFID_NOBUF};
-static struct iobuf mainbuf = {AFID_NOBUF};
-static unsigned bufid = AFID_ID;       /* buffer id counter */
-static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
-static struct here *inhere;            /* list of hear docs while parsing */
-static struct here *acthere;           /* list of active here documents */
-static struct region *areabot;         /* bottom of area */
-static struct region *areatop;         /* top of area */
-static struct region *areanxt;         /* starting point of scan */
-static void * brktop;
-static void * brkaddr;
-
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-static char * current_prompt;
-#endif
-
-
-/* -------- sh.c -------- */
-/*
- * shell
- */
-
-
-extern int msh_main(int argc, char **argv)
-{
-       register int f;
-       register char *s;
-       int cflag;
-       char *name, **ap;
-       int (*iof)();
-
-       initarea();
-       if ((ap = environ) != NULL) {
-               while (*ap)
-                       assign(*ap++, !COPYV);
-               for (ap = environ; *ap;)
-                       export(lookup(*ap++));
-       }
-       closeall();
-       areanum = 1;
-
-       shell = lookup("SHELL");
-       if (shell->value == null)
-               setval(shell, shellname);
-       export(shell);
-
-       homedir = lookup("HOME");
-       if (homedir->value == null)
-               setval(homedir, "/");
-       export(homedir);
-
-       setval(lookup("$"), itoa(getpid(), 5));
-
-       path = lookup("PATH");
-       if (path->value == null)
-               setval(path, search);
-       export(path);
-
-       ifs = lookup("IFS");
-       if (ifs->value == null)
-               setval(ifs, " \t\n");
-
-       prompt = lookup("PS1");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (prompt->value == null)
-#endif
-               setval(prompt, "$ ");
-       if (geteuid() == 0) {
-               setval(prompt, "# ");
-               prompt->status &= ~EXPORT;
-       }
-       cprompt = lookup("PS2");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-       if (cprompt->value == null)
-#endif
-               setval(cprompt, "> ");
-
-       iof = filechar;
-       cflag = 0;
-       name = *argv++;
-       if (--argc >= 1) {
-               if(argv[0][0] == '-' && argv[0][1] != '\0') {
-                       for (s = argv[0]+1; *s; s++)
-                               switch (*s) {
-                               case 'c':
-                                       prompt->status &= ~EXPORT;
-                                       cprompt->status &= ~EXPORT;
-                                       setval(prompt, "");
-                                       setval(cprompt, "");
-                                       cflag = 1;
-                                       if (--argc > 0)
-                                               PUSHIO(aword, *++argv, iof = nlchar);
-                                       break;
-       
-                               case 'q':
-                                       qflag = SIG_DFL;
-                                       break;
-
-                               case 's':
-                                       /* standard input */
-                                       break;
-
-                               case 't':
-                                       prompt->status &= ~EXPORT;
-                                       setval(prompt, "");
-                                       iof = linechar;
-                                       break;
-       
-                               case 'i':
-                                       interactive++;
-                               default:
-                                       if (*s>='a' && *s<='z')
-                                               flag[(int)*s]++;
-                               }
-               } else {
-                       argv--;
-                       argc++;
-               }
-               if (iof == filechar && --argc > 0) {
-                       setval(prompt, "");
-                       setval(cprompt, "");
-                       prompt->status &= ~EXPORT;
-                       cprompt->status &= ~EXPORT;
-                       if (newfile(name = *++argv))
-                               exit(1);
-               }
-       }
-       setdash();
-       if (e.iop < iostack) {
-               PUSHIO(afile, 0, iof);
-               if (isatty(0) && isatty(1) && !cflag) {
-                       interactive++;
-                       printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
-                       printf( "Enter 'help' for a list of built-in commands.\n\n");
-               }
-       }
-       signal(SIGQUIT, qflag);
-       if (name && name[0] == '-') {
-               interactive++;
-               if ((f = open(".profile", 0)) >= 0)
-                       next(remap(f));
-               if ((f = open("/etc/profile", 0)) >= 0)
-                       next(remap(f));
-       }
-       if (interactive)
-               signal(SIGTERM, sig);
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
-               signal(SIGINT, onintr);
-       dolv = argv;
-       dolc = argc;
-       dolv[0] = name;
-       if (dolc > 1) {
-               for (ap = ++argv; --argc > 0;) {
-                       if (assign(*ap = *argv++, !COPYV)) {
-                               dolc--; /* keyword */
-                       } else {
-                               ap++;
-                       }
-               }
-       }       
-       setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
-
-       for (;;) {
-               if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                       current_prompt=prompt->value;
-#else
-                       prs(prompt->value);
-#endif
-               }
-               onecommand();
-       }
-}
-
-static void
-setdash()
-{
-       register char *cp;
-       register int c;
-       char m['z'-'a'+1];
-
-       cp = m;
-       for (c='a'; c<='z'; c++)
-               if (flag[c])
-                       *cp++ = c;
-       *cp = 0;
-       setval(lookup("-"), m);
-}
-
-static int
-newfile(s)
-register char *s;
-{
-       register int f;
-
-       if (strcmp(s, "-") != 0) {
-               f = open(s, 0);
-               if (f < 0) {
-                       prs(s);
-                       err(": cannot open");
-                       return(1);
-               }
-       } else
-               f = 0;
-       next(remap(f));
-       return(0);
-}
-
-static void
-onecommand()
-{
-       register int i;
-       jmp_buf m1;
-
-       while (e.oenv)
-               quitenv();
-       areanum = 1;
-       freehere(areanum);
-       freearea(areanum);
-       garbage();
-       wdlist = 0;
-       iolist = 0;
-       e.errpt = 0;
-       e.linep = line;
-       yynerrs = 0;
-       multiline = 0;
-       inparse = 1;
-       intr = 0;
-       execflg = 0;
-       setjmp(failpt = m1);    /* Bruce Evans' fix */
-       if (setjmp(failpt = m1) || yyparse() || intr) {
-               while (e.oenv)
-                       quitenv();
-               scraphere();
-               if (!interactive && intr)
-                       leave();
-               inparse = 0;
-               intr = 0;
-               return;
-       }
-       inparse = 0;
-       brklist = 0;
-       intr = 0;
-       execflg = 0;
-       if (!flag['n'])
-               execute(outtree, NOPIPE, NOPIPE, 0);
-       if (!interactive && intr) {
-               execflg = 0;
-               leave();
-       }
-       if ((i = trapset) != 0) {
-               trapset = 0;
-               runtrap(i);
-       }
-}
-
-static void
-fail()
-{
-       longjmp(failpt, 1);
-       /* NOTREACHED */
-}
-
-static void
-leave()
-{
-       if (execflg)
-               fail();
-       scraphere();
-       freehere(1);
-       runtrap(0);
-       exit(exstat);
-       /* NOTREACHED */
-}
-
-static void
-warn(s)
-register char *s;
-{
-       if(*s) {
-               prs(s);
-               exstat = -1;
-       }
-       prs("\n");
-       if (flag['e'])
-               leave();
-}
-
-static void
-err(s)
-char *s;
-{
-       warn(s);
-       if (flag['n'])
-               return;
-       if (!interactive)
-               leave();
-       if (e.errpt)
-               longjmp(e.errpt, 1);
-       closeall();
-       e.iop = e.iobase = iostack;
-}
-
-static int
-newenv(f)
-int f;
-{
-       register struct env *ep;
-
-       if (f) {
-               quitenv();
-               return(1);
-       }
-       ep = (struct env *) space(sizeof(*ep));
-       if (ep == NULL) {
-               while (e.oenv)
-                       quitenv();
-               fail();
-       }
-       *ep = e;
-       e.oenv = ep;
-       e.errpt = errpt;
-       return(0);
-}
-
-static void
-quitenv()
-{
-       register struct env *ep;
-       register int fd;
-
-       if ((ep = e.oenv) != NULL) {
-               fd = e.iofd;
-               e = *ep;
-               /* should close `'d files */
-               DELETE(ep);
-               while (--fd >= e.iofd)
-                       close(fd);
-       }
-}
-
-/*
- * Is any character from s1 in s2?
- */
-static int
-anys(s1, s2)
-register char *s1, *s2;
-{
-       while (*s1)
-               if (any(*s1++, s2))
-                       return(1);
-       return(0);
-}
-
-/*
- * Is character c in s?
- */
-static int
-any(c, s)
-register int c;
-register char *s;
-{
-       while (*s)
-               if (*s++ == c)
-                       return(1);
-       return(0);
-}
-
-static char *
-putn(n)
-register int n;
-{
-       return(itoa(n, -1));
-}
-
-static char *
-itoa(u, n)
-register unsigned u;
-int n;
-{
-       register char *cp;
-       static char s[20];
-       int m;
-
-       m = 0;
-       if (n < 0 && (int) u < 0) {
-               m++;
-               u = -u;
-       }
-       cp = s+sizeof(s);
-       *--cp = 0;
-       do {
-               *--cp = u%10 + '0';
-               u /= 10;
-       } while (--n > 0 || u);
-       if (m)
-               *--cp = '-';
-       return(cp);
-}
-
-static void
-next(f)
-int f;
-{
-       PUSHIO(afile, f, filechar);
-}
-
-static void
-onintr(s)
-int s;                         /* ANSI C requires a parameter */
-{
-       signal(SIGINT, onintr);
-       intr = 1;
-       if (interactive) {
-               if (inparse) {
-                       prs("\n");
-                       fail();
-               }
-       }
-       else if (heedint) {
-               execflg = 0;
-               leave();
-       }
-}
-
-static char *
-space(n)
-int n;
-{
-       register char *cp;
-
-       if ((cp = getcell(n)) == 0)
-               err("out of string space");
-       return(cp);
-}
-
-static char *
-strsave(s, a)
-register char *s;
-int a;
-{
-       register char *cp, *xp;
-
-       if ((cp = space(strlen(s)+1)) != NULL) {
-               setarea((char *)cp, a);
-               for (xp = cp; (*xp++ = *s++) != '\0';)
-                       ;
-               return(cp);
-       }
-       return("");
-}
-
-/*
- * trap handling
- */
-static void
-sig(i)
-register int i;
-{
-       trapset = i;
-       signal(i, sig);
-}
-
-static void runtrap(i)
-int i;
-{
-       char *trapstr;
-
-       if ((trapstr = trap[i]) == NULL)
-               return;
-       if (i == 0)
-               trap[i] = 0;
-       RUN(aword, trapstr, nlchar);
-}
-
-/* -------- var.c -------- */
-
-/*
- * Find the given name in the dictionary
- * and return its value.  If the name was
- * not previously there, enter it now and
- * return a null value.
- */
-static struct var *
-lookup(n)
-register char *n;
-{
-       register struct var *vp;
-       register char *cp;
-       register int c;
-       static struct var dummy;
-
-       if (isdigit(*n)) {
-               dummy.name = n;
-               for (c = 0; isdigit(*n) && c < 1000; n++)
-                       c = c*10 + *n-'0';
-               dummy.status = RONLY;
-               dummy.value = c <= dolc? dolv[c]: null;
-               return(&dummy);
-       }
-       for (vp = vlist; vp; vp = vp->next)
-               if (eqname(vp->name, n))
-                       return(vp);
-       cp = findeq(n);
-       vp = (struct var *)space(sizeof(*vp));
-       if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
-               dummy.name = dummy.value = "";
-               return(&dummy);
-       }
-       for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
-               ;
-       if (*cp == 0)
-               *cp = '=';
-       *++cp = 0;
-       setarea((char *)vp, 0);
-       setarea((char *)vp->name, 0);
-       vp->value = null;
-       vp->next = vlist;
-       vp->status = GETCELL;
-       vlist = vp;
-       return(vp);
-}
-
-/*
- * give variable at `vp' the value `val'.
- */
-static void
-setval(vp, val)
-struct var *vp;
-char *val;
-{
-       nameval(vp, val, (char *)NULL);
-}
-
-/*
- * if name is not NULL, it must be
- * a prefix of the space `val',
- * and end with `='.
- * this is all so that exporting
- * values is reasonably painless.
- */
-static void
-nameval(vp, val, name)
-register struct var *vp;
-char *val, *name;
-{
-       register char *cp, *xp;
-       char *nv;
-       int fl;
-
-       if (vp->status & RONLY) {
-               for (xp = vp->name; *xp && *xp != '=';)
-                       putc(*xp++, stderr);
-               err(" is read-only");
-               return;
-       }
-       fl = 0;
-       if (name == NULL) {
-               xp = space(strlen(vp->name)+strlen(val)+2);
-               if (xp == 0)
-                       return;
-               /* make string:  name=value */
-               setarea((char *)xp, 0);
-               name = xp;
-               for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
-                       ;
-               if (*xp++ == 0)
-                       xp[-1] = '=';
-               nv = xp;
-               for (cp = val; (*xp++ = *cp++) != '\0';)
-                       ;
-               val = nv;
-               fl = GETCELL;
-       }
-       if (vp->status & GETCELL)
-               freecell(vp->name);    /* form new string `name=value' */
-       vp->name = name;
-       vp->value = val;
-       vp->status |= fl;
-}
-
-static void
-export(vp)
-struct var *vp;
-{
-       vp->status |= EXPORT;
-}
-
-static void
-ronly(vp)
-struct var *vp;
-{
-       if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
-               vp->status |= RONLY;
-}
-
-static int
-isassign(s)
-register char *s;
-{
-       if (!isalpha((int)*s) && *s != '_')
-               return(0);
-       for (; *s != '='; s++)
-               if (*s == 0 || (!isalnum(*s) && *s != '_'))
-                       return(0);
-       return(1);
-}
-
-static int
-assign(s, cf)
-register char *s;
-int cf;
-{
-       register char *cp;
-       struct var *vp;
-
-       if (!isalpha(*s) && *s != '_')
-               return(0);
-       for (cp = s; *cp != '='; cp++)
-               if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
-                       return(0);
-       vp = lookup(s);
-       nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
-       if (cf != COPYV)
-               vp->status &= ~GETCELL;
-       return(1);
-}
-
-static int
-checkname(cp)
-register char *cp;
-{
-       if (!isalpha(*cp++) && *(cp-1) != '_')
-               return(0);
-       while (*cp)
-               if (!isalnum(*cp++) && *(cp-1) != '_')
-                       return(0);
-       return(1);
-}
-
-static void
-putvlist(f, out)
-register int f, out;
-{
-       register struct var *vp;
-
-       for (vp = vlist; vp; vp = vp->next)
-               if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
-                       if (vp->status & EXPORT)
-                               write(out, "export ", 7);
-                       if (vp->status & RONLY)
-                               write(out, "readonly ", 9);
-                       write(out, vp->name, (int)(findeq(vp->name) - vp->name));
-                       write(out, "\n", 1);
-               }
-}
-
-static int
-eqname(n1, n2)
-register char *n1, *n2;
-{
-       for (; *n1 != '=' && *n1 != 0; n1++)
-               if (*n2++ != *n1)
-                       return(0);
-       return(*n2 == 0 || *n2 == '=');
-}
-
-static char *
-findeq(cp)
-register char *cp;
-{
-       while (*cp != '\0' && *cp != '=')
-               cp++;
-       return(cp);
-}
-
-/* -------- gmatch.c -------- */
-/*
- * int gmatch(string, pattern)
- * char *string, *pattern;
- *
- * Match a pattern as in sh(1).
- */
-
-#define        CMASK   0377
-#define        QUOTE   0200
-#define        QMASK   (CMASK&~QUOTE)
-#define        NOT     '!'     /* might use ^ */
-
-static int
-gmatch(s, p)
-register char *s, *p;
-{
-       register int sc, pc;
-
-       if (s == NULL || p == NULL)
-               return(0);
-       while ((pc = *p++ & CMASK) != '\0') {
-               sc = *s++ & QMASK;
-               switch (pc) {
-               case '[':
-                       if ((p = cclass(p, sc)) == NULL)
-                               return(0);
-                       break;
-
-               case '?':
-                       if (sc == 0)
-                               return(0);
-                       break;
-
-               case '*':
-                       s--;
-                       do {
-                               if (*p == '\0' || gmatch(s, p))
-                                       return(1);
-                       } while (*s++ != '\0');
-                       return(0);
-
-               default:
-                       if (sc != (pc&~QUOTE))
-                               return(0);
-               }
-       }
-       return(*s == 0);
-}
-
-static char *
-cclass(p, sub)
-register char *p;
-register int sub;
-{
-       register int c, d, not, found;
-
-       if ((not = *p == NOT) != 0)
-               p++;
-       found = not;
-       do {
-               if (*p == '\0')
-                       return((char *)NULL);
-               c = *p & CMASK;
-               if (p[1] == '-' && p[2] != ']') {
-                       d = p[2] & CMASK;
-                       p++;
-               } else
-                       d = c;
-               if (c == sub || (c <= sub && sub <= d))
-                       found = !not;
-       } while (*++p != ']');
-       return(found? p+1: (char *)NULL);
-}
-
-
-/* -------- area.c -------- */
-
-/*
- * All memory between (char *)areabot and (char *)(areatop+1) is
- * exclusively administered by the area management routines.
- * It is assumed that sbrk() and brk() manipulate the high end.
- */
-
-#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
-
-static void
-initarea()
-{
-       brkaddr = malloc(65000);
-       brktop = brkaddr + 65000;
-
-       while ((int)sbrk(0) & ALIGN)
-               sbrk(1);
-       areabot = (struct region *)sbrk(REGSIZE);
-
-       areabot->next = areabot;
-       areabot->area = BUSY;
-       areatop = areabot;
-       areanxt = areabot;
-}
-
-char *
-getcell(nbytes)
-unsigned nbytes;
-{
-       register int nregio;
-       register struct region *p, *q;
-       register int i;
-
-       if (nbytes == 0) {
-               puts("getcell(0)");
-               abort();
-       }       /* silly and defeats the algorithm */
-       /*
-        * round upwards and add administration area
-        */
-       nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
-       for (p = areanxt;;) {
-               if (p->area > areanum) {
-                       /*
-                        * merge free cells
-                        */
-                       while ((q = p->next)->area > areanum && q != areanxt)
-                               p->next = q->next;
-                       /*
-                        * exit loop if cell big enough
-                        */
-                       if (q >= p + nregio)
-                               goto found;
-               }
-               p = p->next;
-               if (p == areanxt)
-                       break;
-       }
-       i = nregio >= GROWBY ? nregio : GROWBY;
-       p = (struct region *)sbrk(i * REGSIZE);
-       if (p == (struct region *)-1)
-               return((char *)NULL);
-       p--;
-       if (p != areatop) {
-               puts("not contig");
-               abort();        /* allocated areas are contiguous */
-       }
-       q = p + i;
-       p->next = q;
-       p->area = FREE;
-       q->next = areabot;
-       q->area = BUSY;
-       areatop = q;
-found:
-       /*
-        * we found a FREE area big enough, pointed to by 'p', and up to 'q'
-        */
-       areanxt = p + nregio;
-       if (areanxt < q) {
-               /*
-                * split into requested area and rest
-                */
-               if (areanxt+1 > q) {
-                       puts("OOM");
-                       abort();        /* insufficient space left for admin */
-               }
-               areanxt->next = q;
-               areanxt->area = FREE;
-               p->next = areanxt;
-       }
-       p->area = areanum;
-       return((char *)(p+1));
-}
-
-static void
-freecell(cp)
-char *cp;
-{
-       register struct region *p;
-
-       if ((p = (struct region *)cp) != NULL) {
-               p--;
-               if (p < areanxt)
-                       areanxt = p;
-               p->area = FREE;
-       }
-}
-
-static void
-freearea(a)
-register int a;
-{
-       register struct region *p, *top;
-
-       top = areatop;
-       for (p = areabot; p != top; p = p->next)
-               if (p->area >= a)
-                       p->area = FREE;
-}
-
-static void
-setarea(cp,a)
-char *cp;
-int a;
-{
-       register struct region *p;
-
-       if ((p = (struct region *)cp) != NULL)
-               (p-1)->area = a;
-}
-
-int
-getarea(cp)
-char *cp;
-{
-       return ((struct region*)cp-1)->area;
-}
-
-static void
-garbage()
-{
-       register struct region *p, *q, *top;
-
-       top = areatop;
-       for (p = areabot; p != top; p = p->next) {
-               if (p->area > areanum) {
-                       while ((q = p->next)->area > areanum)
-                               p->next = q->next;
-                       areanxt = p;
-               }
-       }
-#ifdef SHRINKBY
-       if (areatop >= q + SHRINKBY && q->area > areanum) {
-               brk((char *)(q+1));
-               q->next = areabot;
-               q->area = BUSY;
-               areatop = q;
-       }
-#endif
-}
-
-/* -------- csyn.c -------- */
-/*
- * shell: syntax (C version)
- */
-
-
-int
-yyparse()
-{
-       startl  = 1;
-       peeksym = 0;
-       yynerrs = 0;
-       outtree = c_list();
-       musthave('\n', 0);
-       return(yynerrs!=0);
-}
-
-static struct op *
-pipeline(cf)
-int cf;
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = command(cf);
-       if (t != NULL) {
-               while ((c = yylex(0)) == '|') {
-                       if ((p = command(CONTIN)) == NULL)
-                               SYNTAXERR;
-                       if (t->type != TPAREN && t->type != TCOM) {
-                               /* shell statement */
-                               t = block(TPAREN, t, NOBLOCK, NOWORDS);
-                       }
-                       t = block(TPIPE, t, p, NOWORDS);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-static struct op *
-andor()
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = pipeline(0);
-       if (t != NULL) {
-               while ((c = yylex(0)) == LOGAND || c == LOGOR) {
-                       if ((p = pipeline(CONTIN)) == NULL)
-                               SYNTAXERR;
-                       t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-static struct op *
-c_list()
-{
-       register struct op *t, *p;
-       register int c;
-
-       t = andor();
-       if (t != NULL) {
-               if((peeksym = yylex(0)) == '&')
-                       t = block(TASYNC, t, NOBLOCK, NOWORDS);
-               while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) {
-                       if ((p = andor()) == NULL)
-                               return(t);
-                       if((peeksym = yylex(0)) == '&')
-                               p = block(TASYNC, p, NOBLOCK, NOWORDS);
-                       t = list(t, p);
-               }
-               peeksym = c;
-       }
-       return(t);
-}
-
-
-static int
-synio(cf)
-int cf;
-{
-       register struct ioword *iop;
-       register int i;
-       register int c;
-
-       if ((c = yylex(cf)) != '<' && c != '>') {
-               peeksym = c;
-               return(0);
-       }
-       i = yylval.i;
-       musthave(WORD, 0);
-       iop = io(iounit, i, yylval.cp);
-       iounit = IODEFAULT;
-       if (i & IOHERE)
-               markhere(yylval.cp, iop);
-       return(1);
-}
-
-static void
-musthave(c, cf)
-int c, cf;
-{
-       if ((peeksym = yylex(cf)) != c)
-               SYNTAXERR;
-       peeksym = 0;
-}
-
-static struct op *
-simple()
-{
-       register struct op *t;
-
-       t = NULL;
-       for (;;) {
-               switch (peeksym = yylex(0)) {
-               case '<':
-               case '>':
-                       (void) synio(0);
-                       break;
-
-               case WORD:
-                       if (t == NULL) {
-                               t = newtp();
-                               t->type = TCOM;
-                       }
-                       peeksym = 0;
-                       word(yylval.cp);
-                       break;
-
-               default:
-                       return(t);
-               }
-       }
-}
-
-static struct op *
-nested(type, mark)
-int type, mark;
-{
-       register struct op *t;
-
-       multiline++;
-       t = c_list();
-       musthave(mark, 0);
-       multiline--;
-       return(block(type, t, NOBLOCK, NOWORDS));
-}
-
-static struct op *
-command(cf)
-int cf;
-{
-       register struct op *t;
-       struct wdblock *iosave;
-       register int c;
-
-       iosave = iolist;
-       iolist = NULL;
-       if (multiline)
-               cf |= CONTIN;
-       while (synio(cf))
-               cf = 0;
-       switch (c = yylex(cf)) {
-       default:
-               peeksym = c;
-               if ((t = simple()) == NULL) {
-                       if (iolist == NULL)
-                               return((struct op *)NULL);
-                       t = newtp();
-                       t->type = TCOM;
-               }
-               break;
-
-       case '(':
-               t = nested(TPAREN, ')');
-               break;
-
-       case '{':
-               t = nested(TBRACE, '}');
-               break;
-
-       case FOR:
-               t = newtp();
-               t->type = TFOR;
-               musthave(WORD, 0);
-               startl = 1;
-               t->str = yylval.cp;
-               multiline++;
-               t->words = wordlist();
-               if ((c = yylex(0)) != '\n' && c != ';')
-                       peeksym = c;
-               t->left = dogroup(0);
-               multiline--;
-               break;
-
-       case WHILE:
-       case UNTIL:
-               multiline++;
-               t = newtp();
-               t->type = c == WHILE? TWHILE: TUNTIL;
-               t->left = c_list();
-               t->right = dogroup(1);
-               t->words = NULL;
-               multiline--;
-               break;
-
-       case CASE:
-               t = newtp();
-               t->type = TCASE;
-               musthave(WORD, 0);
-               t->str = yylval.cp;
-               startl++;
-               multiline++;
-               musthave(IN, CONTIN);
-               startl++;
-               t->left = caselist();
-               musthave(ESAC, 0);
-               multiline--;
-               break;
-
-       case IF:
-               multiline++;
-               t = newtp();
-               t->type = TIF;
-               t->left = c_list();
-               t->right = thenpart();
-               musthave(FI, 0);
-               multiline--;
-               break;
-       }
-       while (synio(0))
-               ;
-       t = namelist(t);
-       iolist = iosave;
-       return(t);
-}
-
-static struct op *
-dogroup(onlydone)
-int onlydone;
-{
-       register int c;
-       register struct op *mylist;
-
-       c = yylex(CONTIN);
-       if (c == DONE && onlydone)
-               return((struct op *)NULL);
-       if (c != DO)
-               SYNTAXERR;
-       mylist = c_list();
-       musthave(DONE, 0);
-       return(mylist);
-}
-
-static struct op *
-thenpart()
-{
-       register int c;
-       register struct op *t;
-
-       if ((c = yylex(0)) != THEN) {
-               peeksym = c;
-               return((struct op *)NULL);
-       }
-       t = newtp();
-       t->type = 0;
-       t->left = c_list();
-       if (t->left == NULL)
-               SYNTAXERR;
-       t->right = elsepart();
-       return(t);
-}
-
-static struct op *
-elsepart()
-{
-       register int c;
-       register struct op *t;
-
-       switch (c = yylex(0)) {
-       case ELSE:
-               if ((t = c_list()) == NULL)
-                       SYNTAXERR;
-               return(t);
-
-       case ELIF:
-               t = newtp();
-               t->type = TELIF;
-               t->left = c_list();
-               t->right = thenpart();
-               return(t);
-
-       default:
-               peeksym = c;
-               return((struct op *)NULL);
-       }
-}
-
-static struct op *
-caselist()
-{
-       register struct op *t;
-
-       t = NULL;
-       while ((peeksym = yylex(CONTIN)) != ESAC)
-               t = list(t, casepart());
-       return(t);
-}
-
-static struct op *
-casepart()
-{
-       register struct op *t;
-
-       t = newtp();
-       t->type = TPAT;
-       t->words = pattern();
-       musthave(')', 0);
-       t->left = c_list();
-       if ((peeksym = yylex(CONTIN)) != ESAC)
-               musthave(BREAK, CONTIN);
-       return(t);
-}
-
-static char **
-pattern()
-{
-       register int c, cf;
-
-       cf = CONTIN;
-       do {
-               musthave(WORD, cf);
-               word(yylval.cp);
-               cf = 0;
-       } while ((c = yylex(0)) == '|');
-       peeksym = c;
-       word(NOWORD);
-       return(copyw());
-}
-
-static char **
-wordlist()
-{
-       register int c;
-
-       if ((c = yylex(0)) != IN) {
-               peeksym = c;
-               return((char **)NULL);
-       }
-       startl = 0;
-       while ((c = yylex(0)) == WORD)
-               word(yylval.cp);
-       word(NOWORD);
-       peeksym = c;
-       return(copyw());
-}
-
-/*
- * supporting functions
- */
-static struct op *
-list(t1, t2)
-register struct op *t1, *t2;
-{
-       if (t1 == NULL)
-               return(t2);
-       if (t2 == NULL)
-               return(t1);
-       return(block(TLIST, t1, t2, NOWORDS));
-}
-
-static struct op *
-block(type, t1, t2, wp)
-int type;
-struct op *t1, *t2;
-char **wp;
-{
-       register struct op *t;
-
-       t = newtp();
-       t->type = type;
-       t->left = t1;
-       t->right = t2;
-       t->words = wp;
-       return(t);
-}
-
-static int
-rlookup(n)
-register char *n;
-{
-       register struct res *rp;
-
-       for (rp = restab; rp->r_name; rp++)
-               if (strcmp(rp->r_name, n) == 0)
-                       return(rp->r_val);
-       return(0);
-}
-
-static struct op *
-newtp()
-{
-       register struct op *t;
-
-       t = (struct op *)tree(sizeof(*t));
-       t->type = 0;
-       t->words = NULL;
-       t->ioact = NULL;
-       t->left = NULL;
-       t->right = NULL;
-       t->str = NULL;
-       return(t);
-}
-
-static struct op *
-namelist(t)
-register struct op *t;
-{
-       if (iolist) {
-               iolist = addword((char *)NULL, iolist);
-               t->ioact = copyio();
-       } else
-               t->ioact = NULL;
-       if (t->type != TCOM) {
-               if (t->type != TPAREN && t->ioact != NULL) {
-                       t = block(TPAREN, t, NOBLOCK, NOWORDS);
-                       t->ioact = t->left->ioact;
-                       t->left->ioact = NULL;
-               }
-               return(t);
-       }
-       word(NOWORD);
-       t->words = copyw();
-       return(t);
-}
-
-static char **
-copyw()
-{
-       register char **wd;
-
-       wd = getwords(wdlist);
-       wdlist = 0;
-       return(wd);
-}
-
-static void
-word(cp)
-char *cp;
-{
-       wdlist = addword(cp, wdlist);
-}
-
-static struct ioword **
-copyio()
-{
-       register struct ioword **iop;
-
-       iop = (struct ioword **) getwords(iolist);
-       iolist = 0;
-       return(iop);
-}
-
-static struct ioword *
-io(u, f, cp)
-int u;
-int f;
-char *cp;
-{
-       register struct ioword *iop;
-
-       iop = (struct ioword *) tree(sizeof(*iop));
-       iop->io_unit = u;
-       iop->io_flag = f;
-       iop->io_name = cp;
-       iolist = addword((char *)iop, iolist);
-       return(iop);
-}
-
-static void
-zzerr()
-{
-       yyerror("syntax error");
-}
-
-static void
-yyerror(s)
-char *s;
-{
-       yynerrs++;
-       if (interactive && e.iop <= iostack) {
-               multiline = 0;
-               while (eofc() == 0 && yylex(0) != '\n')
-                       ;
-       }
-       err(s);
-       fail();
-}
-
-static int
-yylex(cf)
-int cf;
-{
-       register int c, c1;
-       int atstart;
-
-       if ((c = peeksym) > 0) {
-               peeksym = 0;
-               if (c == '\n')
-                       startl = 1;
-               return(c);
-       }
-       nlseen = 0;
-       e.linep = line;
-       atstart = startl;
-       startl = 0;
-       yylval.i = 0;
-
-loop:
-       while ((c = my_getc(0)) == ' ' || c == '\t')
-               ;
-       switch (c) {
-       default:
-               if (any(c, "0123456789")) {
-                       unget(c1 = my_getc(0));
-                       if (c1 == '<' || c1 == '>') {
-                               iounit = c - '0';
-                               goto loop;
-                       }
-                       *e.linep++ = c;
-                       c = c1;
-               }
-               break;
-
-       case '#':
-               while ((c = my_getc(0)) != 0 && c != '\n')
-                       ;
-               unget(c);
-               goto loop;
-
-       case 0:
-               return(c);
-
-       case '$':
-               *e.linep++ = c;
-               if ((c = my_getc(0)) == '{') {
-                       if ((c = collect(c, '}')) != '\0')
-                               return(c);
-                       goto pack;
-               }
-               break;
-
-       case '`':
-       case '\'':
-       case '"':
-               if ((c = collect(c, c)) != '\0')
-                       return(c);
-               goto pack;
-
-       case '|':
-       case '&':
-       case ';':
-               if ((c1 = dual(c)) != '\0') {
-                       startl = 1;
-                       return(c1);
-               }
-               startl = 1;
-               return(c);
-       case '^':
-               startl = 1;
-               return('|');
-       case '>':
-       case '<':
-               diag(c);
-               return(c);
-
-       case '\n':
-               nlseen++;
-               gethere();
-               startl = 1;
-               if (multiline || cf & CONTIN) {
-                       if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                       current_prompt=cprompt->value;
-#else
-                       prs(cprompt->value);
-#endif
-                       }
-                       if (cf & CONTIN)
-                               goto loop;
-               }
-               return(c);
-
-       case '(':
-       case ')':
-               startl = 1;
-               return(c);
-       }
-
-       unget(c);
-
-pack:
-       while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
-               if (e.linep >= elinep)
-                       err("word too long");
-               else
-                       *e.linep++ = c;
-       unget(c);
-       if(any(c, "\"'`$"))
-               goto loop;
-       *e.linep++ = '\0';
-       if (atstart && (c = rlookup(line))!=0) {
-               startl = 1;
-               return(c);
-       }
-       yylval.cp = strsave(line, areanum);
-       return(WORD);
-}
-
-static int
-collect(c, c1)
-register int c, c1;
-{
-       char s[2];
-
-       *e.linep++ = c;
-       while ((c = my_getc(c1)) != c1) {
-               if (c == 0) {
-                       unget(c);
-                       s[0] = c1;
-                       s[1] = 0;
-                       prs("no closing "); yyerror(s);
-                       return(YYERRCODE);
-               }
-               if (interactive && c == '\n' && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                   current_prompt=cprompt->value;
-#else
-                   prs(cprompt->value);
-#endif
-               }
-               *e.linep++ = c;
-       }
-       *e.linep++ = c;
-       return(0);
-}
-
-static int
-dual(c)
-register int c;
-{
-       char s[3];
-       register char *cp = s;
-
-       *cp++ = c;
-       *cp++ = my_getc(0);
-       *cp = 0;
-       if ((c = rlookup(s)) == 0)
-               unget(*--cp);
-       return(c);
-}
-
-static void
-diag(ec)
-register int ec;
-{
-       register int c;
-
-       c = my_getc(0);
-       if (c == '>' || c == '<') {
-               if (c != ec)
-                       zzerr();
-               yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE;
-               c = my_getc(0);
-       } else
-               yylval.i = ec == '>'? IOWRITE: IOREAD;
-       if (c != '&' || yylval.i == IOHERE)
-               unget(c);
-       else
-               yylval.i |= IODUP;
-}
-
-static char *
-tree(size)
-unsigned size;
-{
-       register char *t;
-
-       if ((t = getcell(size)) == NULL) {
-               prs("command line too complicated\n");
-               fail();
-               /* NOTREACHED */
-       }
-       return(t);
-}
-
-/* VARARGS1 */
-/* ARGSUSED */
-
-/* -------- exec.c -------- */
-
-/*
- * execute tree
- */
-
-
-static int
-execute(t, pin, pout, act)
-register struct op *t;
-int *pin, *pout;
-int act;
-{
-       register struct op *t1;
-       volatile int i, rv, a;
-       char *cp, **wp, **wp2;
-       struct var *vp;
-       struct brkcon bc;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &wp;
-#endif 
-
-
-       if (t == NULL)
-               return(0);
-       rv = 0;
-       a = areanum++;
-       wp = (wp2 = t->words) != NULL
-            ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
-            : NULL;
-
-       switch(t->type) {
-       case TPAREN:
-       case TCOM:
-               {
-                       int child;
-                       rv = forkexec(t, pin, pout, act, wp, &child);
-                       if (child) {
-                               exstat = rv;
-                               leave();
-                       }
-               }
-               break;
-
-       case TPIPE:
-               {
-                   int pv[2];
-                   if ((rv = openpipe(pv)) < 0)
-                       break;
-                   pv[0] = remap(pv[0]);
-                   pv[1] = remap(pv[1]);
-                   (void) execute(t->left, pin, pv, 0);
-                   rv = execute(t->right, pv, pout, 0);
-               }
-               break;
-
-       case TLIST:
-               (void) execute(t->left, pin, pout, 0);
-               rv = execute(t->right, pin, pout, 0);
-               break;
-
-       case TASYNC:
-       {
-               int hinteractive = interactive;
-
-               i = vfork();
-               if (i != 0) {
-                       interactive = hinteractive;
-                       if (i != -1) {
-                               setval(lookup("!"), putn(i));
-                               if (pin != NULL)
-                                       closepipe(pin);
-                               if (interactive) {
-                                       prs(putn(i));
-                                       prs("\n");
-                               }
-                       } else
-                               rv = -1;
-                       setstatus(rv);
-               } else {
-                       signal(SIGINT, SIG_IGN);
-                       signal(SIGQUIT, SIG_IGN);
-                       if (interactive)
-                               signal(SIGTERM, SIG_DFL);
-                       interactive = 0;
-                       if (pin == NULL) {
-                               close(0);
-                               open("/dev/null", 0);
-                       }
-                       exit(execute(t->left, pin, pout, FEXEC));
-               }
-       }
-               break;
-
-       case TOR:
-       case TAND:
-               rv = execute(t->left, pin, pout, 0);
-               if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
-                       rv = execute(t1, pin, pout, 0);
-               break;
-
-       case TFOR:
-               if (wp == NULL) {
-                       wp = dolv+1;
-                       if ((i = dolc) < 0)
-                               i = 0;
-               } else {
-                       i = -1;
-                       while (*wp++ != NULL)
-                               ;                       
-               }
-               vp = lookup(t->str);
-               while (setjmp(bc.brkpt))
-                       if (isbreak)
-                               goto broken;
-               brkset(&bc);
-               for (t1 = t->left; i-- && *wp != NULL;) {
-                       setval(vp, *wp++);
-                       rv = execute(t1, pin, pout, 0);
-               }
-               brklist = brklist->nextlev;
-               break;
-
-       case TWHILE:
-       case TUNTIL:
-               while (setjmp(bc.brkpt))
-                       if (isbreak)
-                               goto broken;
-               brkset(&bc);
-               t1 = t->left;
-               while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
-                       rv = execute(t->right, pin, pout, 0);
-               brklist = brklist->nextlev;
-               break;
-
-       case TIF:
-       case TELIF:
-               if (t->right != NULL) {
-               rv = !execute(t->left, pin, pout, 0) ?
-                       execute(t->right->left, pin, pout, 0):
-                       execute(t->right->right, pin, pout, 0);
-               }
-               break;
-
-       case TCASE:
-               if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
-                       cp = "";
-               if ((t1 = findcase(t->left, cp)) != NULL)
-                       rv = execute(t1, pin, pout, 0);
-               break;
-
-       case TBRACE:
-/*
-               if (iopp = t->ioact)
-                       while (*iopp)
-                               if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
-                                       rv = -1;
-                                       break;
-                               }
-*/
-               if (rv >= 0 && (t1 = t->left))
-                       rv = execute(t1, pin, pout, 0);
-               break;
-       }
-
-broken:
-       t->words = wp2;
-       isbreak = 0;
-       freehere(areanum);
-       freearea(areanum);
-       areanum = a;
-       if (interactive && intr) {
-               closeall();
-               fail();
-       }
-       if ((i = trapset) != 0) {
-               trapset = 0;
-               runtrap(i);
-       }
-       return(rv);
-}
-
-static int
-forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked)
-{
-       int i, rv;
-       int (*shcom)() = NULL;
-       register int f;
-       char *cp = NULL;
-       struct ioword **iopp;
-       int resetsig;
-       char **owp;
-
-       int *hpin = pin;
-       int *hpout = pout;
-       int hforked;
-       char *hwp;
-       int hinteractive;
-       int hintr;
-       struct brkcon * hbrklist;
-       int hexecflg;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &pin;
-       (void) &pout;
-       (void) &wp;
-       (void) &shcom;
-       (void) &cp;
-       (void) &resetsig;
-       (void) &owp;
-#endif 
-
-       owp = wp;
-       resetsig = 0;
-       *pforked = 0;
-       rv = -1;        /* system-detected error */
-       if (t->type == TCOM) {
-               while ((cp = *wp++) != NULL)
-                       ;
-               cp = *wp;
-
-               /* strip all initial assignments */
-               /* not correct wrt PATH=yyy command  etc */
-               if (flag['x'])
-                       echo (cp ? wp: owp);
-               if (cp == NULL && t->ioact == NULL) {
-                       while ((cp = *owp++) != NULL && assign(cp, COPYV))
-                               ;
-                       return(setstatus(0));
-               }
-               else if (cp != NULL)
-                       shcom = inbuilt(cp);
-       }
-       t->words = wp;
-       f = act;
-       if (shcom == NULL && (f & FEXEC) == 0) {
-
-               hpin = pin;
-               hpout = pout;
-               hforked = *pforked;
-               hwp = *wp;
-               hinteractive = interactive;
-               hintr = intr;
-               hbrklist = brklist;
-               hexecflg = execflg;
-       
-               i = vfork();
-               if (i != 0) {
-                       /* who wrote this crappy non vfork safe shit? */
-                       pin = hpin;
-                       pout = hpout;
-                       *pforked = hforked;
-                       *wp = hwp;
-                       interactive = hinteractive;
-                       intr = hintr;
-                       brklist = hbrklist;
-                       execflg = hexecflg;
-
-                       *pforked = 0;
-                       if (i == -1)
-                               return(rv);
-                       if (pin != NULL)
-                               closepipe(pin);
-                       return(pout==NULL? setstatus(waitfor(i,0)): 0);
-               }
-
-               if (interactive) {
-                       signal(SIGINT, SIG_IGN);
-                       signal(SIGQUIT, SIG_IGN);
-                       resetsig = 1;
-               }
-               interactive = 0;
-               intr = 0;
-               (*pforked)++;
-               brklist = 0;
-               execflg = 0;
-       }       
-       if (owp != NULL)
-               while ((cp = *owp++) != NULL && assign(cp, COPYV))
-                       if (shcom == NULL)
-                               export(lookup(cp));
-#ifdef COMPIPE
-       if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
-               err("piping to/from shell builtins not yet done");
-               return(-1);
-       }
-#endif
-       if (pin != NULL) {
-               dup2(pin[0], 0);
-               closepipe(pin);
-       }
-       if (pout != NULL) {
-               dup2(pout[1], 1);
-               closepipe(pout);
-       }
-       if ((iopp = t->ioact) != NULL) {
-               if (shcom != NULL && shcom != doexec) {
-                       prs(cp);
-                       err(": cannot redirect shell command");
-                       return(-1);
-               }
-               while (*iopp)
-                       if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
-                               return(rv);
-       }
-       if (shcom)
-               return(setstatus((*shcom)(t)));
-       /* should use FIOCEXCL */
-       for (i=FDBASE; i<NOFILE; i++)
-               close(i);
-       if (resetsig) {
-               signal(SIGINT, SIG_DFL);
-               signal(SIGQUIT, SIG_DFL);
-       }
-       if (t->type == TPAREN)
-               exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
-       if (wp[0] == NULL)
-               exit(0);
-
-       cp = rexecve(wp[0], wp, makenv());
-       prs(wp[0]); prs(": "); warn(cp);
-       if (!execflg)
-               trap[0] = NULL;
-       leave();
-       /* NOTREACHED */
-       exit(1);
-}
-
-/*
- * 0< 1> are ignored as required
- * within pipelines.
- */
-static int
-iosetup(iop, pipein, pipeout)
-register struct ioword *iop;
-int pipein, pipeout;
-{
-       register int u = -1;
-       char *cp=NULL, *msg;
-
-       if (iop->io_unit == IODEFAULT)  /* take default */
-               iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
-       if (pipein && iop->io_unit == 0)
-               return(0);
-       if (pipeout && iop->io_unit == 1)
-               return(0);
-       msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
-       if ((iop->io_flag & IOHERE) == 0) {
-               cp = iop->io_name;
-               if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
-                       return(1);
-       }
-       if (iop->io_flag & IODUP) {
-               if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
-                       prs(cp);
-                       err(": illegal >& argument");
-                       return(1);
-               }
-               if (*cp == '-')
-                       iop->io_flag = IOCLOSE;
-               iop->io_flag &= ~(IOREAD|IOWRITE);
-       }
-       switch (iop->io_flag) {
-       case IOREAD:
-               u = open(cp, 0);
-               break;
-
-       case IOHERE:
-       case IOHERE|IOXHERE:
-               u = herein(iop->io_name, iop->io_flag&IOXHERE);
-               cp = "here file";
-               break;
-
-       case IOWRITE|IOCAT:
-               if ((u = open(cp, 1)) >= 0) {
-                       lseek(u, (long)0, 2);
-                       break;
-               }
-       case IOWRITE:
-               u = creat(cp, 0666);
-               break;
-
-       case IODUP:
-               u = dup2(*cp-'0', iop->io_unit);
-               break;
-
-       case IOCLOSE:
-               close(iop->io_unit);
-               return(0);
-       }
-       if (u < 0) {
-               prs(cp);
-               prs(": cannot ");
-               warn(msg);
-               return(1);
-       } else {
-               if (u != iop->io_unit) {
-                       dup2(u, iop->io_unit);
-                       close(u);
-               }
-       }
-       return(0);
-}
-
-static void
-echo(wp)
-register char **wp;
-{
-       register int i;
-
-       prs("+");
-       for (i=0; wp[i]; i++) {
-               if (i)
-                       prs(" ");
-               prs(wp[i]);
-       }
-       prs("\n");
-}
-
-static struct op **
-find1case(t, w)
-struct op *t;
-char *w;
-{
-       register struct op *t1;
-       struct op **tp;
-       register char **wp, *cp;
-
-       if (t == NULL)
-               return((struct op **)NULL);
-       if (t->type == TLIST) {
-               if ((tp = find1case(t->left, w)) != NULL)
-                       return(tp);
-               t1 = t->right;  /* TPAT */
-       } else
-               t1 = t;
-       for (wp = t1->words; *wp;)
-               if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
-                       return(&t1->left);
-       return((struct op **)NULL);
-}
-
-static struct op *
-findcase(t, w)
-struct op *t;
-char *w;
-{
-       register struct op **tp;
-
-       return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
-}
-
-/*
- * Enter a new loop level (marked for break/continue).
- */
-static void
-brkset(bc)
-struct brkcon *bc;
-{
-       bc->nextlev = brklist;
-       brklist = bc;
-}
-
-/*
- * Wait for the last process created.
- * Print a message for each process found
- * that was killed by a signal.
- * Ignore interrupt signals while waiting
- * unless `canintr' is true.
- */
-static int
-waitfor(lastpid, canintr)
-register int lastpid;
-int canintr;
-{
-       register int pid, rv;
-       int s;
-       int oheedint = heedint;
-
-       heedint = 0;
-       rv = 0;
-       do {
-               pid = wait(&s);
-               if (pid == -1) {
-                       if (errno != EINTR || canintr)
-                               break;
-               } else {
-                       if ((rv = WAITSIG(s)) != 0) {
-                               if (rv < NSIGNAL) {
-                                       if (signame[rv] != NULL) {
-                                               if (pid != lastpid) {
-                                                       prn(pid);
-                                                       prs(": ");
-                                               }
-                                               prs(signame[rv]);
-                                       }
-                               } else {
-                                       if (pid != lastpid) {
-                                               prn(pid);
-                                               prs(": ");
-                                       }
-                                       prs("Signal "); prn(rv); prs(" ");
-                               }
-                               if (WAITCORE(s))
-                                       prs(" - core dumped");
-                               if (rv >= NSIGNAL || signame[rv])
-                                       prs("\n");
-                               rv = -1;
-                       } else
-                               rv = WAITVAL(s);
-               }
-       } while (pid != lastpid);
-       heedint = oheedint;
-       if (intr) {
-               if (interactive) {
-                       if (canintr)
-                               intr = 0;
-               } else {
-                       if (exstat == 0) exstat = rv;
-                       onintr(0);
-               }
-       }
-       return(rv);
-}
-
-static int
-setstatus(s)
-register int s;
-{
-       exstat = s;
-       setval(lookup("?"), putn(s));
-       return(s);
-}
-
-/*
- * PATH-searching interface to execve.
- * If getenv("PATH") were kept up-to-date,
- * execvp might be used.
- */
-static char *
-rexecve(c, v, envp)
-char *c, **v, **envp;
-{
-       register int i;
-       register char *sp, *tp;
-       int eacces = 0, asis = 0;
-
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       char *name = c;
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
-       name = get_last_path_component(name);
-#endif
-       optind = 1;
-       if (find_applet_by_name(name)) {
-               /* We have to exec here since we vforked.  Running 
-                * run_applet_by_name() won't work and bad things
-                * will happen. */
-               execve("/proc/self/exe", v, envp);
-               execve("busybox", v, envp);
-       }
-#endif
-
-       sp = any('/', c)? "": path->value;
-       asis = *sp == '\0';
-       while (asis || *sp != '\0') {
-               asis = 0;
-               tp = e.linep;
-               for (; *sp != '\0'; tp++)
-                       if ((*tp = *sp++) == ':') {
-                               asis = *sp == '\0';
-                               break;
-                       }
-               if (tp != e.linep)
-                       *tp++ = '/';
-               for (i = 0; (*tp++ = c[i++]) != '\0';)
-                       ;
-
-               execve(e.linep, v, envp);
-               switch (errno) {
-               case ENOEXEC:
-                       *v = e.linep;
-                       tp = *--v;
-                       *v = e.linep;
-                       execve("/bin/sh", v, envp);
-                       *v = tp;
-                       return("no Shell");
-
-               case ENOMEM:
-                       return("program too big");
-
-               case E2BIG:
-                       return("argument list too long");
-
-               case EACCES:
-                       eacces++;
-                       break;
-               }
-       }
-       return(errno==ENOENT ? "not found" : "cannot execute");
-}
-
-/*
- * Run the command produced by generator `f'
- * applied to stream `arg'.
- */
-static int
-run(argp, f)
-struct ioarg *argp;
-int (*f)();
-{
-       struct op *otree;
-       struct wdblock *swdlist;
-       struct wdblock *siolist;
-       jmp_buf ev, rt;
-       xint *ofail;
-       int rv;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &rv;
-#endif
-
-       areanum++;
-       swdlist = wdlist;
-       siolist = iolist;
-       otree = outtree;
-       ofail = failpt;
-       rv = -1;
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               wdlist = 0;
-               iolist = 0;
-               pushio(argp, f);
-               e.iobase = e.iop;
-               yynerrs = 0;
-               if (setjmp(failpt = rt) == 0 && yyparse() == 0)
-                       rv = execute(outtree, NOPIPE, NOPIPE, 0);
-               quitenv();
-       }
-       wdlist = swdlist;
-       iolist = siolist;
-       failpt = ofail;
-       outtree = otree;
-       freearea(areanum--);
-       return(rv);
-}
-
-/* -------- do.c -------- */
-
-/*
- * built-in commands: doX
- */
-
-static int dohelp()
-{
-       int col;
-       const struct builtincmd *x;
-
-       printf("\nBuilt-in commands:\n");
-       printf("-------------------\n");
-
-       for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) {
-               if (!x->name)
-                       continue;
-               col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
-               if (col > 60) {
-                       printf("\n");
-                       col = 0;
-               }
-       }
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
-       {
-               int i;
-               const struct BB_applet *applet;
-               extern const struct BB_applet applets[];
-               extern const size_t NUM_APPLETS;
-
-               for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
-                       if (!applet->name)
-                               continue;
-               
-                       col += printf("%s%s", ((col == 0) ? "\t" : " "), 
-                                       applet->name);
-                       if (col > 60) {
-                               printf("\n");
-                               col = 0;
-                       }
-               }
-       }
-#endif
-       printf("\n\n");
-       return EXIT_SUCCESS;
-}
-
-
-
-static int
-dolabel()
-{
-       return(0);
-}
-
-static int
-dochdir(t)
-register struct op *t;
-{
-       register char *cp, *er;
-
-       if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
-               er = ": no home directory";
-       else if(chdir(cp) < 0)
-               er = ": bad directory";
-       else
-               return(0);
-       prs(cp != NULL? cp: "cd");
-       err(er);
-       return(1);
-}
-
-static int
-doshift(t)
-register struct op *t;
-{
-       register int n;
-
-       n = t->words[1]? getn(t->words[1]): 1;
-       if(dolc < n) {
-               err("nothing to shift");
-               return(1);
-       }
-       dolv[n] = dolv[0];
-       dolv += n;
-       dolc -= n;
-       setval(lookup("#"), putn(dolc));
-       return(0);
-}
-
-/*
- * execute login and newgrp directly
- */
-static int
-dologin(t)
-struct op *t;
-{
-       register char *cp;
-
-       if (interactive) {
-               signal(SIGINT, SIG_DFL);
-               signal(SIGQUIT, SIG_DFL);
-       }
-       cp = rexecve(t->words[0], t->words, makenv());
-       prs(t->words[0]); prs(": "); err(cp);
-       return(1);
-}
-
-static int
-doumask(t)
-register struct op *t;
-{
-       register int i, n;
-       register char *cp;
-
-       if ((cp = t->words[1]) == NULL) {
-               i = umask(0);
-               umask(i);
-               for (n=3*4; (n-=3) >= 0;)
-                       putc('0'+((i>>n)&07), stderr);
-               putc('\n', stderr);
-       } else {
-               for (n=0; *cp>='0' && *cp<='9'; cp++)
-                       n = n*8 + (*cp-'0');
-               umask(n);
-       }
-       return(0);
-}
-
-static int
-doexec(t)
-register struct op *t;
-{
-       register int i;
-       jmp_buf ex;
-       xint *ofail;
-
-       t->ioact = NULL;
-       for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
-               ;
-       if (i == 0)
-               return(1);
-       execflg = 1;
-       ofail = failpt;
-       if (setjmp(failpt = ex) == 0)
-               execute(t, NOPIPE, NOPIPE, FEXEC);
-       failpt = ofail;
-       execflg = 0;
-       return(1);
-}
-
-static int
-dodot(t)
-struct op *t;
-{
-       register int i;
-       register char *sp, *tp;
-       char *cp;
-
-       if ((cp = t->words[1]) == NULL)
-               return(0);
-       sp = any('/', cp)? ":": path->value;
-       while (*sp) {
-               tp = e.linep;
-               while (*sp && (*tp = *sp++) != ':')
-                       tp++;
-               if (tp != e.linep)
-                       *tp++ = '/';
-               for (i = 0; (*tp++ = cp[i++]) != '\0';)
-                       ;
-               if ((i = open(e.linep, 0)) >= 0) {
-                       exstat = 0;
-                       next(remap(i));
-                       return(exstat);
-               }
-       }
-       prs(cp);
-       err(": not found");
-       return(-1);
-}
-
-static int
-dowait(t)
-struct op *t;
-{
-       register int i;
-       register char *cp;
-
-       if ((cp = t->words[1]) != NULL) {
-               i = getn(cp);
-               if (i == 0)
-                       return(0);
-       } else
-               i = -1;
-       setstatus(waitfor(i, 1));
-       return(0);
-}
-
-static int
-doread(t)
-struct op *t;
-{
-       register char *cp, **wp;
-       register int nb = 0;
-       register int  nl = 0;
-
-       if (t->words[1] == NULL) {
-               err("Usage: read name ...");
-               return(1);
-       }
-       for (wp = t->words+1; *wp; wp++) {
-               for (cp = e.linep; !nl && cp < elinep-1; cp++)
-                       if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
-                           (nl = (*cp == '\n')) ||
-                           (wp[1] && any(*cp, ifs->value)))
-                               break;
-               *cp = 0;
-               if (nb <= 0)
-                       break;
-               setval(lookup(*wp), e.linep);
-       }
-       return(nb <= 0);
-}
-
-static int
-doeval(t)
-register struct op *t;
-{
-       return(RUN(awordlist, t->words+1, wdchar));
-}
-
-static int
-dotrap(t)
-register struct op *t;
-{
-       register int  n, i;
-       register int  resetsig;
-
-       if (t->words[1] == NULL) {
-               for (i=0; i<=_NSIG; i++)
-                       if (trap[i]) {
-                               prn(i);
-                               prs(": ");
-                               prs(trap[i]);
-                               prs("\n");
-                       }
-               return(0);
-       }
-       resetsig = isdigit(*t->words[1]);
-       for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
-               n = getsig(t->words[i]);
-               freecell(trap[n]);
-               trap[n] = 0;
-               if (!resetsig) {
-                       if (*t->words[1] != '\0') {
-                               trap[n] = strsave(t->words[1], 0);
-                               setsig(n, sig);
-                       } else
-                               setsig(n, SIG_IGN);
-               } else {
-                       if (interactive)
-                               if (n == SIGINT)
-                                       setsig(n, onintr);
-                               else
-                                       setsig(n, n == SIGQUIT ? SIG_IGN 
-                                                              : SIG_DFL);
-                       else
-                               setsig(n, SIG_DFL);
-               }
-       }
-       return(0);
-}
-
-static int
-getsig(s)
-char *s;
-{
-       register int n;
-
-       if ((n = getn(s)) < 0 || n > _NSIG) {
-               err("trap: bad signal number");
-               n = 0;
-       }
-       return(n);
-}
-
-static void
-setsig( register int n, void (*f)(int))
-{
-       if (n == 0)
-               return;
-       if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
-               ourtrap[n] = 1;
-               signal(n, f);
-       }
-}
-
-static int
-getn(as)
-char *as;
-{
-       register char *s;
-       register int n, m;
-
-       s = as;
-       m = 1;
-       if (*s == '-') {
-               m = -1;
-               s++;
-       }
-       for (n = 0; isdigit(*s); s++)
-               n = (n*10) + (*s-'0');
-       if (*s) {
-               prs(as);
-               err(": bad number");
-       }
-       return(n*m);
-}
-
-static int
-dobreak(t)
-struct op *t;
-{
-       return(brkcontin(t->words[1], 1));
-}
-
-static int
-docontinue(t)
-struct op *t;
-{
-       return(brkcontin(t->words[1], 0));
-}
-
-static int
-brkcontin(cp, val)
-register char *cp;
-int val;
-{
-       register struct brkcon *bc;
-       register int nl;
-
-       nl = cp == NULL? 1: getn(cp);
-       if (nl <= 0)
-               nl = 999;
-       do {
-               if ((bc = brklist) == NULL)
-                       break;
-               brklist = bc->nextlev;
-       } while (--nl);
-       if (nl) {
-               err("bad break/continue level");
-               return(1);
-       }
-       isbreak = val;
-       longjmp(bc->brkpt, 1);
-       /* NOTREACHED */
-}
-
-static int
-doexit(t)
-struct op *t;
-{
-       register char *cp;
-
-       execflg = 0;
-       if ((cp = t->words[1]) != NULL)
-               setstatus(getn(cp));
-       leave();
-       /* NOTREACHED */
-       return(0);
-}
-
-static int
-doexport(t)
-struct op *t;
-{
-       rdexp(t->words+1, export, EXPORT);
-       return(0);
-}
-
-static int
-doreadonly(t)
-struct op *t;
-{
-       rdexp(t->words+1, ronly, RONLY);
-       return(0);
-}
-
-static void
-rdexp(wp, f, key)
-register char **wp;
-void (*f)();
-int key;
-{
-       if (*wp != NULL) {
-               for (; *wp != NULL; wp++) {
-                       if (isassign(*wp)) {
-                               char *cp;
-                               assign(*wp, COPYV);
-                               for (cp = *wp; *cp != '='; cp++)
-                                       ;
-                               *cp = '\0';
-                       }
-                       if (checkname(*wp))
-                               (*f)(lookup(*wp));
-                       else
-                               badid(*wp);
-               }
-       } else
-               putvlist(key, 1);
-}
-
-static void
-badid(s)
-register char *s;
-{
-       prs(s);
-       err(": bad identifier");
-}
-
-static int
-doset(t)
-register struct op *t;
-{
-       register struct var *vp;
-       register char *cp;
-       register int n;
-
-       if ((cp = t->words[1]) == NULL) {
-               for (vp = vlist; vp; vp = vp->next)
-                       varput(vp->name, 1);
-               return(0);
-       }
-       if (*cp == '-') {
-               /* bad: t->words++; */
-               for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
-                       ;
-               if (*++cp == 0)
-                       flag['x'] = flag['v'] = 0;
-               else
-                       for (; *cp; cp++)
-                               switch (*cp) {
-                               case 'e':
-                                       if (!interactive)
-                                               flag['e']++;
-                                       break;
-
-                               default:
-                                       if (*cp>='a' && *cp<='z')
-                                               flag[(int)*cp]++;
-                                       break;
-                               }
-               setdash();
-       }
-       if (t->words[1]) {
-               t->words[0] = dolv[0];
-               for (n=1; t->words[n]; n++)
-                       setarea((char *)t->words[n], 0);
-               dolc = n-1;
-               dolv = t->words;
-               setval(lookup("#"), putn(dolc));
-               setarea((char *)(dolv-1), 0);
-       }
-       return(0);
-}
-
-static void
-varput(s, out)
-register char *s;
-int out;
-{
-       if (isalnum(*s) || *s == '_') {
-               write(out, s, strlen(s));
-               write(out, "\n", 1);
-       }
-}
-
-
-/*
- * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
- * This file contains code for the times builtin.
- */
-static int dotimes ()
-{
-       struct tms buf;
-       long int clk_tck = sysconf(_SC_CLK_TCK);
-
-       times(&buf);
-       printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
-              (int) (buf.tms_utime / clk_tck / 60),
-              ((double) buf.tms_utime) / clk_tck,
-              (int) (buf.tms_stime / clk_tck / 60),
-              ((double) buf.tms_stime) / clk_tck,
-              (int) (buf.tms_cutime / clk_tck / 60),
-              ((double) buf.tms_cutime) / clk_tck,
-              (int) (buf.tms_cstime / clk_tck / 60),
-              ((double) buf.tms_cstime) / clk_tck);
-       return 0;
-}
-
-
-static int (*inbuilt(char *s))()
-{
-       const struct builtincmd *bp;
-
-       for (bp = builtincmds; bp->name != NULL; bp++)
-               if (strcmp(bp->name, s) == 0)
-                       return(bp->builtinfunc);
-
-       return((int(*)())NULL);
-}
-
-/* -------- eval.c -------- */
-
-/*
- * ${}
- * `command`
- * blank interpretation
- * quoting
- * glob
- */
-
-static char ** eval( char **ap, int f)
-{
-       struct wdblock *wb;
-       char **wp;
-       char **wf;
-       jmp_buf ev;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &wp;
-       (void) &ap;
-#endif
-       wp = NULL;
-       wb = NULL;
-       wf = NULL;
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               while (*ap && isassign(*ap))
-                       expand(*ap++, &wb, f & ~DOGLOB);
-               if (flag['k']) {
-                       for (wf = ap; *wf; wf++) {
-                               if (isassign(*wf))
-                                       expand(*wf, &wb, f & ~DOGLOB);
-                       }
-               }
-               for (wb = addword((char *)0, wb); *ap; ap++) {
-                       if (!flag['k'] || !isassign(*ap))
-                               expand(*ap, &wb, f & ~DOKEY);
-               }
-               wb = addword((char *)0, wb);
-               wp = getwords(wb);
-               quitenv();
-       } else
-               gflg = 1;
-       return(gflg? (char **)NULL: wp);
-}
-
-/*
- * Make the exported environment from the exported
- * names in the dictionary. Keyword assignments
- * will already have been done.
- */
-static char **
-makenv()
-
-{
-       register struct wdblock *wb;
-       register struct var *vp;
-
-       wb = NULL;
-       for (vp = vlist; vp; vp = vp->next)
-               if (vp->status & EXPORT)
-                       wb = addword(vp->name, wb);
-       wb = addword((char *)0, wb);
-       return(getwords(wb));
-}
-
-static char *
-evalstr(cp, f)
-register char *cp;
-int f;
-{
-       struct wdblock *wb;
-
-       wb = NULL;
-       if (expand(cp, &wb, f)) {
-               if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
-                       cp = "";
-               DELETE(wb);
-       } else
-               cp = NULL;
-       return(cp);
-}
-
-static int
-expand( char *cp, register struct wdblock **wbp, int f)
-{
-       jmp_buf ev;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &cp;
-#endif
-       gflg = 0;
-       if (cp == NULL)
-               return(0);
-       if (!anys("$`'\"", cp) &&
-           !anys(ifs->value, cp) &&
-           ((f&DOGLOB)==0 || !anys("[*?", cp))) {
-               cp = strsave(cp, areanum);
-               if (f & DOTRIM)
-                       unquote(cp);
-               *wbp = addword(cp, *wbp);
-               return(1);
-       }
-       if (newenv(setjmp(errpt = ev)) == 0) {
-               PUSHIO(aword, cp, strchar);
-               e.iobase = e.iop;
-               while ((cp = blank(f)) && gflg == 0) {
-                       e.linep = cp;
-                       cp = strsave(cp, areanum);
-                       if ((f&DOGLOB) == 0) {
-                               if (f & DOTRIM)
-                                       unquote(cp);
-                               *wbp = addword(cp, *wbp);
-                       } else
-                               *wbp = glob(cp, *wbp);
-               }
-               quitenv();
-       } else
-               gflg = 1;
-       return(gflg == 0);
-}
-
-/*
- * Blank interpretation and quoting
- */
-static char *
-blank(f)
-int f;
-{
-       register int c, c1;
-       register char *sp;
-       int scanequals, foundequals;
-
-       sp = e.linep;
-       scanequals = f & DOKEY;
-       foundequals = 0;
-
-loop:
-       switch (c = subgetc('"', foundequals)) {
-       case 0:
-               if (sp == e.linep)
-                       return(0);
-               *e.linep++ = 0;
-               return(sp);
-
-       default:
-               if (f & DOBLANK && any(c, ifs->value))
-                       goto loop;
-               break;
-
-       case '"':
-       case '\'':
-               scanequals = 0;
-               if (INSUB())
-                       break;
-               for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
-                       if (c == 0)
-                               break;
-                       if (c == '\'' || !any(c, "$`\""))
-                               c |= QUOTE;
-                       *e.linep++ = c;
-               }
-               c = 0;
-       }
-       unget(c);
-       if (!isalpha(c) && c != '_')
-               scanequals = 0;
-       for (;;) {
-               c = subgetc('"', foundequals);
-               if (c == 0 ||
-                   f & (DOBLANK && any(c, ifs->value)) ||
-                   (!INSUB() && any(c, "\"'"))) {
-                       scanequals = 0;
-                       unget(c);
-                       if (any(c, "\"'"))
-                               goto loop;
-                       break;
-               }
-               if (scanequals) {
-                       if (c == '=') {
-                               foundequals = 1;
-                               scanequals  = 0;
-                       }
-                       else if (!isalnum(c) && c != '_')
-                               scanequals = 0;
-               }
-               *e.linep++ = c;
-       }
-       *e.linep++ = 0;
-       return(sp);
-}
-
-/*
- * Get characters, substituting for ` and $
- */
-static int
-subgetc(ec, quoted)
-register int ec;
-int quoted;
-{
-       register char c;
-
-again:
-       c = my_getc(ec);
-       if (!INSUB() && ec != '\'') {
-               if (c == '`') {
-                       if (grave(quoted) == 0)
-                               return(0);
-                       e.iop->task = XGRAVE;
-                       goto again;
-               }
-               if (c == '$' && (c = dollar(quoted)) == 0) {
-                       e.iop->task = XDOLL;
-                       goto again;
-               }
-       }
-       return(c);
-}
-
-/*
- * Prepare to generate the string returned by ${} substitution.
- */
-static int
-dollar(quoted)
-int quoted;
-{
-       int otask;
-       struct io *oiop;
-       char *dolp;
-       register char *s, c, *cp=NULL;
-       struct var *vp;
-
-       c = readc();
-       s = e.linep;
-       if (c != '{') {
-               *e.linep++ = c;
-               if (isalpha(c) || c == '_') {
-                       while ((c = readc())!=0 && (isalnum(c) || c == '_'))
-                               if (e.linep < elinep)
-                                       *e.linep++ = c;
-                       unget(c);
-               }
-               c = 0;
-       } else {
-               oiop = e.iop;
-               otask = e.iop->task;
-               e.iop->task = XOTHER;
-               while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
-                       if (e.linep < elinep)
-                               *e.linep++ = c;
-               if (oiop == e.iop)
-                       e.iop->task = otask;
-               if (c != '}') {
-                       err("unclosed ${");
-                       gflg++;
-                       return(c);
-               }
-       }
-       if (e.linep >= elinep) {
-               err("string in ${} too long");
-               gflg++;
-               e.linep -= 10;
-       }
-       *e.linep = 0;
-       if (*s)
-               for (cp = s+1; *cp; cp++)
-                       if (any(*cp, "=-+?")) {
-                               c = *cp;
-                               *cp++ = 0;
-                               break;
-                       }
-       if (s[1] == 0 && (*s == '*' || *s == '@')) {
-               if (dolc > 1) {
-                       /* currently this does not distinguish $* and $@ */
-                       /* should check dollar */
-                       e.linep = s;
-                       PUSHIO(awordlist, dolv+1, dolchar);
-                       return(0);
-               } else {        /* trap the nasty ${=} */
-                       s[0] = '1';
-                       s[1] = 0;
-               }
-       }
-       vp = lookup(s);
-       if ((dolp = vp->value) == null) {
-               switch (c) {
-               case '=':
-                       if (isdigit(*s)) {
-                               err("cannot use ${...=...} with $n");
-                               gflg++;
-                               break;
-                       }
-                       setval(vp, cp);
-                       dolp = vp->value;
-                       break;
-
-               case '-':
-                       dolp = strsave(cp, areanum);
-                       break;
-
-               case '?':
-                       if (*cp == 0) {
-                               prs("missing value for ");
-                               err(s);
-                       } else
-                               err(cp);
-                       gflg++;
-                       break;
-               }
-       } else if (c == '+')
-               dolp = strsave(cp, areanum);
-       if (flag['u'] && dolp == null) {
-               prs("unset variable: ");
-               err(s);
-               gflg++;
-       }
-       e.linep = s;
-       PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
-       return(0);
-}
-
-/*
- * Run the command in `...` and read its output.
- */
-static int
-grave(quoted)
-int quoted;
-{
-       register int i;
-       char *cp;
-       int pf[2];
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &cp;
-#endif
-       for (cp = e.iop->argp->aword; *cp != '`'; cp++)
-               if (*cp == 0) {
-                       err("no closing `");
-                       return(0);
-               }
-       if (openpipe(pf) < 0)
-               return(0);
-       if ((i = vfork()) == -1) {
-               closepipe(pf);
-               err("try again");
-               return(0);
-       }
-       if (i != 0) {
-               e.iop->argp->aword = ++cp;
-               close(pf[1]);
-               PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
-               return(1);
-       }
-       *cp = 0;
-       /* allow trapped signals */
-       for (i=0; i<=_NSIG; i++)
-               if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
-                       signal(i, SIG_DFL);
-       dup2(pf[1], 1);
-       closepipe(pf);
-       flag['e'] = 0;
-       flag['v'] = 0;
-       flag['n'] = 0;
-       cp = strsave(e.iop->argp->aword, 0);
-       areanum = 1;
-       freehere(areanum);
-       freearea(areanum);      /* free old space */
-       e.oenv = NULL;
-       e.iop = (e.iobase = iostack) - 1;
-       unquote(cp);
-       interactive = 0;
-       PUSHIO(aword, cp, nlchar);
-       onecommand();
-       exit(1);
-}
-
-static char *
-unquote(as)
-register char *as;
-{
-       register char *s;
-
-       if ((s = as) != NULL)
-               while (*s)
-                       *s++ &= ~QUOTE;
-       return(as);
-}
-
-/* -------- glob.c -------- */
-
-/*
- * glob
- */
-
-#define        scopy(x) strsave((x), areanum)
-#define        BLKSIZ  512
-#define        NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
-
-static struct wdblock  *cl, *nl;
-static char    spcl[] = "[?*";
-
-static struct wdblock *
-glob(cp, wb)
-char *cp;
-struct wdblock *wb;
-{
-       register int i;
-       register char *pp;
-
-       if (cp == 0)
-               return(wb);
-       i = 0;
-       for (pp = cp; *pp; pp++)
-               if (any(*pp, spcl))
-                       i++;
-               else if (!any(*pp & ~QUOTE, spcl))
-                       *pp &= ~QUOTE;
-       if (i != 0) {
-               for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
-                       nl = newword(cl->w_nword*2);
-                       for(i=0; i<cl->w_nword; i++) { /* for each argument */
-                               for (pp = cl->w_words[i]; *pp; pp++)
-                                       if (any(*pp, spcl)) {
-                                               globname(cl->w_words[i], pp);
-                                               break;
-                                       }
-                               if (*pp == '\0')
-                                       nl = addword(scopy(cl->w_words[i]), nl);
-                       }
-                       for(i=0; i<cl->w_nword; i++)
-                               DELETE(cl->w_words[i]);
-                       DELETE(cl);
-               }
-               for(i=0; i<cl->w_nword; i++)
-                       unquote(cl->w_words[i]);
-               glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
-               if (cl->w_nword) {
-                       for (i=0; i<cl->w_nword; i++)
-                               wb = addword(cl->w_words[i], wb);
-                       DELETE(cl);
-                       return(wb);
-               }
-       }
-       wb = addword(unquote(cp), wb);
-       return(wb);
-}
-
-static void
-globname(we, pp)
-char *we;
-register char *pp;
-{
-       register char *np, *cp;
-       char *name, *gp, *dp;
-       int k;
-       DIR *dirp;
-       struct dirent *de;
-       char dname[NAME_MAX+1];
-       struct stat dbuf;
-
-       for (np = we; np != pp; pp--)
-               if (pp[-1] == '/')
-                       break;
-       for (dp = cp = space((int)(pp-np)+3); np < pp;)
-               *cp++ = *np++;
-       *cp++ = '.';
-       *cp = '\0';
-       for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
-               *cp++ = *np++;
-       *cp = '\0';
-       dirp = opendir(dp);
-       if (dirp == 0) {
-               DELETE(dp);
-               DELETE(gp);
-               return;
-       }
-       dname[NAME_MAX] = '\0';
-       while ((de=readdir(dirp))!=NULL) {
-               /* XXX Hmmm... What this could be? (abial) */
-               /*
-               if (ent[j].d_ino == 0)
-                       continue;
-               */
-               strncpy(dname, de->d_name, NAME_MAX);
-                       if (dname[0] == '.')
-                               if (*gp != '.')
-                                       continue;
-                       for(k=0; k<NAME_MAX; k++)
-                               if (any(dname[k], spcl))
-                                       dname[k] |= QUOTE;
-                       if (gmatch(dname, gp)) {
-                               name = generate(we, pp, dname, np);
-                               if (*np && !anys(np, spcl)) {
-                                       if (stat(name,&dbuf)) {
-                                               DELETE(name);
-                                               continue;
-                                       }
-                               }
-                               nl = addword(name, nl);
-                       }
-       }
-       closedir(dirp);
-       DELETE(dp);
-       DELETE(gp);
-}
-
-/*
- * generate a pathname as below.
- * start..end1 / middle end
- * the slashes come for free
- */
-static char *
-generate(start1, end1, middle, end)
-char *start1;
-register char *end1;
-char *middle, *end;
-{
-       char *p;
-       register char *op, *xp;
-
-       p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
-       for (xp = start1; xp != end1;)
-               *op++ = *xp++;
-       for (xp = middle; (*op++ = *xp++) != '\0';)
-               ;
-       op--;
-       for (xp = end; (*op++ = *xp++) != '\0';)
-               ;
-       return(p);
-}
-
-static int
-anyspcl(wb)
-register struct wdblock *wb;
-{
-       register int i;
-       register char **wd;
-
-       wd = wb->w_words;
-       for (i=0; i<wb->w_nword; i++)
-               if (anys(spcl, *wd++))
-                       return(1);
-       return(0);
-}
-
-static int
-xstrcmp(p1, p2)
-char *p1, *p2;
-{
-       return(strcmp(*(char **)p1, *(char **)p2));
-}
-
-/* -------- word.c -------- */
-
-static struct wdblock *
-newword(nw)
-register int nw;
-{
-       register struct wdblock *wb;
-
-       wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
-       wb->w_bsize = nw;
-       wb->w_nword = 0;
-       return(wb);
-}
-
-static struct wdblock *
-addword(wd, wb)
-char *wd;
-register struct wdblock *wb;
-{
-       register struct wdblock *wb2;
-       register int nw;
-
-       if (wb == NULL)
-               wb = newword(NSTART);
-       if ((nw = wb->w_nword) >= wb->w_bsize) {
-               wb2 = newword(nw * 2);
-               memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
-               wb2->w_nword = nw;
-               DELETE(wb);
-               wb = wb2;
-       }
-       wb->w_words[wb->w_nword++] = wd;
-       return(wb);
-}
-static 
-char **
-getwords(wb)
-register struct wdblock *wb;
-{
-       register char **wd;
-       register int nb;
-
-       if (wb == NULL)
-               return((char **)NULL);
-       if (wb->w_nword == 0) {
-               DELETE(wb);
-               return((char **)NULL);
-       }
-       wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
-       memcpy((char *)wd, (char *)wb->w_words, nb);
-       DELETE(wb);     /* perhaps should done by caller */
-       return(wd);
-}
-
-int (*func)(char *, char *);
-int    globv;
-
-static void
-glob0(a0, a1, a2, a3)
-char *a0;
-unsigned a1;
-int a2;
-int (*a3) (char *, char *);
-{
-       func = a3;
-       globv = a2;
-       glob1(a0, a0 + a1 * a2);
-}
-
-static void
-glob1(base, lim)
-char *base, *lim;
-{
-       register char *i, *j;
-       int v2;
-       char *lptr, *hptr;
-       int c;
-       unsigned n;
-
-
-       v2 = globv;
-
-top:
-       if ((n=(int)(lim-base)) <= v2)
-               return;
-       n = v2 * (n / (2*v2));
-       hptr = lptr = base+n;
-       i = base;
-       j = lim-v2;
-       for(;;) {
-               if (i < lptr) {
-                       if ((c = (*func)(i, lptr)) == 0) {
-                               glob2(i, lptr -= v2);
-                               continue;
-                       }
-                       if (c < 0) {
-                               i += v2;
-                               continue;
-                       }
-               }
-
-begin:
-               if (j > hptr) {
-                       if ((c = (*func)(hptr, j)) == 0) {
-                               glob2(hptr += v2, j);
-                               goto begin;
-                       }
-                       if (c > 0) {
-                               if (i == lptr) {
-                                       glob3(i, hptr += v2, j);
-                                       i = lptr += v2;
-                                       goto begin;
-                               }
-                               glob2(i, j);
-                               j -= v2;
-                               i += v2;
-                               continue;
-                       }
-                       j -= v2;
-                       goto begin;
-               }
-
-
-               if (i == lptr) {
-                       if (lptr-base >= lim-hptr) {
-                               glob1(hptr+v2, lim);
-                               lim = lptr;
-                       } else {
-                               glob1(base, lptr);
-                               base = hptr+v2;
-                       }
-                       goto top;
-               }
-
-
-               glob3(j, lptr -= v2, i);
-               j = hptr -= v2;
-       }
-}
-
-static void
-glob2(i, j)
-char *i, *j;
-{
-       register char *index1, *index2, c;
-       int m;
-
-       m = globv;
-       index1 = i;
-       index2 = j;
-       do {
-               c = *index1;
-               *index1++ = *index2;
-               *index2++ = c;
-       } while(--m);
-}
-
-static void
-glob3(i, j, k)
-char *i, *j, *k;
-{
-       register char *index1, *index2, *index3;
-       int c;
-       int m;
-
-       m = globv;
-       index1 = i;
-       index2 = j;
-       index3 = k;
-       do {
-               c = *index1;
-               *index1++ = *index3;
-               *index3++ = *index2;
-               *index2++ = c;
-       } while(--m);
-}
-
-/* -------- io.c -------- */
-
-/*
- * shell IO
- */
-
-static int my_getc( int ec)
-{
-       register int c;
-
-       if(e.linep > elinep) {
-               while((c=readc()) != '\n' && c)
-                       ;
-               err("input line too long");
-               gflg++;
-               return(c);
-       }
-       c = readc();
-       if (ec != '\'' && e.iop->task != XGRAVE) {
-               if(c == '\\') {
-                       c = readc();
-                       if (c == '\n' && ec != '\"')
-                               return(my_getc(ec));
-                       c |= QUOTE;
-               }
-       }
-       return(c);
-}
-
-static void
-unget(c)
-int c;
-{
-       if (e.iop >= e.iobase)
-               e.iop->peekc = c;
-}
-
-static int
-eofc()
-
-{
-  return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
-}
-
-static int
-readc()
-{
-       register int c;
-
-       for (; e.iop >= e.iobase; e.iop--)
-               if ((c = e.iop->peekc) != '\0') {
-                       e.iop->peekc = 0;
-                       return(c);
-               }
-               else {
-                   if (e.iop->prev != 0) {
-                       if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
-                               if (c == -1) {
-                                       e.iop++;
-                                       continue;
-                               }
-                               if (e.iop == iostack)
-                                       ioecho(c);
-                               return(e.iop->prev = c);
-                       }
-                       else if (e.iop->task == XIO && e.iop->prev != '\n') {
-                               e.iop->prev = 0;
-                               if (e.iop == iostack)
-                                       ioecho('\n');
-                               return '\n';
-                       }
-                   }
-                   if (e.iop->task == XIO) {
-                       if (multiline)
-                           return e.iop->prev = 0;
-                       if (interactive && e.iop == iostack+1) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                           current_prompt=prompt->value;
-#else
-                           prs(prompt->value);
-#endif
-                       }
-                   }
-               }
-       if (e.iop >= iostack)
-               return(0);
-       leave();
-       /* NOTREACHED */
-       return(0);
-}
-
-static void
-ioecho(c)
-char c;
-{
-       if (flag['v'])
-               write(2, &c, sizeof c);
-}
-
-static void
-pushio(argp, fn)
-struct ioarg *argp;
-int (*fn)();
-{
-       if (++e.iop >= &iostack[NPUSH]) {
-               e.iop--;
-               err("Shell input nested too deeply");
-               gflg++;
-               return;
-       }
-       e.iop->iofn = fn;
-
-       if (argp->afid != AFID_NOBUF)
-         e.iop->argp = argp;
-       else {
-         e.iop->argp  = ioargstack + (e.iop - iostack);
-         *e.iop->argp = *argp;
-         e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
-         if (isatty(e.iop->argp->afile) == 0 &&
-             (e.iop == &iostack[0] ||
-              lseek(e.iop->argp->afile, 0L, 1) != -1)) {
-           if (++bufid == AFID_NOBUF)
-             bufid = AFID_ID;
-           e.iop->argp->afid  = bufid;
-         }
-       }
-
-       e.iop->prev  = ~'\n';
-       e.iop->peekc = 0;
-       e.iop->xchar = 0;
-       e.iop->nlcount = 0;
-       if (fn == filechar || fn == linechar)
-               e.iop->task = XIO;
-       else if (fn == gravechar || fn == qgravechar)
-               e.iop->task = XGRAVE;
-       else
-               e.iop->task = XOTHER;
-}
-
-static struct io *
-setbase(ip)
-struct io *ip;
-{
-       register struct io *xp;
-
-       xp = e.iobase;
-       e.iobase = ip;
-       return(xp);
-}
-
-/*
- * Input generating functions
- */
-
-/*
- * Produce the characters of a string, then a newline, then EOF.
- */
-static int
-nlchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL)
-               return(0);
-       if ((c = *ap->aword++) == 0) {
-               ap->aword = NULL;
-               return('\n');
-       }
-       return(c);
-}
-
-/*
- * Given a list of words, produce the characters
- * in them, with a space after each word.
- */
-static int
-wdchar(ap)
-register struct ioarg *ap;
-{
-       register char c;
-       register char **wl;
-
-       if ((wl = ap->awordlist) == NULL)
-               return(0);
-       if (*wl != NULL) {
-               if ((c = *(*wl)++) != 0)
-                       return(c & 0177);
-               ap->awordlist++;
-               return(' ');
-       }
-       ap->awordlist = NULL;
-       return('\n');
-}
-
-/*
- * Return the characters of a list of words,
- * producing a space between them.
- */
-static int
-dolchar(ap)
-register struct ioarg *ap;
-{
-       register char *wp;
-
-       if ((wp = *ap->awordlist++) != NULL) {
-               PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
-               return(-1);
-       }
-       return(0);
-}
-
-static int
-xxchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL)
-               return(0);
-       if ((c = *ap->aword++) == '\0') {
-               ap->aword = NULL;
-               return(' ');
-       }
-       return(c);
-}
-
-/*
- * Produce the characters from a single word (string).
- */
-static int
-strchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL || (c = *ap->aword++) == 0)
-               return(0);
-       return(c);
-}
-
-/*
- * Produce quoted characters from a single word (string).
- */
-static int
-qstrchar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if (ap->aword == NULL || (c = *ap->aword++) == 0)
-               return(0);
-       return(c|QUOTE);
-}
-
-/*
- * Return the characters from a file.
- */
-static int
-filechar(ap)
-register struct ioarg *ap;
-{
-       register int i;
-       char c;
-       struct iobuf *bp = ap->afbuf;
-
-       if (ap->afid != AFID_NOBUF) {
-         if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
-           if (i)
-             lseek(ap->afile, ap->afpos, 0);
-           i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
-           if (i <= 0) {
-             closef(ap->afile);
-             return 0;
-           }
-           bp->id = ap->afid;
-           bp->ebufp = (bp->bufp  = bp->buf) + i;
-         }
-         ap->afpos++;
-         return *bp->bufp++ & 0177;
-       }
-
-#ifdef BB_FEATURE_COMMAND_EDITING
-       if (interactive) {
-           static char mycommand[BUFSIZ];
-           static int position = 0, size = 0;
-
-           while (size == 0 || position >= size) {
-               cmdedit_read_input(current_prompt, mycommand);
-               size = strlen(mycommand);
-               position = 0;
-           }
-           c = mycommand[position];
-           position++;
-           return(c);
-       } else 
-#endif
-       {
-               i = safe_read(ap->afile, &c, sizeof(c));
-               return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
-       }
-}
-
-/*
- * Return the characters from a here temp file.
- */
-static int
-herechar(ap)
-register struct ioarg *ap;
-{
-       char c;
-
-
-       if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
-               close(ap->afile);
-               c = 0;
-       }
-       return (c);
-
-}
-
-/*
- * Return the characters produced by a process (`...`).
- * Quote them if required, and remove any trailing newline characters.
- */
-static int
-gravechar(ap, iop)
-struct ioarg *ap;
-struct io *iop;
-{
-       register int c;
-
-       if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
-               c = ' ';
-       return(c);
-}
-
-static int
-qgravechar(ap, iop)
-register struct ioarg *ap;
-struct io *iop;
-{
-       register int c;
-
-       if (iop->xchar) {
-               if (iop->nlcount) {
-                       iop->nlcount--;
-                       return('\n'|QUOTE);
-               }
-               c = iop->xchar;
-               iop->xchar = 0;
-       } else if ((c = filechar(ap)) == '\n') {
-               iop->nlcount = 1;
-               while ((c = filechar(ap)) == '\n')
-                       iop->nlcount++;
-               iop->xchar = c;
-               if (c == 0)
-                       return(c);
-               iop->nlcount--;
-               c = '\n';
-       }
-       return(c!=0? c|QUOTE: 0);
-}
-
-/*
- * Return a single command (usually the first line) from a file.
- */
-static int
-linechar(ap)
-register struct ioarg *ap;
-{
-       register int c;
-
-       if ((c = filechar(ap)) == '\n') {
-               if (!multiline) {
-                       closef(ap->afile);
-                       ap->afile = -1; /* illegal value */
-               }
-       }
-       return(c);
-}
-
-static void
-prs(s)
-register char *s;
-{
-       if (*s)
-               write(2, s, strlen(s));
-}
-
-static void
-prn(u)
-unsigned u;
-{
-       prs(itoa(u, 0));
-}
-
-static void
-closef(i)
-register int i;
-{
-       if (i > 2)
-               close(i);
-}
-
-static void
-closeall()
-{
-       register int u;
-
-       for (u=NUFILE; u<NOFILE;)
-               close(u++);
-}
-
-/*
- * remap fd into Shell's fd space
- */
-static int
-remap(fd)
-register int fd;
-{
-       register int i;
-       int map[NOFILE];
-
-       if (fd < e.iofd) {
-               for (i=0; i<NOFILE; i++)
-                       map[i] = 0;
-               do {
-                       map[fd] = 1;
-                       fd = dup(fd);
-               } while (fd >= 0 && fd < e.iofd);
-               for (i=0; i<NOFILE; i++)
-                       if (map[i])
-                               close(i);
-               if (fd < 0)
-                       err("too many files open in shell");
-       }
-       return(fd);
-}
-
-static int
-openpipe(pv)
-register int *pv;
-{
-       register int i;
-
-       if ((i = pipe(pv)) < 0)
-               err("can't create pipe - try again");
-       return(i);
-}
-
-static void
-closepipe(pv)
-register int *pv;
-{
-       if (pv != NULL) {
-               close(*pv++);
-               close(*pv);
-       }
-}
-
-/* -------- here.c -------- */
-
-/*
- * here documents
- */
-
-static void
-markhere(s, iop)
-register char *s;
-struct ioword *iop;
-{
-       register struct here *h, *lh;
-
-       h = (struct here *) space(sizeof(struct here));
-       if (h == 0)
-               return;
-       h->h_tag = evalstr(s, DOSUB);
-       if (h->h_tag == 0)
-               return;
-       h->h_iop = iop;
-       iop->io_name = 0;
-       h->h_next = NULL;
-       if (inhere == 0)
-               inhere = h;
-       else
-               for (lh = inhere; lh!=NULL; lh = lh->h_next)
-                       if (lh->h_next == 0) {
-                               lh->h_next = h;
-                               break;
-                       }
-       iop->io_flag |= IOHERE|IOXHERE;
-       for (s = h->h_tag; *s; s++)
-               if (*s & QUOTE) {
-                       iop->io_flag &= ~ IOXHERE;
-                       *s &= ~ QUOTE;
-               }
-       h->h_dosub = iop->io_flag & IOXHERE;
-}
-
-static void
-gethere()
-{
-       register struct here *h, *hp;
-
-       /* Scan here files first leaving inhere list in place */
-       for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
-         readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
-
-       /* Make inhere list active - keep list intact for scraphere */
-       if (hp != NULL) {
-         hp->h_next = acthere;
-         acthere    = inhere;
-         inhere     = NULL;
-       }
-}
-
-static void
-readhere(name, s, ec)
-char **name;
-register char *s;
-int ec;
-{
-       int tf;
-       char tname[30] = ".msh_XXXXXX";
-       register int c;
-       jmp_buf ev;
-       char myline [LINELIM+1];
-       char *thenext;
-
-       tf = mkstemp(tname);
-       if (tf < 0)
-               return;
-       *name = strsave(tname, areanum);
-       if (newenv(setjmp(errpt = ev)) != 0)
-               unlink(tname);
-       else {
-               pushio(e.iop->argp, e.iop->iofn);
-               e.iobase = e.iop;
-               for (;;) {
-                   if (interactive && e.iop <= iostack) {
-#ifdef BB_FEATURE_COMMAND_EDITING
-                           current_prompt=cprompt->value;
-#else
-                           prs(cprompt->value);
-#endif
-                       }
-                       thenext = myline;
-                       while ((c = my_getc(ec)) != '\n' && c) {
-                               if (ec == '\'')
-                                       c &= ~ QUOTE;
-                               if (thenext >= &myline[LINELIM]) {
-                                       c = 0;
-                                       break;
-                               }
-                               *thenext++ = c;
-                       }
-                       *thenext = 0;
-                       if (strcmp(s, myline) == 0 || c == 0)
-                               break;
-                       *thenext++ = '\n';
-                       write (tf, myline, (int)(thenext-myline));
-               }
-               if (c == 0) {
-                       prs("here document `"); prs(s); err("' unclosed");
-               }
-               quitenv();
-       }
-       close(tf);
-}
-
-/*
- * open here temp file.
- * if unquoted here, expand here temp file into second temp file.
- */
-static int
-herein(hname, xdoll)
-char *hname;
-int xdoll;
-{
-       register int hf;
-       int tf;
-
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &tf;
-#endif
-       if (hname == 0)
-               return(-1);
-       hf = open(hname, 0);
-       if (hf < 0)
-               return (-1);
-       if (xdoll) {
-               char c;
-               char tname[30] = ".msh_XXXXXX";
-               jmp_buf ev;
-       
-               tf = mkstemp(tname);
-               if (tf < 0)
-                       return (-1);
-               if (newenv(setjmp(errpt = ev)) == 0) {
-                       PUSHIO(afile, hf, herechar);
-                       setbase(e.iop);
-                       while ((c = subgetc(0, 0)) != 0) {
-                               c &= ~ QUOTE;
-                               write(tf, &c, sizeof c);
-                       }
-                       quitenv();
-               } else
-                       unlink(tname);
-               close(tf);
-               tf = open(tname, 0);
-               unlink(tname);
-               return (tf);
-       } else
-               return (hf);
-}
-
-static void
-scraphere()
-{
-       register struct here *h;
-
-       for (h = inhere; h != NULL; h = h->h_next) {
-               if (h->h_iop && h->h_iop->io_name)
-                 unlink(h->h_iop->io_name);
-       }
-       inhere = NULL;
-}
-
-/* unlink here temp files before a freearea(area) */
-static void
-freehere(area)
-int area;
-{
-       register struct here *h, *hl;
-
-       hl = NULL;
-       for (h = acthere; h != NULL; h = h->h_next)
-               if (getarea((char *) h) >= area) {
-                       if (h->h_iop->io_name != NULL)
-                               unlink(h->h_iop->io_name);
-                       if (hl == NULL)
-                               acthere = h->h_next;
-                       else
-                               hl->h_next = h->h_next;
-               } else
-                       hl = h;
-}
-
-
-
-/*
- * Copyright (c) 1987,1997, Prentice Hall
- * All rights reserved.
- * 
- * Redistribution and use of the MINIX operating system in source and
- * binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- * 
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * 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.
- * 
- * Neither the name of Prentice Hall nor the names of the software
- * authors or contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
diff --git a/busybox/sleep.c b/busybox/sleep.c
deleted file mode 100644 (file)
index 3bcab88..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sleep implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int sleep_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       if (sleep(atoi(*(++argv))) != 0)
-               perror_msg_and_die("sleep");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/sort.c b/busybox/sort.c
deleted file mode 100644 (file)
index 4f4979c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sort implementation for busybox
- *
- *
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int compare_ascii(const void *x, const void *y)
-{
-       return strcmp(*(char **)x, *(char **)y);
-}
-
-static int compare_numeric(const void *x, const void *y)
-{
-       int z = atoi(*(char **)x) - atoi(*(char **)y);
-       return z ? z : strcmp(*(char **)x, *(char **)y);
-}
-
-int sort_main(int argc, char **argv)
-{
-       FILE *fp;
-       char *line, **lines = NULL;
-       int i, opt, nlines = 0;
-       int (*compare)(const void *, const void *) = compare_ascii;
-#ifdef BB_FEATURE_SORT_REVERSE
-       int reverse = FALSE;
-#endif
-#ifdef BB_FEATURE_SORT_UNIQUE
-       int unique = FALSE;
-#endif
-
-       while ((opt = getopt(argc, argv, "nru")) != -1) {
-               switch (opt) {
-                       case 'n':
-                               compare = compare_numeric;
-                               break;
-#ifdef BB_FEATURE_SORT_REVERSE
-                       case 'r':
-                               reverse = TRUE;
-                               break;
-#endif
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       case 'u':
-                               unique = TRUE;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* read the input */
-       for (i = optind; i == optind || i < argc; i++) {
-               if (argv[i] == NULL)
-                       fp = stdin;
-               else
-                       fp = xfopen(argv[i], "r");
-
-               while ((line = get_line_from_file(fp)) != NULL) {
-                       lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
-                       chomp(line);
-                       lines[nlines++] = line;
-               }
-       }
-
-       /* sort it */
-       qsort(lines, nlines, sizeof(char *), compare);
-
-       /* print it */
-#ifdef BB_FEATURE_SORT_REVERSE
-       if (reverse) {
-               for (i = --nlines; 0 <= i; i--)
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i])))
-#endif
-                               puts(lines[i]);
-       } else
-#endif
-               for (i = 0; i < nlines; i++)
-#ifdef BB_FEATURE_SORT_UNIQUE
-                       if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i])))
-#endif
-                               puts(lines[i]);
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/stty.c b/busybox/stty.c
deleted file mode 100644 (file)
index 2e00a49..0000000
+++ /dev/null
@@ -1,1376 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* stty -- change and print terminal line settings
-   Copyright (C) 1990-1999 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Usage: stty [-ag] [-F device] [setting...]
-
-   Options:
-   -a Write all current settings to stdout in human-readable form.
-   -g Write all current settings to stdout in stty-readable form.
-   -F Open and use the specified device instead of stdin
-
-   If no args are given, write to stdout the baud rate and settings that
-   have been changed from their defaults.  Mode reading and changes
-   are done on the specified device, or stdin if none was specified.
-
-   David MacKenzie <djm@gnu.ai.mit.edu>
-
-   Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
-
-   */
-
-//#define TEST
-
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <getopt.h>
-
-#include <sys/param.h>
-#include <unistd.h>
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <memory.h>
-#include <fcntl.h>
-#include "busybox.h"
-
-#define STREQ(a, b) (strcmp ((a), (b)) == 0)
-
-
-#ifndef _POSIX_VDISABLE
-# define _POSIX_VDISABLE ((unsigned char) 0)
-#endif
-
-#define Control(c) ((c) & 0x1f)
-/* Canonical values for control characters. */
-#ifndef CINTR
-# define CINTR Control ('c')
-#endif
-#ifndef CQUIT
-# define CQUIT 28
-#endif
-#ifndef CERASE
-# define CERASE 127
-#endif
-#ifndef CKILL
-# define CKILL Control ('u')
-#endif
-#ifndef CEOF
-# define CEOF Control ('d')
-#endif
-#ifndef CEOL
-# define CEOL _POSIX_VDISABLE
-#endif
-#ifndef CSTART
-# define CSTART Control ('q')
-#endif
-#ifndef CSTOP
-# define CSTOP Control ('s')
-#endif
-#ifndef CSUSP
-# define CSUSP Control ('z')
-#endif
-#if defined(VEOL2) && !defined(CEOL2)
-# define CEOL2 _POSIX_VDISABLE
-#endif
-/* ISC renamed swtch to susp for termios, but we'll accept either name.  */
-#if defined(VSUSP) && !defined(VSWTCH)
-# define VSWTCH VSUSP
-# define CSWTCH CSUSP
-#endif
-#if defined(VSWTCH) && !defined(CSWTCH)
-# define CSWTCH _POSIX_VDISABLE
-#endif
-
-/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
-   So the default is to disable `swtch.'  */
-#if defined (__sparc__) && defined (__svr4__)
-# undef CSWTCH
-# define CSWTCH _POSIX_VDISABLE
-#endif
-
-#if defined(VWERSE) && !defined (VWERASE)       /* AIX-3.2.5 */
-# define VWERASE VWERSE
-#endif
-#if defined(VDSUSP) && !defined (CDSUSP)
-# define CDSUSP Control ('y')
-#endif
-#if !defined(VREPRINT) && defined(VRPRNT)       /* Irix 4.0.5 */
-# define VREPRINT VRPRNT
-#endif
-#if defined(VREPRINT) && !defined(CRPRNT)
-# define CRPRNT Control ('r')
-#endif
-#if defined(VWERASE) && !defined(CWERASE)
-# define CWERASE Control ('w')
-#endif
-#if defined(VLNEXT) && !defined(CLNEXT)
-# define CLNEXT Control ('v')
-#endif
-#if defined(VDISCARD) && !defined(VFLUSHO)
-# define VFLUSHO VDISCARD
-#endif
-#if defined(VFLUSH) && !defined(VFLUSHO)        /* Ultrix 4.2 */
-# define VFLUSHO VFLUSH
-#endif
-#if defined(CTLECH) && !defined(ECHOCTL)        /* Ultrix 4.3 */
-# define ECHOCTL CTLECH
-#endif
-#if defined(TCTLECH) && !defined(ECHOCTL)       /* Ultrix 4.2 */
-# define ECHOCTL TCTLECH
-#endif
-#if defined(CRTKIL) && !defined(ECHOKE)         /* Ultrix 4.2 and 4.3 */
-# define ECHOKE CRTKIL
-#endif
-#if defined(VFLUSHO) && !defined(CFLUSHO)
-# define CFLUSHO Control ('o')
-#endif
-#if defined(VSTATUS) && !defined(CSTATUS)
-# define CSTATUS Control ('t')
-#endif
-
-/* Which speeds to set.  */
-enum speed_setting {
-       input_speed, output_speed, both_speeds
-};
-
-/* What to output and how.  */
-enum output_type {
-       changed, all, recoverable       /* Default, -a, -g.  */
-};
-
-/* Which member(s) of `struct termios' a mode uses.  */
-enum mode_type {
-       control, input, output, local, combination
-};
-
-
-static const char evenp     [] = "evenp";
-static const char raw       [] = "raw";
-static const char stty_min  [] = "min";
-static const char stty_time [] = "time";
-static const char stty_swtch[] = "swtch";
-static const char stty_eol  [] = "eol";
-static const char stty_eof  [] = "eof";
-static const char parity    [] = "parity";
-static const char stty_oddp [] = "oddp";
-static const char stty_nl   [] = "nl";
-static const char stty_ek   [] = "ek";
-static const char stty_sane [] = "sane";
-static const char cbreak    [] = "cbreak";
-static const char stty_pass8[] = "pass8";
-static const char litout    [] = "litout";
-static const char cooked    [] = "cooked";
-static const char decctlq   [] = "decctlq";
-static const char stty_tabs [] = "tabs";
-static const char stty_lcase[] = "lcase";
-static const char stty_LCASE[] = "LCASE";
-static const char stty_crt  [] = "crt";
-static const char stty_dec  [] = "dec";
-
-
-/* Flags for `struct mode_info'. */
-#define SANE_SET 1              /* Set in `sane' mode.                  */
-#define SANE_UNSET 2            /* Unset in `sane' mode.                */
-#define REV 4                   /* Can be turned off by prepending `-'. */
-#define OMIT 8                  /* Don't display value.                 */
-
-/* Each mode.  */
-struct mode_info {
-       const char *name;       /* Name given on command line.           */
-       enum mode_type type;    /* Which structure element to change.    */
-       char flags;             /* Setting and display options.          */
-       unsigned long bits;     /* Bits to set for this mode.            */
-       unsigned long mask;     /* Other bits to turn off for this mode. */
-};
-
-static const struct  mode_info mode_info[] = {
-       {"parenb",   control,     REV,               PARENB,     0 },
-       {"parodd",   control,     REV,               PARODD,     0 },
-       {"cs5",      control,     0,                 CS5,     CSIZE},
-       {"cs6",      control,     0,                 CS6,     CSIZE},
-       {"cs7",      control,     0,                 CS7,     CSIZE},
-       {"cs8",      control,     0,                 CS8,     CSIZE},
-       {"hupcl",    control,     REV,               HUPCL,      0 },
-       {"hup",      control,     REV        | OMIT, HUPCL,      0 },
-       {"cstopb",   control,     REV,               CSTOPB,     0 },
-       {"cread",    control,     SANE_SET   | REV,  CREAD,      0 },
-       {"clocal",   control,     REV,               CLOCAL,     0 },
-#ifdef CRTSCTS
-       {"crtscts",  control,     REV,               CRTSCTS,    0 },
-#endif
-       {"ignbrk",   input,       SANE_UNSET | REV,  IGNBRK,     0 },
-       {"brkint",   input,       SANE_SET   | REV,  BRKINT,     0 },
-       {"ignpar",   input,       REV,               IGNPAR,     0 },
-       {"parmrk",   input,       REV,               PARMRK,     0 },
-       {"inpck",    input,       REV,               INPCK,      0 },
-       {"istrip",   input,       REV,               ISTRIP,     0 },
-       {"inlcr",    input,       SANE_UNSET | REV,  INLCR,      0 },
-       {"igncr",    input,       SANE_UNSET | REV,  IGNCR,      0 },
-       {"icrnl",    input,       SANE_SET   | REV,  ICRNL,      0 },
-       {"ixon",     input,       REV,               IXON,       0 },
-       {"ixoff",    input,       SANE_UNSET | REV,  IXOFF,      0 },
-       {"tandem",   input,       REV        | OMIT, IXOFF,      0 },
-#ifdef IUCLC
-       {"iuclc",    input,       SANE_UNSET | REV,  IUCLC,      0 },
-#endif
-#ifdef IXANY
-       {"ixany",    input,       SANE_UNSET | REV,  IXANY,      0 },
-#endif
-#ifdef IMAXBEL
-       {"imaxbel",  input,       SANE_SET   | REV,  IMAXBEL,    0 },
-#endif
-       {"opost",    output,      SANE_SET   | REV,  OPOST,      0 },
-#ifdef OLCUC
-       {"olcuc",    output,      SANE_UNSET | REV,  OLCUC,      0 },
-#endif
-#ifdef OCRNL
-       {"ocrnl",    output,      SANE_UNSET | REV,  OCRNL,      0 },
-#endif
-#ifdef ONLCR
-       {"onlcr",    output,      SANE_SET   | REV,  ONLCR,      0 },
-#endif
-#ifdef ONOCR
-       {"onocr",    output,      SANE_UNSET | REV,  ONOCR,      0 },
-#endif
-#ifdef ONLRET
-       {"onlret",   output,      SANE_UNSET | REV,  ONLRET,     0 },
-#endif
-#ifdef OFILL
-       {"ofill",    output,      SANE_UNSET | REV,  OFILL,      0 },
-#endif
-#ifdef OFDEL
-       {"ofdel",    output,      SANE_UNSET | REV,  OFDEL,      0 },
-#endif
-#ifdef NLDLY
-       {"nl1",      output,      SANE_UNSET,        NL1,     NLDLY},
-       {"nl0",      output,      SANE_SET,          NL0,     NLDLY},
-#endif
-#ifdef CRDLY
-       {"cr3",      output,      SANE_UNSET,        CR3,     CRDLY},
-       {"cr2",      output,      SANE_UNSET,        CR2,     CRDLY},
-       {"cr1",      output,      SANE_UNSET,        CR1,     CRDLY},
-       {"cr0",      output,      SANE_SET,          CR0,     CRDLY},
-#endif
-
-#ifdef TABDLY
-       {"tab3",     output,      SANE_UNSET,        TAB3,   TABDLY},
-       {"tab2",     output,      SANE_UNSET,        TAB2,   TABDLY},
-       {"tab1",     output,      SANE_UNSET,        TAB1,   TABDLY},
-       {"tab0",     output,      SANE_SET,          TAB0,   TABDLY},
-#else
-# ifdef OXTABS
-       {"tab3",     output,      SANE_UNSET,        OXTABS,     0 },
-# endif
-#endif
-
-#ifdef BSDLY
-       {"bs1",      output,      SANE_UNSET,        BS1,     BSDLY},
-       {"bs0",      output,      SANE_SET,          BS0,     BSDLY},
-#endif
-#ifdef VTDLY
-       {"vt1",      output,      SANE_UNSET,        VT1,     VTDLY},
-       {"vt0",      output,      SANE_SET,          VT0,     VTDLY},
-#endif
-#ifdef FFDLY
-       {"ff1",      output,      SANE_UNSET,        FF1,     FFDLY},
-       {"ff0",      output,      SANE_SET,          FF0,     FFDLY},
-#endif
-       {"isig",     local,       SANE_SET   | REV,  ISIG,       0 },
-       {"icanon",   local,       SANE_SET   | REV,  ICANON,     0 },
-#ifdef IEXTEN
-       {"iexten",   local,       SANE_SET   | REV,  IEXTEN,     0 },
-#endif
-       {"echo",     local,       SANE_SET   | REV,  ECHO,       0 },
-       {"echoe",    local,       SANE_SET   | REV,  ECHOE,      0 },
-       {"crterase", local,       REV        | OMIT, ECHOE,      0 },
-       {"echok",    local,       SANE_SET   | REV,  ECHOK,      0 },
-       {"echonl",   local,       SANE_UNSET | REV,  ECHONL,     0 },
-       {"noflsh",   local,       SANE_UNSET | REV,  NOFLSH,     0 },
-#ifdef XCASE
-       {"xcase",    local,       SANE_UNSET | REV,  XCASE,      0 },
-#endif
-#ifdef TOSTOP
-       {"tostop",   local,       SANE_UNSET | REV,  TOSTOP,     0 },
-#endif
-#ifdef ECHOPRT
-       {"echoprt",  local,       SANE_UNSET | REV,  ECHOPRT,    0 },
-       {"prterase", local,       REV | OMIT,        ECHOPRT,    0 },
-#endif
-#ifdef ECHOCTL
-       {"echoctl",  local,       SANE_SET   | REV,  ECHOCTL,    0 },
-       {"ctlecho",  local,       REV        | OMIT, ECHOCTL,    0 },
-#endif
-#ifdef ECHOKE
-       {"echoke",   local,       SANE_SET   | REV,  ECHOKE,     0 },
-       {"crtkill",  local,       REV        | OMIT, ECHOKE,     0 },
-#endif
-       {evenp,      combination, REV        | OMIT, 0,          0 },
-       {parity,     combination, REV        | OMIT, 0,          0 },
-       {stty_oddp,  combination, REV        | OMIT, 0,          0 },
-       {stty_nl,    combination, REV        | OMIT, 0,          0 },
-       {stty_ek,    combination, OMIT,              0,          0 },
-       {stty_sane,  combination, OMIT,              0,          0 },
-       {cooked,     combination, REV        | OMIT, 0,          0 },
-       {raw,        combination, REV        | OMIT, 0,          0 },
-       {stty_pass8, combination, REV        | OMIT, 0,          0 },
-       {litout,     combination, REV        | OMIT, 0,          0 },
-       {cbreak,     combination, REV        | OMIT, 0,          0 },
-#ifdef IXANY
-       {decctlq,    combination, REV        | OMIT, 0,          0 },
-#endif
-#if defined (TABDLY) || defined (OXTABS)
-       {stty_tabs,  combination, REV        | OMIT, 0,          0 },
-#endif
-#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
-       {stty_lcase, combination, REV        | OMIT, 0,          0 },
-       {stty_LCASE, combination, REV        | OMIT, 0,          0 },
-#endif
-       {stty_crt,   combination, OMIT,              0,          0 },
-       {stty_dec,   combination, OMIT,              0,          0 },
-};
-
-static const int NUM_mode_info =
-
-       (sizeof(mode_info) / sizeof(struct mode_info));
-
-/* Control character settings.  */
-struct control_info {
-       const char *name;                       /* Name given on command line.  */
-       unsigned char saneval;          /* Value to set for `stty sane'.  */
-       int offset;                                     /* Offset in c_cc.  */
-};
-
-/* Control characters. */
-
-static const struct  control_info control_info[] = {
-       {"intr",     CINTR,   VINTR},
-       {"quit",     CQUIT,   VQUIT},
-       {"erase",    CERASE,  VERASE},
-       {"kill",     CKILL,   VKILL},
-       {stty_eof,   CEOF,    VEOF},
-       {stty_eol,   CEOL,    VEOL},
-#ifdef VEOL2
-       {"eol2",     CEOL2,   VEOL2},
-#endif
-#ifdef VSWTCH
-       {stty_swtch, CSWTCH,  VSWTCH},
-#endif
-       {"start",    CSTART,  VSTART},
-       {"stop",     CSTOP,   VSTOP},
-       {"susp",     CSUSP,   VSUSP},
-#ifdef VDSUSP
-       {"dsusp",    CDSUSP,  VDSUSP},
-#endif
-#ifdef VREPRINT
-       {"rprnt",    CRPRNT,  VREPRINT},
-#endif
-#ifdef VWERASE
-       {"werase",   CWERASE, VWERASE},
-#endif
-#ifdef VLNEXT
-       {"lnext",    CLNEXT,  VLNEXT},
-#endif
-#ifdef VFLUSHO
-       {"flush",    CFLUSHO, VFLUSHO},
-#endif
-#ifdef VSTATUS
-       {"status",   CSTATUS, VSTATUS},
-#endif
-       /* These must be last because of the display routines. */
-       {stty_min,   1,       VMIN},
-       {stty_time,  0,       VTIME},
-};
-
-static const int NUM_control_info =
-       (sizeof(control_info) / sizeof(struct control_info));
-
-
-static const char *  visible(unsigned int ch);
-static unsigned long baud_to_value(speed_t speed);
-static int           recover_mode(char *arg, struct termios *mode);
-static int           screen_columns(void);
-static int           set_mode(const struct mode_info *info,
-                                       int reversed, struct termios *mode);
-static speed_t       string_to_baud(const char *arg);
-static tcflag_t*     mode_type_flag(enum mode_type type, struct termios *mode);
-static void          display_all(struct termios *mode, int fd,
-                                       const char *device_name);
-static void          display_changed(struct termios *mode);
-static void          display_recoverable(struct termios *mode);
-static void          display_settings(enum output_type output_type,
-                                       struct termios *mode, int fd,
-                                       const char *device_name);
-static void          display_speed(struct termios *mode, int fancy);
-static void          display_window_size(int fancy, int fd,
-                                       const char *device_name);
-static void          sane_mode(struct termios *mode);
-static void          set_control_char(const struct control_info *info,
-                                       const char *arg, struct termios *mode);
-static void          set_speed(enum speed_setting type,
-                                       const char *arg, struct termios *mode);
-static void          set_window_size(int rows, int cols, int fd,
-                                       const char *device_name);
-
-/* The width of the screen, for output wrapping. */
-static int max_col;
-
-/* Current position, to know when to wrap. */
-static int current_col;
-
-/* Print format string MESSAGE and optional args.
-   Wrap to next line first if it won't fit.
-   Print a space first unless MESSAGE will start a new line. */
-
-static void wrapf(const char *message, ...)
-{
-       va_list args;
-       char buf[1024];                 /* Plenty long for our needs. */
-       int buflen;
-
-       va_start(args, message);
-       vsprintf(buf, message, args);
-       va_end(args);
-       buflen = strlen(buf);
-       if (current_col + (current_col > 0) + buflen >= max_col) {
-               putchar('\n');
-               current_col = 0;
-       }
-       if (current_col > 0) {
-               putchar(' ');
-               current_col++;
-       }
-       fputs(buf, stdout);
-       current_col += buflen;
-}
-
-static const struct suffix_mult stty_suffixes[] = {
-       {"b",  512 },
-       {"k",  1024},
-       {"B",  1024},
-       {NULL, 0   }
-};
-
-#ifndef TEST
-extern int stty_main(int argc, char **argv)
-#else
-extern int main(int argc, char **argv)
-#endif
-{
-       struct termios mode;
-       enum   output_type output_type;
-       int    optc;
-       int    require_set_attr;
-       int    speed_was_set;
-       int    verbose_output;
-       int    recoverable_output;
-       int    k;
-       int    noargs = 1;
-       char * file_name = NULL;
-       int    fd;
-       const char *device_name;
-
-       output_type = changed;
-       verbose_output = 0;
-       recoverable_output = 0;
-
-       /* Don't print error messages for unrecognized options.  */
-       opterr = 0;
-
-       while ((optc = getopt(argc, argv, "agF:")) != -1) {
-               switch (optc) {
-               case 'a':
-                       verbose_output = 1;
-                       output_type = all;
-                       break;
-
-               case 'g':
-                       recoverable_output = 1;
-                       output_type = recoverable;
-                       break;
-
-               case 'F':
-                       if (file_name)
-                               error_msg_and_die("only one device may be specified");
-                       file_name = optarg;
-                       break;
-
-               default:                /* unrecognized option */
-                       noargs = 0;
-                       break;
-               }
-
-               if (noargs == 0)
-                       break;
-       }
-
-       if (optind < argc)
-               noargs = 0;
-
-       /* Specifying both -a and -g gets an error.  */
-       if (verbose_output && recoverable_output)
-               error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
-
-       /* Specifying any other arguments with -a or -g gets an error.  */
-       if (!noargs && (verbose_output || recoverable_output))
-               error_msg_and_die ("modes may not be set when specifying an output style");
-
-       /* FIXME: it'd be better not to open the file until we've verified
-          that all arguments are valid.  Otherwise, we could end up doing
-          only some of the requested operations and then failing, probably
-          leaving things in an undesirable state.  */
-
-       if (file_name) {
-               int fdflags;
-
-               device_name = file_name;
-               fd = open(device_name, O_RDONLY | O_NONBLOCK);
-               if (fd < 0)
-                       perror_msg_and_die("%s", device_name);
-               if ((fdflags = fcntl(fd, F_GETFL)) == -1
-                       || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
-                       perror_msg_and_die("%s: couldn't reset non-blocking mode",
-                                                          device_name);
-       } else {
-               fd = 0;
-               device_name = "standard input";
-       }
-
-       /* Initialize to all zeroes so there is no risk memcmp will report a
-          spurious difference in an uninitialized portion of the structure.  */
-       memset(&mode, 0, sizeof(mode));
-       if (tcgetattr(fd, &mode))
-               perror_msg_and_die("%s", device_name);
-
-       if (verbose_output || recoverable_output || noargs) {
-               max_col = screen_columns();
-               current_col = 0;
-               display_settings(output_type, &mode, fd, device_name);
-               return EXIT_SUCCESS;
-       }
-
-       speed_was_set = 0;
-       require_set_attr = 0;
-       k = optind;
-       while (k < argc) {
-               int match_found = 0;
-               int reversed = 0;
-               int i;
-
-               if (argv[k][0] == '-') {
-                       ++argv[k];
-                       reversed = 1;
-               }
-               for (i = 0; i < NUM_mode_info; ++i)
-                       if (STREQ(argv[k], mode_info[i].name)) {
-                               match_found = set_mode(&mode_info[i], reversed, &mode);
-                               require_set_attr = 1;
-                               break;
-                       }
-
-               if (match_found == 0 && reversed)
-                       error_msg_and_die("invalid argument `%s'", --argv[k]);
-
-               if (match_found == 0)
-                       for (i = 0; i < NUM_control_info; ++i)
-                               if (STREQ(argv[k], control_info[i].name)) {
-                                       if (k == argc - 1)
-                                           error_msg_and_die("missing argument to `%s'", argv[k]);
-                                       match_found = 1;
-                                       ++k;
-                                       set_control_char(&control_info[i], argv[k], &mode);
-                                       require_set_attr = 1;
-                                       break;
-                               }
-
-               if (match_found == 0) {
-                       if (STREQ(argv[k], "ispeed")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_speed(input_speed, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       } else if (STREQ(argv[k], "ospeed")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_speed(output_speed, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       }
-#ifdef TIOCGWINSZ
-                       else if (STREQ(argv[k], "rows")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_window_size((int) parse_number(argv[k], stty_suffixes),
-                                                               -1, fd, device_name);
-                       } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
-                               if (k == argc - 1)
-                                   error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               set_window_size(-1,
-                                               (int) parse_number(argv[k], stty_suffixes),
-                                               fd, device_name);
-                       } else if (STREQ(argv[k], "size")) {
-                               max_col = screen_columns();
-                               current_col = 0;
-                               display_window_size(0, fd, device_name);
-                       }
-#endif
-#ifdef HAVE_C_LINE
-                       else if (STREQ(argv[k], "line")) {
-                               if (k == argc - 1)
-                                       error_msg_and_die("missing argument to `%s'", argv[k]);
-                               ++k;
-                               mode.c_line = parse_number(argv[k], stty_suffixes);
-                               require_set_attr = 1;
-                       }
-#endif
-                       else if (STREQ(argv[k], "speed")) {
-                               max_col = screen_columns();
-                               display_speed(&mode, 0);
-                       } else if (recover_mode(argv[k], &mode) == 1)
-                               require_set_attr = 1;
-                       else if (string_to_baud(argv[k]) != (speed_t) - 1) {
-                               set_speed(both_speeds, argv[k], &mode);
-                               speed_was_set = 1;
-                               require_set_attr = 1;
-                       } else
-                               error_msg_and_die("invalid argument `%s'", argv[k]);
-               }
-               k++;
-       }
-
-       if (require_set_attr) {
-               struct termios new_mode;
-
-               if (tcsetattr(fd, TCSADRAIN, &mode))
-                       perror_msg_and_die("%s", device_name);
-
-               /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
-                  it performs *any* of the requested operations.  This means it
-                  can report `success' when it has actually failed to perform
-                  some proper subset of the requested operations.  To detect
-                  this partial failure, get the current terminal attributes and
-                  compare them to the requested ones.  */
-
-               /* Initialize to all zeroes so there is no risk memcmp will report a
-                  spurious difference in an uninitialized portion of the structure.  */
-               memset(&new_mode, 0, sizeof(new_mode));
-               if (tcgetattr(fd, &new_mode))
-                       perror_msg_and_die("%s", device_name);
-
-               /* Normally, one shouldn't use memcmp to compare structures that
-                  may have `holes' containing uninitialized data, but we have been
-                  careful to initialize the storage of these two variables to all
-                  zeroes.  One might think it more efficient simply to compare the
-                  modified fields, but that would require enumerating those fields --
-                  and not all systems have the same fields in this structure.  */
-
-               if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
-#ifdef CIBAUD
-                       /* SunOS 4.1.3 (at least) has the problem that after this sequence,
-                          tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
-                          sometimes (m1 != m2).  The only difference is in the four bits
-                          of the c_cflag field corresponding to the baud rate.  To save
-                          Sun users a little confusion, don't report an error if this
-                          happens.  But suppress the error only if we haven't tried to
-                          set the baud rate explicitly -- otherwise we'd never give an
-                          error for a true failure to set the baud rate.  */
-
-                       new_mode.c_cflag &= (~CIBAUD);
-                       if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
-#endif
-                               error_msg_and_die ("%s: unable to perform all requested operations",
-                                        device_name);
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/* Return 0 if not applied because not reversible; otherwise return 1.  */
-
-static int
-set_mode(const struct mode_info *info, int reversed, struct termios *mode)
-{
-       tcflag_t *bitsp;
-
-       if (reversed && (info->flags & REV) == 0)
-               return 0;
-
-       bitsp = mode_type_flag(info->type, mode);
-
-       if (bitsp == NULL) {
-               /* Combination mode. */
-               if (info->name == evenp || info->name == parity) {
-                       if (reversed)
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                       else
-                               mode->c_cflag =
-                                       (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
-               } else if (info->name == stty_oddp) {
-                       if (reversed)
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                       else
-                               mode->c_cflag =
-                                       (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
-               } else if (info->name == stty_nl) {
-                       if (reversed) {
-                               mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
-                               mode->c_oflag = (mode->c_oflag
-#ifdef ONLCR
-                                                                | ONLCR
-#endif
-                                       )
-#ifdef OCRNL
-                                       & ~OCRNL
-#endif
-#ifdef ONLRET
-                                       & ~ONLRET
-#endif
-                                       ;
-                       } else {
-                               mode->c_iflag = mode->c_iflag & ~ICRNL;
-#ifdef ONLCR
-                               mode->c_oflag = mode->c_oflag & ~ONLCR;
-#endif
-                       }
-               } else if (info->name == stty_ek) {
-                       mode->c_cc[VERASE] = CERASE;
-                       mode->c_cc[VKILL] = CKILL;
-               } else if (info->name == stty_sane)
-                       sane_mode(mode);
-               else if (info->name == cbreak) {
-                       if (reversed)
-                               mode->c_lflag |= ICANON;
-                       else
-                               mode->c_lflag &= ~ICANON;
-               } else if (info->name == stty_pass8) {
-                       if (reversed) {
-                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
-                               mode->c_iflag |= ISTRIP;
-                       } else {
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                               mode->c_iflag &= ~ISTRIP;
-                       }
-               } else if (info->name == litout) {
-                       if (reversed) {
-                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
-                               mode->c_iflag |= ISTRIP;
-                               mode->c_oflag |= OPOST;
-                       } else {
-                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
-                               mode->c_iflag &= ~ISTRIP;
-                               mode->c_oflag &= ~OPOST;
-                       }
-               } else if (info->name == raw || info->name == cooked) {
-                       if ((info->name[0] == 'r' && reversed)
-                               || (info->name[0] == 'c' && !reversed)) {
-                               /* Cooked mode. */
-                               mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
-                               mode->c_oflag |= OPOST;
-                               mode->c_lflag |= ISIG | ICANON;
-#if VMIN == VEOF
-                               mode->c_cc[VEOF] = CEOF;
-#endif
-#if VTIME == VEOL
-                               mode->c_cc[VEOL] = CEOL;
-#endif
-                       } else {
-                               /* Raw mode. */
-                               mode->c_iflag = 0;
-                               mode->c_oflag &= ~OPOST;
-                               mode->c_lflag &= ~(ISIG | ICANON
-#ifdef XCASE
-                                                                  | XCASE
-#endif
-                                       );
-                               mode->c_cc[VMIN] = 1;
-                               mode->c_cc[VTIME] = 0;
-                       }
-               }
-#ifdef IXANY
-               else if (info->name == decctlq) {
-                       if (reversed)
-                               mode->c_iflag |= IXANY;
-                       else
-                               mode->c_iflag &= ~IXANY;
-               }
-#endif
-#ifdef TABDLY
-               else if (info->name == stty_tabs) {
-                       if (reversed)
-                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
-                       else
-                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
-               }
-#else
-# ifdef OXTABS
-               else if (info->name == stty_tabs) {
-                       if (reversed)
-                               mode->c_oflag = mode->c_oflag | OXTABS;
-                       else
-                               mode->c_oflag = mode->c_oflag & ~OXTABS;
-               }
-# endif
-#endif
-#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
-               else if (info->name == stty_lcase || info->name == stty_LCASE) {
-                       if (reversed) {
-                               mode->c_lflag &= ~XCASE;
-                               mode->c_iflag &= ~IUCLC;
-                               mode->c_oflag &= ~OLCUC;
-                       } else {
-                               mode->c_lflag |= XCASE;
-                               mode->c_iflag |= IUCLC;
-                               mode->c_oflag |= OLCUC;
-                       }
-               }
-#endif
-               else if (info->name == stty_crt)
-                       mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
-                               | ECHOCTL
-#endif
-#ifdef ECHOKE
-                               | ECHOKE
-#endif
-                               ;
-               else if (info->name == stty_dec) {
-                       mode->c_cc[VINTR] = 3;  /* ^C */
-                       mode->c_cc[VERASE] = 127;       /* DEL */
-                       mode->c_cc[VKILL] = 21; /* ^U */
-                       mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
-                               | ECHOCTL
-#endif
-#ifdef ECHOKE
-                               | ECHOKE
-#endif
-                               ;
-#ifdef IXANY
-                       mode->c_iflag &= ~IXANY;
-#endif
-               }
-       } else if (reversed)
-               *bitsp = *bitsp & ~info->mask & ~info->bits;
-       else
-               *bitsp = (*bitsp & ~info->mask) | info->bits;
-
-       return 1;
-}
-
-static void
-set_control_char(const struct control_info *info, const char *arg,
-                                struct termios *mode)
-{
-       unsigned char value;
-
-       if (info->name == stty_min || info->name == stty_time)
-               value = parse_number(arg, stty_suffixes);
-       else if (arg[0] == '\0' || arg[1] == '\0')
-               value = arg[0];
-       else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
-               value = _POSIX_VDISABLE;
-       else if (arg[0] == '^' && arg[1] != '\0') {     /* Ignore any trailing junk. */
-               if (arg[1] == '?')
-                       value = 127;
-               else
-                       value = arg[1] & ~0140; /* Non-letters get weird results. */
-       } else
-               value = parse_number(arg, stty_suffixes);
-       mode->c_cc[info->offset] = value;
-}
-
-static void
-set_speed(enum speed_setting type, const char *arg, struct termios *mode)
-{
-       speed_t baud;
-
-       baud = string_to_baud(arg);
-       if (type == input_speed || type == both_speeds)
-               cfsetispeed(mode, baud);
-       if (type == output_speed || type == both_speeds)
-               cfsetospeed(mode, baud);
-}
-
-#ifdef TIOCGWINSZ
-
-static int get_win_size(int fd, struct winsize *win)
-{
-       int err = ioctl(fd, TIOCGWINSZ, (char *) win);
-
-       return err;
-}
-
-static void
-set_window_size(int rows, int cols, int fd, const char *device_name)
-{
-       struct winsize win;
-
-       if (get_win_size(fd, &win)) {
-               if (errno != EINVAL)
-                       perror_msg_and_die("%s", device_name);
-               memset(&win, 0, sizeof(win));
-       }
-
-       if (rows >= 0)
-               win.ws_row = rows;
-       if (cols >= 0)
-               win.ws_col = cols;
-
-# ifdef TIOCSSIZE
-       /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
-          The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
-          This comment from sys/ttold.h describes Sun's twisted logic - a better
-          test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
-          At any rate, the problem is gone in Solaris 2.x. */
-
-       if (win.ws_row == 0 || win.ws_col == 0) {
-               struct ttysize ttysz;
-
-               ttysz.ts_lines = win.ws_row;
-               ttysz.ts_cols = win.ws_col;
-
-               win.ws_row = 1;
-               win.ws_col = 1;
-
-               if (ioctl(fd, TIOCSWINSZ, (char *) &win))
-                       perror_msg_and_die("%s", device_name);
-
-               if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
-                       perror_msg_and_die("%s", device_name);
-               return;
-       }
-# endif
-
-       if (ioctl(fd, TIOCSWINSZ, (char *) &win))
-               perror_msg_and_die("%s", device_name);
-}
-
-static void display_window_size(int fancy, int fd, const char *device_name)
-{
-       struct winsize win;
-
-       if (get_win_size(fd, &win)) {
-               if (errno != EINVAL)
-                       perror_msg_and_die("%s", device_name);
-               if (!fancy)
-                       perror_msg_and_die("%s: no size information for this device",
-                                                          device_name);
-       } else {
-               wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
-                         win.ws_row, win.ws_col);
-               if (!fancy)
-                       current_col = 0;
-       }
-}
-#endif
-
-static int screen_columns(void)
-{
-#ifdef TIOCGWINSZ
-       struct winsize win;
-
-       /* With Solaris 2.[123], this ioctl fails and errno is set to
-          EINVAL for telnet (but not rlogin) sessions.
-          On ISC 3.0, it fails for the console and the serial port
-          (but it works for ptys).
-          It can also fail on any system when stdout isn't a tty.
-          In case of any failure, just use the default.  */
-       if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
-               return win.ws_col;
-#endif
-
-       if (getenv("COLUMNS"))
-               return atoi(getenv("COLUMNS"));
-       return 80;
-}
-
-static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
-{
-       switch (type) {
-       case control:
-               return &mode->c_cflag;
-
-       case input:
-               return &mode->c_iflag;
-
-       case output:
-               return &mode->c_oflag;
-
-       case local:
-               return &mode->c_lflag;
-
-       default:                                        /* combination: */
-               return NULL;
-       }
-}
-
-static void
-display_settings(enum output_type output_type, struct termios *mode,
-                                int fd, const char *device_name)
-{
-       switch (output_type) {
-       case changed:
-               display_changed(mode);
-               break;
-
-       case all:
-               display_all(mode, fd, device_name);
-               break;
-
-       case recoverable:
-               display_recoverable(mode);
-               break;
-       }
-}
-
-static void display_changed(struct termios *mode)
-{
-       int i;
-       int empty_line;
-       tcflag_t *bitsp;
-       unsigned long mask;
-       enum mode_type prev_type = control;
-
-       display_speed(mode, 1);
-#ifdef HAVE_C_LINE
-       wrapf("line = %d;", mode->c_line);
-#endif
-       putchar('\n');
-       current_col = 0;
-
-       empty_line = 1;
-       for (i = 0; control_info[i].name != stty_min; ++i) {
-               if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
-                       continue;
-               /* If swtch is the same as susp, don't print both.  */
-#if VSWTCH == VSUSP
-               if (control_info[i].name == stty_swtch)
-                       continue;
-#endif
-               /* If eof uses the same slot as min, only print whichever applies.  */
-#if VEOF == VMIN
-               if ((mode->c_lflag & ICANON) == 0
-                       && (control_info[i].name == stty_eof
-                               || control_info[i].name == stty_eol)) continue;
-#endif
-
-               empty_line = 0;
-               wrapf("%s = %s;", control_info[i].name,
-                         visible(mode->c_cc[control_info[i].offset]));
-       }
-       if ((mode->c_lflag & ICANON) == 0) {
-               wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
-                         (int) mode->c_cc[VTIME]);
-       } else if (empty_line == 0)
-               putchar('\n');
-       current_col = 0;
-
-       empty_line = 1;
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & OMIT)
-                       continue;
-               if (mode_info[i].type != prev_type) {
-                       if (empty_line == 0) {
-                               putchar('\n');
-                               current_col = 0;
-                               empty_line = 1;
-                       }
-                       prev_type = mode_info[i].type;
-               }
-
-               bitsp = mode_type_flag(mode_info[i].type, mode);
-               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
-               if ((*bitsp & mask) == mode_info[i].bits) {
-                       if (mode_info[i].flags & SANE_UNSET) {
-                               wrapf("%s", mode_info[i].name);
-                               empty_line = 0;
-                       }
-               }
-                       else if ((mode_info[i].flags & (SANE_SET | REV)) ==
-                                        (SANE_SET | REV)) {
-                       wrapf("-%s", mode_info[i].name);
-                       empty_line = 0;
-               }
-       }
-       if (empty_line == 0)
-               putchar('\n');
-       current_col = 0;
-}
-
-static void
-display_all(struct termios *mode, int fd, const char *device_name)
-{
-       int i;
-       tcflag_t *bitsp;
-       unsigned long mask;
-       enum mode_type prev_type = control;
-
-       display_speed(mode, 1);
-#ifdef TIOCGWINSZ
-       display_window_size(1, fd, device_name);
-#endif
-#ifdef HAVE_C_LINE
-       wrapf("line = %d;", mode->c_line);
-#endif
-       putchar('\n');
-       current_col = 0;
-
-       for (i = 0; control_info[i].name != stty_min; ++i) {
-               /* If swtch is the same as susp, don't print both.  */
-#if VSWTCH == VSUSP
-               if (control_info[i].name == stty_swtch)
-                       continue;
-#endif
-               /* If eof uses the same slot as min, only print whichever applies.  */
-#if VEOF == VMIN
-               if ((mode->c_lflag & ICANON) == 0
-                       && (control_info[i].name == stty_eof
-                               || control_info[i].name == stty_eol)) continue;
-#endif
-               wrapf("%s = %s;", control_info[i].name,
-                         visible(mode->c_cc[control_info[i].offset]));
-       }
-#if VEOF == VMIN
-       if ((mode->c_lflag & ICANON) == 0)
-#endif
-               wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
-       if (current_col != 0)
-               putchar('\n');
-       current_col = 0;
-
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & OMIT)
-                       continue;
-               if (mode_info[i].type != prev_type) {
-                       putchar('\n');
-                       current_col = 0;
-                       prev_type = mode_info[i].type;
-               }
-
-               bitsp = mode_type_flag(mode_info[i].type, mode);
-               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
-               if ((*bitsp & mask) == mode_info[i].bits)
-                       wrapf("%s", mode_info[i].name);
-               else if (mode_info[i].flags & REV)
-                       wrapf("-%s", mode_info[i].name);
-       }
-       putchar('\n');
-       current_col = 0;
-}
-
-static void display_speed(struct termios *mode, int fancy)
-{
-       if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
-               wrapf(fancy ? "speed %lu baud;" : "%lu\n",
-                         baud_to_value(cfgetospeed(mode)));
-       else
-               wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
-                         baud_to_value(cfgetispeed(mode)),
-                         baud_to_value(cfgetospeed(mode)));
-       if (!fancy)
-               current_col = 0;
-}
-
-static void display_recoverable(struct termios *mode)
-{
-       int i;
-
-       printf("%lx:%lx:%lx:%lx",
-                  (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
-                  (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
-       for (i = 0; i < NCCS; ++i)
-               printf(":%x", (unsigned int) mode->c_cc[i]);
-       putchar('\n');
-}
-
-static int recover_mode(char *arg, struct termios *mode)
-{
-       int i, n;
-       unsigned int chr;
-       unsigned long iflag, oflag, cflag, lflag;
-
-       /* Scan into temporaries since it is too much trouble to figure out
-          the right format for `tcflag_t'.  */
-       if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
-                          &iflag, &oflag, &cflag, &lflag, &n) != 4)
-               return 0;
-       mode->c_iflag = iflag;
-       mode->c_oflag = oflag;
-       mode->c_cflag = cflag;
-       mode->c_lflag = lflag;
-       arg += n;
-       for (i = 0; i < NCCS; ++i) {
-               if (sscanf(arg, ":%x%n", &chr, &n) != 1)
-                       return 0;
-               mode->c_cc[i] = chr;
-               arg += n;
-       }
-
-       /* Fail if there are too many fields.  */
-       if (*arg != '\0')
-               return 0;
-
-       return 1;
-}
-
-struct speed_map {
-       speed_t speed;                          /* Internal form. */
-       unsigned long value;            /* Numeric value. */
-};
-
-static const struct speed_map speeds[] = {
-       {B0, 0},
-       {B50, 50},
-       {B75, 75},
-       {B110, 110},
-       {B134, 134},
-       {B150, 150},
-       {B200, 200},
-       {B300, 300},
-       {B600, 600},
-       {B1200, 1200},
-       {B1800, 1800},
-       {B2400, 2400},
-       {B4800, 4800},
-       {B9600, 9600},
-       {B19200, 19200},
-       {B38400, 38400},
-#ifdef B57600
-       {B57600, 57600},
-#endif
-#ifdef B115200
-       {B115200, 115200},
-#endif
-#ifdef B230400
-       {B230400, 230400},
-#endif
-#ifdef B460800
-       {B460800, 460800},
-#endif
-};
-
-static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
-
-static speed_t string_to_baud(const char *arg)
-{
-       int i;
-
-       for (i = 0; i < NUM_SPEEDS; ++i)
-               if (parse_number(arg, 0) == speeds[i].value)
-                       return speeds[i].speed;
-       return (speed_t) - 1;
-}
-
-static unsigned long baud_to_value(speed_t speed)
-{
-       int i;
-
-       for (i = 0; i < NUM_SPEEDS; ++i)
-               if (speed == speeds[i].speed)
-                       return speeds[i].value;
-       return 0;
-}
-
-static void sane_mode(struct termios *mode)
-{
-       int i;
-       tcflag_t *bitsp;
-
-       for (i = 0; i < NUM_control_info; ++i) {
-#if VMIN == VEOF
-               if (control_info[i].name == stty_min)
-                       break;
-#endif
-               mode->c_cc[control_info[i].offset] = control_info[i].saneval;
-       }
-
-       for (i = 0; i < NUM_mode_info; ++i) {
-               if (mode_info[i].flags & SANE_SET) {
-                       bitsp = mode_type_flag(mode_info[i].type, mode);
-                       *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
-               } else if (mode_info[i].flags & SANE_UNSET) {
-                       bitsp = mode_type_flag(mode_info[i].type, mode);
-                       *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
-               }
-       }
-}
-
-/* Return a string that is the printable representation of character CH.  */
-/* Adapted from `cat' by Torbjorn Granlund.  */
-
-static const char *visible(unsigned int ch)
-{
-       static char buf[10];
-       char *bpout = buf;
-
-       if (ch == _POSIX_VDISABLE)
-               return "<undef>";
-
-       if (ch >= 32) {
-               if (ch < 127)
-                       *bpout++ = ch;
-               else if (ch == 127) {
-                       *bpout++ = '^';
-                       *bpout++ = '?';
-               } else {
-                       *bpout++ = 'M', *bpout++ = '-';
-                       if (ch >= 128 + 32) {
-                               if (ch < 128 + 127)
-                                       *bpout++ = ch - 128;
-                               else {
-                                       *bpout++ = '^';
-                                       *bpout++ = '?';
-                               }
-                       } else {
-                               *bpout++ = '^';
-                               *bpout++ = ch - 128 + 64;
-                       }
-               }
-       } else {
-               *bpout++ = '^';
-               *bpout++ = ch + 64;
-       }
-       *bpout = '\0';
-       return (const char *) buf;
-}
-
-#ifdef TEST
-
-const char *applet_name = "stty";
-
-#endif
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/swaponoff.c b/busybox/swaponoff.c
deleted file mode 100644 (file)
index ce0e2c6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini swapon/swapoff implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <mntent.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/mount.h>
-
-#if __GNU_LIBRARY__ < 5
-/* libc5 doesn't have sys/swap.h, define these here. */ 
-extern int swapon (__const char *__path, int __flags);
-extern int swapoff (__const char *__path);
-#else
-#include <sys/swap.h>
-#endif
-
-#include "busybox.h"
-
-static int whichApp;
-
-static const int SWAPON_APP = 1;
-static const int SWAPOFF_APP = 2;
-
-
-static void swap_enable_disable(char *device)
-{
-       int status;
-
-       if (whichApp == SWAPON_APP)
-               status = swapon(device, 0);
-       else
-               status = swapoff(device);
-
-       if (status != 0)
-               perror_msg_and_die(applet_name);
-}
-
-static void do_em_all()
-{
-       struct mntent *m;
-       FILE *f = setmntent("/etc/fstab", "r");
-
-       if (f == NULL)
-               perror_msg_and_die("/etc/fstab");
-       while ((m = getmntent(f)) != NULL) {
-               if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) {
-                       swap_enable_disable(m->mnt_fsname);
-               }
-       }
-       endmntent(f);
-       exit(EXIT_SUCCESS);
-}
-
-
-extern int swap_on_off_main(int argc, char **argv)
-{
-       if (strcmp(applet_name, "swapon") == 0) {
-               whichApp = SWAPON_APP;
-       } else {
-               whichApp = SWAPOFF_APP;
-       }
-
-       if (argc != 2) {
-               goto usage_and_exit;
-       }
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (**argv == '-') {
-               while (*++(*argv))
-                       switch (**argv) {
-                       case 'a':
-                               {
-                                       struct stat statBuf;
-
-                                       if (stat("/etc/fstab", &statBuf) < 0)
-                                               error_msg_and_die("/etc/fstab file missing");
-                               }
-                               do_em_all();
-                               break;
-                       default:
-                               goto usage_and_exit;
-                       }
-       }
-       swap_enable_disable(*argv);
-       return EXIT_SUCCESS;
-
-  usage_and_exit:
-       show_usage();
-}
diff --git a/busybox/sync.c b/busybox/sync.c
deleted file mode 100644 (file)
index ee22ae1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini sync implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int sync_main(int argc, char **argv)
-{
-       if (argc > 1 && **(argv + 1) == '-')
-               show_usage();
-       sync();
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/sysklogd/klogd.c b/busybox/sysklogd/klogd.c
deleted file mode 100644 (file)
index d7b54e9..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini klogd implementation for busybox
- *
- * Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>.
- * Changes: Made this a standalone busybox module which uses standalone
- *                                     syslog() client interface.
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@mail.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h> /* for our signal() handlers */
-#include <string.h> /* strncpy() */
-#include <errno.h>  /* errno and friends */
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/syslog.h>
-
-#if __GNU_LIBRARY__ < 5
-# ifdef __alpha__
-#   define klogctl syslog
-# endif
-#else
-# include <sys/klog.h>
-#endif
-
-#include "busybox.h"
-
-static void klogd_signal(int sig)
-{
-       klogctl(7, NULL, 0);
-       klogctl(0, 0, 0);
-       //logMessage(0, "Kernel log daemon exiting.");
-       syslog_msg(LOG_DAEMON, 0, "Kernel log daemon exiting.");
-       exit(TRUE);
-}
-
-static void doKlogd (void) __attribute__ ((noreturn));
-static void doKlogd (void)
-{
-       int priority = LOG_INFO;
-       char log_buffer[4096];
-       int i, n, lastc;
-       char *start;
-
-       /* Set up sig handlers */
-       signal(SIGINT, klogd_signal);
-       signal(SIGKILL, klogd_signal);
-       signal(SIGTERM, klogd_signal);
-       signal(SIGHUP, SIG_IGN);
-
-       /* "Open the log. Currently a NOP." */
-       klogctl(1, NULL, 0);
-
-       syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER);
-
-       while (1) {
-               /* Use kernel syscalls */
-               memset(log_buffer, '\0', sizeof(log_buffer));
-               n = klogctl(2, log_buffer, sizeof(log_buffer));
-               if (n < 0) {
-                       char message[80];
-
-                       if (errno == EINTR)
-                               continue;
-                       snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", 
-                                                                                               errno, strerror(errno));
-                       syslog_msg(LOG_DAEMON, LOG_SYSLOG | LOG_ERR, message);
-                       exit(1);
-               }
-
-               /* klogctl buffer parsing modelled after code in dmesg.c */
-               start=&log_buffer[0];
-               lastc='\0';
-               for (i=0; i<n; i++) {
-                       if (lastc == '\0' && log_buffer[i] == '<') {
-                               priority = 0;
-                               i++;
-                               while (isdigit(log_buffer[i])) {
-                                       priority = priority*10+(log_buffer[i]-'0');
-                                       i++;
-                               }
-                               if (log_buffer[i] == '>') i++;
-                               start = &log_buffer[i];
-                       }
-                       if (log_buffer[i] == '\n') {
-                               log_buffer[i] = '\0';  /* zero terminate this message */
-                               syslog_msg(LOG_DAEMON, LOG_KERN | priority, start);
-                               start = &log_buffer[i+1];
-                               priority = LOG_INFO;
-                       }
-                       lastc = log_buffer[i];
-               }
-       }
-}
-
-extern int klogd_main(int argc, char **argv)
-{
-       /* no options, no getopt */
-       int opt;
-       int doFork = TRUE;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "n")) > 0) {
-               switch (opt) {
-                       case 'n':
-                               doFork = FALSE;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (doFork == TRUE) {
-               if (daemon(0, 1) < 0)
-                       perror_msg_and_die("daemon");
-       }
-       doKlogd();
-       
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/sysklogd/logger.c b/busybox/sysklogd/logger.c
deleted file mode 100644 (file)
index 9f73091..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini logger implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "busybox.h"
-#if !defined BB_SYSLOGD
-
-#define SYSLOG_NAMES
-#include <sys/syslog.h>
-
-#else
-#include <sys/syslog.h>
-#  ifndef __dietlibc__
-       /* We have to do this since the header file defines static
-        * structures.  Argh.... bad libc, bad, bad...
-        */
-       typedef struct _code {
-               char *c_name;
-               int c_val;
-       } CODE;
-       extern CODE prioritynames[];
-       extern CODE facilitynames[];
-#  endif
-#endif
-
-/* Decode a symbolic name to a numeric value 
- * this function is based on code
- * Copyright (c) 1983, 1993
- * The Regents of the University of California.  All rights reserved.
- *  
- * Original copyright notice is retained at the end of this file.
- */
-static int decode(char *name, CODE * codetab)
-{
-       CODE *c;
-
-       if (isdigit(*name))
-               return (atoi(name));
-       for (c = codetab; c->c_name; c++) {
-               if (!strcasecmp(name, c->c_name)) {
-                       return (c->c_val);
-               }
-       }
-
-       return (-1);
-}
-
-/* Decode a symbolic name to a numeric value 
- * this function is based on code
- * Copyright (c) 1983, 1993
- * The Regents of the University of California.  All rights reserved.
- *
- * Original copyright notice is retained at the end of this file.
- */
-static int pencode(char *s)
-{
-       char *save;
-       int lev, fac = LOG_USER;
-
-       for (save = s; *s && *s != '.'; ++s);
-       if (*s) {
-               *s = '\0';
-               fac = decode(save, facilitynames);
-               if (fac < 0)
-                       error_msg_and_die("unknown facility name: %s", save);
-               *s++ = '.';
-       } else {
-               s = save;
-       }
-       lev = decode(s, prioritynames);
-       if (lev < 0)
-               error_msg_and_die("unknown priority name: %s", save);
-       return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
-}
-
-
-extern int logger_main(int argc, char **argv)
-{
-       int pri = LOG_USER | LOG_NOTICE;
-       int option = 0;
-       int c, i, len, opt;
-       char *message=NULL, buf[1024], name[128];
-
-       /* Fill out the name string early (may be overwritten later) */
-       my_getpwuid(name, geteuid());
-
-       /* Parse any options */
-       while ((opt = getopt(argc, argv, "p:st:")) > 0) {
-               switch (opt) {
-                       case 's':
-                               option |= LOG_PERROR;
-                               break;
-                       case 'p':
-                               pri = pencode(optarg);
-                               break;
-                       case 't':
-                               strncpy(name, optarg, sizeof(name));
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       openlog(name, option, (pri | LOG_FACMASK));
-       if (optind == argc) {
-               do {
-                       /* read from stdin */
-                       i = 0;
-                       while ((c = getc(stdin)) != EOF && c != '\n' && 
-                                       i < (sizeof(buf)-1)) {
-                               buf[i++] = c;
-                       }
-                       if (i > 0) {
-                               buf[i++] = '\0';
-                               syslog(pri, "%s", buf);
-                       }
-               } while (c != EOF);
-       } else {
-               len = 1; /* for the '\0' */
-               message=xcalloc(1, 1);
-               for (i = optind; i < argc; i++) {
-                       len += strlen(argv[i]);
-                       len += 1;  /* for the space between the args */
-                       message = xrealloc(message, len);
-                       strcat(message, argv[i]);
-                       strcat(message, " ");
-               }
-               message[strlen(message)-1] = '\0';
-               syslog(pri, "%s", message);
-       }
-
-       closelog();
-       return EXIT_SUCCESS;
-}
-
-
-/*-
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This is the original license statement for the decode and pencode functions.
- *
- * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
-
diff --git a/busybox/sysklogd/logread.c b/busybox/sysklogd/logread.c
deleted file mode 100644 (file)
index d334962..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * circular buffer syslog implementation for busybox
- *
- * Copyright (C) 2000 by Gennady Feldman <gfeldman@cachier.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ipc.h>
-#include <sys/types.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
-#include <signal.h>
-#include <setjmp.h>
-#include "busybox.h"
-
-#if __GNU_LIBRARY__ < 5
-#error Sorry.  Looks like you are using libc5.  
-#error libc5 shm support isnt good enough.
-#error Please disable BB_FEATURE_IPC_SYSLOG 
-#endif 
-
-
-static const long KEY_ID = 0x414e4547; /*"GENA"*/
-
-static struct shbuf_ds {
-       int size;               // size of data written
-       int head;               // start of message list
-       int tail;               // end of message list
-       char data[1];           // data/messages
-} *buf = NULL;                 // shared memory pointer
-
-
-// Semaphore operation structures
-static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup
-static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn
-
-static int     log_shmid = -1; // ipc shared memory id
-static int     log_semid = -1; // ipc semaphore id
-static jmp_buf jmp_env;
-
-static void error_exit(const char *str);
-static void interrupted(int sig);
-
-/*
- * sem_up - up()'s a semaphore.
- */
-static inline void sem_up(int semid)
-{
-       if ( semop(semid, SMrup, 1) == -1 ) 
-               error_exit("semop[SMrup]");
-}
-
-/*
- * sem_down - down()'s a semaphore
- */                            
-static inline void sem_down(int semid)
-{
-       if ( semop(semid, SMrdn, 2) == -1 )
-               error_exit("semop[SMrdn]");
-}
-
-extern int logread_main(int argc, char **argv)
-{
-       int i;
-       
-       /* no options, no getopt */
-       if (argc > 1)
-               show_usage();
-       
-       // handle intrrupt signal
-       if (setjmp(jmp_env)) goto output_end;
-       
-       // attempt to redefine ^C signal
-       signal(SIGINT, interrupted);
-       
-       if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1)
-               error_exit("Can't find circular buffer");
-       
-       // Attach shared memory to our char*
-       if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL)
-               error_exit("Can't get access to circular buffer from syslogd");
-
-       if ( (log_semid = semget(KEY_ID, 0, 0)) == -1)
-               error_exit("Can't get access to semaphone(s) for circular buffer from syslogd");
-
-       sem_down(log_semid);    
-       // Read Memory 
-       i=buf->head;
-
-       //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size);
-       if (buf->head == buf->tail) {
-               printf("<empty syslog>\n");
-       }
-       
-       while ( i != buf->tail) {
-               printf("%s", buf->data+i);
-               i+= strlen(buf->data+i) + 1;
-               if (i >= buf->size )
-                       i=0;
-       }
-       sem_up(log_semid);
-
-output_end:
-       if (log_shmid != -1) 
-               shmdt(buf);
-               
-       return EXIT_SUCCESS;            
-}
-
-static void interrupted(int sig){
-       signal(SIGINT, SIG_IGN);
-       longjmp(jmp_env, 1);
-}
-
-static void error_exit(const char *str){
-       perror(str);
-       //release all acquired resources
-       if (log_shmid != -1) 
-               shmdt(buf);
-
-       exit(1);
-}
diff --git a/busybox/sysklogd/syslogd.c b/busybox/sysklogd/syslogd.c
deleted file mode 100644 (file)
index 25bc68f..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini syslogd implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/param.h>
-
-#include "busybox.h"
-
-/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
-#define SYSLOG_NAMES
-#include <sys/syslog.h>
-#include <sys/uio.h>
-
-/* Path for the file where all log messages are written */
-#define __LOG_FILE "/var/log/messages"
-
-/* Path to the unix socket */
-static char lfile[BUFSIZ];
-
-static char *logFilePath = __LOG_FILE;
-
-/* interval between marks in seconds */
-static int MarkInterval = 20 * 60;
-
-/* localhost's name */
-static char LocalHostName[32];
-
-#ifdef BB_FEATURE_REMOTE_LOG
-#include <netinet/in.h>
-/* udp socket for logging to remote host */
-static int remotefd = -1;
-/* where do we log? */
-static char *RemoteHost;
-/* what port to log to? */
-static int RemotePort = 514;
-/* To remote log or not to remote log, that is the question. */
-static int doRemoteLog = FALSE;
-static int local_logging = FALSE;
-#endif
-
-/* circular buffer variables/structures */
-#ifdef BB_FEATURE_IPC_SYSLOG
-
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
-
-/* our shared key */
-static const long KEY_ID = 0x414e4547; /*"GENA"*/
-
-// Semaphore operation structures
-static struct shbuf_ds {
-       int size;               // size of data written
-       int head;               // start of message list
-       int tail;               // end of message list
-       char data[1];           // data/messages
-} *buf = NULL;                 // shared memory pointer
-
-static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
-static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
-
-static int     shmid = -1;     // ipc shared memory id
-static int     s_semid = -1;   // ipc semaphore id
-int    data_size = 16000; // data size
-int    shm_size = 16000 + sizeof(*buf); // our buffer size
-static int circular_logging = FALSE;
-
-/*
- * sem_up - up()'s a semaphore.
- */
-static inline void sem_up(int semid)
-{
-       if ( semop(semid, SMwup, 1) == -1 )
-               perror_msg_and_die("semop[SMwup]");
-}
-
-/*
- * sem_down - down()'s a semaphore
- */
-static inline void sem_down(int semid)
-{
-       if ( semop(semid, SMwdn, 3) == -1 )
-               perror_msg_and_die("semop[SMwdn]");
-}
-
-
-void ipcsyslog_cleanup(void){
-       printf("Exiting Syslogd!\n");
-       if (shmid != -1)
-               shmdt(buf);
-
-       if (shmid != -1)
-               shmctl(shmid, IPC_RMID, NULL);
-       if (s_semid != -1)
-               semctl(s_semid, 0, IPC_RMID, 0);
-}
-
-void ipcsyslog_init(void){
-       if (buf == NULL){
-           if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
-                       perror_msg_and_die("shmget");
-
-
-           if ((buf = shmat(shmid, NULL, 0)) == NULL)
-                       perror_msg_and_die("shmat");
-
-
-           buf->size=data_size;
-           buf->head=buf->tail=0;
-
-           // we'll trust the OS to set initial semval to 0 (let's hope)
-           if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
-               if (errno == EEXIST){
-                  if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
-                   perror_msg_and_die("semget");
-               }else
-                       perror_msg_and_die("semget");
-           }
-       }else{
-               printf("Buffer already allocated just grab the semaphore?");
-       }
-}
-
-/* write message to buffer */
-void circ_message(const char *msg){
-       int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
-
-       sem_down(s_semid);
-
-       /*
-        * Circular Buffer Algorithm:
-        * --------------------------
-        *
-        * Start-off w/ empty buffer of specific size SHM_SIZ
-        * Start filling it up w/ messages. I use '\0' as separator to break up messages.
-        * This is also very handy since we can do printf on message.
-        *
-        * Once the buffer is full we need to get rid of the first message in buffer and
-        * insert the new message. (Note: if the message being added is >1 message then
-        * we will need to "remove" >1 old message from the buffer). The way this is done
-        * is the following:
-        *      When we reach the end of the buffer we set a mark and start from the beginning.
-        *      Now what about the beginning and end of the buffer? Well we have the "head"
-        *      index/pointer which is the starting point for the messages and we have "tail"
-        *      index/pointer which is the ending point for the messages. When we "display" the
-        *      messages we start from the beginning and continue until we reach "tail". If we
-        *      reach end of buffer, then we just start from the beginning (offset 0). "head" and
-        *      "tail" are actually offsets from the beginning of the buffer.
-        *
-        * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
-        *       a threasafe way of handling shared memory operations.
-        */
-       if ( (buf->tail + l) < buf->size ){
-               /* before we append the message we need to check the HEAD so that we won't
-                  overwrite any of the message that we still need and adjust HEAD to point
-                  to the next message! */
-               if ( buf->tail < buf->head){
-                       if ( (buf->tail + l) >= buf->head ){
-                         /* we need to move the HEAD to point to the next message
-                          * Theoretically we have enough room to add the whole message to the
-                          * buffer, because of the first outer IF statement, so we don't have
-                          * to worry about overflows here!
-                          */
-                          int k= buf->tail + l - buf->head; /* we need to know how many bytes
-                                                               we are overwriting to make
-                                                               enough room */
-                          char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
-                          if (c != NULL) {/* do a sanity check just in case! */
-                               buf->head = c - buf->data + 1; /* we need to convert pointer to
-                                                                 offset + skip the '\0' since
-                                                                 we need to point to the beginning
-                                                                 of the next message */
-                               /* Note: HEAD is only used to "retrieve" messages, it's not used
-                                       when writing messages into our buffer */
-                          }else{ /* show an error message to know we messed up? */
-                               printf("Weird! Can't find the terminator token??? \n");
-                               buf->head=0;
-                          }
-                       }
-               } /* in other cases no overflows have been done yet, so we don't care! */
-
-               /* we should be ok to append the message now */
-               strncpy(buf->data + buf->tail,msg,l); /* append our message */
-               buf->tail+=l; /* count full message w/ '\0' terminating char */
-       }else{
-               /* we need to break up the message and "circle" it around */
-               char *c;
-               int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
-               
-               /* We need to move HEAD! This is always the case since we are going
-                * to "circle" the message.
-                */
-               c=memchr(buf->data + k ,'\0', buf->size - k);
-               
-               if (c != NULL) /* if we don't have '\0'??? weird!!! */{
-                       /* move head pointer*/
-                       buf->head=c-buf->data+1; 
-                       
-                       /* now write the first part of the message */                   
-                       strncpy(buf->data + buf->tail, msg, l - k - 1);
-                       
-                       /* ALWAYS terminate end of buffer w/ '\0' */
-                       buf->data[buf->size-1]='\0'; 
-                       
-                       /* now write out the rest of the string to the beginning of the buffer */
-                       strcpy(buf->data, &msg[l-k-1]);
-
-                       /* we need to place the TAIL at the end of the message */
-                       buf->tail = k + 1;
-               }else{
-                       printf("Weird! Can't find the terminator token from the beginning??? \n");
-                       buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
-               }
-               
-       }
-       sem_up(s_semid);
-}
-#endif
-/* Note: There is also a function called "message()" in init.c */
-/* Print a message to the log file. */
-static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-static void message (char *fmt, ...)
-{
-       int fd;
-       struct flock fl;
-       va_list arguments;
-
-       fl.l_whence = SEEK_SET;
-       fl.l_start  = 0;
-       fl.l_len    = 1;
-
-#ifdef BB_FEATURE_IPC_SYSLOG
-       if ((circular_logging == TRUE) && (buf != NULL)){
-                       char b[1024];
-                       va_start (arguments, fmt);
-                       vsprintf (b, fmt, arguments);
-                       va_end (arguments);
-                       circ_message(b);
-
-       }else
-#endif
-       if ((fd = device_open (logFilePath,
-                                                  O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
-                                                  O_NONBLOCK)) >= 0) {
-               fl.l_type = F_WRLCK;
-               fcntl (fd, F_SETLKW, &fl);
-               va_start (arguments, fmt);
-               vdprintf (fd, fmt, arguments);
-               va_end (arguments);
-               fl.l_type = F_UNLCK;
-               fcntl (fd, F_SETLKW, &fl);
-               close (fd);
-       } else {
-               /* Always send console messages to /dev/console so people will see them. */
-               if ((fd = device_open (_PATH_CONSOLE,
-                                                          O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
-                       va_start (arguments, fmt);
-                       vdprintf (fd, fmt, arguments);
-                       va_end (arguments);
-                       close (fd);
-               } else {
-                       fprintf (stderr, "Bummer, can't print: ");
-                       va_start (arguments, fmt);
-                       vfprintf (stderr, fmt, arguments);
-                       fflush (stderr);
-                       va_end (arguments);
-               }
-       }
-}
-
-static void logMessage (int pri, char *msg)
-{
-       time_t now;
-       char *timestamp;
-       static char res[20] = "";
-       CODE *c_pri, *c_fac;
-
-       if (pri != 0) {
-               for (c_fac = facilitynames;
-                               c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
-               for (c_pri = prioritynames;
-                               c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
-               if (c_fac->c_name == NULL || c_pri->c_name == NULL)
-                       snprintf(res, sizeof(res), "<%d>", pri);
-               else
-                       snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
-       }
-
-       if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
-                       msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
-               time(&now);
-               timestamp = ctime(&now) + 4;
-               timestamp[15] = '\0';
-       } else {
-               timestamp = msg;
-               timestamp[15] = '\0';
-               msg += 16;
-       }
-
-       /* todo: supress duplicates */
-
-#ifdef BB_FEATURE_REMOTE_LOG
-       /* send message to remote logger */
-       if ( -1 != remotefd){
-static const int IOV_COUNT = 2;
-               struct iovec iov[IOV_COUNT];
-               struct iovec *v = iov;
-
-               memset(&res, 0, sizeof(res));
-               snprintf(res, sizeof(res), "<%d>", pri);
-               v->iov_base = res ;
-               v->iov_len = strlen(res);          
-               v++;
-
-               v->iov_base = msg;
-               v->iov_len = strlen(msg);          
-
-               if ( -1 == writev(remotefd,iov, IOV_COUNT)){
-                       error_msg_and_die("syslogd: cannot write to remote file handle on" 
-                                       "%s:%d",RemoteHost,RemotePort);
-               }
-       }
-       if (local_logging == TRUE)
-#endif
-               /* now spew out the message to wherever it is supposed to go */
-               message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
-
-
-}
-
-static void quit_signal(int sig)
-{
-       logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
-       unlink(lfile);
-#ifdef BB_FEATURE_IPC_SYSLOG
-       ipcsyslog_cleanup();
-#endif
-
-       exit(TRUE);
-}
-
-static void domark(int sig)
-{
-       if (MarkInterval > 0) {
-               logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
-               alarm(MarkInterval);
-       }
-}
-
-/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
- * enabled, we otherwise get a "storage size isn't constant error. */
-#define BUFSIZE 1023
-static int serveConnection (int conn)
-{
-       RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1);
-       int    n_read;
-       char *p = tmpbuf;
-
-       n_read = read (conn, tmpbuf, BUFSIZE );
-
-       while (p < tmpbuf + n_read) {
-
-               int           pri = (LOG_USER | LOG_NOTICE);
-               char          line[ BUFSIZE + 1 ];
-               unsigned char c;
-
-               char *q = line;
-
-               tmpbuf[ n_read - 1 ] = '\0';
-
-               while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) {
-                       if (c == '<') {
-                       /* Parse the magic priority number. */
-                               pri = 0;
-                               while (isdigit (*(++p))) {
-                                       pri = 10 * pri + (*p - '0');
-                               }
-                               if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
-                                       pri = (LOG_USER | LOG_NOTICE);
-                               }
-                       } else if (c == '\n') {
-                               *q++ = ' ';
-                       } else if (iscntrl (c) && (c < 0177)) {
-                               *q++ = '^';
-                               *q++ = c ^ 0100;
-                       } else {
-                               *q++ = c;
-                       }
-                       p++;
-               }
-               *q = '\0';
-               p++;
-               /* Now log it */
-               logMessage (pri, line);
-       }
-       RELEASE_BB_BUFFER (tmpbuf);
-       return n_read;
-}
-
-
-#ifdef BB_FEATURE_REMOTE_LOG
-static void init_RemoteLog (void){
-
-  struct sockaddr_in remoteaddr;
-  struct hostent *hostinfo;
-  int len = sizeof(remoteaddr);
-
-  memset(&remoteaddr, 0, len);
-
-  remotefd = socket(AF_INET, SOCK_DGRAM, 0);
-
-  if (remotefd < 0) {
-    error_msg_and_die("syslogd: cannot create socket");
-  }
-
-  hostinfo = xgethostbyname(RemoteHost);
-
-  remoteaddr.sin_family = AF_INET;
-  remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
-  remoteaddr.sin_port = htons(RemotePort);
-
-  /* 
-     Since we are using UDP sockets, connect just sets the default host and port 
-     for future operations
-  */
-  if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
-    error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort);
-  }
-
-}
-#endif
-
-static void doSyslogd (void) __attribute__ ((noreturn));
-static void doSyslogd (void)
-{
-       struct sockaddr_un sunx;
-       socklen_t addrLength;
-
-
-       int sock_fd;
-       fd_set fds;
-
-       /* Set up signal handlers. */
-       signal (SIGINT,  quit_signal);
-       signal (SIGTERM, quit_signal);
-       signal (SIGQUIT, quit_signal);
-       signal (SIGHUP,  SIG_IGN);
-       signal (SIGCHLD,  SIG_IGN);
-#ifdef SIGCLD
-       signal (SIGCLD,  SIG_IGN);
-#endif
-       signal (SIGALRM, domark);
-       alarm (MarkInterval);
-
-       /* Create the syslog file so realpath() can work. */
-       if (realpath (_PATH_LOG, lfile) != NULL)
-               unlink (lfile);
-
-       memset (&sunx, 0, sizeof (sunx));
-       sunx.sun_family = AF_UNIX;
-       strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
-       if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
-
-       addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
-       if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5)))
-               perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
-
-       if (chmod (lfile, 0666) < 0)
-               perror_msg_and_die ("Could not set permission on " _PATH_LOG);
-
-       FD_ZERO (&fds);
-       FD_SET (sock_fd, &fds);
-
-#ifdef BB_FEATURE_IPC_SYSLOG
-       if (circular_logging == TRUE ){
-          ipcsyslog_init();
-       }
-#endif
-
-        #ifdef BB_FEATURE_REMOTE_LOG
-        if (doRemoteLog == TRUE){
-          init_RemoteLog();
-        }
-        #endif
-
-       logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
-
-       for (;;) {
-
-               fd_set readfds;
-               int    n_ready;
-               int    fd;
-
-               memcpy (&readfds, &fds, sizeof (fds));
-
-               if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) {
-                       if (errno == EINTR) continue; /* alarm may have happened. */
-                       perror_msg_and_die ("select error");
-               }
-
-               for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) {
-                       if (FD_ISSET (fd, &readfds)) {
-
-                               --n_ready;
-
-                               if (fd == sock_fd) {
-                                       int   conn;
-
-                                       //printf("New Connection request.\n");
-                                       if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) {
-                                               perror_msg_and_die ("accept error");
-                                       }
-
-                                       FD_SET(conn, &fds);
-                                       //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE);
-                               } else {
-                                       //printf("Serving connection: %i\n",fd);
-                                         if ( serveConnection(fd) <= 0 ) {
-                                           close (fd);
-                                           FD_CLR(fd, &fds);
-            }
-                               } /* fd == sock_fd */
-                       }/* FD_ISSET() */
-               }/* for */
-       } /* for main loop */
-}
-
-extern int syslogd_main(int argc, char **argv)
-{
-       int opt;
-       int doFork = TRUE;
-
-       char *p;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
-               switch (opt) {
-                       case 'm':
-                               MarkInterval = atoi(optarg) * 60;
-                               break;
-                       case 'n':
-                               doFork = FALSE;
-                               break;
-                       case 'O':
-                               logFilePath = strdup(optarg);
-                               break;
-#ifdef BB_FEATURE_REMOTE_LOG
-                       case 'R':
-                               RemoteHost = strdup(optarg);
-                               if ( (p = strchr(RemoteHost, ':'))){
-                                       RemotePort = atoi(p+1);
-                                       *p = '\0';
-                               }
-                               doRemoteLog = TRUE;
-                               break;
-                       case 'L':
-                               local_logging = TRUE;
-                               break;
-#endif
-#ifdef BB_FEATURE_IPC_SYSLOG
-                       case 'C':
-                               circular_logging = TRUE;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-#ifdef BB_FEATURE_REMOTE_LOG
-       /* If they have not specified remote logging, then log locally */
-       if (doRemoteLog == FALSE)
-               local_logging = TRUE;
-#endif
-
-
-       /* Store away localhost's name before the fork */
-       gethostname(LocalHostName, sizeof(LocalHostName));
-       if ((p = strchr(LocalHostName, '.'))) {
-               *p++ = '\0';
-       }
-
-       umask(0);
-
-       if (doFork == TRUE) {
-               if (daemon(0, 1) < 0)
-                       perror_msg_and_die("daemon");
-       }
-       doSyslogd();
-
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/syslogd.c b/busybox/syslogd.c
deleted file mode 100644 (file)
index 25bc68f..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini syslogd implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
- *
- * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/param.h>
-
-#include "busybox.h"
-
-/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
-#define SYSLOG_NAMES
-#include <sys/syslog.h>
-#include <sys/uio.h>
-
-/* Path for the file where all log messages are written */
-#define __LOG_FILE "/var/log/messages"
-
-/* Path to the unix socket */
-static char lfile[BUFSIZ];
-
-static char *logFilePath = __LOG_FILE;
-
-/* interval between marks in seconds */
-static int MarkInterval = 20 * 60;
-
-/* localhost's name */
-static char LocalHostName[32];
-
-#ifdef BB_FEATURE_REMOTE_LOG
-#include <netinet/in.h>
-/* udp socket for logging to remote host */
-static int remotefd = -1;
-/* where do we log? */
-static char *RemoteHost;
-/* what port to log to? */
-static int RemotePort = 514;
-/* To remote log or not to remote log, that is the question. */
-static int doRemoteLog = FALSE;
-static int local_logging = FALSE;
-#endif
-
-/* circular buffer variables/structures */
-#ifdef BB_FEATURE_IPC_SYSLOG
-
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
-
-/* our shared key */
-static const long KEY_ID = 0x414e4547; /*"GENA"*/
-
-// Semaphore operation structures
-static struct shbuf_ds {
-       int size;               // size of data written
-       int head;               // start of message list
-       int tail;               // end of message list
-       char data[1];           // data/messages
-} *buf = NULL;                 // shared memory pointer
-
-static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
-static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
-
-static int     shmid = -1;     // ipc shared memory id
-static int     s_semid = -1;   // ipc semaphore id
-int    data_size = 16000; // data size
-int    shm_size = 16000 + sizeof(*buf); // our buffer size
-static int circular_logging = FALSE;
-
-/*
- * sem_up - up()'s a semaphore.
- */
-static inline void sem_up(int semid)
-{
-       if ( semop(semid, SMwup, 1) == -1 )
-               perror_msg_and_die("semop[SMwup]");
-}
-
-/*
- * sem_down - down()'s a semaphore
- */
-static inline void sem_down(int semid)
-{
-       if ( semop(semid, SMwdn, 3) == -1 )
-               perror_msg_and_die("semop[SMwdn]");
-}
-
-
-void ipcsyslog_cleanup(void){
-       printf("Exiting Syslogd!\n");
-       if (shmid != -1)
-               shmdt(buf);
-
-       if (shmid != -1)
-               shmctl(shmid, IPC_RMID, NULL);
-       if (s_semid != -1)
-               semctl(s_semid, 0, IPC_RMID, 0);
-}
-
-void ipcsyslog_init(void){
-       if (buf == NULL){
-           if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
-                       perror_msg_and_die("shmget");
-
-
-           if ((buf = shmat(shmid, NULL, 0)) == NULL)
-                       perror_msg_and_die("shmat");
-
-
-           buf->size=data_size;
-           buf->head=buf->tail=0;
-
-           // we'll trust the OS to set initial semval to 0 (let's hope)
-           if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
-               if (errno == EEXIST){
-                  if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
-                   perror_msg_and_die("semget");
-               }else
-                       perror_msg_and_die("semget");
-           }
-       }else{
-               printf("Buffer already allocated just grab the semaphore?");
-       }
-}
-
-/* write message to buffer */
-void circ_message(const char *msg){
-       int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
-
-       sem_down(s_semid);
-
-       /*
-        * Circular Buffer Algorithm:
-        * --------------------------
-        *
-        * Start-off w/ empty buffer of specific size SHM_SIZ
-        * Start filling it up w/ messages. I use '\0' as separator to break up messages.
-        * This is also very handy since we can do printf on message.
-        *
-        * Once the buffer is full we need to get rid of the first message in buffer and
-        * insert the new message. (Note: if the message being added is >1 message then
-        * we will need to "remove" >1 old message from the buffer). The way this is done
-        * is the following:
-        *      When we reach the end of the buffer we set a mark and start from the beginning.
-        *      Now what about the beginning and end of the buffer? Well we have the "head"
-        *      index/pointer which is the starting point for the messages and we have "tail"
-        *      index/pointer which is the ending point for the messages. When we "display" the
-        *      messages we start from the beginning and continue until we reach "tail". If we
-        *      reach end of buffer, then we just start from the beginning (offset 0). "head" and
-        *      "tail" are actually offsets from the beginning of the buffer.
-        *
-        * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
-        *       a threasafe way of handling shared memory operations.
-        */
-       if ( (buf->tail + l) < buf->size ){
-               /* before we append the message we need to check the HEAD so that we won't
-                  overwrite any of the message that we still need and adjust HEAD to point
-                  to the next message! */
-               if ( buf->tail < buf->head){
-                       if ( (buf->tail + l) >= buf->head ){
-                         /* we need to move the HEAD to point to the next message
-                          * Theoretically we have enough room to add the whole message to the
-                          * buffer, because of the first outer IF statement, so we don't have
-                          * to worry about overflows here!
-                          */
-                          int k= buf->tail + l - buf->head; /* we need to know how many bytes
-                                                               we are overwriting to make
-                                                               enough room */
-                          char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
-                          if (c != NULL) {/* do a sanity check just in case! */
-                               buf->head = c - buf->data + 1; /* we need to convert pointer to
-                                                                 offset + skip the '\0' since
-                                                                 we need to point to the beginning
-                                                                 of the next message */
-                               /* Note: HEAD is only used to "retrieve" messages, it's not used
-                                       when writing messages into our buffer */
-                          }else{ /* show an error message to know we messed up? */
-                               printf("Weird! Can't find the terminator token??? \n");
-                               buf->head=0;
-                          }
-                       }
-               } /* in other cases no overflows have been done yet, so we don't care! */
-
-               /* we should be ok to append the message now */
-               strncpy(buf->data + buf->tail,msg,l); /* append our message */
-               buf->tail+=l; /* count full message w/ '\0' terminating char */
-       }else{
-               /* we need to break up the message and "circle" it around */
-               char *c;
-               int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
-               
-               /* We need to move HEAD! This is always the case since we are going
-                * to "circle" the message.
-                */
-               c=memchr(buf->data + k ,'\0', buf->size - k);
-               
-               if (c != NULL) /* if we don't have '\0'??? weird!!! */{
-                       /* move head pointer*/
-                       buf->head=c-buf->data+1; 
-                       
-                       /* now write the first part of the message */                   
-                       strncpy(buf->data + buf->tail, msg, l - k - 1);
-                       
-                       /* ALWAYS terminate end of buffer w/ '\0' */
-                       buf->data[buf->size-1]='\0'; 
-                       
-                       /* now write out the rest of the string to the beginning of the buffer */
-                       strcpy(buf->data, &msg[l-k-1]);
-
-                       /* we need to place the TAIL at the end of the message */
-                       buf->tail = k + 1;
-               }else{
-                       printf("Weird! Can't find the terminator token from the beginning??? \n");
-                       buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
-               }
-               
-       }
-       sem_up(s_semid);
-}
-#endif
-/* Note: There is also a function called "message()" in init.c */
-/* Print a message to the log file. */
-static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-static void message (char *fmt, ...)
-{
-       int fd;
-       struct flock fl;
-       va_list arguments;
-
-       fl.l_whence = SEEK_SET;
-       fl.l_start  = 0;
-       fl.l_len    = 1;
-
-#ifdef BB_FEATURE_IPC_SYSLOG
-       if ((circular_logging == TRUE) && (buf != NULL)){
-                       char b[1024];
-                       va_start (arguments, fmt);
-                       vsprintf (b, fmt, arguments);
-                       va_end (arguments);
-                       circ_message(b);
-
-       }else
-#endif
-       if ((fd = device_open (logFilePath,
-                                                  O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
-                                                  O_NONBLOCK)) >= 0) {
-               fl.l_type = F_WRLCK;
-               fcntl (fd, F_SETLKW, &fl);
-               va_start (arguments, fmt);
-               vdprintf (fd, fmt, arguments);
-               va_end (arguments);
-               fl.l_type = F_UNLCK;
-               fcntl (fd, F_SETLKW, &fl);
-               close (fd);
-       } else {
-               /* Always send console messages to /dev/console so people will see them. */
-               if ((fd = device_open (_PATH_CONSOLE,
-                                                          O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
-                       va_start (arguments, fmt);
-                       vdprintf (fd, fmt, arguments);
-                       va_end (arguments);
-                       close (fd);
-               } else {
-                       fprintf (stderr, "Bummer, can't print: ");
-                       va_start (arguments, fmt);
-                       vfprintf (stderr, fmt, arguments);
-                       fflush (stderr);
-                       va_end (arguments);
-               }
-       }
-}
-
-static void logMessage (int pri, char *msg)
-{
-       time_t now;
-       char *timestamp;
-       static char res[20] = "";
-       CODE *c_pri, *c_fac;
-
-       if (pri != 0) {
-               for (c_fac = facilitynames;
-                               c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
-               for (c_pri = prioritynames;
-                               c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
-               if (c_fac->c_name == NULL || c_pri->c_name == NULL)
-                       snprintf(res, sizeof(res), "<%d>", pri);
-               else
-                       snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
-       }
-
-       if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
-                       msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
-               time(&now);
-               timestamp = ctime(&now) + 4;
-               timestamp[15] = '\0';
-       } else {
-               timestamp = msg;
-               timestamp[15] = '\0';
-               msg += 16;
-       }
-
-       /* todo: supress duplicates */
-
-#ifdef BB_FEATURE_REMOTE_LOG
-       /* send message to remote logger */
-       if ( -1 != remotefd){
-static const int IOV_COUNT = 2;
-               struct iovec iov[IOV_COUNT];
-               struct iovec *v = iov;
-
-               memset(&res, 0, sizeof(res));
-               snprintf(res, sizeof(res), "<%d>", pri);
-               v->iov_base = res ;
-               v->iov_len = strlen(res);          
-               v++;
-
-               v->iov_base = msg;
-               v->iov_len = strlen(msg);          
-
-               if ( -1 == writev(remotefd,iov, IOV_COUNT)){
-                       error_msg_and_die("syslogd: cannot write to remote file handle on" 
-                                       "%s:%d",RemoteHost,RemotePort);
-               }
-       }
-       if (local_logging == TRUE)
-#endif
-               /* now spew out the message to wherever it is supposed to go */
-               message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
-
-
-}
-
-static void quit_signal(int sig)
-{
-       logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
-       unlink(lfile);
-#ifdef BB_FEATURE_IPC_SYSLOG
-       ipcsyslog_cleanup();
-#endif
-
-       exit(TRUE);
-}
-
-static void domark(int sig)
-{
-       if (MarkInterval > 0) {
-               logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
-               alarm(MarkInterval);
-       }
-}
-
-/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
- * enabled, we otherwise get a "storage size isn't constant error. */
-#define BUFSIZE 1023
-static int serveConnection (int conn)
-{
-       RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1);
-       int    n_read;
-       char *p = tmpbuf;
-
-       n_read = read (conn, tmpbuf, BUFSIZE );
-
-       while (p < tmpbuf + n_read) {
-
-               int           pri = (LOG_USER | LOG_NOTICE);
-               char          line[ BUFSIZE + 1 ];
-               unsigned char c;
-
-               char *q = line;
-
-               tmpbuf[ n_read - 1 ] = '\0';
-
-               while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) {
-                       if (c == '<') {
-                       /* Parse the magic priority number. */
-                               pri = 0;
-                               while (isdigit (*(++p))) {
-                                       pri = 10 * pri + (*p - '0');
-                               }
-                               if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
-                                       pri = (LOG_USER | LOG_NOTICE);
-                               }
-                       } else if (c == '\n') {
-                               *q++ = ' ';
-                       } else if (iscntrl (c) && (c < 0177)) {
-                               *q++ = '^';
-                               *q++ = c ^ 0100;
-                       } else {
-                               *q++ = c;
-                       }
-                       p++;
-               }
-               *q = '\0';
-               p++;
-               /* Now log it */
-               logMessage (pri, line);
-       }
-       RELEASE_BB_BUFFER (tmpbuf);
-       return n_read;
-}
-
-
-#ifdef BB_FEATURE_REMOTE_LOG
-static void init_RemoteLog (void){
-
-  struct sockaddr_in remoteaddr;
-  struct hostent *hostinfo;
-  int len = sizeof(remoteaddr);
-
-  memset(&remoteaddr, 0, len);
-
-  remotefd = socket(AF_INET, SOCK_DGRAM, 0);
-
-  if (remotefd < 0) {
-    error_msg_and_die("syslogd: cannot create socket");
-  }
-
-  hostinfo = xgethostbyname(RemoteHost);
-
-  remoteaddr.sin_family = AF_INET;
-  remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
-  remoteaddr.sin_port = htons(RemotePort);
-
-  /* 
-     Since we are using UDP sockets, connect just sets the default host and port 
-     for future operations
-  */
-  if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
-    error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort);
-  }
-
-}
-#endif
-
-static void doSyslogd (void) __attribute__ ((noreturn));
-static void doSyslogd (void)
-{
-       struct sockaddr_un sunx;
-       socklen_t addrLength;
-
-
-       int sock_fd;
-       fd_set fds;
-
-       /* Set up signal handlers. */
-       signal (SIGINT,  quit_signal);
-       signal (SIGTERM, quit_signal);
-       signal (SIGQUIT, quit_signal);
-       signal (SIGHUP,  SIG_IGN);
-       signal (SIGCHLD,  SIG_IGN);
-#ifdef SIGCLD
-       signal (SIGCLD,  SIG_IGN);
-#endif
-       signal (SIGALRM, domark);
-       alarm (MarkInterval);
-
-       /* Create the syslog file so realpath() can work. */
-       if (realpath (_PATH_LOG, lfile) != NULL)
-               unlink (lfile);
-
-       memset (&sunx, 0, sizeof (sunx));
-       sunx.sun_family = AF_UNIX;
-       strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
-       if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
-
-       addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
-       if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5)))
-               perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
-
-       if (chmod (lfile, 0666) < 0)
-               perror_msg_and_die ("Could not set permission on " _PATH_LOG);
-
-       FD_ZERO (&fds);
-       FD_SET (sock_fd, &fds);
-
-#ifdef BB_FEATURE_IPC_SYSLOG
-       if (circular_logging == TRUE ){
-          ipcsyslog_init();
-       }
-#endif
-
-        #ifdef BB_FEATURE_REMOTE_LOG
-        if (doRemoteLog == TRUE){
-          init_RemoteLog();
-        }
-        #endif
-
-       logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
-
-       for (;;) {
-
-               fd_set readfds;
-               int    n_ready;
-               int    fd;
-
-               memcpy (&readfds, &fds, sizeof (fds));
-
-               if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) {
-                       if (errno == EINTR) continue; /* alarm may have happened. */
-                       perror_msg_and_die ("select error");
-               }
-
-               for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) {
-                       if (FD_ISSET (fd, &readfds)) {
-
-                               --n_ready;
-
-                               if (fd == sock_fd) {
-                                       int   conn;
-
-                                       //printf("New Connection request.\n");
-                                       if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) {
-                                               perror_msg_and_die ("accept error");
-                                       }
-
-                                       FD_SET(conn, &fds);
-                                       //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE);
-                               } else {
-                                       //printf("Serving connection: %i\n",fd);
-                                         if ( serveConnection(fd) <= 0 ) {
-                                           close (fd);
-                                           FD_CLR(fd, &fds);
-            }
-                               } /* fd == sock_fd */
-                       }/* FD_ISSET() */
-               }/* for */
-       } /* for main loop */
-}
-
-extern int syslogd_main(int argc, char **argv)
-{
-       int opt;
-       int doFork = TRUE;
-
-       char *p;
-
-       /* do normal option parsing */
-       while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
-               switch (opt) {
-                       case 'm':
-                               MarkInterval = atoi(optarg) * 60;
-                               break;
-                       case 'n':
-                               doFork = FALSE;
-                               break;
-                       case 'O':
-                               logFilePath = strdup(optarg);
-                               break;
-#ifdef BB_FEATURE_REMOTE_LOG
-                       case 'R':
-                               RemoteHost = strdup(optarg);
-                               if ( (p = strchr(RemoteHost, ':'))){
-                                       RemotePort = atoi(p+1);
-                                       *p = '\0';
-                               }
-                               doRemoteLog = TRUE;
-                               break;
-                       case 'L':
-                               local_logging = TRUE;
-                               break;
-#endif
-#ifdef BB_FEATURE_IPC_SYSLOG
-                       case 'C':
-                               circular_logging = TRUE;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-#ifdef BB_FEATURE_REMOTE_LOG
-       /* If they have not specified remote logging, then log locally */
-       if (doRemoteLog == FALSE)
-               local_logging = TRUE;
-#endif
-
-
-       /* Store away localhost's name before the fork */
-       gethostname(LocalHostName, sizeof(LocalHostName));
-       if ((p = strchr(LocalHostName, '.'))) {
-               *p++ = '\0';
-       }
-
-       umask(0);
-
-       if (doFork == TRUE) {
-               if (daemon(0, 1) < 0)
-                       perror_msg_and_die("daemon");
-       }
-       doSyslogd();
-
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/tail.c b/busybox/tail.c
deleted file mode 100644 (file)
index 90cc2a6..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tail implementation for busybox
- *
- *
- * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <fcntl.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-static const struct suffix_mult tail_suffixes[] = {
-       { "b", 512 },
-       { "k", 1024 },
-       { "m", 1048576 },
-       { NULL, 0 }
-};
-
-static const int BYTES = 0;
-static const int LINES = 1;
-
-static char *tailbuf;
-static int taillen;
-static int newline;
-
-static void tailbuf_append(char *buf, int len)
-{
-       tailbuf = xrealloc(tailbuf, taillen + len);
-       memcpy(tailbuf + taillen, buf, len);
-       taillen += len;
-}
-
-static void tailbuf_trunc()
-{
-       char *s;
-       s = memchr(tailbuf, '\n', taillen);
-       memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf));
-       taillen -= (s + 1) - tailbuf;
-       newline = 0;
-}
-
-int tail_main(int argc, char **argv)
-{
-       int from_top = 0, units = LINES, count = 10, sleep_period = 1;
-       int show_headers = 0, hide_headers = 0, follow = 0;
-       int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0;
-       char *s, *start, *end, buf[BUFSIZ];
-       int i, opt;
-
-       while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) {
-               switch (opt) {
-                       case 'f':
-                               follow = 1;
-                               break;
-#ifdef BB_FEATURE_FANCY_TAIL
-                       case 'c':
-                               units = BYTES;
-                               /* FALLS THROUGH */
-#endif
-                       case 'n':
-                               count = parse_number(optarg, tail_suffixes);
-                               if (count < 0)
-                                       count = -count;
-                               if (optarg[0] == '+')
-                                       from_top = 1;
-                               break;
-#ifdef BB_FEATURE_FANCY_TAIL
-                       case 'q':
-                               hide_headers = 1;
-                               break;
-                       case 's':
-                               sleep_period = parse_number(optarg, 0);
-                               break;
-                       case 'v':
-                               show_headers = 1;
-                               break;
-#endif
-                       default:
-                               show_usage();
-               }
-       }
-
-       /* open all the files */
-       fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1));
-       if (argc == optind) {
-               fds[nfiles++] = STDIN_FILENO;
-               argv[optind] = "standard input";
-       } else {
-               for (i = optind; i < argc; i++) {
-                       if (strcmp(argv[i], "-") == 0) {
-                               fds[nfiles++] = STDIN_FILENO;
-                               argv[i] = "standard input";
-                       } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) {
-                               perror_msg("%s", argv[i]);
-                               status = EXIT_FAILURE;
-                       }
-               }
-       }
-       
-#ifdef BB_FEATURE_FANCY_TAIL
-       /* tail the files */
-       if (!from_top && units == BYTES)
-               tailbuf = xmalloc(count);
-#endif
-
-       for (i = 0; i < nfiles; i++) {
-               if (fds[i] == -1)
-                       continue;
-               if (!count) {
-                       lseek(fds[i], 0, SEEK_END);
-                       continue;
-               }
-               seen = 0;
-               if (show_headers || (!hide_headers && nfiles > 1))
-                       printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]);
-               while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
-                       if (from_top) {
-#ifdef BB_FEATURE_FANCY_TAIL
-                               if (units == BYTES) {
-                                       if (count - 1 <= seen)
-                                               nwrite = nread;
-                                       else if (count - 1 <= seen + nread)
-                                               nwrite = nread + seen - (count - 1);
-                                       else
-                                               nwrite = 0;
-                                       seen += nread;
-                               } else {
-#else
-                               {
-#endif
-                                       if (count - 1 <= seen)
-                                               nwrite = nread;
-                                       else {
-                                               nwrite = 0;
-                                               for (s = memchr(buf, '\n', nread); s != NULL;
-                                                               s = memchr(s+1, '\n', nread - (s + 1 - buf))) {
-                                                       if (count - 1 <= ++seen) {
-                                                               nwrite = nread - (s + 1 - buf);
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               }
-                               if (full_write(STDOUT_FILENO, buf + nread - nwrite,
-                                                       nwrite) < 0) {
-                                       perror_msg("write");
-                                       status = EXIT_FAILURE;
-                                       break;
-                               }
-                       } else {
-#ifdef BB_FEATURE_FANCY_TAIL
-                               if (units == BYTES) {
-                                       if (nread < count) {
-                                               memmove(tailbuf, tailbuf + nread, count - nread);
-                                               memcpy(tailbuf + count - nread, buf, nread);
-                                       } else {
-                                               memcpy(tailbuf, buf + nread - count, count);
-                                       }
-                                       seen += nread;
-                               } else {
-#else
-                               {
-#endif
-                                       for (start = buf, end = memchr(buf, '\n', nread);
-                                                       end != NULL; start = end+1,
-                                                       end = memchr(start, '\n', nread - (start - buf))) {
-                                               if (newline && count <= seen)
-                                                       tailbuf_trunc();
-                                               tailbuf_append(start, end - start + 1);
-                                               seen++;
-                                               newline = 1;
-                                       }
-                                       if (newline && count <= seen && nread - (start - buf) > 0)
-                                               tailbuf_trunc();
-                                       tailbuf_append(start, nread - (start - buf));
-                               }
-                       }
-               }
-
-               if (nread < 0) {
-                       perror_msg("read");
-                       status = EXIT_FAILURE;
-               }
-
-#ifdef BB_FEATURE_FANCY_TAIL
-               if (!from_top && units == BYTES) {
-                       if (count < seen)
-                               seen = count;
-                       if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) {
-                               perror_msg("write");
-                               status = EXIT_FAILURE;
-                       }
-               }
-#endif
-
-               if (!from_top && units == LINES) {
-                       if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) {
-                               perror_msg("write");
-                               status = EXIT_FAILURE;
-                       }
-               }
-
-               taillen = 0;
-       }
-
-       while (follow) {
-               sleep(sleep_period);
-
-               for (i = 0; i < nfiles; i++) {
-                       if (fds[i] == -1)
-                               continue;
-
-                       if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
-                               if (show_headers || (!hide_headers && nfiles > 1))
-                                       printf("\n==> %s <==\n", argv[optind + i]);
-
-                               do {
-                                       full_write(STDOUT_FILENO, buf, nread);
-                               } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0);
-                       }
-
-                       if (nread < 0) {
-                               perror_msg("read");
-                               status = EXIT_FAILURE;
-                       }
-               }
-       }
-
-       return status;
-}
diff --git a/busybox/tar.c b/busybox/tar.c
deleted file mode 100644 (file)
index 389d7f0..0000000
+++ /dev/null
@@ -1,1150 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tar implementation for busybox 
- *
- * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
- * ground up.  It still has remnents of the old code lying about, but it is
- * very different now (i.e., cleaner, less global variables, etc.)
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * Based in part in the tar implementation in sash
- *  Copyright (c) 1999 by David I. Bell
- *  Permission is granted to use, distribute, or modify this source,
- *  provided that this copyright notice remains intact.
- *  Permission to distribute sash derived code under the GPL has been granted.
- *
- * Based in part on the tar implementation from busybox-0.28
- *  Copyright (C) 1995 Bruce Perens
- *  This is free software under the GNU General Public License.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <utime.h>
-#include <sys/types.h>
-#include <sys/sysmacros.h>
-#include <getopt.h>
-#include <fnmatch.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Tar file constants  */
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
-enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */
-
-/* POSIX tar Header Block, from POSIX 1003.1-1990  */
-struct TarHeader
-{
-                                /* byte offset */
-       char name[NAME_SIZE];         /*   0-99 */
-       char mode[8];                 /* 100-107 */
-       char uid[8];                  /* 108-115 */
-       char gid[8];                  /* 116-123 */
-       char size[12];                /* 124-135 */
-       char mtime[12];               /* 136-147 */
-       char chksum[8];               /* 148-155 */
-       char typeflag;                /* 156-156 */
-       char linkname[NAME_SIZE];     /* 157-256 */
-       char magic[6];                /* 257-262 */
-       char version[2];              /* 263-264 */
-       char uname[32];               /* 265-296 */
-       char gname[32];               /* 297-328 */
-       char devmajor[8];             /* 329-336 */
-       char devminor[8];             /* 337-344 */
-       char prefix[155];             /* 345-499 */
-       char padding[12];             /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
-};
-typedef struct TarHeader TarHeader;
-
-
-/* A few useful constants */
-#define TAR_MAGIC          "ustar"        /* ustar and a null */
-#define TAR_VERSION        "  "           /* Be compatable with GNU tar format */
-static const int TAR_MAGIC_LEN = 6;
-static const int TAR_VERSION_LEN = 2;
-static const int TAR_BLOCK_SIZE = 512;
-
-/* A nice enum with all the possible tar file content types */
-enum TarFileType 
-{
-       REGTYPE  = '0',            /* regular file */
-       REGTYPE0 = '\0',           /* regular file (ancient bug compat)*/
-       LNKTYPE  = '1',            /* hard link */
-       SYMTYPE  = '2',            /* symbolic link */
-       CHRTYPE  = '3',            /* character special */
-       BLKTYPE  = '4',            /* block special */
-       DIRTYPE  = '5',            /* directory */
-       FIFOTYPE = '6',            /* FIFO special */
-       CONTTYPE = '7',            /* reserved */
-       GNULONGLINK = 'K',         /* GNU long (>100 chars) link name */
-       GNULONGNAME = 'L',         /* GNU long (>100 chars) file name */
-};
-typedef enum TarFileType TarFileType;
-
-/* This struct ignores magic, non-numeric user name, 
- * non-numeric group name, and the checksum, since
- * these are all ignored by BusyBox tar. */ 
-struct TarInfo
-{
-       int              tarFd;          /* An open file descriptor for reading from the tarball */
-       char *           name;           /* File name */
-       mode_t           mode;           /* Unix mode, including device bits. */
-       uid_t            uid;            /* Numeric UID */
-       gid_t            gid;            /* Numeric GID */
-       size_t           size;           /* Size of file */
-       time_t           mtime;          /* Last-modified time */
-       enum TarFileType type;           /* Regular, directory, link, etc. */
-       char *           linkname;       /* Name for symbolic and hard links */
-       long             devmajor;       /* Major number for special device */
-       long             devminor;       /* Minor number for special device */
-};
-typedef struct TarInfo TarInfo;
-
-/* Local procedures to restore files from a tar file.  */
-static int readTarFile(int tarFd, int extractFlag, int listFlag, 
-               int tostdoutFlag, int verboseFlag, char** extractList,
-               char** excludeList);
-
-#ifdef BB_FEATURE_TAR_CREATE
-/* Local procedures to save files into a tar file.  */
-static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
-               char** excludeList);
-#endif
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-static struct option longopts[] = {
-       { "exclude", 1, NULL, 'e' },
-       { NULL, 0, NULL, 0 }
-};
-#endif
-
-extern int tar_main(int argc, char **argv)
-{
-       char** excludeList=NULL;
-       char** extractList=NULL;
-       const char *tarName="-";
-       const char *cwd=NULL;
-#if defined BB_FEATURE_TAR_EXCLUDE
-       int excludeListSize=0;
-       FILE *fileList;
-       char file[256];
-#endif
-#if defined BB_FEATURE_TAR_GZIP
-       FILE *comp_file = NULL;
-       int unzipFlag    = FALSE;
-#endif
-       int listFlag     = FALSE;
-       int extractFlag  = FALSE;
-       int createFlag   = FALSE;
-       int verboseFlag  = FALSE;
-       int tostdoutFlag = FALSE;
-       int status       = FALSE;
-       int opt;
-       pid_t pid;
-
-       if (argc <= 1)
-               show_usage();
-
-       if (argv[1][0] != '-') {
-               char *tmp = xmalloc(strlen(argv[1]) + 2);
-               tmp[0] = '-';
-               strcpy(tmp + 1, argv[1]);
-               argv[1] = tmp;
-       }
-
-       while (
-#ifndef BB_FEATURE_TAR_EXCLUDE
-                       (opt = getopt(argc, argv, "cxtzvOf:pC:"))
-#else
-                       (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL))
-#endif
-                       > 0) {
-               switch (opt) {
-                       case 'c':
-                               if (extractFlag == TRUE || listFlag == TRUE)
-                                       goto flagError;
-                               createFlag = TRUE;
-                               break;
-                       case 'x':
-                               if (listFlag == TRUE || createFlag == TRUE)
-                                       goto flagError;
-                               extractFlag = TRUE;
-                               break;
-                       case 't':
-                               if (extractFlag == TRUE || createFlag == TRUE)
-                                       goto flagError;
-                               listFlag = TRUE;
-                               break;
-#ifdef BB_FEATURE_TAR_GZIP
-                       case 'z':
-                               unzipFlag = TRUE;
-                               break;
-#endif
-                       case 'v':
-                               verboseFlag = TRUE;
-                               break;
-                       case 'O':
-                               tostdoutFlag = TRUE;
-                               break;
-                       case 'f':
-                               if (*tarName != '-')
-                                       error_msg_and_die( "Only one 'f' option allowed");
-                               tarName = optarg;
-                               break;
-#if defined BB_FEATURE_TAR_EXCLUDE
-                       case 'e':
-                               excludeList=xrealloc( excludeList,
-                                               sizeof(char *) * (excludeListSize+2));
-                               excludeList[excludeListSize] = optarg;
-                               /* Tack a NULL onto the end of the list */
-                               excludeList[++excludeListSize] = NULL;
-                       case 'X':
-                               fileList = xfopen(optarg, "r");
-                               while (fgets(file, sizeof(file), fileList) != NULL) {
-                                       excludeList = xrealloc(excludeList,
-                                                       sizeof(char *) * (excludeListSize+2));
-                                       chomp(file);
-                                       excludeList[excludeListSize] = xstrdup(file);
-                                       /* Tack a NULL onto the end of the list */
-                                       excludeList[++excludeListSize] = NULL;
-                               }
-                               fclose(fileList);
-                               break;
-#endif
-                       case 'p':
-                               break;
-                       case 'C':
-                               cwd = xgetcwd((char *)cwd);
-                               if (chdir(optarg)) {
-                                       printf("cd: %s: %s\n", optarg, strerror(errno));
-                                       return EXIT_FAILURE;
-                               }
-                               break;
-                       default:
-                                       show_usage();
-               }
-       }
-
-       /*
-        * Do the correct type of action supplying the rest of the
-        * command line arguments as the list of files to process.
-        */
-       if (createFlag == TRUE) {
-#ifndef BB_FEATURE_TAR_CREATE
-               error_msg_and_die( "This version of tar was not compiled with tar creation support.");
-#else
-#ifdef BB_FEATURE_TAR_GZIP
-               if (unzipFlag==TRUE)
-                       error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip");
-#endif
-               status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList);
-#endif
-       }
-       if (listFlag == TRUE || extractFlag == TRUE) {
-               int tarFd;
-               if (argv[optind])
-                       extractList = argv + optind;
-               /* Open the tar file for reading.  */
-               if (!strcmp(tarName, "-"))
-                       tarFd = fileno(stdin);
-               else
-                       tarFd = open(tarName, O_RDONLY);
-               if (tarFd < 0)
-                       perror_msg_and_die("Error opening '%s'", tarName);
-
-#ifdef BB_FEATURE_TAR_GZIP     
-               /* unzip tarFd in a seperate process */
-               if (unzipFlag == TRUE) {
-                       comp_file = fdopen(tarFd, "r");
-
-                       /* set the buffer size */
-                       setvbuf(comp_file, NULL, _IOFBF, 0x8000);
-
-                       if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) {
-                               error_msg_and_die("Couldnt unzip file");
-                       }
-               }
-#endif                 
-               status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag,
-                                       verboseFlag, extractList, excludeList);
-               close(tarFd);
-#ifdef BB_FEATURE_TAR_GZIP     
-               if (unzipFlag == TRUE) {
-                       gz_close(pid);
-                       fclose(comp_file);
-               }
-#endif                 
-       }
-
-       if (cwd)
-               chdir(cwd);
-       if (status == TRUE)
-               return EXIT_SUCCESS;
-       else
-               return EXIT_FAILURE;
-
-  flagError:
-       error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified");
-}
-                                       
-static void
-fixUpPermissions(TarInfo *header)
-{
-       struct utimbuf t;
-       /* Now set permissions etc. for the new file */
-       chown(header->name, header->uid, header->gid);
-       chmod(header->name, header->mode);
-       /* Reset the time */
-       t.actime = time(0);
-       t.modtime = header->mtime;
-       utime(header->name, &t);
-}
-                               
-static int
-tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       size_t  writeSize;
-       size_t  readSize;
-       size_t  actualWriteSz;
-       char    buffer[20 * TAR_BLOCK_SIZE];
-       size_t  size = header->size;
-       int outFd=fileno(stdout);
-
-       /* Open the file to be written, if a file is supposed to be written */
-       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
-               /* Create the path to the file, just in case it isn't there...
-                * This should not screw up path permissions or anything. */
-               char *buf, *dir;
-               buf = xstrdup (header->name);
-               dir = dirname (buf);
-               make_directory (dir, -1, FILEUTILS_RECUR);
-               free (buf);
-               if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, 
-                                               header->mode & ~S_IFMT)) < 0) {
-                       error_msg(io_error, header->name, strerror(errno)); 
-                       return( FALSE);
-               }
-       }
-
-       /* Write out the file, if we are supposed to be doing that */
-       while ( size > 0 ) {
-               actualWriteSz=0;
-               if ( size > sizeof(buffer) )
-                       writeSize = readSize = sizeof(buffer);
-               else {
-                       int mod = size % TAR_BLOCK_SIZE;
-                       if ( mod != 0 )
-                               readSize = size + (TAR_BLOCK_SIZE - mod);
-                       else
-                               readSize = size;
-                       writeSize = size;
-               }
-               if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) {
-                       /* Tarball seems to have a problem */
-                       error_msg("Unexpected EOF in archive"); 
-                       return( FALSE);
-               }
-               if ( readSize < writeSize )
-                       writeSize = readSize;
-
-               /* Write out the file, if we are supposed to be doing that */
-               if (extractFlag==TRUE) {
-
-                       if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) {
-                               /* Output file seems to have a problem */
-                               error_msg(io_error, header->name, strerror(errno)); 
-                               return( FALSE);
-                       }
-               } else {
-                       actualWriteSz=writeSize;
-               }
-
-               size -= actualWriteSz;
-       }
-
-       /* Now we are done writing the file out, so try 
-        * and fix up the permissions and whatnot */
-       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
-               close(outFd);
-               fixUpPermissions(header);
-       }
-       return( TRUE);
-}
-
-static int
-tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0)
-               return( FALSE);
-
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-static int
-tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (link(header->linkname, header->name) < 0) {
-               perror_msg("%s: Cannot create hard link to '%s'", header->name,
-                               header->linkname); 
-               return( FALSE);
-       }
-
-       /* Now set permissions etc. for the new directory */
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-static int
-tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-#ifdef S_ISLNK
-       if (symlink(header->linkname, header->name) < 0) {
-               perror_msg("%s: Cannot create symlink to '%s'", header->name,
-                               header->linkname); 
-               return( FALSE);
-       }
-       /* Try to change ownership of the symlink.
-        * If libs doesn't support that, don't bother.
-        * Changing the pointed-to-file is the Wrong Thing(tm).
-        */
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-       lchown(header->name, header->uid, header->gid);
-#endif
-
-       /* Do not change permissions or date on symlink,
-        * since it changes the pointed to file instead.  duh. */
-#else
-       error_msg("%s: Cannot create symlink to '%s': %s", 
-                       header->name, header->linkname, 
-                       "symlinks not supported"); 
-#endif
-       return( TRUE);
-}
-
-static int
-tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag)
-{
-       if (extractFlag==FALSE || tostdoutFlag==TRUE)
-               return( TRUE);
-
-       if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) {
-               if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) {
-                       perror_msg("%s: Cannot mknod", header->name); 
-                       return( FALSE);
-               }
-       } else if (S_ISFIFO(header->mode)) {
-               if (mkfifo(header->name, header->mode) < 0) {
-                       perror_msg("%s: Cannot mkfifo", header->name); 
-                       return( FALSE);
-               }
-       }
-
-       /* Now set permissions etc. for the new directory */
-       fixUpPermissions(header);
-       return( TRUE);
-}
-
-/* Parse the tar header and fill in the nice struct with the details */
-static int
-readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
-{
-       int i;
-       long chksum, sum=0;
-       unsigned char *s = (unsigned char *)rawHeader;
-
-       header->name  = rawHeader->name;
-       /* Check for and relativify any absolute paths */
-       if ( *(header->name) == '/' ) {
-               static int alreadyWarned=FALSE;
-
-               while (*(header->name) == '/')
-                       header->name++;
-
-               if (alreadyWarned == FALSE) {
-                       error_msg("Removing leading '/' from member names");
-                       alreadyWarned = TRUE;
-               }
-       }
-
-       header->mode  = strtol(rawHeader->mode, NULL, 8);
-       header->uid   = strtol(rawHeader->uid, NULL, 8);
-       header->gid   = strtol(rawHeader->gid, NULL, 8);
-       header->size  = strtol(rawHeader->size, NULL, 8);
-       header->mtime = strtol(rawHeader->mtime, NULL, 8);
-       chksum = strtol(rawHeader->chksum, NULL, 8);
-       header->type  = rawHeader->typeflag;
-       header->linkname  = rawHeader->linkname;
-       header->devmajor  = strtol(rawHeader->devmajor, NULL, 8);
-       header->devminor  = strtol(rawHeader->devminor, NULL, 8);
-
-       /* Check the checksum */
-       for (i = sizeof(*rawHeader); i-- != 0;) {
-               sum += *s++;
-       }
-       /* Remove the effects of the checksum field (replace 
-        * with blanks for the purposes of the checksum) */
-       s = rawHeader->chksum;
-       for (i = sizeof(rawHeader->chksum) ; i-- != 0;) {
-               sum -= *s++;
-       }
-       sum += ' ' * sizeof(rawHeader->chksum);
-       if (sum == chksum )
-               return ( TRUE);
-       return( FALSE);
-}
-
-static int exclude_file(char **excluded_files, const char *file)
-{
-       int i;
-
-       if (excluded_files == NULL)
-               return 0;
-
-       for (i = 0; excluded_files[i] != NULL; i++) {
-               if (excluded_files[i][0] == '/') {
-                       if (fnmatch(excluded_files[i], file,
-                                               FNM_PATHNAME | FNM_LEADING_DIR) == 0)
-                               return 1;
-               } else {
-                       const char *p;
-
-                       for (p = file; p[0] != '\0'; p++) {
-                               if ((p == file || p[-1] == '/') && p[0] != '/' &&
-                                               fnmatch(excluded_files[i], p,
-                                                       FNM_PATHNAME | FNM_LEADING_DIR) == 0)
-                                       return 1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int extract_file(char **extract_files, const char *file)
-{
-       int i;
-
-       if (extract_files == NULL)
-               return 1;
-
-       for (i = 0; extract_files[i] != NULL; i++) {
-               if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0)
-                       return 1;
-       }
-
-       return 0;
-}
-
-/*
- * Read a tar file and extract or list the specified files within it.
- * If the list is empty than all files are extracted or listed.
- */
-static int readTarFile(int tarFd, int extractFlag, int listFlag, 
-               int tostdoutFlag, int verboseFlag, char** extractList,
-               char** excludeList)
-{
-       int status;
-       int errorFlag=FALSE;
-       int skipNextHeaderFlag=FALSE;
-       TarHeader rawHeader;
-       TarInfo header;
-
-       /* Read the tar file, and iterate over it one file at a time */
-       while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) {
-
-               /* Try to read the header */
-               if ( readTarHeader(&rawHeader, &header) == FALSE ) {
-                       if ( *(header.name) == '\0' ) {
-                               goto endgame;
-                       } else {
-                               errorFlag=TRUE;
-                               error_msg("Bad tar header, skipping");
-                               continue;
-                       }
-               }
-               if ( *(header.name) == '\0' )
-                       continue;
-               header.tarFd = tarFd;
-
-               /* Skip funky extra GNU headers that precede long files */
-               if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) {
-                       skipNextHeaderFlag=TRUE;
-                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                               errorFlag = TRUE;
-                       continue;
-               }
-               if ( skipNextHeaderFlag == TRUE ) { 
-                       skipNextHeaderFlag=FALSE;
-                       error_msg(name_longer_than_foo, NAME_SIZE); 
-                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                               errorFlag = TRUE;
-                       continue;
-               }
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-               if (exclude_file(excludeList, header.name)) {
-                       /* There are not the droids you're looking for, move along */
-                       /* If it is a regular file, pretend to extract it with
-                        * the extractFlag set to FALSE, so the junk in the tarball
-                        * is properly skipped over */
-                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
-                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                                       errorFlag = TRUE;
-                       }
-                       continue;
-               }
-#endif
-
-               if (!extract_file(extractList, header.name)) {
-                       /* There are not the droids you're looking for, move along */
-                       /* If it is a regular file, pretend to extract it with
-                        * the extractFlag set to FALSE, so the junk in the tarball
-                        * is properly skipped over */
-                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
-                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
-                                       errorFlag = TRUE;
-                       }
-                       continue;
-               }
-
-               if (listFlag == TRUE) {
-                       /* Special treatment if the list (-t) flag is on */
-                       if (verboseFlag == TRUE) {
-                               int len, len1;
-                               char buf[35];
-                               struct tm *tm = localtime (&(header.mtime));
-
-                               len=printf("%s ", mode_string(header.mode));
-                               my_getpwuid(buf, header.uid);
-                               if (! *buf)
-                                       len+=printf("%d", header.uid);
-                               else
-                                       len+=printf("%s", buf);
-                               my_getgrgid(buf, header.gid);
-                               if (! *buf)
-                                       len+=printf("/%-d ", header.gid);
-                               else
-                                       len+=printf("/%-s ", buf);
-
-                               if (header.type==CHRTYPE || header.type==BLKTYPE) {
-                                       len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", 
-                                                       header.devmajor, header.devminor);
-                               } else {
-                                       len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size);
-                               }
-                               /* Jump through some hoops to make the columns match up */
-                               for(;(len+len1)<31;len++)
-                                       printf(" ");
-                               printf(buf);
-
-                               /* Use ISO 8610 time format */
-                               if (tm) { 
-                                       printf ("%04d-%02d-%02d %02d:%02d:%02d ", 
-                                                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
-                                                       tm->tm_hour, tm->tm_min, tm->tm_sec);
-                               }
-                       }
-                       printf("%s", header.name);
-                       if (verboseFlag == TRUE) {
-                               if (header.type==LNKTYPE)       /* If this is a link, say so */
-                                       printf(" link to %s", header.linkname);
-                               else if (header.type==SYMTYPE)
-                                       printf(" -> %s", header.linkname);
-                       }
-                       printf("\n");
-               }
-
-               /* List contents if we are supposed to do that */
-               if (verboseFlag == TRUE && extractFlag == TRUE) {
-                       /* Now the normal listing */
-                       FILE *vbFd = stdout;
-                       if (tostdoutFlag == TRUE)       // If the archive goes to stdout, verbose to stderr
-                               vbFd = stderr;
-                       fprintf(vbFd, "%s\n", header.name);
-               }
-                       
-               /* Remove files if we would overwrite them */
-               if (extractFlag == TRUE && tostdoutFlag == FALSE)
-                       unlink(header.name);
-
-               /* If we got here, we can be certain we have a legitimate 
-                * header to work with.  So work with it.  */
-               switch ( header.type ) {
-                       case REGTYPE:
-                       case REGTYPE0:
-                               /* If the name ends in a '/' then assume it is
-                                * supposed to be a directory, and fall through */
-                               if (!last_char_is(header.name,'/')) {
-                                       if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE)
-                                               errorFlag=TRUE;
-                                       break;
-                               }
-                       case DIRTYPE:
-                               if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case LNKTYPE:
-                               if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case SYMTYPE:
-                               if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-                       case CHRTYPE:
-                       case BLKTYPE:
-                       case FIFOTYPE:
-                               if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE)
-                                       errorFlag=TRUE;
-                               break;
-#if 0
-                       /* Handled earlier */
-                       case GNULONGNAME:
-                       case GNULONGLINK:
-                               skipNextHeaderFlag=TRUE;
-                               break;
-#endif
-                       default:
-                               error_msg("Unknown file type '%c' in tar file", header.type);
-                               close( tarFd);
-                               return( FALSE);
-               }
-       }
-       close(tarFd);
-       if (status > 0) {
-               /* Bummer - we read a partial header */
-               perror_msg("Error reading tar file");
-               return ( FALSE);
-       }
-       else if (errorFlag==TRUE) {
-               error_msg( "Error exit delayed from previous errors");
-               return( FALSE);
-       } else 
-               return( status);
-
-       /* Stuff to do when we are done */
-endgame:
-       close( tarFd);
-       if ( *(header.name) == '\0' ) {
-               if (errorFlag==TRUE)
-                       error_msg( "Error exit delayed from previous errors");
-               else
-                       return( TRUE);
-       } 
-       return( FALSE);
-}
-
-
-#ifdef BB_FEATURE_TAR_CREATE
-
-/*
-** writeTarFile(),  writeFileToTarball(), and writeTarHeader() are
-** the only functions that deal with the HardLinkInfo structure.
-** Even these functions use the xxxHardLinkInfo() functions.
-*/
-typedef struct HardLinkInfo HardLinkInfo;
-struct HardLinkInfo
-{
-       HardLinkInfo *next;           /* Next entry in list */
-       dev_t dev;                    /* Device number */
-       ino_t ino;                    /* Inode number */
-       short linkCount;              /* (Hard) Link Count */
-       char name[1];                 /* Start of filename (must be last) */
-};
-
-/* Some info to be carried along when creating a new tarball */
-struct TarBallInfo
-{
-       char* fileName;               /* File name of the tarball */
-       int tarFd;                    /* Open-for-write file descriptor
-                                                                        for the tarball */
-       struct stat statBuf;          /* Stat info for the tarball, letting
-                                                                        us know the inode and device that the
-                                                                        tarball lives, so we can avoid trying 
-                                                                        to include the tarball into itself */
-       int verboseFlag;              /* Whether to print extra stuff or not */
-       char** excludeList;           /* List of files to not include */
-       HardLinkInfo *hlInfoHead;     /* Hard Link Tracking Information */
-       HardLinkInfo *hlInfo;         /* Hard Link Info for the current file */
-};
-typedef struct TarBallInfo TarBallInfo;
-
-
-/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static void
-addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
-               short linkCount, const char *name)
-{
-       /* Note: hlInfoHeadPtr can never be NULL! */
-       HardLinkInfo *hlInfo;
-
-       hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
-       if (hlInfo) {
-               hlInfo->next = *hlInfoHeadPtr;
-               *hlInfoHeadPtr = hlInfo;
-               hlInfo->dev = dev;
-               hlInfo->ino = ino;
-               hlInfo->linkCount = linkCount;
-               strcpy(hlInfo->name, name);
-       }
-       return;
-}
-
-static void
-freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
-{
-       HardLinkInfo *hlInfo = NULL;
-       HardLinkInfo *hlInfoNext = NULL;
-
-       if (hlInfoHeadPtr) {
-               hlInfo = *hlInfoHeadPtr;
-               while (hlInfo) {
-                       hlInfoNext = hlInfo->next;
-                       free(hlInfo);
-                       hlInfo = hlInfoNext;
-               }
-               *hlInfoHeadPtr = NULL;
-       }
-       return;
-}
-
-/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
-static HardLinkInfo *
-findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
-{
-       while(hlInfo) {
-               if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
-                       break;
-               hlInfo = hlInfo->next;
-       }
-       return(hlInfo);
-}
-
-/* Put an octal string into the specified buffer.
- * The number is zero and space padded and possibly null padded.
- * Returns TRUE if successful.  */ 
-static int putOctal (char *cp, int len, long value)
-{
-       int tempLength;
-       char tempBuffer[32];
-       char *tempString = tempBuffer;
-
-       /* Create a string of the specified length with an initial space,
-        * leading zeroes and the octal number, and a trailing null.  */
-       sprintf (tempString, "%0*lo", len - 1, value);
-
-       /* If the string is too large, suppress the leading space.  */
-       tempLength = strlen (tempString) + 1;
-       if (tempLength > len) {
-               tempLength--;
-               tempString++;
-       }
-
-       /* If the string is still too large, suppress the trailing null.  */
-       if (tempLength > len)
-               tempLength--;
-
-       /* If the string is still too large, fail.  */
-       if (tempLength > len)
-               return FALSE;
-
-       /* Copy the string to the field.  */
-       memcpy (cp, tempString, len);
-
-       return TRUE;
-}
-
-/* Write out a tar header for the specified file/directory/whatever */
-static int
-writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name,
-               const char *real_name, struct stat *statbuf)
-{
-       long chksum=0;
-       struct TarHeader header;
-       const unsigned char *cp = (const unsigned char *) &header;
-       ssize_t size = sizeof(struct TarHeader);
-               
-       memset( &header, 0, size);
-
-       strncpy(header.name, header_name, sizeof(header.name)); 
-
-       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
-       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
-       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
-       putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
-       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
-       strncpy(header.magic, TAR_MAGIC TAR_VERSION, 
-                       TAR_MAGIC_LEN + TAR_VERSION_LEN );
-
-       /* Enter the user and group names (default to root if it fails) */
-       my_getpwuid(header.uname, statbuf->st_uid);
-       if (! *header.uname)
-               strcpy(header.uname, "root");
-       my_getgrgid(header.gname, statbuf->st_gid);
-       if (! *header.uname)
-               strcpy(header.uname, "root");
-
-       if (tbInfo->hlInfo) {
-               /* This is a hard link */
-               header.typeflag = LNKTYPE;
-               strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               char *lpath = xreadlink(real_name);
-               if (!lpath) /* Already printed err msg inside xreadlink() */
-                       return ( FALSE);
-               header.typeflag  = SYMTYPE;
-               strncpy(header.linkname, lpath, sizeof(header.linkname)); 
-               free(lpath);
-       } else if (S_ISDIR(statbuf->st_mode)) {
-               header.typeflag  = DIRTYPE;
-               strncat(header.name, "/", sizeof(header.name)); 
-       } else if (S_ISCHR(statbuf->st_mode)) {
-               header.typeflag  = CHRTYPE;
-               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
-       } else if (S_ISBLK(statbuf->st_mode)) {
-               header.typeflag  = BLKTYPE;
-               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
-       } else if (S_ISFIFO(statbuf->st_mode)) {
-               header.typeflag  = FIFOTYPE;
-       } else if (S_ISREG(statbuf->st_mode)) {
-               header.typeflag  = REGTYPE;
-               putOctal(header.size, sizeof(header.size), statbuf->st_size);
-       } else {
-               error_msg("%s: Unknown file type", real_name);
-               return ( FALSE);
-       }
-
-       /* Calculate and store the checksum (i.e., the sum of all of the bytes of
-        * the header).  The checksum field must be filled with blanks for the
-        * calculation.  The checksum field is formatted differently from the
-        * other fields: it has [6] digits, a null, then a space -- rather than
-        * digits, followed by a null like the other fields... */
-       memset(header.chksum, ' ', sizeof(header.chksum));
-       cp = (const unsigned char *) &header;
-       while (size-- > 0)
-               chksum += *cp++;
-       putOctal(header.chksum, 7, chksum);
-       
-       /* Now write the header out to disk */
-       if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
-               error_msg(io_error, real_name, strerror(errno)); 
-               return ( FALSE);
-       }
-       /* Pad the header up to the tar block size */
-       for (; size<TAR_BLOCK_SIZE; size++) {
-               write(tbInfo->tarFd, "\0", 1);
-       }
-       /* Now do the verbose thing (or not) */
-       if (tbInfo->verboseFlag==TRUE) {
-               FILE *vbFd = stdout;
-               if (tbInfo->tarFd == fileno(stdout))    // If the archive goes to stdout, verbose to stderr
-                       vbFd = stderr;
-               fprintf(vbFd, "%s\n", header.name);
-       }
-
-       return ( TRUE);
-}
-
-
-static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
-{
-       struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
-       const char *header_name;
-
-       /*
-       ** Check to see if we are dealing with a hard link.
-       ** If so -
-       ** Treat the first occurance of a given dev/inode as a file while
-       ** treating any additional occurances as hard links.  This is done
-       ** by adding the file information to the HardLinkInfo linked list.
-       */
-       tbInfo->hlInfo = NULL;
-       if (statbuf->st_nlink > 1) {
-               tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, 
-                               statbuf->st_ino);
-               if (tbInfo->hlInfo == NULL)
-                       addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
-                                       statbuf->st_ino, statbuf->st_nlink, fileName);
-       }
-
-       /* It is against the rules to archive a socket */
-       if (S_ISSOCK(statbuf->st_mode)) {
-               error_msg("%s: socket ignored", fileName);
-               return( TRUE);
-       }
-
-       /* It is a bad idea to store the archive we are in the process of creating,
-        * so check the device and inode to be sure that this particular file isn't
-        * the new tarball */
-       if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
-                       tbInfo->statBuf.st_ino == statbuf->st_ino) {
-               error_msg("%s: file is the archive; skipping", fileName);
-               return( TRUE);
-       }
-
-       header_name = fileName;
-       while (header_name[0] == '/') {
-               static int alreadyWarned=FALSE;
-               if (alreadyWarned==FALSE) {
-                       error_msg("Removing leading '/' from member names");
-                       alreadyWarned=TRUE;
-               }
-               header_name++;
-       }
-
-       if (strlen(fileName) >= NAME_SIZE) {
-               error_msg(name_longer_than_foo, NAME_SIZE);
-               return ( TRUE);
-       }
-
-       if (header_name[0] == '\0')
-               return TRUE;
-
-#if defined BB_FEATURE_TAR_EXCLUDE
-       if (exclude_file(tbInfo->excludeList, header_name)) {
-               return SKIP;
-       }
-#endif
-
-       if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) {
-               return( FALSE);
-       } 
-
-       /* Now, if the file is a regular file, copy it out to the tarball */
-       if ((tbInfo->hlInfo == NULL)
-       &&  (S_ISREG(statbuf->st_mode))) {
-               int  inputFileFd;
-               char buffer[BUFSIZ];
-               ssize_t size=0, readSize=0;
-
-               /* open the file we want to archive, and make sure all is well */
-               if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
-                       error_msg("%s: Cannot open: %s", fileName, strerror(errno));
-                       return( FALSE);
-               }
-               
-               /* write the file to the archive */
-               while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
-                       if (full_write(tbInfo->tarFd, buffer, size) != size ) {
-                               /* Output file seems to have a problem */
-                               error_msg(io_error, fileName, strerror(errno)); 
-                               return( FALSE);
-                       }
-                       readSize+=size;
-               }
-               if (size == -1) {
-                       error_msg(io_error, fileName, strerror(errno)); 
-                       return( FALSE);
-               }
-               /* Pad the file up to the tar block size */
-               for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
-                       write(tbInfo->tarFd, "\0", 1);
-               }
-               close( inputFileFd);
-       }
-
-       return( TRUE);
-}
-
-static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
-               char** excludeList)
-{
-       int tarFd=-1;
-       int errorFlag=FALSE;
-       ssize_t size;
-       struct TarBallInfo tbInfo;
-       tbInfo.verboseFlag = verboseFlag;
-       tbInfo.hlInfoHead = NULL;
-
-       /* Make sure there is at least one file to tar up.  */
-       if (*argv == NULL)
-               error_msg_and_die("Cowardly refusing to create an empty archive");
-
-       /* Open the tar file for writing.  */
-       if (!strcmp(tarName, "-"))
-               tbInfo.tarFd = fileno(stdout);
-       else
-               tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-       if (tbInfo.tarFd < 0) {
-               perror_msg( "Error opening '%s'", tarName);
-               freeHardLinkInfo(&tbInfo.hlInfoHead);
-               return ( FALSE);
-       }
-       tbInfo.excludeList=excludeList;
-       /* Store the stat info for the tarball's file, so
-        * can avoid including the tarball into itself....  */
-       if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
-               error_msg_and_die(io_error, tarName, strerror(errno)); 
-
-       /* Read the directory/files and iterate over them one at a time */
-       while (*argv != NULL) {
-               if (recursive_action(*argv++, TRUE, FALSE, FALSE,
-                                       writeFileToTarball, writeFileToTarball, 
-                                       (void*) &tbInfo) == FALSE) {
-                       errorFlag = TRUE;
-               }
-       }
-       /* Write two empty blocks to the end of the archive */
-       for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
-               write(tbInfo.tarFd, "\0", 1);
-       }
-
-       /* To be pedantically correct, we would check if the tarball
-        * is smaller than 20 tar blocks, and pad it if it was smaller,
-        * but that isn't necessary for GNU tar interoperability, and
-        * so is considered a waste of space */
-
-       /* Hang up the tools, close up shop, head home */
-       close(tarFd);
-       if (errorFlag == TRUE) {
-               error_msg("Error exit delayed from previous errors");
-               freeHardLinkInfo(&tbInfo.hlInfoHead);
-               return(FALSE);
-       }
-       freeHardLinkInfo(&tbInfo.hlInfoHead);
-       return( TRUE);
-}
-
-
-#endif
-
diff --git a/busybox/tee.c b/busybox/tee.c
deleted file mode 100644 (file)
index 439cf7d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tee implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "busybox.h"
-#include <getopt.h>
-#include <stdio.h>
-
-int
-tee_main(int argc, char **argv)
-{
-       char *mode = "w";
-       int c, i, status = 0, nfiles = 0;
-       FILE **files;
-
-       while ((c = getopt(argc, argv, "a")) != EOF) {
-               switch (c) {
-               case 'a': 
-                       mode = "a";
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1));
-       files[nfiles++] = stdout;
-       while (optind < argc) {
-               if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) {
-                       nfiles--;
-                       perror_msg("%s", argv[optind-1]);
-                       status = 1;
-               }
-       }
-
-       while ((c = getchar()) != EOF)
-               for (i = 0; i < nfiles; i++)
-                       putc(c, files[i]);
-
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/telnet.c b/busybox/telnet.c
deleted file mode 100644 (file)
index ce82a0e..0000000
+++ /dev/null
@@ -1,711 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * telnet implementation for busybox
- *
- * Author: Tomi Ollila <too@iki.fi>
- * Copyright (C) 1994-2000 by Tomi Ollila
- *
- * Created: Thu Apr  7 13:29:41 1994 too
- * Last modified: Fri Jun  9 14:34:24 2000 too
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * HISTORY
- * Revision 3.1  1994/04/17  11:31:54  too
- * initial revision
- * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen
- * <andersen@lineo.com> 
- * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
- * <jam@ltsp.org>
- *
- */
-
-#include <termios.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <signal.h>
-#include <arpa/telnet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include "busybox.h"
-
-#if 0
-static const int DOTRACE = 1;
-#endif
-
-#ifdef DOTRACE
-#include <arpa/inet.h> /* for inet_ntoa()... */
-#define TRACE(x, y) do { if (x) printf y; } while (0)
-#else
-#define TRACE(x, y) 
-#endif
-
-#if 0
-#define USE_POLL
-#include <sys/poll.h>
-#else
-#include <sys/time.h>
-#endif
-
-#define DATABUFSIZE  128
-#define IACBUFSIZE   128
-
-static const int CHM_TRY = 0;
-static const int CHM_ON = 1;
-static const int CHM_OFF = 2;
-
-static const int UF_ECHO = 0x01;
-static const int UF_SGA = 0x02;
-
-enum {
-       TS_0 = 1,
-       TS_IAC = 2,
-       TS_OPT = 3,
-       TS_SUB1 = 4,
-       TS_SUB2 = 5,
-};
-
-#define WriteCS(fd, str) write(fd, str, sizeof str -1)
-
-typedef unsigned char byte;
-
-/* use globals to reduce size ??? */ /* test this hypothesis later */
-static struct Globalvars {
-       int             netfd; /* console fd:s are 0 and 1 (and 2) */
-    /* same buffer used both for network and console read/write */
-       char    buf[DATABUFSIZE]; /* allocating so static size is smaller */
-       byte    telstate; /* telnet negotiation state from network input */
-       byte    telwish;  /* DO, DONT, WILL, WONT */
-       byte    charmode;
-       byte    telflags;
-       byte    gotsig;
-       /* buffer to handle telnet negotiations */
-       char    iacbuf[IACBUFSIZE];
-       short   iaclen; /* could even use byte */
-       struct termios termios_def;     
-       struct termios termios_raw;     
-} G;
-
-#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
-
-#ifdef USE_GLOBALVAR_PTR
-struct Globalvars * Gptr;
-#define G (*Gptr)
-#else
-static struct Globalvars G;
-#endif
-
-static inline void iacflush()
-{
-       write(G.netfd, G.iacbuf, G.iaclen);
-       G.iaclen = 0;
-}
-
-/* Function prototypes */
-static int getport(char * p);
-static struct in_addr getserver(char * p);
-static int create_socket();
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port);
-static int remote_connect(struct in_addr addr, int port);
-static void rawmode();
-static void cookmode();
-static void do_linemode();
-static void will_charmode();
-static void telopt(byte c);
-static int subneg(byte c);
-#if 0
-static int local_bind(int port);
-#endif
-
-/* Some globals */
-static int one = 1;
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static char *ttype;
-#endif
-
-static void doexit(int ev)
-{
-       cookmode();
-       exit(ev);
-}      
-
-static void conescape()
-{
-       char b;
-
-       if (G.gotsig)   /* came from line  mode... go raw */
-               rawmode();
-
-       WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
-                       " l     go to line mode\r\n"
-                       " c     go to character mode\r\n"
-                       " z     suspend telnet\r\n"
-                       " e     exit telnet\r\n");
-
-       if (read(0, &b, 1) <= 0)
-               doexit(1);
-
-       switch (b)
-       {
-       case 'l':
-               if (!G.gotsig)
-               {
-                       do_linemode();
-                       goto rrturn;
-               }
-               break;
-       case 'c':
-               if (G.gotsig)
-               {
-                       will_charmode();
-                       goto rrturn;
-               }
-               break;
-       case 'z':
-               cookmode();
-               kill(0, SIGTSTP);
-               rawmode();
-               break;
-       case 'e':
-               doexit(0);
-       }
-
-       WriteCS(1, "continuing...\r\n");
-
-       if (G.gotsig)
-               cookmode();
-       
- rrturn:
-       G.gotsig = 0;
-       
-}
-static void handlenetoutput(int len)
-{
-       /*      here we could do smart tricks how to handle 0xFF:s in output
-        *      stream  like writing twice every sequence of FF:s (thus doing
-        *      many write()s. But I think interactive telnet application does
-        *      not need to be 100% 8-bit clean, so changing every 0xff:s to
-        *      0x7f:s */
-
-       int i;
-       byte * p = G.buf;
-
-       for (i = len; i > 0; i--, p++)
-       {
-               if (*p == 0x1d)
-               {
-                       conescape();
-                       return;
-               }
-               if (*p == 0xff)
-                       *p = 0x7f;
-       }
-       write(G.netfd, G.buf, len);
-}
-
-
-static void handlenetinput(int len)
-{
-       int i;
-       int cstart = 0;
-
-       for (i = 0; i < len; i++)
-       {
-               byte c = G.buf[i];
-
-               if (G.telstate == 0) /* most of the time state == 0 */
-               {
-                       if (c == IAC)
-                       {
-                               cstart = i;
-                               G.telstate = TS_IAC;
-                       }
-               }
-               else
-                       switch (G.telstate)
-                        {
-                        case TS_0:
-                                if (c == IAC)
-                                        G.telstate = TS_IAC;
-                                else
-                                        G.buf[cstart++] = c;
-                                break;
-
-                        case TS_IAC:
-                                if (c == IAC) /* IAC IAC -> 0xFF */
-                                {
-                                        G.buf[cstart++] = c;
-                                        G.telstate = TS_0;
-                                        break;
-                                }
-                                /* else */
-                                switch (c)
-                                {
-                                case SB:
-                                        G.telstate = TS_SUB1;
-                                        break;
-                                case DO:
-                                case DONT:
-                                case WILL:
-                                case WONT:
-                                        G.telwish =  c;
-                                        G.telstate = TS_OPT;
-                                        break;
-                                default:
-                                        G.telstate = TS_0;     /* DATA MARK must be added later */
-                                }
-                                break;
-                        case TS_OPT: /* WILL, WONT, DO, DONT */
-                                telopt(c);
-                                G.telstate = TS_0;
-                                break;
-                        case TS_SUB1: /* Subnegotiation */
-                        case TS_SUB2: /* Subnegotiation */
-                                if (subneg(c) == TRUE)
-                                        G.telstate = TS_0;
-                                break;
-                        }
-       }
-       if (G.telstate)
-       {
-               if (G.iaclen)                   iacflush();
-               if (G.telstate == TS_0) G.telstate = 0;
-
-               len = cstart;
-       }
-
-       if (len)
-               write(1, G.buf, len);
-}
-
-
-/* ******************************* */
-
-static inline void putiac(int c)
-{
-       G.iacbuf[G.iaclen++] = c;
-}
-
-
-static void putiac2(byte wwdd, byte c)
-{
-       if (G.iaclen + 3 > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(wwdd);
-       putiac(c);
-}
-
-#if 0
-static void putiac1(byte c)
-{
-       if (G.iaclen + 2 > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(c);
-}
-#endif
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static void putiac_subopt(byte c, char *str)
-{
-       int     len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
-
-       if (G.iaclen + len > IACBUFSIZE)
-               iacflush();
-
-       putiac(IAC);
-       putiac(SB);
-       putiac(c);
-       putiac(0);
-
-       while(*str)
-               putiac(*str++);
-
-       putiac(IAC);
-       putiac(SE);
-}
-#endif
-
-/* void putiacstring (subneg strings) */
-
-/* ******************************* */
-
-static char const escapecharis[] = "\r\nEscape character is ";
-
-static void setConMode()
-{
-       if (G.telflags & UF_ECHO)
-       {
-               if (G.charmode == CHM_TRY) {
-                       G.charmode = CHM_ON;
-                       printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
-                       rawmode();
-               }
-       }
-       else
-       {
-               if (G.charmode != CHM_OFF) {
-                       G.charmode = CHM_OFF;
-                       printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
-                       cookmode();
-               }
-       }
-}
-
-/* ******************************* */
-
-static void will_charmode()
-{
-       G.charmode = CHM_TRY;
-       G.telflags |= (UF_ECHO | UF_SGA);
-       setConMode();
-  
-       putiac2(DO, TELOPT_ECHO);
-       putiac2(DO, TELOPT_SGA);
-       iacflush();
-}
-
-static void do_linemode()
-{
-       G.charmode = CHM_TRY;
-       G.telflags &= ~(UF_ECHO | UF_SGA);
-       setConMode();
-
-       putiac2(DONT, TELOPT_ECHO);
-       putiac2(DONT, TELOPT_SGA);
-       iacflush();
-}
-
-/* ******************************* */
-
-static inline void to_notsup(char c)
-{
-       if      (G.telwish == WILL)     putiac2(DONT, c);
-       else if (G.telwish == DO)       putiac2(WONT, c);
-}
-
-static inline void to_echo()
-{
-       /* if server requests ECHO, don't agree */
-       if      (G.telwish == DO) {     putiac2(WONT, TELOPT_ECHO);     return; }
-       else if (G.telwish == DONT)     return;
-  
-       if (G.telflags & UF_ECHO)
-       {
-               if (G.telwish == WILL)
-                       return;
-       }
-       else
-               if (G.telwish == WONT)
-                       return;
-
-       if (G.charmode != CHM_OFF)
-               G.telflags ^= UF_ECHO;
-
-       if (G.telflags & UF_ECHO)
-               putiac2(DO, TELOPT_ECHO);
-       else
-               putiac2(DONT, TELOPT_ECHO);
-
-       setConMode();
-       WriteCS(1, "\r\n");  /* sudden modec */
-}
-
-static inline void to_sga()
-{
-       /* daemon always sends will/wont, client do/dont */
-
-       if (G.telflags & UF_SGA)
-       {
-               if (G.telwish == WILL)
-                       return;
-       }
-       else
-               if (G.telwish == WONT)
-                       return;
-  
-       if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
-               putiac2(DO, TELOPT_SGA);
-       else
-               putiac2(DONT, TELOPT_SGA);
-
-       return;
-}
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-static inline void to_ttype()
-{
-       /* Tell server we will (or won't) do TTYPE */
-
-       if(ttype)
-               putiac2(WILL, TELOPT_TTYPE);
-       else
-               putiac2(WONT, TELOPT_TTYPE);
-
-       return;
-}
-#endif
-
-static void telopt(byte c)
-{
-       switch (c)
-       {
-       case TELOPT_ECHO:               to_echo(c);             break;
-       case TELOPT_SGA:                to_sga(c);              break;
-#ifdef BB_FEATURE_TELNET_TTYPE
-       case TELOPT_TTYPE:              to_ttype(c);    break;
-#endif
-       default:                                to_notsup(c);   break;
-       }
-}
-
-
-/* ******************************* */
-
-/* subnegotiation -- ignore all (except TTYPE) */
-
-static int subneg(byte c)
-{
-       switch (G.telstate)
-       {
-       case TS_SUB1:
-               if (c == IAC)
-                       G.telstate = TS_SUB2;
-#ifdef BB_FEATURE_TELNET_TTYPE
-               else
-               if (c == TELOPT_TTYPE)
-                       putiac_subopt(TELOPT_TTYPE,ttype);
-#endif
-               break;
-       case TS_SUB2:
-               if (c == SE)
-                       return TRUE;
-               G.telstate = TS_SUB1;
-               /* break; */
-       }
-       return FALSE;
-}
-
-/* ******************************* */
-
-static void fgotsig(int sig)
-{
-       G.gotsig = sig;
-}
-
-
-static void rawmode()
-{
-       tcsetattr(0, TCSADRAIN, &G.termios_raw);
-}      
-
-static void cookmode()
-{
-       tcsetattr(0, TCSADRAIN, &G.termios_def);
-}
-
-extern int telnet_main(int argc, char** argv)
-{
-       struct in_addr host;
-       int port;
-       int len;
-#ifdef USE_POLL
-       struct pollfd ufds[2];
-#else  
-       fd_set readfds;
-       int maxfd;
-#endif 
-
-#ifdef BB_FEATURE_TELNET_TTYPE
-    ttype = getenv("TERM");
-#endif
-
-       memset(&G, 0, sizeof G);
-
-       if (tcgetattr(0, &G.termios_def) < 0)
-               exit(1);
-       
-       G.termios_raw = G.termios_def;
-       cfmakeraw(&G.termios_raw);
-       
-       if (argc < 2)   show_usage();
-       port = (argc > 2)? getport(argv[2]): 23;
-       
-       host = getserver(argv[1]);
-
-       G.netfd = remote_connect(host, port);
-
-       signal(SIGINT, fgotsig);
-
-#ifdef USE_POLL
-       ufds[0].fd = 0; ufds[1].fd = G.netfd;
-       ufds[0].events = ufds[1].events = POLLIN;
-#else  
-       FD_ZERO(&readfds);
-       FD_SET(0, &readfds);
-       FD_SET(G.netfd, &readfds);
-       maxfd = G.netfd + 1;
-#endif
-       
-       while (1)
-       {
-#ifndef USE_POLL
-               fd_set rfds = readfds;
-               
-               switch (select(maxfd, &rfds, NULL, NULL, NULL))
-#else
-               switch (poll(ufds, 2, -1))
-#endif                 
-               {
-               case 0:
-                       /* timeout */
-               case -1:
-                       /* error, ignore and/or log something, bay go to loop */
-                       if (G.gotsig)
-                               conescape();
-                       else
-                               sleep(1);
-                       break;
-               default:
-
-#ifdef USE_POLL
-                       if (ufds[0].revents) /* well, should check POLLIN, but ... */
-#else                          
-                       if (FD_ISSET(0, &rfds))
-#endif                         
-                       {
-                               len = read(0, G.buf, DATABUFSIZE);
-
-                               if (len <= 0)
-                                       doexit(0);
-
-                               TRACE(0, ("Read con: %d\n", len));
-                               
-                               handlenetoutput(len);
-                       }
-
-#ifdef USE_POLL
-                       if (ufds[1].revents) /* well, should check POLLIN, but ... */
-#else                          
-                       if (FD_ISSET(G.netfd, &rfds))
-#endif                         
-                       {
-                               len = read(G.netfd, G.buf, DATABUFSIZE);
-
-                               if (len <= 0)
-                               {
-                                       WriteCS(1, "Connection closed by foreign host.\r\n");
-                                       doexit(1);
-                               }
-                               TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
-
-                               handlenetinput(len);
-                       }
-               }
-       }
-}
-
-static int getport(char * p)
-{
-       unsigned int port = atoi(p);
-
-       if ((unsigned)(port - 1 ) > 65534)
-       {
-               error_msg_and_die("%s: bad port number", p);
-       }
-       return port;
-}
-
-static struct in_addr getserver(char * host)
-{
-       struct in_addr addr;
-
-       struct hostent * he;
-       he = xgethostbyname(host);
-       memcpy(&addr, he->h_addr, sizeof addr);
-
-       TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
-
-       return addr;
-}
-
-static int create_socket()
-{
-       return socket(AF_INET, SOCK_STREAM, 0);
-}
-
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
-{
-       memset(addr, 0, sizeof(struct sockaddr_in));
-       addr->sin_family = AF_INET;
-       addr->sin_port = htons(port);
-}
-  
-#if 0
-static int local_bind(int port)
-{
-       struct sockaddr_in s_addr;
-       int s = create_socket();
-  
-       setup_sockaddr_in(&s_addr, port);
-  
-       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-  
-       if (bind(s, &s_addr, sizeof s_addr) < 0)
-       {
-               char * e = sys_errlist[errno];
-               syserrorexit("bind");
-               exit(1);
-       }
-       listen(s, 1);
-       
-       return s;
-}
-#endif
-
-static int remote_connect(struct in_addr addr, int port)
-{
-       struct sockaddr_in s_addr;
-       int s = create_socket();
-
-       setup_sockaddr_in(&s_addr, port);
-       s_addr.sin_addr = addr;
-
-       setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
-
-       if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
-       {
-               perror_msg_and_die("Unable to connect to remote host");
-       }
-       return s;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/busybox/test.c b/busybox/test.c
deleted file mode 100644 (file)
index 9c66cbb..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * test implementation for busybox
- *
- * Copyright (c) by a whole pile of folks: 
- *
- *     test(1); version 7-like  --  author Erik Baalbergen
- *     modified by Eric Gisin to be used as built-in.
- *     modified by Arnold Robbins to add SVR3 compatibility
- *     (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
- *     modified by J.T. Conklin for NetBSD.
- *     modified by Herbert Xu to be used as built-in in ash.
- *     modified by Erik Andersen <andersee@debian.org> to be used 
- *     in busybox.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice states:
- *     "This program is in the Public Domain."
- */
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-/* test(1) accepts the following grammar:
-       oexpr   ::= aexpr | aexpr "-o" oexpr ;
-       aexpr   ::= nexpr | nexpr "-a" aexpr ;
-       nexpr   ::= primary | "!" primary
-       primary ::= unary-operator operand
-               | operand binary-operator operand
-               | operand
-               | "(" oexpr ")"
-               ;
-       unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
-               "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
-
-       binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
-                       "-nt"|"-ot"|"-ef";
-       operand ::= <any legal UNIX file name>
-*/
-
-enum token {
-       EOI,
-       FILRD,
-       FILWR,
-       FILEX,
-       FILEXIST,
-       FILREG,
-       FILDIR,
-       FILCDEV,
-       FILBDEV,
-       FILFIFO,
-       FILSOCK,
-       FILSYM,
-       FILGZ,
-       FILTT,
-       FILSUID,
-       FILSGID,
-       FILSTCK,
-       FILNT,
-       FILOT,
-       FILEQ,
-       FILUID,
-       FILGID,
-       STREZ,
-       STRNZ,
-       STREQ,
-       STRNE,
-       STRLT,
-       STRGT,
-       INTEQ,
-       INTNE,
-       INTGE,
-       INTGT,
-       INTLE,
-       INTLT,
-       UNOT,
-       BAND,
-       BOR,
-       LPAREN,
-       RPAREN,
-       OPERAND
-};
-
-enum token_types {
-       UNOP,
-       BINOP,
-       BUNOP,
-       BBINOP,
-       PAREN
-};
-
-static const struct t_op {
-       const char *op_text;
-       short op_num, op_type;
-} ops [] = {
-       {"-r",  FILRD,  UNOP},
-       {"-w",  FILWR,  UNOP},
-       {"-x",  FILEX,  UNOP},
-       {"-e",  FILEXIST,UNOP},
-       {"-f",  FILREG, UNOP},
-       {"-d",  FILDIR, UNOP},
-       {"-c",  FILCDEV,UNOP},
-       {"-b",  FILBDEV,UNOP},
-       {"-p",  FILFIFO,UNOP},
-       {"-u",  FILSUID,UNOP},
-       {"-g",  FILSGID,UNOP},
-       {"-k",  FILSTCK,UNOP},
-       {"-s",  FILGZ,  UNOP},
-       {"-t",  FILTT,  UNOP},
-       {"-z",  STREZ,  UNOP},
-       {"-n",  STRNZ,  UNOP},
-       {"-h",  FILSYM, UNOP},          /* for backwards compat */
-       {"-O",  FILUID, UNOP},
-       {"-G",  FILGID, UNOP},
-       {"-L",  FILSYM, UNOP},
-       {"-S",  FILSOCK,UNOP},
-       {"=",   STREQ,  BINOP},
-       {"!=",  STRNE,  BINOP},
-       {"<",   STRLT,  BINOP},
-       {">",   STRGT,  BINOP},
-       {"-eq", INTEQ,  BINOP},
-       {"-ne", INTNE,  BINOP},
-       {"-ge", INTGE,  BINOP},
-       {"-gt", INTGT,  BINOP},
-       {"-le", INTLE,  BINOP},
-       {"-lt", INTLT,  BINOP},
-       {"-nt", FILNT,  BINOP},
-       {"-ot", FILOT,  BINOP},
-       {"-ef", FILEQ,  BINOP},
-       {"!",   UNOT,   BUNOP},
-       {"-a",  BAND,   BBINOP},
-       {"-o",  BOR,    BBINOP},
-       {"(",   LPAREN, PAREN},
-       {")",   RPAREN, PAREN},
-       {0,     0,      0}
-};
-
-static char **t_wp;
-static struct t_op const *t_wp_op;
-static gid_t *group_array = NULL;
-static int ngroups;
-
-static enum token t_lex();
-static int oexpr();
-static int aexpr();
-static int nexpr();
-static int binop();
-static int primary();
-static int filstat();
-static int getn();
-static int newerf();
-static int olderf();
-static int equalf();
-static void syntax();
-static int test_eaccess();
-static int is_a_group_member();
-static void initialize_group_array();
-
-extern int
-test_main(int argc, char** argv)
-{
-       int     res;
-
-       if (strcmp(applet_name, "[") == 0) {
-               if (strcmp(argv[--argc], "]"))
-                       error_msg_and_die("missing ]");
-               argv[argc] = NULL;
-       }
-       /* Implement special cases from POSIX.2, section 4.62.4 */
-       switch (argc) {
-       case 1:
-               exit( 1);
-       case 2:
-               exit (*argv[1] == '\0');
-       case 3:
-               if (argv[1][0] == '!' && argv[1][1] == '\0') {
-                       exit (!(*argv[2] == '\0'));
-               }
-               break;
-       case 4:
-               if (argv[1][0] != '!' || argv[1][1] != '\0') {
-                       if (t_lex(argv[2]), 
-                           t_wp_op && t_wp_op->op_type == BINOP) {
-                               t_wp = &argv[1];
-                               exit (binop() == 0);
-                       }
-               }
-               break;
-       case 5:
-               if (argv[1][0] == '!' && argv[1][1] == '\0') {
-                       if (t_lex(argv[3]), 
-                           t_wp_op && t_wp_op->op_type == BINOP) {
-                               t_wp = &argv[2];
-                               exit (!(binop() == 0));
-                       }
-               }
-               break;
-       }
-
-       t_wp = &argv[1];
-       res = !oexpr(t_lex(*t_wp));
-
-       if (*t_wp != NULL && *++t_wp != NULL)
-               syntax(*t_wp, "unknown operand");
-
-       return( res);
-}
-
-static void
-syntax(op, msg)
-       char    *op;
-       char    *msg;
-{
-       if (op && *op)
-               error_msg_and_die("%s: %s", op, msg);
-       else
-               error_msg_and_die("%s", msg);
-}
-
-static int
-oexpr(n)
-       enum token n;
-{
-       int res;
-
-       res = aexpr(n);
-       if (t_lex(*++t_wp) == BOR)
-               return oexpr(t_lex(*++t_wp)) || res;
-       t_wp--;
-       return res;
-}
-
-static int
-aexpr(n)
-       enum token n;
-{
-       int res;
-
-       res = nexpr(n);
-       if (t_lex(*++t_wp) == BAND)
-               return aexpr(t_lex(*++t_wp)) && res;
-       t_wp--;
-       return res;
-}
-
-static int
-nexpr(n)
-       enum token n;                   /* token */
-{
-       if (n == UNOT)
-               return !nexpr(t_lex(*++t_wp));
-       return primary(n);
-}
-
-static int
-primary(n)
-       enum token n;
-{
-       int res;
-
-       if (n == EOI)
-               syntax(NULL, "argument expected");
-       if (n == LPAREN) {
-               res = oexpr(t_lex(*++t_wp));
-               if (t_lex(*++t_wp) != RPAREN)
-                       syntax(NULL, "closing paren expected");
-               return res;
-       }
-       if (t_wp_op && t_wp_op->op_type == UNOP) {
-               /* unary expression */
-               if (*++t_wp == NULL)
-                       syntax(t_wp_op->op_text, "argument expected");
-               switch (n) {
-               case STREZ:
-                       return strlen(*t_wp) == 0;
-               case STRNZ:
-                       return strlen(*t_wp) != 0;
-               case FILTT:
-                       return isatty(getn(*t_wp));
-               default:
-                       return filstat(*t_wp, n);
-               }
-       }
-
-       if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
-               return binop();
-       }         
-
-       return strlen(*t_wp) > 0;
-}
-
-static int
-binop()
-{
-       const char *opnd1, *opnd2;
-       struct t_op const *op;
-
-       opnd1 = *t_wp;
-       (void) t_lex(*++t_wp);
-       op = t_wp_op;
-
-       if ((opnd2 = *++t_wp) == (char *)0)
-               syntax(op->op_text, "argument expected");
-               
-       switch (op->op_num) {
-       case STREQ:
-               return strcmp(opnd1, opnd2) == 0;
-       case STRNE:
-               return strcmp(opnd1, opnd2) != 0;
-       case STRLT:
-               return strcmp(opnd1, opnd2) < 0;
-       case STRGT:
-               return strcmp(opnd1, opnd2) > 0;
-       case INTEQ:
-               return getn(opnd1) == getn(opnd2);
-       case INTNE:
-               return getn(opnd1) != getn(opnd2);
-       case INTGE:
-               return getn(opnd1) >= getn(opnd2);
-       case INTGT:
-               return getn(opnd1) > getn(opnd2);
-       case INTLE:
-               return getn(opnd1) <= getn(opnd2);
-       case INTLT:
-               return getn(opnd1) < getn(opnd2);
-       case FILNT:
-               return newerf (opnd1, opnd2);
-       case FILOT:
-               return olderf (opnd1, opnd2);
-       case FILEQ:
-               return equalf (opnd1, opnd2);
-       }
-       /* NOTREACHED */
-       return 1;
-}
-
-static int
-filstat(nm, mode)
-       char *nm;
-       enum token mode;
-{
-       struct stat s;
-       unsigned int i;
-
-       if (mode == FILSYM) {
-#ifdef S_IFLNK
-               if (lstat(nm, &s) == 0) {
-                       i = S_IFLNK;
-                       goto filetype;
-               }
-#endif
-               return 0;
-       }
-
-       if (stat(nm, &s) != 0) 
-               return 0;
-
-       switch (mode) {
-       case FILRD:
-               return test_eaccess(nm, R_OK) == 0;
-       case FILWR:
-               return test_eaccess(nm, W_OK) == 0;
-       case FILEX:
-               return test_eaccess(nm, X_OK) == 0;
-       case FILEXIST:
-               return 1;
-       case FILREG:
-               i = S_IFREG;
-               goto filetype;
-       case FILDIR:
-               i = S_IFDIR;
-               goto filetype;
-       case FILCDEV:
-               i = S_IFCHR;
-               goto filetype;
-       case FILBDEV:
-               i = S_IFBLK;
-               goto filetype;
-       case FILFIFO:
-#ifdef S_IFIFO
-               i = S_IFIFO;
-               goto filetype;
-#else
-               return 0;
-#endif
-       case FILSOCK:
-#ifdef S_IFSOCK
-               i = S_IFSOCK;
-               goto filetype;
-#else
-               return 0;
-#endif
-       case FILSUID:
-               i = S_ISUID;
-               goto filebit;
-       case FILSGID:
-               i = S_ISGID;
-               goto filebit;
-       case FILSTCK:
-               i = S_ISVTX;
-               goto filebit;
-       case FILGZ:
-               return s.st_size > 0L;
-       case FILUID:
-               return s.st_uid == geteuid();
-       case FILGID:
-               return s.st_gid == getegid();
-       default:
-               return 1;
-       }
-
-filetype:
-       return ((s.st_mode & S_IFMT) == i);
-
-filebit:
-       return ((s.st_mode & i) != 0);
-}
-
-static enum token
-t_lex(s)
-       char *s;
-{
-       struct t_op const *op = ops;
-
-       if (s == 0) {
-               t_wp_op = (struct t_op *)0;
-               return EOI;
-       }
-       while (op->op_text) {
-               if (strcmp(s, op->op_text) == 0) {
-                       t_wp_op = op;
-                       return op->op_num;
-               }
-               op++;
-       }
-       t_wp_op = (struct t_op *)0;
-       return OPERAND;
-}
-
-/* atoi with error detection */
-static int
-getn(s)
-       char *s;
-{
-       char *p;
-       long r;
-
-       errno = 0;
-       r = strtol(s, &p, 10);
-
-       if (errno != 0)
-         error_msg_and_die("%s: out of range", s);
-
-       while (isspace(*p))
-         p++;
-       
-       if (*p)
-         error_msg_and_die("%s: bad number", s);
-
-       return (int) r;
-}
-
-static int
-newerf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_mtime > b2.st_mtime);
-}
-
-static int
-olderf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_mtime < b2.st_mtime);
-}
-
-static int
-equalf (f1, f2)
-char *f1, *f2;
-{
-       struct stat b1, b2;
-
-       return (stat (f1, &b1) == 0 &&
-               stat (f2, &b2) == 0 &&
-               b1.st_dev == b2.st_dev &&
-               b1.st_ino == b2.st_ino);
-}
-
-/* Do the same thing access(2) does, but use the effective uid and gid,
-   and don't make the mistake of telling root that any file is
-   executable. */
-static int
-test_eaccess (path, mode)
-char *path;
-int mode;
-{
-       struct stat st;
-       unsigned int euid = geteuid();
-
-       if (stat (path, &st) < 0)
-               return (-1);
-
-       if (euid == 0) {
-               /* Root can read or write any file. */
-               if (mode != X_OK)
-               return (0);
-
-               /* Root can execute any file that has any one of the execute
-                  bits set. */
-               if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
-                       return (0);
-       }
-
-       if (st.st_uid == euid)          /* owner */
-               mode <<= 6;
-       else if (is_a_group_member (st.st_gid))
-               mode <<= 3;
-
-       if (st.st_mode & mode)
-               return (0);
-
-       return (-1);
-}
-
-static void
-initialize_group_array ()
-{
-       ngroups = getgroups(0, NULL);
-       group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
-       getgroups(ngroups, group_array);
-}
-
-/* Return non-zero if GID is one that we have in our groups list. */
-static int
-is_a_group_member (gid)
-gid_t gid;
-{
-       register int i;
-
-       /* Short-circuit if possible, maybe saving a call to getgroups(). */
-       if (gid == getgid() || gid == getegid())
-               return (1);
-
-       if (ngroups == 0)
-               initialize_group_array ();
-
-       /* Search through the list looking for GID. */
-       for (i = 0; i < ngroups; i++)
-               if (gid == group_array[i])
-                       return (1);
-
-       return (0);
-}
diff --git a/busybox/tests/.cvsignore b/busybox/tests/.cvsignore
deleted file mode 100644 (file)
index 3645cf9..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-cp
-cp_*.bb
-cp_*.gnu
-cp_tests
-date
-df
-du
-ln
-ln_*.bb
-ln_*.gnu
-ln_tests
-mv
-mv_*.bb
-mv_*.gnu
-mv_tests
-syslog_test
diff --git a/busybox/tests/Makefile b/busybox/tests/Makefile
deleted file mode 100644 (file)
index 8ad304d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# busybox/tests/Makefile - Run through all defined tests.
-# ------------------------
-# Copyright (C) 2000  Karl M. Hegbloom <karlheg@debian.org>  GPL
-
-all:: message_header
-
-message_header:
-       @echo
-       @echo BusyBox Test Suite.
-       @echo
-       (cd ..; tests/busybox.REGRESS.sh)
-
-clean::
-
-distclean: clean
-
-.PHONY: all clean distclean message_header
-
-include $(wildcard *_tests.mk)
-
-BBL := $(shell pushd .. >/dev/null &&          \
-                ${MAKE} busybox.links >/dev/null && \
-              popd >/dev/null &&               \
-              cat ../busybox.links |           \
-                sed -e 's,.*/\(.*\)$$,\1,')
-
-../busybox:
-       cd .. && ${MAKE} busybox
-
-${BBL}: ../busybox
-       rm -f $@
-       ln ../busybox $@
-
-syslog_test: syslog_test.c
diff --git a/busybox/tests/cp_tests.mk b/busybox/tests/cp_tests.mk
deleted file mode 100644 (file)
index b96c5ce..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-# cp_tests.mk - Set of test cases for busybox cp
-# -------------
-# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
-#
-
-# GNU `cp'
-GCP = /bin/cp
-# BusyBox `cp'
-BCP = $(shell pwd)/cp
-
-all:: cp_tests
-clean:: cp_clean
-
-cp_clean:
-       - rm -rf cp_tests cp_*.{gnu,bb} cp
-
-# check_cp_dir_to_dir_wo_a removed from this list; see below
-cp_tests: cp_clean cp check_exists check_simple_cp check_cp_symlnk \
-       check_cp_symlink_w_a check_cp_files_to_dir check_cp_files_to_dir_w_d \
-       check_cp_files_to_dir_w_p check_cp_files_to_dir_w_p_and_d \
-       check_cp_dir_to_dir_w_a \
-       check_cp_dir_to_dir_w_a_take_two
-
-check_exists:
-       @echo;
-       @echo "No output from diff means busybox cp is functioning properly.";
-       @echo "Some tests might show timestamp differences that are Ok.";
-
-       @echo;
-       @echo Verify that busybox cp exists;
-       @echo ------------------------------;
-       [ -x ${BCP} ] || exit 0
-
-       @echo;
-       mkdir cp_tests;
-
-check_simple_cp:
-       @echo Copy a file to a copy of the file;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../cp_afile_afilecopy.gnu; \
-        ${GCP} afile afilecopy;                \
-        ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu;
-
-       @echo;
-       rm -rf cp_tests/*;
-
-       @echo;
-       cd cp_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../cp_afile_afilecopy.bb; \
-        ${BCP} afile afilecopy;                \
-        ls -l afile afilecopy >> ../cp_afile_afilecopy.bb;
-
-       @echo;
-       @echo Might show timestamp differences.
-       -diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb;
-
-       @echo;
-       rm -rf cp_tests/*;
-
-check_cp_symlnk:
-       @echo; echo Copy a file pointed to by a symlink;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        mkdir here there;                      \
-        echo A file > afile;                   \
-        cd here;                               \
-         ln -s ../afile .;                     \
-
-       @echo;
-       cd cp_tests;                            \
-        ls -lR . > ../cp_symlink.gnu;          \
-        ${GCP} here/afile there;               \
-        ls -lR . >> ../cp_symlink.gnu;
-
-       @echo;
-       rm -rf cp_tests/there/*;
-
-       sleep 1;
-
-       @echo;
-       cd cp_tests;                            \
-        ls -lR . > ../cp_symlink.bb;           \
-        ${BCP} here/afile there;               \
-        ls -lR . >> ../cp_symlink.bb;
-
-       @echo;
-       @echo Will show timestamp difference.
-       -diff -u cp_symlink.gnu cp_symlink.bb;
-
-       @echo;
-       rm -rf cp_tests/*
-
-check_cp_symlink_w_a:
-       @echo; echo Copy a symlink, useing the -a switch.;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file > afile;                   \
-        mkdir here there;                      \
-        cd here;                               \
-         ln -s ../afile .
-
-       cd cp_tests;                            \
-        ls -lR . > ../cp_a_symlink.gnu;        \
-        ${GCP} -a here/afile there;            \
-        ls -lR . >> ../cp_a_symlink.gnu;
-
-       @echo;
-       rm -rf cp_tests/there/*;
-
-       sleep 1;
-
-       @echo;
-       cd cp_tests;                            \
-        echo A file > afile;                   \
-        ls -lR . > ../cp_a_symlink.bb;         \
-        ${BCP} -a here/afile there;            \
-        ls -lR . >> ../cp_a_symlink.bb;
-
-       @echo;
-       diff -u cp_a_symlink.gnu cp_a_symlink.bb;
-
-       @echo;
-       rm -rf cp_tests/*;
-
-
-check_cp_files_to_dir:
-       # Copy a set of files to a directory.
-       @echo; echo Copy a set of files to a directory.;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        ln -s afile1 symlink1;                 \
-        mkdir there;
-
-       cd cp_tests;                            \
-        ${GCP} afile1 afile2 symlink1 there/;  \
-        ls -lR > ../cp_files_dir.gnu;
-
-       @echo;
-       rm -rf cp_tests/there/*;
-
-       @echo;
-       cd cp_tests;                            \
-        ${BCP} afile1 afile2 symlink1 there/;  \
-        ls -lR > ../cp_files_dir.bb;
-
-       @echo;
-       diff -u cp_files_dir.gnu cp_files_dir.bb;
-
-       @echo;
-       rm -rf cp_tests/*;
-
-check_cp_files_to_dir_w_d:
-       # Copy a set of files to a directory with the -d switch.
-       @echo; echo Copy a set of files to a directory with the -d switch.;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${GCP} -d afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_d_files_dir.gnu;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-       @echo;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${BCP} -d afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_d_files_dir.bb;
-
-       @echo;
-       diff -u cp_d_files_dir.gnu cp_d_files_dir.bb;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-check_cp_files_to_dir_w_p:
-       # Copy a set of files to a directory with the -p switch.
-       @echo; echo Copy a set of files to a directory with the -p switch.;
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${GCP} -p afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_p_files_dir.gnu;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-       @echo;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${BCP} -p afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_p_files_dir.bb;
-
-       @echo;
-       diff -u cp_p_files_dir.gnu cp_p_files_dir.bb;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-
-check_cp_files_to_dir_w_p_and_d:
-       @echo; echo Copy a set of files to a directory with -p and -d switches.
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${GCP} -p -d afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_pd_files_dir.gnu;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-       @echo;
-       cd cp_tests;                            \
-        echo A file number one > afile1;       \
-        echo A file number two, blah. > afile2; \
-        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
-        ln -s afile1 symlink1;                 \
-        mkdir there1;                          \
-        ${BCP} -p -d afile1 afile2 symlink1 there1/; \
-        ls -lR > ../cp_pd_files_dir.bb;
-
-       @echo;
-       diff -u cp_pd_files_dir.gnu cp_pd_files_dir.bb;
-
-       @echo;
-       rm -rf cp_tests/{afile{1,2},symlink1,there1};
-
-# This test doesn't work any more; gnu cp now _does_ copy a directory
-# to a subdirectory of itself.  What's worse, that "feature" has no
-# (documented) way to be disabled with command line switches.
-# It's not obvious that busybox cp should mimic this behavior.
-# For now, this test is removed from the cp_tests list, above.
-check_cp_dir_to_dir_wo_a:
-       # Copy a directory to another directory, without the -a switch.
-       @echo; echo Copy a directory to another directory, without the -a switch.
-       @echo ------------------------------;
-       @echo There should be an error message about cannot cp a dir to a subdir of itself.
-       cd cp_tests;                            \
-        touch a b c;                           \
-        mkdir adir;                            \
-        ls -lR . > ../cp_a_star_adir.gnu;      \
-        ${GCP} -a * adir;                      \
-        ls -lR . >> ../cp_a_star_adir.gnu;
-
-       @echo
-       @echo There should be an error message about cannot cp a dir to a subdir of itself.
-       cd cp_tests;                            \
-        rm -rf adir;                           \
-        mkdir adir;                            \
-        ls -lR . > ../cp_a_star_adir.bb;       \
-        ${BCP} -a * adir;                      \
-        ls -lR . >> ../cp_a_star_adir.bb;
-
-       @echo;
-       diff -u cp_a_star_adir.gnu cp_a_star_adir.bb;
-
-       # Done
-       @echo;
-       rm -rf cp_tests;
-       @echo; echo Done.
-
-
-check_cp_dir_to_dir_w_a:
-       @echo; echo Copy a directory into another directory with the -a switch.
-       @echo ------------------------------;
-       cd cp_tests;                            \
-        mkdir dir{a,b};                        \
-        echo A file > dira/afile;              \
-        echo A file in dirb > dirb/afileindirb; \
-        ln -s dira/afile dira/alinktoafile;    \
-        mkdir dira/subdir1;                    \
-        echo Another file > dira/subdir1/anotherfile; \
-        ls -lR . > ../cp_a_dira_dirb.gnu;      \
-        ${GCP} -a dira dirb;                   \
-        ls -lR . >> ../cp_a_dira_dirb.gnu;
-
-       @echo;
-       rm -rf cp_tests/dir{a,b};
-
-       @echo;
-       cd cp_tests;                            \
-        mkdir dir{a,b};                        \
-        echo A file > dira/afile;              \
-        echo A file in dirb > dirb/afileindirb; \
-        ln -s dira/afile dira/alinktoafile;    \
-        mkdir dira/subdir1;                    \
-        echo Another file > dira/subdir1/anotherfile; \
-        ls -lR . > ../cp_a_dira_dirb.bb;       \
-        ${BCP} -a dira dirb;                   \
-        ls -lR . >> ../cp_a_dira_dirb.bb;
-
-       @echo;
-       diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb;
-
-       @echo;
-       rm -rf cp_tests/dir{a,b};
-
-
-check_cp_dir_to_dir_w_a_take_two:
-       @echo; echo Copy a directory into another directory with the -a switch;
-       @echo ------------------------------;
-       mkdir -p cp_tests/gnu;                  \
-        mkdir -p cp_tests/bb;                  \
-        cd cp_tests;                           \
-        mkdir here there;                      \
-        echo A file > here/afile;              \
-        mkdir here/adir;                       \
-        touch here/adir/afileinadir;           \
-        ln -s $$(pwd) here/alink;
-
-       @echo;
-       cd cp_tests/gnu;                        \
-        ls -lR . > ../../cp_a_dir_dir.gnu;     \
-        ${GCP} -a here/ there/;                \
-        ls -lR . >> ../../cp_a_dir_dir.gnu;
-
-       @echo;
-       rm -rf cp_tests/there/*;
-
-       sleep 1;
-
-       @echo;
-       cd cp_tests/bb;                         \
-        ls -lR . > ../../cp_a_dir_dir.bb;              \
-        ${BCP} -a here/ there/;                \
-        ls -lR . >> ../../cp_a_dir_dir.bb;
-
-       @echo;
-       echo "Erik 1"
-       diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb;
-       echo "Erik 2"
-
-       @echo;
-       echo "Erik 3"
-       rm -rf cp_tests/*;
-
-
diff --git a/busybox/tests/ln_tests.mk b/busybox/tests/ln_tests.mk
deleted file mode 100644 (file)
index 3110f81..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-# ln_tests.mk - Set of tests for busybox ln
-# -------------
-# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
-#
-
-# GNU `ln'
-GLN = /bin/ln
-# BusyBox `ln'
-BLN = $(shell pwd)/ln
-
-all:: ln_tests
-clean:: ln_clean
-
-ln_clean:
-       rm -rf ln_tests ln_*.{gnu,bb} ln
-
-ln_tests: ln_clean ln
-       @echo;
-       @echo "No output from diff means busybox ln is functioning properly.";
-
-       @echo;
-       ${BLN} || true;
-
-       @echo;
-       mkdir ln_tests;
-
-       @echo;
-       cd ln_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../ln_afile_newname.gnu; \
-        ${GLN} afile newname;                  \
-        ls -l afile newname >> ../ln_afile_newname.gnu;
-
-       @echo;
-       rm -f ln_tests/{afile,newname};
-
-       @echo;
-       cd ln_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../ln_afile_newname.bb;  \
-        ${BLN} afile newname;                  \
-        ls -l afile newname >> ../ln_afile_newname.bb;
-
-       @echo;
-       diff -u ln_afile_newname.gnu ln_afile_newname.bb
-
-       @echo;
-       rm -f ln_tests/{afile,newname};
-
-       @echo;
-       cd ln_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../ln_s_afile_newname.gnu;       \
-        ${GLN} -s afile newname;               \
-        ls -l afile newname >> ../ln_s_afile_newname.gnu;
-
-       @echo;
-       rm -f ln_tests/{afile,newname};
-
-       @echo;
-       cd ln_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../ln_s_afile_newname.bb;        \
-        ${BLN} -s afile newname;               \
-        ls -l afile newname >> ../ln_s_afile_newname.bb;
-
-       @echo;
-       diff -u ln_s_afile_newname.gnu ln_s_afile_newname.bb
-
-       @echo;
-       rm -f ln_tests/{afile,newname};
diff --git a/busybox/tests/multibuild.pl b/busybox/tests/multibuild.pl
deleted file mode 100755 (executable)
index 94930bd..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/perl
-
-# multibuild.pl
-# Tests BusyBox-0.48 (at least) to see if each applet builds
-# properly on its own.  The most likely problems this will
-# flush out are those involving preprocessor instructions in
-# utility.c.
-#
-# TODO: some time it might be nice to list absolute and 
-# differential object sizes for each option...
-#
-
-$logfile = "multibuild.log";
-
-# How to handle all the BB_FEATURE_FOO lines
-if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
-if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
-# neither means, leave that part of Config.h alone
-
-# Support building from pristine source
-$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
-
-# Move the config file to a safe place
--e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
-
-# Clear previous log file, if any
-unlink($logfile);
-
-# Parse the config file
-open(C,"<Config.h.orig") || die;
-while (<C>) {
-       if ($in_trailer) {
-               if (!$in_olympus) {
-                       s/^\/\/#/#/ if ($choice eq "all" && !/USE_DEVPS_PATCH/);
-                       s/^#/\/\/#/ if ($choice eq "none");
-               }
-               $in_olympus=1 if /End of Features List/;
-               $trailer .= $_;
-       } else {
-               $in_trailer=1 if /End of Applications List/;
-               if (/^\/*#define BB_([A-Z0-9_]*)/) {
-                       push @apps, $1;
-               }
-       }
-}
-close C;
-
-# Do the real work ...
-$failed_tests=0;
-for $a (@apps) {
-       # print "Testing build of applet $a ...\n";
-       open (O, ">Config.h") || die;
-       print O "#define BB_$a\n", $trailer;
-       close O;
-       system("echo -e '\n***\n$a\n***' >>$logfile");
-       # With a fast computer and 1-second resolution on file timestamps, this
-       # process pushes beyond the limits of what unix make can understand.
-       # That's why need to weed out obsolete files before restarting make.
-       $result{$a} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1");
-       $flag = $result{$a} ? "FAILED!!!" : "ok";
-       printf("Applet %-20s: %s\n", $a, $flag);
-       $total_tests++;
-       $failed_tests++ if $flag eq "FAILED!!!";
-       # pause long enough to let user stop us with a ^C
-       select(undef, undef, undef, 0.03);
-}
-
-# Clean up our mess
-system("mv -f Config.h.orig Config.h");
-
-print "$total_tests applets tested, $failed_tests failures\n";
-print "See $logfile for details.\n";
-
diff --git a/busybox/tests/multifeat.pl b/busybox/tests/multifeat.pl
deleted file mode 100755 (executable)
index adcb30b..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/perl
-#
-# multifeat.pl
-#
-# Turns on all applets, then tests turning on one feature at a time through
-# iterative compilations. Tests if any features depend on each other in any
-# weird ways or such-like problems.
-#
-# Hacked by Mark Whitley, but based *heavily* on multibuild.pl which was
-# written by Larry Doolittle.
-
-$logfile = "multifeat.log";
-
-# How to handle all the BB_APPLET lines
-# (most thorough testing occurs when you call it with the -all switch)
-if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
-if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
-# neither means, leave that part of Config.h alone
-
-# Support building from pristine source
-$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
-
-# Move the config file to a safe place
--e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
-
-# Clear previous log file, if any
-unlink($logfile);
-
-# Parse the config file
-open(C,"<Config.h.orig") || die;
-$in_applist=1;
-$in_features=0;
-$in_olympus=0;
-while (<C>) {
-       if ($in_applist) {
-               s/^\/\/#/#/ if ($choice eq "all");
-               s/^#/\/\/#/ if ($choice eq "none");
-               $header .= $_;
-               if (/End of Applications List/) {
-                       $in_applist=0;
-                       $in_features=1
-               }
-       }
-       elsif ($in_features) {
-               if (/^\/*#define BB_FEATURE_([A-Z0-9_]*)/) {
-                       push @features, $1;
-               }
-               if (/End of Features List/) {
-                       $in_features=0;
-                       $in_olympus=1
-               }
-       } elsif ($in_olympus) {
-               $trailer .= $_;
-       }
-}
-close C;
-
-# Do the real work ...
-$failed_tests=0;
-for $f (@features) {
-       # print "Testing build with feature $f ...\n";
-       open (O, ">Config.h") || die;
-       print O $header, "#define BB_FEATURE_$f\n", $trailer;
-       close O;
-       system("echo -e '\n***\n$f\n***' >>$logfile");
-       # With a fast computer and 1-second resolution on file timestamps, this
-       # process pushes beyond the limits of what unix make can understand.
-       # That's why need to weed out obsolete files before restarting make.
-       $result{$f} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1");
-       $flag = $result{$f} ? "FAILED!!!" : "ok";
-       printf("Feature %-20s: %s\n", $f, $flag);
-       $total_tests++;
-       $failed_tests++ if $flag eq "FAILED!!!";
-       # pause long enough to let user stop us with a ^C
-       select(undef, undef, undef, 0.03);
-}
-
-# Clean up our mess
-system("mv -f Config.h.orig Config.h");
-
-print "$total_tests applets tested, $failed_tests failures\n";
-print "See $logfile for details.\n";
-
diff --git a/busybox/tests/mv_tests.mk b/busybox/tests/mv_tests.mk
deleted file mode 100644 (file)
index f03e08a..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-# mv_tests.mk - Set of tests cases for busybox mv
-# -------------
-# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
-#
-
-# GNU `mv'
-GMV = /bin/mv
-# BusyBox `mv'
-BMV = $(shell pwd)/mv
-
-all:: mv_tests
-clean:: mv_clean
-
-mv_clean:
-       rm -rf mv_tests mv_*.{gnu,bb} mv
-
-mv_tests: mv_clean mv
-       @echo;
-       @echo "No output from diff means busybox mv is functioning properly.";
-       @echo;
-       @echo "No such file or directory is good; it means the old file got removed.";
-       @echo;
-       ${BMV} || true;
-
-       @echo;
-       mkdir mv_tests;
-
-       @echo;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../mv_afile_newname.gnu; \
-        ${GMV} afile newname;                  \
-        ls -l newname >> ../mv_afile_newname.gnu;
-       -ls -l mv_tests/afile;
-
-       @echo;
-       rm -f mv_tests/{afile,newname};
-
-       @echo;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ls -l afile > ../mv_afile_newname.bb;  \
-        ${BMV} afile newname;                  \
-        ls -l newname >> ../mv_afile_newname.bb;
-       -ls -l mv_tests/afile;
-
-       @echo;
-       diff -u mv_afile_newname.gnu mv_afile_newname.bb;
-
-       @echo;
-       rm -f mv_tests/{afile,newname};
-
-       @echo; echo ------------------------------;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ln -s afile symlink;                   \
-        ls -l afile symlink > ../mv_symlink_newname.gnu; \
-        ${GMV} symlink newname;                \
-        ls -l afile newname >> ../mv_symlink_newname.gnu;
-       -ls -l mv_tests/symlink;
-
-       @echo;
-       rm -f mv_tests/{afile,newname};
-
-       @echo;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ln -s afile symlink;                   \
-        ls -l afile symlink > ../mv_symlink_newname.bb;\
-        ${BMV} symlink newname;                \
-        ls -l afile newname >> ../mv_symlink_newname.bb;
-       -ls -l mv_tests/symlink;
-
-       @echo;
-       diff -u mv_symlink_newname.gnu mv_symlink_newname.bb;
-
-       @echo;
-       rm -rf mv_tests/*;
-
-       @echo; echo ------------------------------;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ln -s afile symlink;                   \
-        mkdir newdir;                          \
-        ls -lR > ../mv_file_symlink_dir.gnu;   \
-        ${GMV} symlink afile newdir;           \
-        ls -lR >> ../mv_file_symlink_dir.gnu;
-       -ls -l mv_tests/{symlink,afile};
-
-       @echo;
-       rm -rf mv_tests/*
-
-       @echo; echo ------------------------------;
-       cd mv_tests;                            \
-        echo A file > afile;                   \
-        ln -s afile symlink;                   \
-        mkdir newdir;                          \
-        ls -lR > ../mv_file_symlink_dir.bb;    \
-        ${BMV} symlink afile newdir;           \
-        ls -lR >> ../mv_file_symlink_dir.bb;
-       -ls -l mv_tests/{symlink,afile};
-
-       @echo;
-       diff -u mv_file_symlink_dir.gnu mv_file_symlink_dir.bb;
-
-       @echo;
-       rm -rf mv_tests/*;
-
-       @echo; echo ------------------------------;
-       cd mv_tests;                            \
-        mkdir dir{a,b};                        \
-        echo A file > dira/afile;              \
-        echo A file in dirb > dirb/afileindirb; \
-        ln -s dira/afile dira/alinktoafile;    \
-        mkdir dira/subdir1;                    \
-        echo Another file > dira/subdir1/anotherfile; \
-        ls -lR . > ../mv_dira_dirb.gnu;        \
-        ${GMV} dira dirb;                      \
-        ls -lR . >> ../mv_dira_dirb.gnu;
-
-       # false;
-       @echo;
-       rm -rf mv_tests/dir{a,b};
-
-       @echo;
-       cd mv_tests;                            \
-        mkdir dir{a,b};                        \
-        echo A file > dira/afile;              \
-        echo A file in dirb > dirb/afileindirb; \
-        ln -s dira/afile dira/alinktoafile;    \
-        mkdir dira/subdir1;                    \
-        echo Another file > dira/subdir1/anotherfile; \
-        ls -lR . > ../mv_dira_dirb.bb;         \
-        ${BMV} dira dirb;                      \
-        ls -lR . >> ../mv_dira_dirb.bb;
-
-       @echo;
-       diff -u mv_dira_dirb.gnu mv_dira_dirb.bb;
-
-       # false;
-       @echo;
-       rm -rf mv_tests/dir{a,b};
-
-       @echo; echo ------------------------------;
-       @echo There should be an error message about cannot mv a dir to a subdir of itself.
-       cd mv_tests;                            \
-        mkdir adir;                            \
-        touch -r . a b c adir;                 \
-        ls -lR . > ../mv_a_star_adir.gnu;      \
-        ${GMV} * adir;                         \
-        ls -lR . >> ../mv_a_star_adir.gnu;
-
-       @echo
-       @echo There should be an error message about cannot mv a dir to a subdir of itself.
-       cd mv_tests;                            \
-        rm -rf a b c adir;                     \
-        mkdir adir;                            \
-        touch -r . a b c adir;                 \
-        ls -lR . > ../mv_a_star_adir.bb;       \
-        ${BMV} * adir;                 \
-        ls -lR . >> ../mv_a_star_adir.bb;
-
-       @echo;
-       diff -u mv_a_star_adir.gnu mv_a_star_adir.bb;
-
-       @echo;
-       rm -rf mv_test/*;
diff --git a/busybox/tests/sh.testcases b/busybox/tests/sh.testcases
deleted file mode 100644 (file)
index e2a7587..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-# try running this with bash, ksh, ash, and hush.
-
-# simple quoting rules.
-echo a  b
-echo "a  b"
-echo a "" b
-echo a '' b
-echo hello?
-echo "hello?"
-echo t* hello
-echo t\* hello
-
-# quick and painless exit for lash
-if false; then true; exit; fi
-
-# fairly simple command substitution
-echo `echo -e foo\\\necho bar`
-
-echo THIS IS A TEST >foo
-cat $(echo FOO | tr 'A-Z' 'a-z')
-cat foo | tr 'A-Z' 'a-z'
-cat $(echo FOO | tr 'A-Z' 'a-z') | tr 'A-Z' 'a-z'
-
-cat foo | if true;  then tr 'A-Z' 'a-z'; else echo bar1; fi
-cat foo | if false; then tr 'A-Z' 'a-z'; else echo bar2; fi
-if true;  then tr 'A-Z' 'a-z'; else echo bar3; fi <foo
-if false; then tr 'A-Z' 'a-z'; else echo bar4; fi <foo
-if true || false; then echo foo; else echo bar5; fi
-if true && false; then echo bar6; else echo foo; fi
-
-# basic distinction between local and env variables
-unset FOO
-FOO=bar env | grep FOO
-echo "but not here: $FOO"
-FOO=bar
-env | grep FOO
-echo "yes, here: $FOO"
-FOO=
-echo a $FOO b
-echo "a $FOO b"
-
-# not quite so basic variables.  Credit to Matt Kraai.
-unset FOO
-FOO=bar
-export FOO
-env | grep FOO
-unset FOO
-export FOO=bar
-FOO=baz
-env | grep FOO
-
-# interaction between environment variables and if/then and subshells
-FOO=default
-if true; then FOO=new; fi
-echo $FOO
-FOO=default
-(FOO=bogus)
-echo $FOO
-
-# make sure we can duplicate file descriptors properly
-echo replacement >foo 2>&1
-cat foo
-cat doesnt_exist >foo 2>&1
-tr 'a-z' 'A-Z' <foo
-
-# fairly simple example of hush expanding variables too early
-unset TMP
-rm -f fish
-TMP=fish && >$TMP
-ls fish
-
-# ash, lash, and hush do not create fish; bash and ksh do.
-# Thanks to Tapani Tarvainen <tt@mit.jyu.fi> for this stress test.
-unset TMP
-rm -f fish
-TMP=fish >$TMP
-ls fish
-
-# The following example shows that hush's parser is
-# not _really_ Bourne compatible
-echo "echo Hello World" >"a=b"
-unset a
-chmod a+x "a=b"
-PATH=$PATH:.
-"a=b"
-echo $a
-
-# assuming the shell wasn't too buggy, clean up the mess
-rm -f a=b fish foo
diff --git a/busybox/tests/syslog_test.c b/busybox/tests/syslog_test.c
deleted file mode 100644 (file)
index fb4c691..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <syslog.h>
-
-int do_log(char* msg, int delay)
-{
-  openlog("testlog", LOG_PID, LOG_DAEMON);
-  while(1) {
-    syslog(LOG_ERR, "%s: testing one, two, three\n", msg);
-    sleep(delay);
-  }
-  closelog();
-  return(0);
-};
-
-int main(void)
-{
-  if (fork()==0)
-    do_log("A", 2);
-  do_log("B", 3);
-}
diff --git a/busybox/tests/testcases b/busybox/tests/testcases
deleted file mode 100644 (file)
index 2aad9b6..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-# testcases
-#
-# This file should be filled with test cases to test applets that:
-#
-#  - can somehow produce output (we can't test sync or sleep)
-#  - have a GNU (or other) counterpart
-#  - are not interactive (don't require a ^C or anything)
-#  - don't require extensive setup or cleanup (a litte setup is fine)
-#  - don't have huge and possibly damaging effects (fsck, swapoff)
-#
-# If possible, a test case should be made that tests each option the applet
-# supports. When a new option is added, a new test case should be written for
-# it. When somebody reports a bug with a testcase, that testcase should be
-# added here as well.
-#
-# Some other guidelines to follow:
-#
-#  - please try to keep applets alphabetized, it will make life easier
-#  - use the file tester.sh or testcases when you need to do a non-destructive
-#    test on a file (i.e., cat, md5sum)
-#  - try to make the applet you're testing the first thing on the line (this
-#    not always possible)
-#  - (???) if you have to create a temporary file, call it TMPFILE
-#  - pipe symbols that represent real pipes need a space in front of them
-#     (so the test script can find them and add the "../busybox" after it).
-#  - pipe symbols that are not used for pipes need to be shell-escaped,
-#     with a double \.  See the expr test cases.
-
-
-# ar
-
-# basename
-basename `pwd`
-
-# cat
-cat tester.sh
-echo hello there | cat tester.sh -
-
-# chmod
-# chown
-# chgrp
-# chroot
-# chvt - can't be tested here
-# clear - can't be tested here
-# cmp
-# cp
-
-# cut
-echo "1234" | cut -c1
-echo "1234" | cut -c 1
-echo "1234567890" | cut -c2-7
-echo "1234567890" | cut -c 2-7
-echo "f1       f2" | cut -f2
-echo "f1       f2" | cut -f 2
-echo "f1       f2      f3      f4      f5" | cut -f2-4
-echo "f1       f2      f3      f4      f5" | cut -f 2-4
-
-# date
-date
-date -R
-date -u
-date +%d/%m/%y
-
-# dc - needs an input file
-
-# dd
-# BUG: record count line goes to stdout instead of stderr
-dd if=/dev/urandom of=O bs=1k count=1 ; ls -l O ; rm O
-
-# deallocvt
-
-# df
-# XXX: minor formatting differences
-df
-df .
-df -k
-df -h
-df -m
-
-# dirname
-dirname `pwd`
-
-# dmesg (XXX: change the silly cmd business in the source)
-dmesg
-dmesg -n 8
-dmesg -s 512
-# I really don't want to do this next one
-#dmesg -c
-
-# dos2unix - needs an input file
-# dpkg
-# dpkg_deb
-
-# du
-# BUG: rounding behavior differs from GNU du
-du
-du -s
-du -l
-du -k
-du -h
-du -m
-
-# dumpkmap - no counterprt?
-# dutmp - no counterprt?
-
-# echo
-echo "foo bar baz"
-echo -n "no newline"
-
-
-# expr
-expr 1 \\| 1
-expr 1 \\| 0
-expr 0 \\| 1
-expr 0 \\| 0
-
-expr 1 \\& 1
-expr 1 \\& 0
-expr 0 \\& 1
-expr 0 \\& 0
-
-expr 0 \\< 1
-expr 1 \\< 0
-
-expr 1 \\> 0
-expr 0 \\> 1
-
-expr 0 \\<= 1
-expr 1 \\<= 0
-expr 1 \\<= 1
-
-expr 1 \\>= 0
-expr 0 \\>= 1
-expr 1 \\>= 1
-
-expr 1 + 2
-expr 2 - 1
-expr 2 \\* 3
-expr 12 / 2
-expr 12 % 5
-
-# somebody else can do all the string stuff
-
-
-# fbset - can't be tested here
-# fdflush
-# find
-find .
-
-# free
-# XXX: minor formatting differences
-free
-
-# freeramdisk
-# fsck.minix - won't test
-# getopt
-
-# grep
-grep -l strdup ../*.c
-grep -c strdup ../*.c
-grep -lc strdup ../*.c
-grep -cv strdup ../*.c
-grep -i null ../grep.c
-grep -e strdup -e regcomp -e atexit ../grep.c
-
-# gunzip
-
-# gzip
-# XXX: compressed output differs from gzip-1.2.4, but decompresses fine
-echo testing 1 2 3 >tmpfile1; gzip tmpfile1; echo tmpfile*; md5sum tmpfile1.gz; rm tmpfile1.gz
-echo testing 1 2 3 | gzip >tmpfile1.gz; md5sum tmpfile1.gz; rm tmpfile1.gz
-
-
-# halt - won't test, dangerous
-
-# head
-head tester.sh
-head -n 2 tester.sh
-
-# hostid
-hostid
-
-# hostname
-# XXX: minor formatting differences
-hostname
-hostname -s
-hostname -i
-hostname -d
-# not going to do this next one
-#hostname -F
-
-# id
-# BUG: Busybox id doesn't print supplemental groups
-id
-id -u
-id -g
-id -ur
-id -un
-
-
-# ifconfig
-# requires BB_FEATURE_IFCONFIG_STATUS
-ifconfig
-#ifconfig -a
-#ifconfig eth0
-#ifconfig lo
-
-# init - won't test
-# insmod - won't test
-
-# kill
-#kill -l
-# not going to do any more
-
-# length
-# ln - see ln_tests.mk
-# loadacm
-# loadfont
-# loadkmap
-# logger
-# logname
-
-# ls
-# XXX: minor formatting differences
-ls ../e*
-ls -l ../e*
-ls -s ../e*
-ls -h ../e*
-ls -1 ../e*
-
-# lsmod
-lsmod
-
-# makedevs
-
-# md5sum
-md5sum tester.sh
-
-# mkdir
-mkdir D ; ls -ld D ; rmdir D
-
-# mkfifo
-#
-# we will test making one. actually testing pushing data through it requires
-# more interaction than we can manage here.
-# (these lines turn up an existing ls bug)
-mkfifo F ; ls -l F ; rm F
-mkfifo -m 0600 F ; ls -l F ; rm F
-
-# mkfs.minix - won't test
-# mknod
-# mkswap - won't test
-# mktemp
-# more - can't test: interactive
-
-# mount
-# BUG: proc line starts with /proc instead of proc
-mount
-# not going to test mount with any args, can't be done safely or sanely
-
-# mt
-# mv - see mv_tests.mk
-# nc
-# nfsmount
-# nslookup
-# ping
-ping -c 3 yahoo.com
-# pivot_root
-# poweroff - won't test
-# printf
-# ps - there's lotsa differences between busybox ps and any other ps
-
-# pwd
-pwd
-
-# rdate - won't test
-
-# readlink
-ln -sf tester.sh L ; readlink L ; rm -f L
-
-# reboot - won't test
-# renice - won't test
-# reset - can't test: no output
-
-# rm
-touch F ; rm F
-
-# rmdir
-# rmmod - won't test: dangerous
-
-# route
-# XXX: doesn't DNS resolve
-route
-
-# rpm2cpio
-
-# sed - we can do some one-liners here, some testing is a little
-# difficult to do in just this space (like a,i,c cmds).
-
-# test ^$ matching
-echo foo | sed -ne '/^$/p'
-echo -e "foo\\n\\nbar" | sed -ne '/^$/p'
-
-sed -e '/test$/d' testcases
-sed -e '/^echo/d' testcases
-sed -e '/test/s/dangerous/PELIGROSO/' testcases
-sed -ne '1,/getopt/p' ../pwd.c
-sed -e '/getopt/r ../pwd.c' ../sed.c
-
-
-# setkeycodes
-
-# sh - note that we cannot test the shell interactively here
-sh -c "echo a b c"
-sh -c ">"
-sh -c "a"
-sh sh.testcases
-
-
-# sleep - can't test: produces no output
-
-# sort
-sort tester.sh
-sort -n tester.sh
-sort -r tester.sh
-
-# stty
-# swapon - won't test: dangerous
-# swapoff - won't test: dangerous
-# sync - can't test: no output
-# syslogd - won't test: too involved
-
-# tail
-tail tester.sh
-tail -n 2  tester.sh
-
-# tar
-
-# tee
-echo "please tee me!" | tee A B C ; cat A B C
-echo "please tee me!" | tee A B C ; echo "tee me too!" | tee -a A B C ; cat A B C ; rm A B C
-
-# telnet - can't test: interactive
-
-# test
-# tftp
-
-# touch
-touch tmpfile1; ls tmpfile1; rm -f tmpfile1
-touch -c tmpfile1; ls tmpfile1; rm -f tmpfile1
-
-# tr
-# BUG: Busybox tr range handling minix style [a-z] instead of GNU # style a-z
-echo "cbaab" | tr abc zyx
-echo "TESTING A B C" | tr [A-Z] [a-z]
-# not GNU compatible
-echo fdhrnzvfu bffvsentr | tr [a-z] [n-z][a-m]
-echo abc[] | tr a[b AXB
-echo testing | tr -d aeiou
-
-# true
-true ; echo $?
-
-# false
-false ; echo $?
-
-# tty
-# umount
-# uname
-# uniq
-# unix2dos
-# update
-
-# uptime
-# BUG: doesn't print number of users
-uptime
-
-# usleep
-# uudecode
-# uuencode
-# watchdog
-
-# wc
-wc tester.sh
-wc -c tester.sh
-wc -w tester.sh
-wc -l tester.sh
-wc -L tester.sh
-
-# wget
-
-# which
-which ls
-
-# whoami
-whoami
-
-# xargs
-# XXX: Busygox xargs divides filenames with '\n' instead of ' '
-ls -1 ../e* | xargs
-ls -1 ../e* | xargs md5sum
-
-# yes - can't test: interactive (needs ^C)
-
diff --git a/busybox/tests/tester.sh b/busybox/tests/tester.sh
deleted file mode 100755 (executable)
index a767c6c..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/bin/bash
-#
-# tester.sh - reads testcases from file and tests busybox applets vs GNU
-# counterparts
-#
-# This should be run from within the tests/ directory. Before you run it, you
-# should compile up a busybox that has all applets and all features turned on.
-
-# set up defaults (can be changed with cmd-line options)
-BUSYBOX=../busybox
-TESTCASES=testcases
-LOGFILE=tester.log
-BB_OUT=bb.out
-GNU_OUT=gnu.out
-SETUP=""
-CLEANUP=""
-KEEPTMPFILES="no"
-DEBUG=2
-
-
-#while getopts 'p:t:l:b:g:s:c:kd:' opt
-while getopts 'p:t:l:s:c:kd:' opt
-do
-       case $opt in
-               p) BUSYBOX=$OPTARG; ;;
-               t) TESTCASES=$OPTARG; ;;
-               l) LOGFILE=$OPTARG; ;;
-#              b) BB_OUT=$OPTARG; ;;
-#              g) GNU_OUT=$OPTARG; ;;
-               s) SETUP=$OPTARG; ;;
-               c) CLEANUP=$OPTARG; ;;
-               k) KEEPTMPFILES="yes"; ;;
-               d) DEBUG=$OPTARG; ;;
-               *)
-                       echo "usage: $0 [-ptlbgsc]"
-                       echo "  -p PATH  path to busybox executable (default=$BUSYBOX)"
-                       echo "  -t FILE  run testcases in FILE (default=$TESTCASES)"
-                       echo "  -l FILE  log test results in FILE (default=$LOGFILE)"
-#                      echo "  -b FILE  store temporary busybox output in FILE"
-#                      echo "  -g FILE  store temporary GNU output in FILE"
-                       echo "  -s FILE  (setup) run commands in FILE before testcases"
-                       echo "  -c FILE  (cleanup) run commands in FILE after testcases"
-                       echo "  -k       keep temporary output files (don't delete them)"
-                       echo "  -d NUM   set level of debugging output"
-                       echo "           0 = no output"
-                       echo "           1 = output failures / whoops lines only"
-                       echo "           2 = (default) output setup / cleanup msgs and testcase lines"
-                       echo "           3+= other debug noise (internal stuff)"
-                       exit 1
-                       ;;
-       esac
-done
-#shift `expr $OPTIND - 1`
-
-
-# maybe print some debug output
-if [ $DEBUG -ge 3 ]
-then
-       echo "BUSYBOX=$BUSYBOX"
-       echo "TESTCASES=$TESTCASES"
-       echo "LOGFILE=$LOGFILE"
-       echo "BB_OUT=$BB_OUT"
-       echo "GNU_OUT=$GNU_OUT"
-       echo "SETUP=$SETUP"
-       echo "CLEANUP=$CLEANUP"
-       echo "DEBUG=$DEBUG"
-fi
-
-
-# do sanity checks
-if [ ! -e $BUSYBOX ]
-then
-       echo "Busybox executable: $BUSYBOX not found!"
-       exit 1
-fi
-
-if [ ! -e $TESTCASES ]
-then
-       echo "Testcases file: $TESTCASES not found!"
-       exit 1
-fi
-
-
-# do normal setup
-[ -e $LOGFILE ] && rm $LOGFILE
-unalias -a     # gets rid of aliases that might create different output
-
-
-# do extra setup (if any)
-if [ ! -z "$SETUP" ] 
-then
-       [ $DEBUG -ge 2 ] && echo "running setup commands in $SETUP"
-       source $SETUP
-fi
-
-
-# go through each line in the testcase file
-cat $TESTCASES | while read line
-do
-       #echo $line
-       # only process non-blank lines and non-comment lines
-       if [ "$line" ]
-       then
-               if [ `echo "$line" | cut -c1` != "#" ]
-               then
-
-                       # test if the applet was compiled into busybox
-                       # (this only tests the applet at the beginning of the line)
-                       #applet=`echo $line | cut -d' ' -f1`
-                       applet=`echo $line | sed 's/\(^[^ ;]*\)[ ;].*/\1/'`
-                       $BUSYBOX 2>&1 | grep -qw $applet
-                       if [ $? -eq 1 ]
-                       then
-                               echo "WHOOPS: $applet not compiled into busybox" | tee -a $LOGFILE
-                       else
-
-                               # execute line using gnu / system programs
-                               [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE
-                               sh -c "$line" > $GNU_OUT
-
-                               # change line to include "busybox" before every statement
-                               line="$BUSYBOX $line"
-                               # is this a bash-2-ism?
-                               # line=${line//;/; $BUSYBOX }
-                               # line=${line//|/| $BUSYBOX }
-                               # assume $BUSYBOX has no commas
-                               line=`echo "$line" | sed -e 's,;,; '$BUSYBOX, \
-                                                      -e 's, |, | '$BUSYBOX,`
-
-                               # execute line using busybox programs
-                               [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE
-                               sh -c "$line" > $BB_OUT
-
-                               # see if they match
-                               diff -q $BB_OUT $GNU_OUT > /dev/null
-                               if [ $? -eq 1 ]
-                               then
-                                       [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE
-                                       diff -u $BB_OUT $GNU_OUT >> $LOGFILE 
-                               fi
-                       fi
-               fi
-       fi
-done
-
-[ $DEBUG -gt 0 ] && echo "Finished. Results are in $LOGFILE"
-
-
-# do normal cleanup
-[ "$KEEPTMPFILES" = "no" ] && rm -f $BB_OUT $GNU_OUT
-
-
-# do extra cleanup (if any)
-if [ ! -z "$CLEANUP" ] 
-then
-       [ $DEBUG -ge 2 ] && echo "running cleanup commands in $CLEANUP"
-       source $CLEANUP
-fi
diff --git a/busybox/tests/tst-syslogd.c b/busybox/tests/tst-syslogd.c
deleted file mode 100644 (file)
index bae10af..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  tst-syslogd.c - tests concurrent threads calling syslog
- *
- *  build with: gcc -Wall tst-syslogd.c -lpthread
- */
-
-#include <stdio.h>
-#include <pthread.h>
-#include <syslog.h>
-#include <unistd.h>
-
-void *log_func(void *arg)
-{
-       int i;
-       int thrid = (int)arg;
-
-       openlog(NULL, LOG_PERROR | LOG_PID, LOG_USER);
-       for (i = 0; i < 10; i++) {
-               syslog(LOG_DEBUG, "thread %i iter %i\n", thrid, i);
-               sleep(thrid); /* this mixes things up a bit */
-       }
-       closelog();
-
-       return NULL;
-}
-
-int main(int argc, char **argv)
-{
-       pthread_t thr1, thr2, thr3;
-       int id1 = 1;
-       int id2 = 2;
-       int id3 = 3;
-
-       pthread_create(&thr1, NULL, log_func, (void *)id1);
-       pthread_create(&thr2, NULL, log_func, (void *)id2);
-       pthread_create(&thr3, NULL, log_func, (void *)id3);
-
-       pthread_join(thr1, NULL);
-       pthread_join(thr2, NULL);
-       pthread_join(thr3, NULL);
-
-       return 0;
-}
-
diff --git a/busybox/tftp.c b/busybox/tftp.c
deleted file mode 100644 (file)
index 999b5d7..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* tftp.c                                                                    */
-/*                                                                           */
-/* A simple tftp client for busybox.                                         */
-/* Tries to follow RFC1350.                                                  */
-/* Only "octet" mode and 512-byte data blocks are supported.                 */
-/*                                                                           */
-/* Copyright (C) 2001 Magnus Damm <damm@opensource.se>                       */
-/*                                                                           */
-/* Parts of the code based on:                                               */
-/*                                                                           */
-/* atftp:  Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>   */
-/*                        and Remi Lefebvre <remi@debian.org>                */
-/*                                                                           */
-/* utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>                         */
-/*                                                                           */
-/* This program is free software; you can redistribute it and/or modify      */
-/* it under the terms of the GNU General Public License as published by      */
-/* the Free Software Foundation; either version 2 of the License, or         */
-/* (at your option) any later version.                                       */
-/*                                                                           */
-/* This program is distributed in the hope that it will be useful,           */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          */
-/* General Public License for more details.                                  */
-/*                                                                           */
-/* You should have received a copy of the GNU General Public License         */
-/* along with this program; if not, write to the Free Software               */
-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */
-/*                                                                           */
-/* ------------------------------------------------------------------------- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "busybox.h"
-
-//#define BB_FEATURE_TFTP_DEBUG
-
-static const char *tftp_error_msg[] = {
-       "Undefined error",
-       "File not found",
-       "Access violation",
-       "Disk full or allocation error",
-       "Illegal TFTP operation",
-       "Unknown transfer ID",
-       "File already exists",
-       "No such user"
-};
-
-const int tftp_cmd_get = 1;
-const int tftp_cmd_put = 2;
-
-static inline int tftp(const int cmd, const struct hostent *host,
-       const char *serverfile, int localfd, const int port, int tftp_bufsize)
-{
-       const int cmd_get = cmd & tftp_cmd_get;
-       const int cmd_put = cmd & tftp_cmd_put;
-       const int bb_tftp_num_retries = 5;
-
-       struct sockaddr_in sa;
-       struct sockaddr_in from;
-       struct timeval tv;
-       socklen_t fromlen;
-       fd_set rfds;
-       char *cp;
-       unsigned short tmp;
-       int socketfd;
-       int len;
-       int opcode = 0;
-       int finished = 0;
-       int timeout = bb_tftp_num_retries;
-       int block_nr = 1;
-       RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); // Why 4 ?
-
-       tftp_bufsize += 4;
-
-       if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror_msg("socket");
-               return EXIT_FAILURE;
-       }
-
-       len = sizeof(sa);
-
-       memset(&sa, 0, len);
-       bind(socketfd, (struct sockaddr *)&sa, len);
-
-       sa.sin_family = host->h_addrtype;
-       sa.sin_port = htons(port);
-       memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
-                  sizeof(sa.sin_addr));
-
-       /* build opcode */
-
-       if (cmd_get) {
-               opcode = 1;     // read request = 1
-       }
-
-       if (cmd_put) {
-               opcode = 2;     // write request = 2
-       }
-
-       while (1) {
-
-
-               /* build packet of type "opcode" */
-
-
-               cp = buf;
-
-               *((unsigned short *) cp) = htons(opcode);
-
-               cp += 2;
-
-               /* add filename and mode */
-
-               if ((cmd_get && (opcode == 1)) || // read request = 1
-                       (cmd_put && (opcode == 2))) { // write request = 2
-
-                       /* what is this trying to do ? */
-                       while (cp != &buf[tftp_bufsize - 1]) {
-                               if ((*cp = *serverfile++) == '\0')
-                                       break;
-                               cp++;
-                       }
-                       /* and this ? */
-                       if ((*cp != '\0') || (&buf[tftp_bufsize - 1] - cp) < 7) {
-                               error_msg("too long server-filename");
-                               break;
-                       }
-
-                       memcpy(cp + 1, "octet", 6);
-                       cp += 7;
-               }
-
-               /* add ack and data */
-
-               if ((cmd_get && (opcode == 4)) || // acknowledgement = 4
-                       (cmd_put && (opcode == 3))) { // data packet == 3
-
-                       *((unsigned short *) cp) = htons(block_nr);
-
-                       cp += 2;
-
-                       block_nr++;
-
-                       if (cmd_put && (opcode == 3)) { // data packet == 3
-                               len = read(localfd, cp, tftp_bufsize - 4);
-
-                               if (len < 0) {
-                                       perror_msg("read");
-                                       break;
-                               }
-
-                               if (len != (tftp_bufsize - 4)) {
-                                       finished++;
-                               }
-
-                               cp += len;
-                       } else if (finished) {
-                               break;
-                       }
-               }
-
-
-               /* send packet */
-
-
-               do {
-
-                       len = cp - buf;
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-                       printf("sending %u bytes\n", len);
-                       for (cp = buf; cp < &buf[len]; cp++)
-                               printf("%02x ", *cp);
-                       printf("\n");
-#endif
-                       if (sendto(socketfd, buf, len, 0,
-                                       (struct sockaddr *) &sa, sizeof(sa)) < 0) {
-                               perror_msg("send");
-                               len = -1;
-                               break;
-                       }
-
-
-                       /* receive packet */
-
-
-                       memset(&from, 0, sizeof(from));
-                       fromlen = sizeof(from);
-
-                       tv.tv_sec = 5; // BB_TFPT_TIMEOUT = 5
-                       tv.tv_usec = 0;
-
-                       FD_ZERO(&rfds);
-                       FD_SET(socketfd, &rfds);
-
-                       switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
-                       case 1:
-                               len = recvfrom(socketfd, buf, tftp_bufsize, 0,
-                                               (struct sockaddr *) &from, &fromlen);
-
-                               if (len < 0) {
-                                       perror_msg("recvfrom");
-                                       break;
-                               }
-
-                               timeout = 0;
-
-                               if (sa.sin_port == htons(port)) {
-                                       sa.sin_port = from.sin_port;
-                               }
-                               if (sa.sin_port == from.sin_port) {
-                                       break;
-                               }
-
-                               /* fall-through for bad packets! */
-                               /* discard the packet - treat as timeout */
-                               timeout = bb_tftp_num_retries;
-
-                       case 0:
-                               error_msg("timeout");
-
-                               if (timeout == 0) {
-                                       len = -1;
-                                       error_msg("last timeout");
-                               } else {
-                                       timeout--;
-                               }
-                               break;
-
-                       default:
-                               perror_msg("select");
-                               len = -1;
-                       }
-
-               } while (timeout && (len >= 0));
-
-               if (len < 0) {
-                       break;
-               }
-
-               /* process received packet */
-
-
-               opcode = ntohs(*((unsigned short *) buf));
-               tmp = ntohs(*((unsigned short *) &buf[2]));
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-               printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
-#endif
-
-               if (cmd_get && (opcode == 3)) { // data packet == 3
-
-                       if (tmp == block_nr) {
-                               len = write(localfd, &buf[4], len - 4);
-
-                               if (len < 0) {
-                                       perror_msg("write");
-                                       break;
-                               }
-
-                               if (len != (tftp_bufsize - 4)) {
-                                       finished++;
-                               }
-
-                               opcode = 4; // acknowledgement = 4
-                               continue;
-                       }
-               }
-
-               if (cmd_put && (opcode == 4)) { // acknowledgement = 4
-
-                       if (tmp == (block_nr - 1)) {
-                               if (finished) {
-                                       break;
-                               }
-
-                               opcode = 3; // data packet == 3
-                               continue;
-                       }
-               }
-
-               if (opcode == 5) { // error code == 5
-                       char *msg = NULL;
-
-                       if (buf[4] != '\0') {
-                               msg = &buf[4];
-                               buf[tftp_bufsize - 1] = '\0';
-                       } else if (tmp < (sizeof(tftp_error_msg) / sizeof(char *))) {
-                               msg = (char *) tftp_error_msg[tmp];
-                       }
-
-                       if (msg) {
-                               error_msg("server says: %s", msg);
-                       }
-
-                       break;
-               }
-       }
-
-       close(socketfd);
-
-       return finished ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-int tftp_main(int argc, char **argv)
-{
-       struct hostent *host = NULL;
-       char *localfile = NULL;
-       char *remotefile = NULL;
-       int port = 69;
-       int cmd = 0;
-       int fd = -1;
-       int flags = 0;
-       int opt;
-       int result;
-       int blocksize = 512;
-
-       while ((opt = getopt(argc, argv, "b:gpl:r:")) != -1) {
-               switch (opt) {
-               case 'b':
-                       blocksize = atoi(optarg);
-                       break;
-#ifdef BB_FEATURE_TFTP_GET
-               case 'g':
-                       cmd = tftp_cmd_get;
-                       flags = O_WRONLY | O_CREAT;
-                       break;
-#endif
-#ifdef BB_FEATURE_TFTP_PUT
-               case 'p':
-                       cmd = tftp_cmd_put;
-                       flags = O_RDONLY;
-                       break;
-#endif
-               case 'l': 
-                       localfile = xstrdup(optarg);
-                       break;
-               case 'r':
-                       remotefile = xstrdup(optarg);
-                       break;
-               }
-       }
-
-       if ((cmd == 0) || (optind == argc)) {
-               show_usage();
-       }
-
-       fd = open(localfile, flags, 0644);
-       if (fd < 0) {
-               perror_msg_and_die("local file");
-       }
-
-       host = xgethostbyname(argv[optind]);
-
-       if (optind + 2 == argc) {
-               port = atoi(argv[optind + 1]);
-       }
-
-#ifdef BB_FEATURE_TFTP_DEBUG
-       printf("using server \"%s\", serverfile \"%s\","
-               "localfile \"%s\".\n",
-               inet_ntoa(*((struct in_addr *) host->h_addr)),
-               remotefile, localfile);
-#endif
-
-       result = tftp(cmd, host, remotefile, fd, port, blocksize);
-       close(fd);
-
-       return(result);
-}
\ No newline at end of file
diff --git a/busybox/touch.c b/busybox/touch.c
deleted file mode 100644 (file)
index 1718da7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini touch implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int touch_main(int argc, char **argv)
-{
-       int fd;
-       int create = TRUE;
-
-       /* Parse options */
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 'c':
-                               create = FALSE;
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-
-       if (argc < 1) {
-               show_usage();
-       }
-
-       while (argc > 0) {
-               fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT,
-                               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-               if (fd < 0) {
-                       if (create == FALSE && errno == ENOENT)
-                               return EXIT_SUCCESS;
-                       else {
-                               perror_msg_and_die("%s", *argv);
-                       }
-               }
-               close(fd);
-               if (utime(*argv, NULL)) {
-                       perror_msg_and_die("%s", *argv);
-               }
-               argc--;
-               argv++;
-       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/tr.c b/busybox/tr.c
deleted file mode 100644 (file)
index 5b7b8d0..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tr implementation for busybox
- *
- * Copyright (c) Michiel Huisjes
- *
- * This version of tr is adapted from Minix tr and was modified 
- * by Erik Andersen <andersee@debian.org> to be used in busybox.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Original copyright notice is retained at the end of this file.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
- * enabled, we otherwise get a "storage size isn't constant error. */
-#define ASCII 0377
-
-/* some "globals" shared across this file */
-static char com_fl, del_fl, sq_fl;
-static short in_index, out_index;
-/* these last are pointers to static buffers declared in tr_main */
-static unsigned char *poutput, *pinput;
-static unsigned char *pvector;
-static char *pinvec, *poutvec;
-
-
-static void convert()
-{
-       short read_chars = 0;
-       short c, coded;
-       short last = -1;
-
-       for (;;) {
-               if (in_index == read_chars) {
-                       if ((read_chars = read(0, (char *) pinput, BUFSIZ)) <= 0) {
-                               if (write(1, (char *) poutput, out_index) != out_index)
-                                       error_msg("%s", write_error);
-                               exit(0);
-                       }
-                       in_index = 0;
-               }
-               c = pinput[in_index++];
-               coded = pvector[c];
-               if (del_fl && pinvec[c])
-                       continue;
-               if (sq_fl && last == coded && (pinvec[c] || poutvec[coded]))
-                       continue;
-               poutput[out_index++] = last = coded;
-               if (out_index == BUFSIZ) {
-                       if (write(1, (char *) poutput, out_index) != out_index)
-                               error_msg_and_die("%s", write_error);
-                       out_index = 0;
-               }
-       }
-
-       /* NOTREACHED */
-}
-
-static void map(register unsigned char *string1, unsigned int string1_len,
-               register unsigned char *string2, unsigned int string2_len)
-{
-       unsigned char last = '0';
-       unsigned int i, j;
-
-       for (j = 0, i = 0; i < string1_len; i++) {
-               if (string2_len <= j)
-                       pvector[string1[i]] = last;
-               else
-                       pvector[string1[i]] = last = string2[j++];
-       }
-}
-
-/* supported constructs:
- *   Ranges,  e.g.,  [0-9]  ==>  0123456789
- *   Escapes, e.g.,  \a     ==>  Control-G
- */
-static unsigned int expand(const char *arg, register unsigned char *buffer)
-{
-       unsigned char *buffer_start = buffer;
-       int i, ac;
-
-       while (*arg) {
-               if (*arg == '\\') {
-                       arg++;
-                       *buffer++ = process_escape_sequence(&arg);
-               } else if (*(arg+1) == '-') {
-                       ac = *(arg+2);
-                       if(ac == 0) {
-                               *buffer++ = *arg++;
-                               continue;
-                       }
-                       i = *arg;
-                       while (i <= ac)
-                               *buffer++ = i++;
-                       arg += 3; /* Skip the assumed a-z */
-               } else if (*arg == '[') {
-                       arg++;
-                       i = *arg++;
-                       if (*arg++ != '-') {
-                               *buffer++ = '[';
-                               arg -= 2;
-                               continue;
-                       }
-                       ac = *arg++;
-                       while (i <= ac)
-                               *buffer++ = i++;
-                       arg++;                          /* Skip the assumed ']' */
-               } else
-                       *buffer++ = *arg++;
-       }
-
-       return (buffer - buffer_start);
-}
-
-static int complement(unsigned char *buffer, int buffer_len)
-{
-       register short i, j, ix;
-       char conv[ASCII + 2];
-
-       ix = 0;
-       for (i = 0; i <= ASCII; i++) {
-               for (j = 0; j < buffer_len; j++)
-                       if (buffer[j] == i)
-                               break;
-               if (j == buffer_len)
-                       conv[ix++] = i & ASCII;
-       }
-       memcpy(buffer, conv, ix);
-       return ix;
-}
-
-extern int tr_main(int argc, char **argv)
-{
-       register unsigned char *ptr;
-       int output_length=0, input_length;
-       int idx = 1;
-       int i;
-       RESERVE_BB_BUFFER(output, BUFSIZ);
-       RESERVE_BB_BUFFER(input,  BUFSIZ);
-       RESERVE_BB_UBUFFER(vector, ASCII+1);
-       RESERVE_BB_BUFFER(invec,  ASCII+1);
-       RESERVE_BB_BUFFER(outvec, ASCII+1);
-
-       /* ... but make them available globally */
-       poutput = output;
-       pinput  = input;
-       pvector = vector;
-       pinvec  = invec;
-       poutvec = outvec;
-
-       if (argc > 1 && argv[idx][0] == '-') {
-               for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
-                       switch (*ptr) {
-                       case 'c':
-                               com_fl = TRUE;
-                               break;
-                       case 'd':
-                               del_fl = TRUE;
-                               break;
-                       case 's':
-                               sq_fl = TRUE;
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-               idx++;
-       }
-       for (i = 0; i <= ASCII; i++) {
-               vector[i] = i;
-               invec[i] = outvec[i] = FALSE;
-       }
-
-       if (argv[idx] != NULL) {
-               input_length = expand(argv[idx++], input);
-               if (com_fl)
-                       input_length = complement(input, input_length);
-               if (argv[idx] != NULL) {
-                       if (*argv[idx] == '\0')
-                               error_msg_and_die("STRING2 cannot be empty");
-                       output_length = expand(argv[idx], output);
-                       map(input, input_length, output, output_length);
-               }
-               for (i = 0; i < input_length; i++)
-                       invec[(int)input[i]] = TRUE;
-               for (i = 0; i < output_length; i++)
-                       outvec[(int)output[i]] = TRUE;
-       }
-       convert();
-       return (0);
-}
-
-/*
- * Copyright (c) 1987,1997, Prentice Hall
- * All rights reserved.
- * 
- * Redistribution and use of the MINIX operating system in source and
- * binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- * 
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 
- * 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.
- * 
- * Neither the name of Prentice Hall nor the names of the software
- * authors or contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
diff --git a/busybox/traceroute.c b/busybox/traceroute.c
deleted file mode 100644 (file)
index a3abd0a..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Van Jacobson.
- *
- * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by the University of
- *      California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * traceroute host  - trace the route ip packets follow going to "host".
- * Notes
- * -----
- * This program must be run by root or be setuid.  (I suggest that
- * you *don't* make it setuid -- casual use could result in a lot
- * of unnecessary traffic on our poor, congested nets.)
- *
- * I stole the idea for this program from Steve Deering.  Since
- * the first release, I've learned that had I attended the right
- * IETF working group meetings, I also could have stolen it from Guy
- * Almes or Matt Mathis.  I don't know (or care) who came up with
- * the idea first.  I envy the originators' perspicacity and I'm
- * glad they didn't keep the idea a secret.
- *
- * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
- * enhancements to the original distribution.
- *
- * I've hacked up a round-trip-route version of this that works by
- * sending a loose-source-routed udp datagram through the destination
- * back to yourself.  Unfortunately, SO many gateways botch source
- * routing, the thing is almost worthless.  Maybe one day...
- *
- *  -- Van Jacobson (van@helios.ee.lbl.gov)
- *     Tue Dec 20 03:50:13 PST 1988
- */
-
-#undef BB_FEATURE_TRACEROUTE_VERBOSE
-//#define BB_FEATURE_TRACEROUTE_VERBOSE
-#undef BB_FEATURE_TRACEROUTE_SO_DEBUG   /* not in documentation man */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <endian.h>
-#include <arpa/inet.h>
-#include <netinet/udp.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-
- /* It turns out that libc5 doesn't have proper icmp support
- * built into it header files, so we have to supplement it */
-#if __GNU_LIBRARY__ < 5
-static const int ICMP_MINLEN = 8;                              /* abs minimum */
-
-struct icmp_ra_addr
-{
-  u_int32_t ira_addr;
-  u_int32_t ira_preference;
-};
-
-
-struct icmp
-{
-  u_int8_t  icmp_type; /* type of message, see below */
-  u_int8_t  icmp_code; /* type sub code */
-  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
-  union
-  {
-    u_char ih_pptr;            /* ICMP_PARAMPROB */
-    struct in_addr ih_gwaddr;  /* gateway address */
-    struct ih_idseq            /* echo datagram */
-    {
-      u_int16_t icd_id;
-      u_int16_t icd_seq;
-    } ih_idseq;
-    u_int32_t ih_void;
-
-    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
-    struct ih_pmtu
-    {
-      u_int16_t ipm_void;
-      u_int16_t ipm_nextmtu;
-    } ih_pmtu;
-
-    struct ih_rtradv
-    {
-      u_int8_t irt_num_addrs;
-      u_int8_t irt_wpa;
-      u_int16_t irt_lifetime;
-    } ih_rtradv;
-  } icmp_hun;
-#define        icmp_pptr       icmp_hun.ih_pptr
-#define        icmp_gwaddr     icmp_hun.ih_gwaddr
-#define        icmp_id         icmp_hun.ih_idseq.icd_id
-#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
-#define        icmp_void       icmp_hun.ih_void
-#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
-#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
-#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
-#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
-#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
-  union
-  {
-    struct
-    {
-      u_int32_t its_otime;
-      u_int32_t its_rtime;
-      u_int32_t its_ttime;
-    } id_ts;
-    struct
-    {
-      struct ip idi_ip;
-      /* options and then 64 bits of data */
-    } id_ip;
-    struct icmp_ra_addr id_radv;
-    u_int32_t   id_mask;
-    u_int8_t    id_data[1];
-  } icmp_dun;
-#define        icmp_otime      icmp_dun.id_ts.its_otime
-#define        icmp_rtime      icmp_dun.id_ts.its_rtime
-#define        icmp_ttime      icmp_dun.id_ts.its_ttime
-#define        icmp_ip         icmp_dun.id_ip.idi_ip
-#define        icmp_radv       icmp_dun.id_radv
-#define        icmp_mask       icmp_dun.id_mask
-#define        icmp_data       icmp_dun.id_data
-};
-
-#define        ICMP_MINLEN     8                               /* abs minimum */
-#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
-#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
-#define        ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
-#define        ICMP_UNREACH_NET                0       /* bad net */
-#define        ICMP_UNREACH_HOST               1       /* bad host */
-#define        ICMP_UNREACH_PROTOCOL           2       /* bad protocol */
-#define        ICMP_UNREACH_PORT               3       /* bad port */
-#define        ICMP_UNREACH_NEEDFRAG           4       /* IP_DF caused drop */
-#define        ICMP_UNREACH_SRCFAIL            5       /* src route failed */
-#endif
-
-
-#define MAXPACKET       65535   /* max ip packet size */
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN  64
-#endif
-
-/*
- * format of a (udp) probe packet.
- */
-struct opacket {
-       struct ip ip;
-       struct udphdr udp;
-       u_char seq;             /* sequence number of this packet */
-       u_char ttl;             /* ttl packet left with */
-       struct timeval tv;      /* time packet left */
-};
-
-/*
- * Definitions for internet protocol version 4.
- * Per RFC 791, September 1981.
- */
-#define IPVERSION       4
-
-
-#include "busybox.h"
-
-static u_char  packet[512];            /* last inbound (icmp) packet */
-static struct opacket  *outpacket;     /* last output (udp) packet */
-
-static int s;                          /* receive (icmp) socket file descriptor */
-static int sndsock;                    /* send (udp) socket file descriptor */
-
-static struct sockaddr whereto;        /* Who to try to reach */
-static int datalen;                    /* How much data */
-
-static char *hostname;
-
-static int max_ttl = 30;
-static u_short ident;
-static u_short port = 32768+666;       /* start udp dest port # for probe packets */
-
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-static int verbose;
-#endif
-static int waittime = 5;               /* time to wait for response (in seconds) */
-static int nflag;                      /* print addresses numerically */
-
-/*
- * Construct an Internet address representation.
- * If the nflag has been supplied, give
- * numeric value, otherwise try for symbolic name.
- */
-static inline void
-inetname(struct sockaddr_in *from)
-{
-       char *cp;
-       struct hostent *hp;
-       static char domain[MAXHOSTNAMELEN + 1];
-       static int first = 1;
-       const char *ina;
-
-       if (first && !nflag) {
-               first = 0;
-               if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
-                   (cp = strchr(domain, '.')))
-                       (void) strcpy(domain, cp + 1);
-               else
-                       domain[0] = 0;
-       }
-       cp = 0;
-       if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
-               hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
-               if (hp) {
-                       if ((cp = strchr(hp->h_name, '.')) &&
-                           !strcmp(cp + 1, domain))
-                               *cp = 0;
-                       cp = (char *)hp->h_name;
-               }
-       }
-       ina = inet_ntoa(from->sin_addr);
-       if (nflag)
-               printf(" %s", ina);
-       else
-               printf(" %s (%s)", (cp ? cp : ina), ina);
-}
-
-static inline void
-print(u_char *buf, int cc, struct sockaddr_in *from)
-{
-       struct ip *ip;
-       int hlen;
-
-       ip = (struct ip *) buf;
-       hlen = ip->ip_hl << 2;
-       cc -= hlen;
-
-       inetname(from);
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-       if (verbose)
-               printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
-#endif
-}
-
-static inline double
-deltaT(struct timeval *t1p, struct timeval *t2p)
-{
-       double dt;
-
-       dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
-            (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
-       return (dt);
-}
-
-static inline int
-wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
-{
-       fd_set fds;
-       static struct timeval wait;
-       int cc = 0;
-       int fromlen = sizeof (*from);
-
-       FD_ZERO(&fds);
-       FD_SET(sock, &fds);
-       if (reset_timer) {
-               /*
-                * traceroute could hang if someone else has a ping
-                * running and our ICMP reply gets dropped but we don't
-                * realize it because we keep waking up to handle those
-                * other ICMP packets that keep coming in.  To fix this,
-                * "reset_timer" will only be true if the last packet that
-                * came in was for us or if this is the first time we're
-                * waiting for a reply since sending out a probe.  Note
-                * that this takes advantage of the select() feature on
-                * Linux where the remaining timeout is written to the
-                * struct timeval area.
-                */
-               wait.tv_sec = waittime;
-               wait.tv_usec = 0;
-       }
-
-       if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
-               cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
-                           (struct sockaddr *)from, &fromlen);
-
-       return(cc);
-}
-
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-/*
- * Convert an ICMP "type" field to a printable string.
- */
-static inline const char *
-pr_type(t)
-       u_char t;
-{
-       static const char * const ttab[] = {
-       "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
-       "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
-       "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
-       "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
-       "Info Reply"
-       };
-
-       if(t > 16)
-               return("OUT-OF-RANGE");
-
-       return(ttab[t]);
-}
-#endif
-
-static inline int
-packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
-{
-       struct icmp *icp;
-       u_char type, code;
-       int hlen;
-       struct ip *ip;
-
-       ip = (struct ip *) buf;
-       hlen = ip->ip_hl << 2;
-       if (cc < hlen + ICMP_MINLEN) {
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-               if (verbose)
-                       printf("packet too short (%d bytes) from %s\n", cc,
-                               inet_ntoa(from->sin_addr));
-#endif
-               return (0);
-       }
-       cc -= hlen;
-       icp = (struct icmp *)(buf + hlen);
-       type = icp->icmp_type; code = icp->icmp_code;
-       if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
-           type == ICMP_UNREACH) {
-               struct ip *hip;
-               struct udphdr *up;
-
-               hip = &icp->icmp_ip;
-               hlen = hip->ip_hl << 2;
-               up = (struct udphdr *)((u_char *)hip + hlen);
-               if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
-                   up->source == htons(ident) &&
-                   up->dest == htons(port+seq))
-                       return (type == ICMP_TIMXCEED? -1 : code+1);
-       }
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-       if (verbose) {
-               int i;
-               u_long *lp = (u_long *)&icp->icmp_ip;
-
-               printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
-                       cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
-                       type, pr_type(type), icp->icmp_code);
-               for (i = 4; i < cc ; i += sizeof(long))
-                       printf("%2d: x%8.8lx\n", i, *lp++);
-       }
-#endif
-       return(0);
-}
-
-static void             /* not inline */
-send_probe(int seq, int ttl)
-{
-       struct opacket *op = outpacket;
-       struct ip *ip = &op->ip;
-       struct udphdr *up = &op->udp;
-       int i;
-       struct timezone tz;
-
-       ip->ip_off = 0;
-       ip->ip_hl = sizeof(*ip) >> 2;
-       ip->ip_p = IPPROTO_UDP;
-       ip->ip_len = datalen;
-       ip->ip_ttl = ttl;
-       ip->ip_v = IPVERSION;
-       ip->ip_id = htons(ident+seq);
-
-       up->source = htons(ident);
-       up->dest = htons(port+seq);
-       up->len = htons((u_short)(datalen - sizeof(struct ip)));
-       up->check = 0;
-
-       op->seq = seq;
-       op->ttl = ttl;
-       (void) gettimeofday(&op->tv, &tz);
-
-       i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
-                  sizeof(struct sockaddr));
-       if (i < 0 || i != datalen)  {
-               if (i<0)
-                       perror("sendto");
-               printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
-                       datalen, i);
-               (void) fflush(stdout);
-       }
-}
-
-
-int
-#ifndef BB_TRACEROUTE
-main(argc, argv)
-#else
-traceroute_main(argc, argv)
-#endif
-       int argc;
-       char *argv[];
-{
-       extern char *optarg;
-       extern int optind;
-       struct hostent *hp;
-       struct sockaddr_in from, *to;
-       int ch, i, on, probe, seq, tos, ttl;
-
-       int options = 0;                /* socket options */
-       char *source = 0;
-       int nprobes = 3;
-
-       on = 1;
-       seq = tos = 0;
-       to = (struct sockaddr_in *)&whereto;
-       while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
-               switch(ch) {
-               case 'd':
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-                       options |= SO_DEBUG;
-#endif
-                       break;
-               case 'm':
-                       max_ttl = atoi(optarg);
-                       if (max_ttl <= 1)
-                               error_msg_and_die("max ttl must be >1.");
-                       break;
-               case 'n':
-                       nflag++;
-                       break;
-               case 'p':
-                       port = atoi(optarg);
-                       if (port < 1)
-                               error_msg_and_die("port must be >0.");
-                       break;
-               case 'q':
-                       nprobes = atoi(optarg);
-                       if (nprobes < 1)
-                               error_msg_and_die("nprobes must be >0.");
-                       break;
-               case 'r':
-                       options |= SO_DONTROUTE;
-                       break;
-               case 's':
-                       /*
-                        * set the ip source address of the outbound
-                        * probe (e.g., on a multi-homed host).
-                        */
-                       source = optarg;
-                       break;
-               case 't':
-                       tos = atoi(optarg);
-                       if (tos < 0 || tos > 255)
-                               error_msg_and_die("tos must be 0 to 255.");
-                       break;
-               case 'v':
-#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
-                       verbose++;
-#endif
-                       break;
-               case 'w':
-                       waittime = atoi(optarg);
-                       if (waittime <= 1)
-                               error_msg_and_die("wait must be >1 sec.");
-                       break;
-               default:
-                       show_usage();
-               }
-       argc -= optind;
-       argv += optind;
-
-       if (argc < 1)
-               show_usage();
-
-       setlinebuf (stdout);
-
-       memset(&whereto, 0, sizeof(struct sockaddr));
-       hp = xgethostbyname(*argv);
-                       to->sin_family = hp->h_addrtype;
-       memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
-                       hostname = (char *)hp->h_name;
-       if (*++argv)
-               datalen = atoi(*argv);
-       if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
-               error_msg_and_die("packet size must be 0 <= s < %d.",
-                   MAXPACKET - sizeof(struct opacket));
-       datalen += sizeof(struct opacket);
-       outpacket = (struct opacket *)xmalloc((unsigned)datalen);
-       memset(outpacket, 0, datalen);
-       outpacket->ip.ip_dst = to->sin_addr;
-       outpacket->ip.ip_tos = tos;
-       outpacket->ip.ip_v = IPVERSION;
-       outpacket->ip.ip_id = 0;
-
-       ident = (getpid() & 0xffff) | 0x8000;
-
-       if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
-               perror_msg_and_die(can_not_create_raw_socket);
-
-       s = create_icmp_socket();
-
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-       if (options & SO_DEBUG)
-               (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
-                                 (char *)&on, sizeof(on));
-#endif
-       if (options & SO_DONTROUTE)
-               (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
-                                 (char *)&on, sizeof(on));
-#ifdef SO_SNDBUF
-       if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
-                      sizeof(datalen)) < 0)
-               perror_msg_and_die("SO_SNDBUF");
-#endif SO_SNDBUF
-#ifdef IP_HDRINCL
-       if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
-                      sizeof(on)) < 0)
-               perror_msg_and_die("IP_HDRINCL");
-#endif IP_HDRINCL
-#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
-       if (options & SO_DEBUG)
-               (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
-                                 (char *)&on, sizeof(on));
-#endif
-       if (options & SO_DONTROUTE)
-               (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
-                                 (char *)&on, sizeof(on));
-
-       if (source) {
-               memset(&from, 0, sizeof(struct sockaddr));
-               from.sin_family = AF_INET;
-               from.sin_addr.s_addr = inet_addr(source);
-               if (from.sin_addr.s_addr == -1)
-                       error_msg_and_die("unknown host %s", source);
-               outpacket->ip.ip_src = from.sin_addr;
-#ifndef IP_HDRINCL
-               if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
-                       perror_msg_and_die("bind");
-#endif IP_HDRINCL
-       }
-
-       fprintf(stderr, "traceroute to %s (%s)", hostname,
-               inet_ntoa(to->sin_addr));
-       if (source)
-               fprintf(stderr, " from %s", source);
-       fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
-
-       for (ttl = 1; ttl <= max_ttl; ++ttl) {
-               u_long lastaddr = 0;
-               int got_there = 0;
-               int unreachable = 0;
-
-               printf("%2d ", ttl);
-               for (probe = 0; probe < nprobes; ++probe) {
-                       int cc, reset_timer;
-                       struct timeval t1, t2;
-                       struct timezone tz;
-                       struct ip *ip;
-
-                       (void) gettimeofday(&t1, &tz);
-                       send_probe(++seq, ttl);
-                       reset_timer = 1;
-                       while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
-                               (void) gettimeofday(&t2, &tz);
-                               if ((i = packet_ok(packet, cc, &from, seq))) {
-                                       reset_timer = 1;
-                                       if (from.sin_addr.s_addr != lastaddr) {
-                                               print(packet, cc, &from);
-                                               lastaddr = from.sin_addr.s_addr;
-                                       }
-                                       printf("  %g ms", deltaT(&t1, &t2));
-                                       switch(i - 1) {
-                                       case ICMP_UNREACH_PORT:
-                                               ip = (struct ip *)packet;
-                                               if (ip->ip_ttl <= 1)
-                                                       printf(" !");
-                                               ++got_there;
-                                               break;
-                                       case ICMP_UNREACH_NET:
-                                               ++unreachable;
-                                               printf(" !N");
-                                               break;
-                                       case ICMP_UNREACH_HOST:
-                                               ++unreachable;
-                                               printf(" !H");
-                                               break;
-                                       case ICMP_UNREACH_PROTOCOL:
-                                               ++got_there;
-                                               printf(" !P");
-                                               break;
-                                       case ICMP_UNREACH_NEEDFRAG:
-                                               ++unreachable;
-                                               printf(" !F");
-                                               break;
-                                       case ICMP_UNREACH_SRCFAIL:
-                                               ++unreachable;
-                                               printf(" !S");
-                                               break;
-                                       }
-                                       break;
-                               } else
-                                       reset_timer = 0;
-                       }
-                       if (cc == 0)
-                               printf(" *");
-                       (void) fflush(stdout);
-               }
-               putchar('\n');
-               if (got_there || unreachable >= nprobes-1)
-                       exit(0);
-       }
-
-       return 0;
-}
diff --git a/busybox/true_false.c b/busybox/true_false.c
deleted file mode 100644 (file)
index 7618343..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini true/false implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdlib.h>
-#include "busybox.h"
-
-
-extern int true_main(int argc, char **argv)
-{
-       return EXIT_SUCCESS;
-}
-
-extern int false_main(int argc, char **argv)
-{
-       return EXIT_FAILURE;
-}
diff --git a/busybox/tty.c b/busybox/tty.c
deleted file mode 100644 (file)
index 4510c29..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini tty implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-extern int tty_main(int argc, char **argv)
-{
-       char *tty;
-
-       if (argc > 1) {
-               if (argv[1][0] != '-' || argv[1][1] != 's')
-                       show_usage();
-       } else {
-               tty = ttyname(0);
-               if (tty)
-                       puts(tty);
-               else
-                       puts("not a tty");
-       }
-       return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/busybox/umount.c b/busybox/umount.c
deleted file mode 100644 (file)
index 74638d2..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini umount implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-/* Teach libc5 about realpath -- it includes it but the 
- * prototype is missing... */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-extern char *realpath(const char *path, char *resolved_path);
-#endif
-
-static const int MNT_FORCE = 1;
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS.  */
-static const int MS_RDONLY = 1;        /* Mount read-only.  */
-
-extern int mount (__const char *__special_file, __const char *__dir,
-                       __const char *__fstype, unsigned long int __rwflag,
-                       __const void *__data);
-extern int umount (__const char *__special_file);
-extern int umount2 (__const char *__special_file, int __flags);
-
-struct _mtab_entry_t {
-       char *device;
-       char *mountpt;
-       struct _mtab_entry_t *next;
-};
-
-static struct _mtab_entry_t *mtab_cache = NULL;
-
-
-
-#if defined BB_FEATURE_MOUNT_FORCE
-static int doForce = FALSE;
-#endif
-#if defined BB_FEATURE_MOUNT_LOOP
-static int freeLoop = TRUE;
-#endif
-#if defined BB_FEATURE_MTAB_SUPPORT
-static int useMtab = TRUE;
-#endif
-static int umountAll = FALSE;
-static int doRemount = FALSE;
-extern const char mtab_file[]; /* Defined in utility.c */
-
-
-
-/* These functions are here because the getmntent functions do not appear
- * to be re-entrant, which leads to all sorts of problems when we try to
- * use them recursively - randolph
- *
- * TODO: Perhaps switch to using Glibc's getmntent_r
- *        -Erik
- */
-static void mtab_read(void)
-{
-       struct _mtab_entry_t *entry = NULL;
-       struct mntent *e;
-       FILE *fp;
-
-       if (mtab_cache != NULL)
-               return;
-
-       if ((fp = setmntent(mtab_file, "r")) == NULL) {
-               error_msg("Cannot open %s", mtab_file);
-               return;
-       }
-       while ((e = getmntent(fp))) {
-               entry = xmalloc(sizeof(struct _mtab_entry_t));
-               entry->device = strdup(e->mnt_fsname);
-               entry->mountpt = strdup(e->mnt_dir);
-               entry->next = mtab_cache;
-               mtab_cache = entry;
-       }
-       endmntent(fp);
-}
-
-static char *mtab_getinfo(const char *match, const char which)
-{
-       struct _mtab_entry_t *cur = mtab_cache;
-
-       while (cur) {
-               if (strcmp(cur->mountpt, match) == 0 ||
-                       strcmp(cur->device, match) == 0) {
-                       if (which == MTAB_GETMOUNTPT) {
-                               return cur->mountpt;
-                       } else {
-#if !defined BB_FEATURE_MTAB_SUPPORT
-                               if (strcmp(cur->device, "/dev/root") == 0) {
-                                       /* Adjusts device to be the real root device,
-                                        * or leaves device alone if it can't find it */
-                                       cur->device = find_real_root_device_name(cur->device);
-                               }
-#endif
-                               return cur->device;
-                       }
-               }
-               cur = cur->next;
-       }
-       return NULL;
-}
-
-static char *mtab_next(void **iter)
-{
-       char *mp;
-
-       if (iter == NULL || *iter == NULL)
-               return NULL;
-       mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
-       *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
-       return mp;
-}
-
-static char *mtab_first(void **iter)
-{
-       struct _mtab_entry_t *mtab_iter;
-
-       if (!iter)
-               return NULL;
-       mtab_iter = mtab_cache;
-       *iter = (void *) mtab_iter;
-       return mtab_next(iter);
-}
-
-/* Don't bother to clean up, since exit() does that 
- * automagically, so we can save a few bytes */
-#ifdef BB_FEATURE_CLEAN_UP
-static void mtab_free(void)
-{
-       struct _mtab_entry_t *this, *next;
-
-       this = mtab_cache;
-       while (this) {
-               next = this->next;
-               if (this->device)
-                       free(this->device);
-               if (this->mountpt)
-                       free(this->mountpt);
-               free(this);
-               this = next;
-       }
-}
-#endif
-
-static int do_umount(const char *name)
-{
-       int status;
-       char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
-
-       if (blockDevice && strcmp(blockDevice, name) == 0)
-               name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
-
-       status = umount(name);
-
-#if defined BB_FEATURE_MOUNT_LOOP
-       if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
-               /* this was a loop device, delete it */
-               del_loop(blockDevice);
-#endif
-#if defined BB_FEATURE_MOUNT_FORCE
-       if (status != 0 && doForce == TRUE) {
-               status = umount2(blockDevice, MNT_FORCE);
-               if (status != 0) {
-                       error_msg_and_die("forced umount of %s failed!", blockDevice);
-               }
-       }
-#endif
-       if (status != 0 && doRemount == TRUE && errno == EBUSY) {
-               status = mount(blockDevice, name, NULL,
-                                          MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
-               if (status == 0) {
-                       error_msg("%s busy - remounted read-only", blockDevice);
-               } else {
-                       error_msg("Cannot remount %s read-only", blockDevice);
-               }
-       }
-       if (status == 0) {
-#if defined BB_FEATURE_MTAB_SUPPORT
-               if (useMtab == TRUE)
-                       erase_mtab(name);
-#endif
-               return (TRUE);
-       }
-       return (FALSE);
-}
-
-static int umount_all(void)
-{
-       int status = TRUE;
-       char *mountpt;
-       void *iter;
-
-       for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
-               /* Never umount /proc on a umount -a */
-               if (strstr(mountpt, "proc")!= NULL)
-                       continue;
-               if (!do_umount(mountpt)) {
-                       /* Don't bother retrying the umount on busy devices */
-                       if (errno == EBUSY) {
-                               perror_msg("%s", mountpt);
-                               status = FALSE;
-                               continue;
-                       }
-                       if (!do_umount(mountpt)) {
-                               printf("Couldn't umount %s on %s: %s\n",
-                                          mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
-                                          strerror(errno));
-                               status = FALSE;
-                       }
-               }
-       }
-       return (status);
-}
-
-extern int umount_main(int argc, char **argv)
-{
-       char path[PATH_MAX];
-
-       if (argc < 2) {
-               show_usage();
-       }
-#ifdef BB_FEATURE_CLEAN_UP
-       atexit(mtab_free);
-#endif
-
-       /* Parse any options */
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*++(*argv))
-                       switch (**argv) {
-                       case 'a':
-                               umountAll = TRUE;
-                               break;
-#if defined BB_FEATURE_MOUNT_LOOP
-                       case 'l':
-                               freeLoop = FALSE;
-                               break;
-#endif
-#ifdef BB_FEATURE_MTAB_SUPPORT
-                       case 'n':
-                               useMtab = FALSE;
-                               break;
-#endif
-#ifdef BB_FEATURE_MOUNT_FORCE
-                       case 'f':
-                               doForce = TRUE;
-                               break;
-#endif
-                       case 'r':
-                               doRemount = TRUE;
-                               break;
-                       case 'v':
-                               break; /* ignore -v */
-                       default:
-                               show_usage();
-                       }
-       }
-
-       mtab_read();
-       if (umountAll == TRUE) {
-               if (umount_all() == TRUE)
-                       return EXIT_SUCCESS;
-               else
-                       return EXIT_FAILURE;
-       }
-       if (realpath(*argv, path) == NULL)
-               perror_msg_and_die("%s", path);
-       if (do_umount(path) == TRUE)
-               return EXIT_SUCCESS;
-       perror_msg_and_die("%s", *argv);
-}
-
diff --git a/busybox/uname.c b/busybox/uname.c
deleted file mode 100644 (file)
index f7e2291..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* uname -- print system information
-   Copyright (C) 1989-1999 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-/* Option              Example
-
-   -s, --sysname       SunOS
-   -n, --nodename      rocky8
-   -r, --release       4.0
-   -v, --version
-   -m, --machine       sun
-   -a, --all           SunOS rocky8 4.0  sun
-
-   The default behavior is equivalent to `-s'.
-
-   David MacKenzie <djm@gnu.ai.mit.edu> */
-
-/* Busyboxed by Erik Andersen */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-
-#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H)
-# include <sys/systeminfo.h>
-#endif
-#include "busybox.h"
-
-static void print_element(unsigned int mask, char *element);
-
-/* Values that are bitwise or'd into `toprint'. */
-/* Operating system name. */
-static const int PRINT_SYSNAME = 1;
-
-/* Node name on a communications network. */
-static const int PRINT_NODENAME = 2;
-
-/* Operating system release. */
-static const int PRINT_RELEASE = 4;
-
-/* Operating system version. */
-static const int PRINT_VERSION = 8;
-
-/* Machine hardware name. */
-static const int PRINT_MACHINE = 16;
-
- /* Host processor type. */
-static const int PRINT_PROCESSOR = 32;
-
-/* Mask indicating which elements of the name to print. */
-static unsigned char toprint;
-
-
-int uname_main(int argc, char **argv)
-{
-       struct utsname name;
-       char processor[256];
-
-#if defined(__sparc__) && defined(__linux__)
-       char *fake_sparc = getenv("FAKE_SPARC");
-#endif
-
-       toprint = 0;
-
-       /* Parse any options */
-       //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*(++(*argv))) {
-                       switch (**argv) {
-                       case 's':
-                               toprint |= PRINT_SYSNAME;
-                               break;
-                       case 'n':
-                               toprint |= PRINT_NODENAME;
-                               break;
-                       case 'r':
-                               toprint |= PRINT_RELEASE;
-                               break;
-                       case 'v':
-                               toprint |= PRINT_VERSION;
-                               break;
-                       case 'm':
-                               toprint |= PRINT_MACHINE;
-                               break;
-                       case 'p':
-                               toprint |= PRINT_PROCESSOR;
-                               break;
-                       case 'a':
-                               toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
-                                                  PRINT_PROCESSOR | PRINT_VERSION |
-                                                  PRINT_MACHINE);
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-
-       if (toprint == 0)
-               toprint = PRINT_SYSNAME;
-
-       if (uname(&name) == -1)
-               perror_msg("cannot get system name");
-
-#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE)
-       if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1)
-               perror_msg("cannot get processor type");
-}
-
-#else
-       strcpy(processor, "unknown");
-#endif
-
-#if defined(__sparc__) && defined(__linux__)
-       if (fake_sparc != NULL
-               && (fake_sparc[0] == 'y'
-                       || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc");
-#endif
-
-       print_element(PRINT_SYSNAME, name.sysname);
-       print_element(PRINT_NODENAME, name.nodename);
-       print_element(PRINT_RELEASE, name.release);
-       print_element(PRINT_VERSION, name.version);
-       print_element(PRINT_MACHINE, name.machine);
-       print_element(PRINT_PROCESSOR, processor);
-
-       return EXIT_SUCCESS;
-}
-
-/* If the name element set in MASK is selected for printing in `toprint',
-   print ELEMENT; then print a space unless it is the last element to
-   be printed, in which case print a newline. */
-
-static void print_element(unsigned int mask, char *element)
-{
-       if (toprint & mask) {
-               toprint &= ~mask;
-               printf("%s%c", element, toprint ? ' ' : '\n');
-       }
-}
diff --git a/busybox/uniq.c b/busybox/uniq.c
deleted file mode 100644 (file)
index 53e3c64..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini uniq implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by John Beppu <beppu@lineo.com>
- * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int print_count;
-static int print_uniq = 1;
-static int print_duplicates = 1;
-
-static void print_line(char *line, int count, FILE *fp)
-{
-       if ((print_duplicates && count > 1) || (print_uniq && count == 1)) {
-               if (print_count)
-                       fprintf(fp, "%7d\t%s", count, line);
-               else
-                       fputs(line, fp);
-       }
-}
-
-int uniq_main(int argc, char **argv)
-{
-       FILE *in = stdin, *out = stdout;
-       char *lastline = NULL, *input;
-       int opt, count = 0;
-
-       /* parse argv[] */
-       while ((opt = getopt(argc, argv, "cdu")) > 0) {
-               switch (opt) {
-                       case 'c':
-                               print_count = 1;
-                               break;
-                       case 'd':
-                               print_duplicates = 1;
-                               print_uniq = 0;
-                               break;
-                       case 'u':
-                               print_duplicates = 0;
-                               print_uniq = 1;
-                               break;
-               }
-       }
-
-       if (argv[optind] != NULL) {
-               in = xfopen(argv[optind], "r");
-               if (argv[optind+1] != NULL)
-                       out = xfopen(argv[optind+1], "w");
-       }
-
-       while ((input = get_line_from_file(in)) != NULL) {
-               if (lastline == NULL || strcmp(input, lastline) != 0) {
-                       print_line(lastline, count, out);
-                       free(lastline);
-                       lastline = input;
-                       count = 0;
-               }
-               count++;
-       }
-       print_line(lastline, count, out);
-       free(lastline);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/update.c b/busybox/update.c
deleted file mode 100644 (file)
index 27a04dd..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini update implementation for busybox; much pasted from update-2.11
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
- * Copyright (c) 2000 by Karl M. Hegbloom <karlheg@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/*
- * Note: This program is only necessary if you are running a 2.0.x (or
- * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically.
- */
-
-#include <sys/param.h>
-#include <sys/syslog.h>
-#include <unistd.h> /* for getopt() */
-#include <stdlib.h>
-
-#if __GNU_LIBRARY__ > 5
-       #include <sys/kdaemon.h>
-#else
-       extern int bdflush (int func, long int data);
-#endif
-
-#include "busybox.h"
-
-static unsigned int sync_duration = 30;
-static unsigned int flush_duration = 5;
-static int use_sync = 0;
-
-extern int update_main(int argc, char **argv)
-{
-       int pid;
-       int opt;
-
-       while ((opt = getopt(argc, argv, "Ss:f:")) > 0) {
-               switch (opt) {
-                       case 'S':
-                               use_sync = 1;
-                               break;
-                       case 's':
-                               sync_duration = atoi(optarg);
-                               break;
-                       case 'f':
-                               flush_duration = atoi(optarg);
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-       
-       if (daemon(0, 1) < 0)
-               perror_msg_and_die("daemon");
-
-#ifdef OPEN_MAX
-       for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
-#else
-       /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */
-       for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid);
-#endif
-
-       /* This is no longer necessary since 1.3.5x, but it will harmlessly
-        * exit if that is the case.
-        */
-
-       /* set the program name that will show up in a 'ps' listing */
-       argv[0] = "bdflush (update)";
-       argv[1] = NULL;
-       argv[2] = NULL;
-       for (;;) {
-               if (use_sync) {
-                       sleep(sync_duration);
-                       sync();
-               } else {
-                       sleep(flush_duration);
-                       if (bdflush(1, 0) < 0) {
-                               openlog("update", LOG_CONS, LOG_DAEMON);
-                               syslog(LOG_INFO,
-                                               "This kernel does not need update(8). Exiting.");
-                               closelog();
-                               return EXIT_SUCCESS;
-                       }
-               }
-       }
-
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/uptime.c b/busybox/uptime.c
deleted file mode 100644 (file)
index 6758d95..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini uptime implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* This version of uptime doesn't display the number of users on the system,
- * since busybox init doesn't mess with utmp.  For folks using utmp that are
- * just dying to have # of users reported, feel free to write it as some type
- * of BB_FEATURE_UTMP_SUPPORT #define
- */
-
-/* getopt not needed */
-
-
-#include <stdio.h>
-#include <time.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static const int FSHIFT = 16;              /* nr of bits of precision */
-#define FIXED_1         (1<<FSHIFT)     /* 1.0 as fixed-point */
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-
-extern int uptime_main(int argc, char **argv)
-{
-       int updays, uphours, upminutes;
-       struct sysinfo info;
-       struct tm *current_time;
-       time_t current_secs;
-
-       time(&current_secs);
-       current_time = localtime(&current_secs);
-
-       sysinfo(&info);
-
-       printf(" %2d:%02d%s  up ", 
-                       current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, 
-                       current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am");
-       updays = (int) info.uptime / (60*60*24);
-       if (updays)
-               printf("%d day%s, ", updays, (updays != 1) ? "s" : "");
-       upminutes = (int) info.uptime / 60;
-       uphours = (upminutes / 60) % 24;
-       upminutes %= 60;
-       if(uphours)
-               printf("%2d:%02d, ", uphours, upminutes);
-       else
-               printf("%d min, ", upminutes);
-
-       printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", 
-                       LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), 
-                       LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), 
-                       LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2]));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/usage.c b/busybox/usage.c
deleted file mode 100644 (file)
index dfea1f9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "busybox.h"
-
-const char usage_messages[] =
-
-#define MAKE_USAGE
-#include "usage.h"
-
-#include "applets.h"
-
-;
diff --git a/busybox/usage.h b/busybox/usage.h
deleted file mode 100644 (file)
index 4d38c43..0000000
+++ /dev/null
@@ -1,1826 +0,0 @@
-#define adjtimex_trivial_usage \
-       "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
-#define adjtimex_full_usage \
-       "Reads and optionally sets system timebase parameters.\n" \
-       "See adjtimex(2).\n\n" \
-       "Options:\n" \
-       "\t-q\t\tquiet mode - do not print\n" \
-       "\t-o offset\ttime offset, microseconds\n" \
-       "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \
-       "\t\t\t(positive values make the system clock run fast)\n" \
-       "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \
-       "\t-p timeconstant\n"
-
-#define ar_trivial_usage \
-       "-[ov][ptx] ARCHIVE FILES"
-#define ar_full_usage \
-       "Extract or list FILES from an ar archive.\n\n" \
-       "Options:\n" \
-       "\t-o\t\tpreserve original dates\n" \
-       "\t-p\t\textract to stdout\n" \
-       "\t-t\t\tlist\n" \
-       "\t-x\t\textract\n" \
-       "\t-v\t\tverbosely list files processed\n"
-
-#define basename_trivial_usage \
-       "FILE [SUFFIX]"
-#define basename_full_usage \
-       "Strips directory path and suffixes from FILE.\n" \
-       "If specified, also removes any trailing SUFFIX."
-#define basename_example_usage \
-       "$ basename /usr/local/bin/foo\n" \
-       "foo\n" \
-       "$ basename /usr/local/bin/\n" \
-       "bin\n" \
-       "$ basename /foo/bar.txt .txt\n" \
-       "bar"
-
-#define cat_trivial_usage \
-       "[FILE]..."
-#define cat_full_usage \
-       "Concatenates FILE(s) and prints them to stdout."
-#define cat_example_usage \
-       "$ cat /proc/uptime\n" \
-       "110716.72 17.67"
-
-#define chgrp_trivial_usage \
-       "[OPTION]... GROUP FILE..."
-#define chgrp_full_usage \
-       "Change the group membership of each FILE to GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chgrp_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chgrp root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chmod_trivial_usage \
-       "[-R] MODE[,MODE]... FILE..."
-#define chmod_full_usage \
-       "Each MODE is one or more of the letters ugoa, one of the\n" \
-       "symbols +-= and one or more of the letters rwxst.\n\n" \
-       "Options:\n" \
-       "\t-R\tChanges files and directories recursively."
-#define chmod_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chmod u+x /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*\n" \
-       "$ chmod 444 /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chown_trivial_usage \
-       "[ -Rh ]...  OWNER[<.|:>[GROUP]] FILE..."
-#define chown_full_usage \
-       "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
-       "\nOptions:\n" \
-       "\t-R\tChanges files and directories recursively.\n" \
-       "\t-h\tDo not dereference symbolic links."
-#define chown_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo\n" \
-       "$ chown root.root /tmp/foo\n" \
-       "ls -l /tmp/foo\n" \
-       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
-
-#define chroot_trivial_usage \
-       "NEWROOT [COMMAND...]"
-#define chroot_full_usage \
-       "Run COMMAND with root directory set to NEWROOT."
-#define chroot_example_usage \
-       "$ ls -l /bin/ls\n" \
-       "lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
-       "$ mount /dev/hdc1 /mnt -t minix\n" \
-       "$ chroot /mnt\n" \
-       "$ ls -l /bin/ls\n" \
-       "-rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*\n"
-
-#define chvt_trivial_usage \
-       "N"
-#define chvt_full_usage \
-       "Changes the foreground virtual terminal to /dev/ttyN"
-
-#define clear_trivial_usage \
-       ""
-#define clear_full_usage \
-       "Clear screen."
-
-#define cmp_trivial_usage \
-       "FILE1 [FILE2]"
-#define cmp_full_usage \
-       "\t-s\tquiet mode - do not print\n" \
-       "Compare files."
-
-#define cp_trivial_usage \
-       "[OPTION]... SOURCE DEST"
-#define cp_full_usage \
-       "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
-       "\n" \
-       "\t-a\tSame as -dpR\n" \
-       "\t-d\tPreserves links\n" \
-       "\t-p\tPreserves file attributes if possible\n" \
-       "\t-f\tforce (implied; ignored) - always set\n" \
-       "\t-R\tCopies directories recursively"
-
-#define cpio_trivial_usage \
-       "-[dimtuv][F cpiofile]"
-#define cpio_full_usage \
-       "Extract or list files from a cpio archive\n" \
-       "Main operation mode:\n" \
-       "\td\t\tmake leading directories\n" \
-       "\ti\t\textract\n" \
-       "\tm\t\tpreserve mtime\n" \
-       "\tt\t\tlist\n" \
-       "\tu\t\tunconditional overwrite\t" \
-       "\tF\t\tinput from file\t"
-       
-#define cut_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define cut_full_usage \
-       "Prints selected fields from each input FILE to standard output.\n\n" \
-       "Options:\n" \
-       "\t-b LIST\t\tOutput only bytes from LIST\n" \
-       "\t-c LIST\t\tOutput only characters from LIST\n" \
-       "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \
-       "\t-s\t\tOutput only the lines containing delimiter\n" \
-       "\t-f N\t\tPrint only these fields\n" \
-       "\t-n\t\tIgnored"
-#define cut_example_usage \
-       "$ echo "Hello world" | cut -f 1 -d ' '\n" \
-       "Hello\n" \
-       "$ echo "Hello world" | cut -f 2 -d ' '\n" \
-       "world\n"
-
-#define date_trivial_usage \
-       "[OPTION]... [+FORMAT]"
-#define date_full_usage \
-       "Displays the current time in the given FORMAT, or sets the system date.\n" \
-       "\nOptions:\n" \
-       "\t-R\t\tOutputs RFC-822 compliant date string\n" \
-       "\t-d STRING\tdisplay time described by STRING, not `now'\n" \
-       "\t-s\t\tSets time described by STRING\n" \
-       "\t-u\t\tPrints or sets Coordinated Universal Time"
-#define date_example_usage \
-       "$ date\n" \
-       "Wed Apr 12 18:52:41 MDT 2000\n"
-
-#define dc_trivial_usage \
-       "expression ..."
-#define dc_full_usage \
-       "This is a Tiny RPN calculator that understands the\n" \
-       "following operations: +, -, /, *, and, or, not, eor.\n" \
-       "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16"
-#define dc_example_usage \
-       "$ dc 2 2 +\n" \
-       "4\n" \
-       "$ dc 8 8 \* 2 2 + /\n" \
-       "16\n" \
-       "$ dc 0 1 and\n" \
-       "0\n" \
-       "$ dc 0 1 or\n" \
-       "1\n" \
-       "$ echo 72 9 div 8 mul | dc\n" \
-       "64\n"
-
-#define dd_trivial_usage \
-       "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \
-       "\t  [seek=N] [conv=notrunc|sync]"
-#define dd_full_usage \
-       "Copy a file, converting and formatting according to options\n\n" \
-       "\tif=FILE\t\tread from FILE instead of stdin\n" \
-       "\tof=FILE\t\twrite to FILE instead of stdout\n" \
-       "\tbs=N\t\tread and write N bytes at a time\n" \
-       "\tcount=N\t\tcopy only N input blocks\n" \
-       "\tskip=N\t\tskip N input blocks\n" \
-       "\tseek=N\t\tskip N output blocks\n" \
-       "\tconv=notrunc\tdon't truncate output file\n" \
-       "\tconv=sync\tpad blocks with zeros\n" \
-       "\n" \
-       "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
-       "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
-#define dd_example_usage \
-       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
-       "4+0 records in\n" \
-       "4+0 records out\n"
-
-#define deallocvt_trivial_usage \
-       "N"
-#define deallocvt_full_usage \
-        "Deallocate unused virtual terminal /dev/ttyN"
-
-
-#ifdef BB_FEATURE_HUMAN_READABLE
-  #define USAGE_HUMAN_READABLE(a) a
-  #define USAGE_NOT_HUMAN_READABLE(a)
-#else
-  #define USAGE_HUMAN_READABLE(a) 
-  #define USAGE_NOT_HUMAN_READABLE(a) a
-#endif
-#define df_trivial_usage \
-       "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
-#define df_full_usage \
-       "Print the filesystem space used and space available.\n\n" \
-       "Options:\n" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define df_example_usage \
-       "$ df\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n" \
-       "/dev/sda1                64216     36364     27852  57% /boot\n" \
-       "$ df /dev/sda3\n" \
-       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
-       "/dev/sda3              8690864   8553540    137324  98% /\n"
-
-#define dirname_trivial_usage \
-       "[FILENAME ...]"
-#define dirname_full_usage \
-       "Strips non-directory suffix from FILENAME"
-#define dirname_example_usage \
-       "$ dirname /tmp/foo\n" \
-       "/tmp\n" \
-       "$ dirname /tmp/foo/\n" \
-       "/tmp\n"
-
-#define dmesg_trivial_usage \
-       "[-c] [-n LEVEL] [-s SIZE]"
-#define dmesg_full_usage \
-       "Prints or controls the kernel ring buffer\n\n" \
-       "Options:\n" \
-       "\t-c\t\tClears the ring buffer's contents after printing\n" \
-       "\t-n LEVEL\tSets console logging level\n" \
-       "\t-s SIZE\t\tUse a buffer of size SIZE"
-
-#define dos2unix_trivial_usage \
-       "[option] [FILE]"
-#define dos2unix_full_usage \
-       "Converts FILE from dos format to unix format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define dpkg_trivial_usage \
-       "-i package_file\n"
-       "[-CPru] package_name"
-#define dpkg_full_usage \
-       "\t-i\tInstall the package\n" \
-       "\t-C\tConfigure an unpackaged package\n" \
-       "\t-P\tPurge all files of a package\n" \
-       "\t-r\tRemove all but the configuration files for a package\n" \
-       "\t-u\tUnpack a package, but dont configure it\n"
-
-#define dpkg_deb_trivial_usage \
-       "[-cefItxX] FILE [argument]"
-#define dpkg_deb_full_usage \
-       "Perform actions on debian packages (.debs)\n\n" \
-       "Options:\n" \
-       "\t-c\tList contents of filesystem tree\n" \
-       "\t-e\tExtract control files to [argument] directory\n" \
-       "\t-f\tDisplay control field name starting with [argument]\n" \
-       "\t-I\tDisplay the control filenamed [argument]\n" \
-       "\t-t\tExtract filesystem tree to stdout in tar format\n" \
-       "\t-x\tExtract packages filesystem tree to directory\n" \
-       "\t-X\tVerbose extract"
-#define dpkg_deb_example_usage \
-       "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
-
-#define du_trivial_usage \
-       "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..."
-#define du_full_usage \
-       "Summarizes disk space used for each FILE and/or directory.\n" \
-       "Disk space is printed in units of 1024 bytes.\n\n" \
-       "Options:\n" \
-       "\t-l\tcount sizes many times if hard linked\n" \
-       "\t-s\tdisplay only a total for each argument" \
-       USAGE_HUMAN_READABLE( \
-       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-m\tprint sizes in megabytes\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\n\t-k\tprint sizes in kilobytes(compatibility)")
-#define du_example_usage \
-       "$ du\n" \
-       "16      ./CVS\n" \
-       "12      ./kernel-patches/CVS\n" \
-       "80      ./kernel-patches\n" \
-       "12      ./tests/CVS\n" \
-       "36      ./tests\n" \
-       "12      ./scripts/CVS\n" \
-       "16      ./scripts\n" \
-       "12      ./docs/CVS\n" \
-       "104     ./docs\n" \
-       "2417    .\n"
-
-#define dumpkmap_trivial_usage \
-       "> keymap"
-#define dumpkmap_full_usage \
-       "Prints out a binary keyboard translation table to standard output."
-#define dumpkmap_example_usage \
-       "$ dumpkmap > keymap\n"
-
-#define dutmp_trivial_usage \
-       "[FILE]"
-#define dutmp_full_usage \
-       "Dump utmp file format (pipe delimited) from FILE\n" \
-       "or stdin to stdout.  (i.e., 'dutmp /var/run/utmp')"
-#define dutmp_example_usage \
-       "$ dutmp /var/run/utmp\n" \
-       "8|7||si|||0|0|0|955637625|760097|0\n" \
-       "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \
-       "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \
-       "8|125||l4|||0|0|0|955637629|998367|0\n" \
-       "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \
-       "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \
-       "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n"
-
-#define echo_trivial_usage \
-       "[-neE] [ARG ...]"
-#define echo_full_usage \
-       "Prints the specified ARGs to stdout\n\n" \
-       "Options:\n" \
-       "\t-n\tsuppress trailing newline\n" \
-       "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
-       "\t-E\tdisable interpretation of backslash-escaped characters"
-#define echo_example_usage \
-       "$ echo "Erik is cool"\n" \
-       "Erik is cool\n" \
-       "$  echo -e "Erik\\nis\\ncool"\n" \
-       "Erik\n" \
-       "is\n" \
-       "cool\n" \
-       "$ echo "Erik\\nis\\ncool"\n" \
-       "Erik\\nis\\ncool\n"
-
-#define env_trivial_usage \
-       "[-iu] [-] [name=value]... [command]"
-#define env_full_usage \
-       "Prints the current environment or runs a program after setting\n" \
-       "up the specified environment.\n\n" \
-       "Options:\n" \
-       "\t-, -i\tstart with an empty environment\n" \
-       "\t-u\tremove variable from the environment\n"
-
-#define expr_trivial_usage \
-       "EXPRESSION"
-#define expr_full_usage \
-       "Prints the value of EXPRESSION to standard output.\n\n" \
-       "EXPRESSION may be:\n" \
-       "\tARG1 |  ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
-       "\tARG1 &  ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
-       "\tARG1 <  ARG2 ARG1 is less than ARG2\n" \
-       "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \
-       "\tARG1 =  ARG2 ARG1 is equal to ARG2\n" \
-       "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \
-       "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \
-       "\tARG1 >  ARG2 ARG1 is greater than ARG2\n" \
-       "\tARG1 +  ARG2 arithmetic sum of ARG1 and ARG2\n" \
-       "\tARG1 -  ARG2 arithmetic difference of ARG1 and ARG2\n" \
-       "\tARG1 *  ARG2 arithmetic product of ARG1 and ARG2\n" \
-       "\tARG1 /  ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \
-       "\tARG1 %  ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \
-       "\tSTRING : REGEXP             anchored pattern match of REGEXP in STRING\n" \
-       "\tmatch STRING REGEXP         same as STRING : REGEXP\n" \
-       "\tsubstr STRING POS LENGTH    substring of STRING, POS counted from 1\n" \
-       "\tindex STRING CHARS          index in STRING where any CHARS is found,\n" \
-       "\t                            or 0\n" \
-       "\tlength STRING               length of STRING\n" \
-       "\tquote TOKEN                 interpret TOKEN as a string, even if\n" \
-       "\t                            it is a keyword like `match' or an\n" \
-       "\t                            operator like `/'\n" \
-       "\t( EXPRESSION )              value of EXPRESSION\n\n" \
-       "Beware that many operators need to be escaped or quoted for shells.\n" \
-       "Comparisons are arithmetic if both ARGs are numbers, else\n" \
-       "lexicographical.  Pattern matches return the string matched between \n" \
-       "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
-       "of characters matched or 0."
-
-#define false_trivial_usage \
-       ""
-#define false_full_usage \
-       "Return an exit code of FALSE (1)."
-#define false_example_usage \
-       "$ false\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#define fbset_trivial_usage \
-       "[options] [mode]"
-#define fbset_full_usage \
-       "Show and modify frame buffer settings"
-#define fbset_example_usage \
-       "$ fbset\n" \
-       "mode "1024x768-76"\n" \
-       "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
-       "\tgeometry 1024 768 1024 768 16\n" \
-       "\ttimings 12714 128 32 16 4 128 4\n" \
-       "\taccel false\n" \
-       "\trgba 5/11,6/5,5/0,0/0\n" \
-       "endmode\n"
-
-#define fdflush_trivial_usage \
-       "DEVICE"
-#define fdflush_full_usage \
-       "Forces floppy disk drive to detect disk change"
-
-#ifdef BB_FEATURE_FIND_TYPE
-  #define USAGE_FIND_TYPE(a) a
-#else
-  #define USAGE_FIND_TYPE(a)
-#endif
-#ifdef BB_FEATURE_FIND_PERM
-  #define USAGE_FIND_PERM(a) a
-#else
-  #define USAGE_FIND_PERM(a)
-#endif
-#ifdef BB_FEATURE_FIND_MTIME
-  #define USAGE_FIND_MTIME(a) a
-#else
-  #define USAGE_FIND_MTIME(a)
-#endif
-
-#define find_trivial_usage \
-       "[PATH...] [EXPRESSION]"
-#define find_full_usage \
-       "Search for files in a directory hierarchy.  The default PATH is\n" \
-       "the current directory; default EXPRESSION is '-print'\n" \
-       "\nEXPRESSION may consist of:\n" \
-       "\t-follow\t\tDereference symbolic links.\n" \
-       "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
-       "\t-print\t\tPrint (default and assumed).\n" \
-       USAGE_FIND_TYPE( \
-       "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
-) USAGE_FIND_PERM( \
-       "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \
-) USAGE_FIND_MTIME( \
-       "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days")
-#define find_example_usage \
-       "$ find / -name /etc/passwd\n" \
-       "/etc/passwd\n"
-
-#define free_trivial_usage \
-       ""
-#define free_full_usage \
-       "Displays the amount of free and used system memory"
-#define free_example_usage \
-       "$ free\n" \
-       "              total         used         free       shared      buffers\n" \
-       "  Mem:       257628       248724         8904        59644        93124\n" \
-       " Swap:       128516         8404       120112\n" \
-       "Total:       386144       257128       129016\n" \
-
-#define freeramdisk_trivial_usage \
-       "DEVICE"
-#define freeramdisk_full_usage \
-       "Frees all memory used by the specified ramdisk."
-#define freeramdisk_example_usage \
-       "$ freeramdisk /dev/ram2\n"
-
-#define fsck_minix_trivial_usage \
-       "[-larvsmf] /dev/name"
-#define fsck_minix_full_usage \
-       "Performs a consistency check for MINIX filesystems.\n\n" \
-       "Options:\n" \
-       "\t-l\tLists all filenames\n" \
-       "\t-r\tPerform interactive repairs\n" \
-       "\t-a\tPerform automatic repairs\n" \
-       "\t-v\tverbose\n" \
-       "\t-s\tOutputs super-block information\n" \
-       "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
-       "\t-f\tForce file system check."
-
-#define getopt_trivial_usage \
-       "[OPTIONS]..."
-#define getopt_full_usage \
-       "Parse command options\n" \
-       "\t-a, --alternative            Allow long options starting with single -\n" \
-       "\t-l, --longoptions=longopts   Long options to be recognized\n" \
-       "\t-n, --name=progname          The name under which errors are reported\n" \
-       "\t-o, --options=optstring      Short options to be recognized\n" \
-       "\t-q, --quiet                  Disable error reporting by getopt(3)\n" \
-       "\t-Q, --quiet-output           No normal output\n" \
-       "\t-s, --shell=shell            Set shell quoting conventions\n" \
-       "\t-T, --test                   Test for getopt(1) version\n" \
-       "\t-u, --unqote                 Do not quote the output"
-#define getopt_example_usage \
-        "$ cat getopt.test\n" \
-        "#!/bin/sh\n" \
-        "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
-        "       -n 'example.busybox' -- "$@"`\n" \
-        "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
-        "eval set -- "$GETOPT"\n" \
-        "while true ; do\n" \
-        " case $1 in\n" \
-        "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
-        "   -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \
-        "   -c|--c-long)\n" \
-        "     case "$2" in\n" \
-        "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
-        "       *)  echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \
-        "     esac ;;\n" \
-        "   --) shift ; break ;;\n" \
-        "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
-        " esac\n" \
-        "done\n"
-
-#define grep_trivial_usage \
-       "[-ihHnqvs] PATTERN [FILEs...]"
-#define grep_full_usage \
-       "Search for PATTERN in each FILE or standard input.\n\n" \
-       "Options:\n" \
-       "\t-H\tprefix output lines with filename where match was found\n" \
-       "\t-h\tsuppress the prefixing filename on output\n" \
-       "\t-i\tignore case distinctions\n" \
-       "\t-l\tlist names of files that match\n" \
-       "\t-n\tprint line number with output lines\n" \
-       "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \
-       "\t-v\tselect non-matching lines\n" \
-       "\t-s\tsuppress file open/read error messages"
-#define grep_example_usage \
-       "$ grep root /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "$ grep ^[rR]oo. /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n"
-
-#define gunzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gunzip_full_usage \
-       "Uncompress FILE (or standard input if FILE is '-').\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output\n" \
-       "\t-t\tTest compressed file integrity"
-#define gunzip_example_usage \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
-       "$ ls -la /tmp/BusyBox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
-
-#define gzip_trivial_usage \
-       "[OPTION]... FILE"
-#define gzip_full_usage \
-       "Compress FILE with maximum compression.\n" \
-       "When FILE is '-', reads standard input.  Implies -c.\n\n" \
-       "Options:\n" \
-       "\t-c\tWrite output to standard output instead of FILE.gz\n" \
-       "\t-d\tdecompress"
-#define gzip_example_usage \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
-       "$ gzip /tmp/busybox.tar\n" \
-       "$ ls -la /tmp/busybox*\n" \
-       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
-
-#define halt_trivial_usage \
-       ""
-#define halt_full_usage \
-       "Halt the system."
-
-#define head_trivial_usage \
-       "[OPTION] [FILE]..."
-#define head_full_usage \
-       "Print first 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-n NUM\t\tPrint first NUM lines instead of first 10"
-#define head_example_usage \
-       "$ head -n 2 /etc/passwd\n" \
-       "root:x:0:0:root:/root:/bin/bash\n" \
-       "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
-
-#define hostid_trivial_usage \
-       ""
-#define hostid_full_usage \
-       "Print out a unique 32-bit identifier for the machine."
-
-#define hostname_trivial_usage \
-       "[OPTION] {hostname | -F FILE}"
-#define hostname_full_usage \
-       "Get or set the hostname or DNS domain name. If a hostname is given\n" \
-       "(or FILE with the -F parameter), the host name will be set.\n\n" \
-       "Options:\n" \
-       "\t-s\t\tShort\n" \
-       "\t-i\t\tAddresses for the hostname\n" \
-       "\t-d\t\tDNS domain name\n" \
-       "\t-F, --file FILE\tUse the contents of FILE to specify the hostname"
-#define hostname_example_usage \
-       "$ hostname\n" \
-       "sage \n"
-
-#define id_trivial_usage \
-       "[OPTIONS]... [USERNAME]"
-#define id_full_usage \
-       "Print information for USERNAME or the current user\n\n" \
-       "Options:\n" \
-       "\t-g\tprints only the group ID\n" \
-       "\t-u\tprints only the user ID\n" \
-       "\t-n\tprint a name instead of a number (with for -ug)\n" \
-       "\t-r\tprints the real user ID instead of the effective ID (with -ug)"
-#define id_example_usage \
-       "$ id\n" \
-       "uid=1000(andersen) gid=1000(andersen)\n"
-
-#ifdef BB_FEATURE_IFCONFIG_SLIP
-  #define USAGE_SIOCSKEEPALIVE(a) a
-#else
-  #define USAGE_SIOCSKEEPALIVE(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
-  #define USAGE_IFCONFIG_MII(a) a
-#else
-  #define USAGE_IFCONFIG_MII(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_HW
-  #define USAGE_IFCONFIG_HW(a) a
-#else
-  #define USAGE_IFCONFIG_HW(a)
-#endif
-#ifdef BB_FEATURE_IFCONFIG_STATUS
-  #define USAGE_IFCONFIG_OPT_A(a) a
-#else
-  #define USAGE_IFCONFIG_OPT_A(a)
-#endif
-
-#define ifconfig_trivial_usage \
-       USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
-#define ifconfig_full_usage \
-       "configure a network interface\n\n" \
-       "Options:\n" \
-       "\t[[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n" \
-       "\t[netmask <address>]  [dstaddr <address>]\n" \
-       USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
-       "\t" USAGE_IFCONFIG_HW("[hw ether <address>]  ") \
-    "[metric <NN>]  [mtu <NN>]\n" \
-       "\t[[-]trailers]  [[-]arp]  [[-]allmulti]\n" \
-       "\t[multicast]  [[-]promisc]  [txqueuelen <NN>]  [[-]dynamic]\n" \
-       USAGE_IFCONFIG_MII("\t[mem_start <NN>]  [io_addr <NN>]  [irq <NN>]\n") \
-       "\t[up|down] ..."
-
-#define init_trivial_usage \
-       ""
-#define init_full_usage \
-       "Init is the parent of all processes."
-#define init_notes_usage \
-"This version of init is designed to be run only by the kernel.\n" \
-"\n" \
-"BusyBox init doesn't support multiple runlevels.  The runlevels field of\n" \
-"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \
-"runlevels, use sysvinit.\n" \
-"\n" \
-"BusyBox init works just fine without an inittab.  If no inittab is found, \n" \
-"it has the following default behavior:\n" \
-"\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      ::askfirst:/bin/sh\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/sbin/swapoff -a\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"\n" \
-"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
-"\n" \
-"      tty2::askfirst:/bin/sh\n" \
-"      tty3::askfirst:/bin/sh\n" \
-"      tty4::askfirst:/bin/sh\n" \
-"\n" \
-"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
-"\n" \
-"      <id>:<runlevels>:<action>:<process>\n" \
-"\n" \
-"      <id>: \n" \
-"\n" \
-"              WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
-"              The id field is used by BusyBox init to specify the controlling tty for\n" \
-"              the specified process to run on.  The contents of this field are\n" \
-"              appended to "/dev/" and used as-is.  There is no need for this field to\n" \
-"              be unique, although if it isn't you may have strange results.  If this\n" \
-"              field is left blank, the controlling tty is set to the console.  Also\n" \
-"              note that if BusyBox detects that a serial console is in use, then only\n" \
-"              entries whose controlling tty is either the serial console or /dev/null\n" \
-"              will be run.  BusyBox init does nothing with utmp.  We don't need no\n" \
-"              stinkin' utmp.\n" \
-"\n" \
-"      <runlevels>: \n" \
-"\n" \
-"              The runlevels field is completely ignored.\n" \
-"\n" \
-"      <action>: \n" \
-"\n" \
-"              Valid actions include: sysinit, respawn, askfirst, wait, \n" \
-"              once, ctrlaltdel, and shutdown.\n" \
-"\n" \
-"              The available actions can be classified into two groups: actions\n" \
-"              that are run only once, and actions that are re-run when the specified\n" \
-"              process exits.\n" \
-"\n" \
-"              Run only-once actions:\n" \
-"\n" \
-"                      'sysinit' is the first item run on boot.  init waits until all\n" \
-"                      sysinit actions are completed before continuing.  Following the\n" \
-"                      completion of all sysinit actions, all 'wait' actions are run.\n" \
-"                      'wait' actions, like  'sysinit' actions, cause init to wait until\n" \
-"                      the specified task completes.  'once' actions are asynchronous,\n" \
-"                      therefore, init does not wait for them to complete.  'ctrlaltdel'\n" \
-"                      actions are run when the system detects that someone on the system\n" \
-"                       console has pressed the CTRL-ALT-DEL key combination.  Typically one\n" \
-"                       wants to run 'reboot' at this point to cause the system to reboot.\n" \
-"                      Finally the 'shutdown' action specifies the actions to taken when\n" \
-"                       init is told to reboot.  Unmounting filesystems and disabling swap\n" \
-"                       is a very good here\n" \
-"\n" \
-"              Run repeatedly actions:\n" \
-"\n" \
-"                      'respawn' actions are run after the 'once' actions.  When a process\n" \
-"                      started with a 'respawn' action exits, init automatically restarts\n" \
-"                      it.  Unlike sysvinit, BusyBox init does not stop processes from\n" \
-"                      respawning out of control.  The 'askfirst' actions acts just like\n" \
-"                      respawn, except that before running the specified process it\n" \
-"                      displays the line "Please press Enter to activate this console."\n" \
-"                      and then waits for the user to press enter before starting the\n" \
-"                      specified process.  \n" \
-"\n" \
-"              Unrecognized actions (like initdefault) will cause init to emit an\n" \
-"              error message, and then go along with its business.  All actions are\n" \
-"              run in the reverse order from how they appear in /etc/inittab.\n" \
-"\n" \
-"      <process>: \n" \
-"\n" \
-"              Specifies the process to be executed and it's command line.\n" \
-"\n" \
-"Example /etc/inittab file:\n" \
-"\n" \
-"      # This is run first except when booting in single-user mode.\n" \
-"      #\n" \
-"      ::sysinit:/etc/init.d/rcS\n" \
-"      \n" \
-"      # /bin/sh invocations on selected ttys\n" \
-"      #\n" \
-"      # Start an "askfirst" shell on the console (whatever that may be)\n" \
-"      ::askfirst:-/bin/sh\n" \
-"      # Start an "askfirst" shell on /dev/tty2-4\n" \
-"      tty2::askfirst:-/bin/sh\n" \
-"      tty3::askfirst:-/bin/sh\n" \
-"      tty4::askfirst:-/bin/sh\n" \
-"      \n" \
-"      # /sbin/getty invocations for selected ttys\n" \
-"      #\n" \
-"      tty4::respawn:/sbin/getty 38400 tty5\n" \
-"      tty5::respawn:/sbin/getty 38400 tty6\n" \
-"      \n" \
-"      \n" \
-"      # Example of how to put a getty on a serial line (for a terminal)\n" \
-"      #\n" \
-"      #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
-"      #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
-"      #\n" \
-"      # Example how to put a getty on a modem line.\n" \
-"      #::respawn:/sbin/getty 57600 ttyS2\n" \
-"      \n" \
-"      # Stuff to do before rebooting\n" \
-"      ::ctrlaltdel:/sbin/reboot\n" \
-"      ::shutdown:/bin/umount -a -r\n" \
-"      ::shutdown:/sbin/swapoff -a\n"
-
-#define insmod_trivial_usage \
-       "[OPTION]... MODULE [symbol=value]..."
-#define insmod_full_usage \
-       "Loads the specified kernel modules into the kernel.\n\n" \
-       "Options:\n" \
-       "\t-f\tForce module to load into the wrong kernel version.\n" \
-       "\t-k\tMake module autoclean-able.\n" \
-       "\t-v\tverbose output\n"  \
-       "\t-L\tLock to prevent simultaneous loads of a module\n" \
-       "\t-x\tdo not export externs"
-
-#define kill_trivial_usage \
-       "[-signal] process-id [process-id ...]"
-#define kill_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define kill_example_usage \
-       "$ ps | grep apache\n" \
-       "252 root     root     S [apache]\n" \
-       "263 www-data www-data S [apache]\n" \
-       "264 www-data www-data S [apache]\n" \
-       "265 www-data www-data S [apache]\n" \
-       "266 www-data www-data S [apache]\n" \
-       "267 www-data www-data S [apache]\n" \
-       "$ kill 252\n"
-
-#define killall_trivial_usage \
-       "[-signal] process-name [process-name ...]"
-#define killall_full_usage \
-       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
-       "Options:\n" \
-       "\t-l\tList all signal names and numbers."
-#define killall_example_usage \
-       "$ killall apache\n" 
-
-#define klogd_trivial_usage \
-       "-n"
-#define klogd_full_usage \
-       "Kernel logger.\n"\
-       "Options:\n"\
-       "\t-n\tRun as a foreground process."
-
-#define length_trivial_usage \
-       "STRING"
-#define length_full_usage \
-       "Prints out the length of the specified STRING."
-#define length_example_usage \
-       "$ length Hello\n" \
-       "5\n"
-
-#define ln_trivial_usage \
-       "[OPTION] TARGET... LINK_NAME|DIRECTORY"
-#define ln_full_usage \
-       "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
-       "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-s\tmake symbolic links instead of hard links\n" \
-       "\t-f\tremove existing destination files\n" \
-       "\t-n\tno dereference symlinks - treat like normal file"
-#define ln_example_usage \
-       "$ ln -s BusyBox /tmp/ls\n" \
-       "$ ls -l /tmp/ls\n" \
-       "lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -> BusyBox*\n" 
-
-#define loadacm_trivial_usage \
-       "< mapfile"
-#define loadacm_full_usage \
-       "Loads an acm from standard input."
-#define loadacm_example_usage \
-       "$ loadacm < /etc/i18n/acmname\n" 
-
-#define loadfont_trivial_usage \
-       "< font"
-#define loadfont_full_usage \
-       "Loads a console font from standard input."
-#define loadfont_example_usage \
-       "$ loadfont < /etc/i18n/fontname\n" 
-
-#define loadkmap_trivial_usage \
-       "< keymap"
-#define loadkmap_full_usage \
-       "Loads a binary keyboard translation table from standard input."
-#define loadkmap_example_usage \
-       "$ loadkmap < /etc/i18n/lang-keymap\n" 
-
-#define logger_trivial_usage \
-       "[OPTION]... [MESSAGE]"
-#define logger_full_usage \
-       "Write MESSAGE to the system log.  If MESSAGE is omitted, log stdin.\n\n" \
-       "Options:\n" \
-       "\t-s\tLog to stderr as well as the system log.\n" \
-       "\t-t\tLog using the specified tag (defaults to user name).\n" \
-       "\t-p\tEnter the message with the specified priority.\n" \
-       "\t\tThis may be numerical or a ``facility.level'' pair."
-#define logger_example_usage \
-       "$ logger "hello"\n" 
-
-#define logname_trivial_usage \
-       ""
-#define logname_full_usage \
-       "Print the name of the current user."
-#define logname_example_usage \
-       "$ logname\n" \
-       "root\n" 
-
-#define logread_trivial_usage \
-        ""
-
-#define logread_full_usage \
-        "Shows the messages from syslogd (using circular buffer)."
-
-#ifdef BB_FEATURE_LS_TIMESTAMPS
-  #define USAGE_LS_TIMESTAMPS(a) a
-#else
-  #define USAGE_LS_TIMESTAMPS(a)
-#endif
-#ifdef BB_FEATURE_LS_FILETYPES
-  #define USAGE_LS_FILETYPES(a) a
-#else
-  #define USAGE_LS_FILETYPES(a)
-#endif
-#ifdef BB_FEATURE_LS_FOLLOWLINKS
-  #define USAGE_LS_FOLLOWLINKS(a) a
-#else
-  #define USAGE_LS_FOLLOWLINKS(a)
-#endif
-#ifdef BB_FEATURE_LS_RECURSIVE
-  #define USAGE_LS_RECURSIVE(a) a
-#else
-  #define USAGE_LS_RECURSIVE(a)
-#endif
-#ifdef BB_FEATURE_LS_SORTFILES
-  #define USAGE_LS_SORTFILES(a) a
-#else
-  #define USAGE_LS_SORTFILES(a)
-#endif
-#ifdef BB_FEATURE_AUTOWIDTH
-  #define USAGE_AUTOWIDTH(a) a
-#else
-  #define USAGE_AUTOWIDTH(a)
-#endif
-#define ls_trivial_usage \
-       "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]"
-#define ls_full_usage \
-       "List directory contents\n\n" \
-       "Options:\n" \
-       "\t-1\tlist files in a single column\n" \
-       "\t-A\tdo not list implied . and ..\n" \
-       "\t-a\tdo not hide entries starting with .\n" \
-       "\t-C\tlist entries by columns\n" \
-       USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \
-       "\t-d\tlist directory entries instead of contents\n" \
-       USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \
-       USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \
-       "\t-i\tlist the i-node for each file\n" \
-       "\t-l\tuse a long listing format\n" \
-       "\t-n\tlist numeric UIDs and GIDs instead of names\n" \
-       USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \
-       USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \
-       USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \
-       USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \
-       USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \
-       "\t-s\tlist the size of each file, in blocks\n" \
-       USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \
-       USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \
-       USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \
-       USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \
-       USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \
-       "\t-x\tlist entries by lines instead of by columns\n" \
-       USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \
-       USAGE_HUMAN_READABLE( \
-       "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
-       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
-       "\t-k\tprint sizes in kilobytes(compatibility)") 
-
-#define lsmod_trivial_usage \
-       ""
-#define lsmod_full_usage \
-       "List the currently loaded kernel modules."
-
-#define makedevs_trivial_usage \
-       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
-#define makedevs_full_usage \
-       "Creates a range of block or character special files\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
-       "FIRST specifies the number appended to NAME to create the first device.\n" \
-       "LAST specifies the number of the last item that should be created.\n" \
-       "If 's' is the last argument, the base device is created as well.\n\n" \
-       "For example:\n" \
-       "\tmakedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63\n" \
-       "\tmakedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8"
-#define makedevs_example_usage \
-       "$ makedevs /dev/ttyS c 4 66 2 63\n" \
-       "[creates ttyS2-ttyS63]\n" \
-       "$ makedevs /dev/hda b 3 0 0 8 s\n" \
-       "[creates hda,hda1-hda8]\n" 
-
-#define md5sum_trivial_usage \
-       "[OPTION] [FILE]...\n" \
-       "or: md5sum [OPTION] -c [FILE]"
-#define md5sum_full_usage \
-       "Print or check MD5 checksums.\n\n" \
-       "Options:\n" \
-       "With no FILE, or when FILE is -, read standard input.\n\n" \
-       "\t-b\tread files in binary mode\n" \
-       "\t-c\tcheck MD5 sums against given list\n" \
-       "\t-t\tread files in text mode (default)\n" \
-       "\t-g\tread a string\n" \
-       "\nThe following two options are useful only when verifying checksums:\n" \
-       "\t-s\tdon't output anything, status code shows success\n" \
-       "\t-w\twarn about improperly formated MD5 checksum lines"
-#define md5sum_example_usage \
-       "$ md5sum < busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003\n" \
-       "$ md5sum busybox\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "$ md5sum -c -\n" \
-       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
-       "busybox: OK\n" \
-       "^D\n"
-
-#define mkdir_trivial_usage \
-       "[OPTION] DIRECTORY..."
-#define mkdir_full_usage \
-       "Create the DIRECTORY(ies) if they do not already exist\n\n" \
-       "Options:\n" \
-       "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \
-       "\t-p\tno error if existing, make parent directories as needed"
-#define mkdir_example_usage \
-       "$ mkdir /tmp/foo\n" \
-       "$ mkdir /tmp/foo\n" \
-       "/tmp/foo: File exists\n" \
-       "$ mkdir /tmp/foo/bar/baz\n" \
-       "/tmp/foo/bar/baz: No such file or directory\n" \
-       "$ mkdir -p /tmp/foo/bar/baz\n" 
-
-#define mkfifo_trivial_usage \
-       "[OPTIONS] name"
-#define mkfifo_full_usage \
-       "Creates a named pipe (identical to 'mknod name p')\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the pipe using the specified mode (default a=rw)"
-
-#define mkfs_minix_trivial_usage \
-       "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
-#define mkfs_minix_full_usage \
-       "Make a MINIX filesystem.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck the device for bad blocks\n" \
-       "\t-n [14|30]\tSpecify the maximum length of filenames\n" \
-       "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \
-       "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \
-       "\t-v\t\tMake a Minix version 2 filesystem"
-
-#define mknod_trivial_usage \
-       "[OPTIONS] NAME TYPE MAJOR MINOR"
-#define mknod_full_usage \
-       "Create a special file (block, character, or pipe).\n\n" \
-       "Options:\n" \
-       "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
-       "TYPEs include:\n" \
-       "\tb:\tMake a block (buffered) device.\n" \
-       "\tc or u:\tMake a character (un-buffered) device.\n" \
-       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
-#define mknod_example_usage \
-       "$ mknod /dev/fd0 b 2 0 \n" \
-       "$ mknod -m 644 /tmp/pipe p\n" 
-
-#define mkswap_trivial_usage \
-       "[-c] [-v0|-v1] device [block-count]"
-#define mkswap_full_usage \
-       "Prepare a disk partition to be used as a swap partition.\n\n" \
-       "Options:\n" \
-       "\t-c\t\tCheck for read-ability.\n" \
-       "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
-       "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
-       "\tblock-count\tNumber of block to use (default is entire partition)."
-
-#define mktemp_trivial_usage \
-       "[-q] TEMPLATE"
-#define mktemp_full_usage \
-       "Creates a temporary file with its name based on TEMPLATE.\n" \
-       "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)."
-#define mktemp_example_usage \
-       "$ mktemp /tmp/temp.XXXXXX\n" \
-       "/tmp/temp.mWiLjM\n" \
-       "$ ls -la /tmp/temp.mWiLjM\n" \
-       "-rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM\n" 
-
-#define modprobe_trivial_usage \
-       "[FILE ...]"
-#define modprobe_full_usage \
-       "Used for hight level module loading and unloading."
-#define modprobe_example_usage \
-       "$ modprobe cdrom\n" 
-
-#define more_trivial_usage \
-       "[FILE ...]"
-#define more_full_usage \
-       "More is a filter for viewing FILE one screenful at a time."
-#define more_example_usage \
-       "$ dmesg | more\n" 
-
-#ifdef BB_FEATURE_MOUNT_LOOP
-  #define USAGE_MOUNT_LOOP(a) a
-#else
-  #define USAGE_MOUNT_LOOP(a)
-#endif
-#ifdef BB_FEATURE_MTAB_SUPPORT
-  #define USAGE_MTAB(a) a
-#else
-  #define USAGE_MTAB(a)
-#endif
-#define mount_trivial_usage \
-       "[flags] DEVICE NODE [-o options,more-options]"
-#define mount_full_usage \
-       "Mount a filesystem\n\n" \
-       "Flags:\n"  \
-       "\t-a:\t\tMount all filesystems in fstab.\n" \
-       USAGE_MTAB( \
-       "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
-       "\t-n:\t\tDon't write a mount table entry.\n" \
-       ) \
-       "\t-o option:\tOne of many filesystem options, listed below.\n" \
-       "\t-r:\t\tMount the filesystem read-only.\n" \
-       "\t-t fs-type:\tSpecify the filesystem type.\n" \
-       "\t-w:\t\tMount for reading and writing (default).\n" \
-       "\n" \
-       "Options for use with the \"-o\" flag:\n" \
-       "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
-       "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
-       "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
-       "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
-       USAGE_MOUNT_LOOP( \
-       "\tloop:\t\tMounts a file via loop device.\n" \
-       ) \
-       "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
-       "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
-       "\tro/rw:\t\tMount for read-only / read-write.\n" \
-       "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
-       "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
-       "You'll have to see the written documentation for those filesystems."
-#define mount_example_usage \
-       "$ mount\n" \
-       "/dev/hda3 on / type minix (rw)\n" \
-       "proc on /proc type proc (rw)\n" \
-       "devpts on /dev/pts type devpts (rw)\n" \
-       "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
-       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" 
-
-#define mt_trivial_usage \
-       "[-f device] opcode value"
-#define mt_full_usage \
-       "Control magnetic tape drive operation\n" \
-       "\nAvailable Opcodes:\n\n" \
-       "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
-       "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
-       "ras3 reset retension rew rewoffline seek setblk setdensity\n" \
-       "setpart tell unload unlock weof wset"
-
-#define mv_trivial_usage \
-       "SOURCE DEST\n" \
-       "or: mv SOURCE... DIRECTORY"
-#define mv_full_usage \
-       "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY."
-#define mv_example_usage \
-       "$ mv /tmp/foo /bin/bar\n" 
-
-#define nc_trivial_usage \
-       "[IP] [port]" 
-#define nc_full_usage \
-       "Netcat opens a pipe to IP:port"
-#define nc_example_usage \
-       "$ nc foobar.somedomain.com 25\n" \
-       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
-       "help\n" \
-       "214-Commands supported:\n" \
-       "214-    HELO EHLO MAIL RCPT DATA AUTH\n" \
-       "214     NOOP QUIT RSET HELP\n" \
-       "quit\n" \
-       "221 foobar closing connection\n" 
-
-#define nslookup_trivial_usage \
-       "[HOST] [SERVER]"
-#define nslookup_full_usage \
-       "Queries the nameserver for the IP address of the given HOST\n" \
-       "optionally using a specified DNS server"
-#define nslookup_example_usage \
-       "$ nslookup localhost\n" \
-       "Server:     default\n" \
-       "Address:    default\n" \
-       "\n" \
-       "Name:       debian\n" \
-       "Address:    127.0.0.1\n" 
-
-#define pidof_trivial_usage \
-       "process-name [process-name ...]"
-#define pidof_full_usage \
-       "Lists the PIDs of all processes with names that match the names on the command line"
-#define pidof_example_usage \
-       "$ pidof init\n" \
-       "1\n"
-
-#ifndef BB_FEATURE_FANCY_PING
-#define ping_trivial_usage "host"
-#define ping_full_usage    "Send ICMP ECHO_REQUEST packets to network hosts"
-#else
-#define ping_trivial_usage \
-       "[OPTION]... host"
-#define ping_full_usage \
-       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
-       "Options:\n" \
-       "\t-c COUNT\tSend only COUNT pings.\n" \
-       "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
-       "\t-q\t\tQuiet mode, only displays output at start\n" \
-       "\t\t\tand when finished."
-#endif
-#define ping_example_usage \
-       "$ ping localhost\n" \
-       "PING slag (127.0.0.1): 56 data bytes\n" \
-       "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
-       "\n" \
-       "--- debian ping statistics ---\n" \
-       "1 packets transmitted, 1 packets received, 0% packet loss\n" \
-       "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 
-
-#define pivot_root_trivial_usage \
-       "NEW_ROOT PUT_OLD"
-#define pivot_root_full_usage \
-       "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
-       "the new root file system."
-
-#define poweroff_trivial_usage \
-       ""
-#define poweroff_full_usage \
-       "Halt the system and request that the kernel shut off the power."
-
-#define printf_trivial_usage \
-       "FORMAT [ARGUMENT...]"
-#define printf_full_usage \
-       "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
-       "Where FORMAT controls the output exactly as in C printf."
-#define printf_example_usage \
-       "$ printf "Val=%d\\n" 5\n" \
-       "Val=5\n" 
-
-#define ps_trivial_usage \
-       ""
-#define ps_full_usage \
-       "Report process status\n" \
-       "\nThis version of ps accepts no options."
-#define ps_example_usage \
-       "$ ps\n" \
-       "  PID  Uid      Gid State Command\n" \
-       "    1 root     root     S init\n" \
-       "    2 root     root     S [kflushd]\n" \
-       "    3 root     root     S [kupdate]\n" \
-       "    4 root     root     S [kpiod]\n" \
-       "    5 root     root     S [kswapd]\n" \
-       "  742 andersen andersen S [bash]\n" \
-       "  743 andersen andersen S -bash\n" \
-       "  745 root     root     S [getty]\n" \
-       " 2990 andersen andersen R ps\n"
-
-#define pwd_trivial_usage \
-       ""
-#define pwd_full_usage \
-       "Print the full filename of the current working directory."
-#define pwd_example_usage \
-       "$ pwd\n" \
-       "/root\n"
-
-#define rdate_trivial_usage \
-       "[OPTION] HOST"
-#define rdate_full_usage \
-       "Get and possibly set the system date and time from a remote HOST.\n\n" \
-       "Options:\n" \
-       "\t-s\tSet the system date and time (default).\n" \
-       "\t-p\tPrint the date and time."
-
-#define readlink_trivial_usage \
-       ""
-#define readlink_full_usage \
-       "Read a symbolic link."
-
-#define reboot_trivial_usage \
-       ""
-#define reboot_full_usage \
-       "Reboot the system."
-
-#define renice_trivial_usage \
-       "priority pid [pid ...]"
-#define renice_full_usage \
-       "Changes priority of running processes. Allowed priorities range\n" \
-       "from 20 (the process runs only when nothing else is running) to 0\n" \
-       "(default priority) to -20 (almost nothing else ever gets to run)."
-
-#define reset_trivial_usage \
-       ""
-#define reset_full_usage \
-       "Resets the screen."
-
-#define rm_trivial_usage \
-       "[OPTION]... FILE..."
-#define rm_full_usage \
-       "Remove (unlink) the FILE(s).  You may use '--' to\n" \
-       "indicate that all following arguments are non-options.\n\n" \
-       "Options:\n" \
-       "\t-i\t\talways prompt before removing each destination" \
-       "\t-f\t\tremove existing destinations, never prompt\n" \
-       "\t-r or -R\tremove the contents of directories recursively"
-#define rm_example_usage \
-       "$ rm -rf /tmp/foo\n"
-
-#define rmdir_trivial_usage \
-       "[OPTION]... DIRECTORY..."
-#define rmdir_full_usage \
-       "Remove the DIRECTORY(ies), if they are empty."
-#define rmdir_example_usage \
-       "# rmdir /tmp/foo\n"
-
-#define rmmod_trivial_usage \
-       "[OPTION]... [MODULE]..."
-#define rmmod_full_usage \
-       "Unloads the specified kernel modules from the kernel.\n\n" \
-       "Options:\n" \
-       "\t-a\tTry to remove all unused kernel modules."
-#define rmmod_example_usage \
-       "$ rmmod tulip\n"
-
-#define route_trivial_usage \
-       "[{add|del|flush}]"
-#define route_full_usage \
-       "Edit the kernel's routing tables"
-
-#define rpm2cpio_trivial_usage \
-       "package.rpm"
-#define rpm2cpio_full_usage \
-       "Outputs a cpio archive of the rpm file."
-
-#define sed_trivial_usage \
-       "[-nef] pattern [files...]"
-#define sed_full_usage \
-       "Options:\n" \
-       "\t-n\t\tsuppress automatic printing of pattern space\n" \
-       "\t-e script\tadd the script to the commands to be executed\n" \
-       "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \
-       "\n" \
-       "If no -e or -f is given, the first non-option argument is taken as the\n" \
-       "sed script to interpret. All remaining arguments are names of input\n" \
-       "files; if no input files are specified, then the standard input is read."
-#define sed_example_usage \
-       "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
-       "bar\n"
-
-#define setkeycodes_trivial_usage \
-       "SCANCODE KEYCODE ..."
-#define setkeycodes_full_usage \
-       "Set entries into the kernel's scancode-to-keycode map,\n" \
-       "allowing unusual keyboards to generate usable keycodes.\n\n" \
-       "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
-       "and KEYCODE is given in decimal"
-#define setkeycodes_example_usage \
-       "$ setkeycodes e030 127\n"
-
-#define lash_trivial_usage \
-       "[FILE]...\n" \
-       "or: sh -c command [args]..."
-#define lash_full_usage \
-       "lash: The BusyBox LAme SHell (command interpreter)"
-#define lash_notes_usage \
-"This command does not yet have proper documentation.\n" \
-"\n" \
-"Use lash just as you would use any other shell.  It properly handles pipes,\n" \
-"redirects, job control, can be used as the shell for scripts, and has a\n" \
-"sufficient set of builtins to do what is needed.  It does not (yet) support\n" \
-"Bourne Shell syntax.  If you need things like "if-then-else", "while", and such\n" \
-"use ash or bash.  If you just need a very simple and extremely small shell,\n" \
-"this will do the job."
-
-#define sleep_trivial_usage \
-       "N"
-#define sleep_full_usage \
-       "Pause for N seconds."
-#define sleep_example_usage \
-       "$ sleep 2\n" \
-       "[2 second delay results]\n"
-
-
-#ifdef BB_FEATURE_SORT_UNIQUE
-  #define USAGE_SORT_UNIQUE(a) a
-#else
-  #define USAGE_SORT_UNIQUE(a)
-#endif
-#ifdef BB_FEATURE_SORT_REVERSE
-  #define USAGE_SORT_REVERSE(a) a
-#else
-  #define USAGE_SORT_REVERSE(a)
-#endif
-#define sort_trivial_usage \
-       "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
-#define sort_full_usage \
-       "Sorts lines of text in the specified files\n\n"\
-       "Options:\n" \
-       USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
-       USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
-       "\t-n\tsort numerics"
-#define sort_example_usage \
-       "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
-       "a\n" \
-       "b\n" \
-       "c\n" \
-       "d\n" \
-       "e\n" \
-       "f\n"
-
-#define stty_trivial_usage \
-       "[-a|g] [-F DEVICE] [SETTING]..."
-#define stty_full_usage \
-       "Without arguments, prints baud rate, line discipline," \
-       "\nand deviations from stty sane." \
-       "\n\nOptions:" \
-       "\n\t-F DEVICE\topen device instead of stdin" \
-       "\n\t-a\t\tprint all current settings in human-readable form" \
-       "\n\t-g\t\tprint in stty-readable form" \
-       "\n\t[SETTING]\tsee manpage"
-
-#define swapoff_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapoff_full_usage \
-       "Stop swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStop swapping on all swap devices"
-
-#define swapon_trivial_usage \
-       "[OPTION] [DEVICE]"
-#define swapon_full_usage \
-       "Start swapping virtual memory pages on DEVICE.\n\n" \
-       "Options:\n" \
-       "\t-a\tStart swapping on all swap devices"
-
-#define sync_trivial_usage \
-       ""
-#define sync_full_usage \
-       "Write all buffered filesystem blocks to disk."
-
-
-#ifdef BB_FEATURE_REMOTE_LOG
-  #define USAGE_REMOTE_LOG(a) a
-#else
-  #define USAGE_REMOTE_LOG(a)
-#endif
-#define syslogd_trivial_usage \
-       "[OPTION]..."
-#define syslogd_full_usage \
-       "Linux system and kernel logging utility.\n" \
-       "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \
-       "Options:\n" \
-       "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \
-       "\t-n\t\tRun as a foreground process\n" \
-       "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \
-       USAGE_REMOTE_LOG( \
-       "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \
-       "\t-L\t\tLog locally and via network logging (default is network only)")
-#define syslogd_example_usage \
-       "$ syslogd -R masterlog:514\n" \
-       "$ syslogd -R 192.168.1.1:601\n"
-
-
-#ifndef BB_FEATURE_FANCY_TAIL
-  #define USAGE_UNSIMPLE_TAIL(a)
-#else
-  #define USAGE_UNSIMPLE_TAIL(a) a
-#endif
-#define tail_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tail_full_usage \
-       "Print last 10 lines of each FILE to standard output.\n" \
-       "With more than one FILE, precede each with a header giving the\n" \
-       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
-       "Options:\n" \
-       USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \
-       "\t-n N[kbm]\tprint last N lines instead of last 10\n" \
-       "\t-f\t\toutput data as the file grows" \
-       USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \
-       "\t-s SEC\t\twait SEC seconds between reads with -f\n" \
-       "\t-v\t\talways output headers giving file names\n\n" \
-       "If the first character of N (bytes or lines) is a '+', output begins with \n" \
-       "the Nth item from the start of each file, otherwise, print the last N items\n" \
-       "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." )
-#define tail_example_usage \
-       "$ tail -n 1 /etc/resolv.conf\n" \
-       "nameserver 10.0.0.1\n"
-
-#ifdef BB_FEATURE_TAR_CREATE
-  #define USAGE_TAR_CREATE(a) a
-#else
-  #define USAGE_TAR_CREATE(a)
-#endif
-#ifdef BB_FEATURE_TAR_EXCLUDE
-  #define USAGE_TAR_EXCLUDE(a) a
-#else
-  #define USAGE_TAR_EXCLUDE(a)
-#endif
-#define tar_trivial_usage \
-       "-[" USAGE_TAR_CREATE("c") "xtvO] " \
-       USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \
-       "[-f TARFILE] [-C DIR] [FILE(s)] ..."
-#define tar_full_usage \
-       "Create, extract, or list files from a tar file.\n\n" \
-       "Options:\n" \
-       USAGE_TAR_CREATE("\tc\t\tcreate\n") \
-       "\tx\t\textract\n" \
-       "\tt\t\tlist\n" \
-       "\nFile selection:\n" \
-       "\tf\t\tname of TARFILE or \"-\" for stdin\n" \
-       "\tO\t\textract to stdout\n" \
-       USAGE_TAR_EXCLUDE( \
-       "\texclude\t\tfile to exclude\n" \
-        "\tX\t\tfile with names to exclude\n" \
-       ) \
-       "\tC\t\tchange to directory DIR before operation\n" \
-       "\tv\t\tverbosely list files processed"
-#define tar_example_usage \
-       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
-       "$ tar -cf /tmp/tarball.tar /usr/local\n"
-
-#define tee_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define tee_full_usage \
-       "Copy standard input to each FILE, and also to standard output.\n\n" \
-       "Options:\n" \
-       "\t-a\tappend to the given FILEs, do not overwrite"
-#define tee_example_usage \
-       "$ echo "Hello" | tee /tmp/foo\n" \
-       "$ cat /tmp/foo\n" \
-       "Hello\n"
-
-#define telnet_trivial_usage \
-       "HOST [PORT]"
-#define telnet_full_usage \
-       "Telnet is used to establish interactive communication with another\n"\
-       "computer over a network using the TELNET protocol."
-
-#define test_trivial_usage \
-       "EXPRESSION\n  or   [ EXPRESSION ]"
-#define test_full_usage \
-       "Checks file types and compares values returning an exit\n" \
-       "code determined by the value of EXPRESSION."
-#define test_example_usage \
-       "$ test 1 -eq 2\n" \
-       "$ echo $?\n" \
-       "1\n" \
-       "$ test 1 -eq 1\n" \
-       "$ echo $? \n" \
-       "0\n" \
-       "$ [ -d /etc ]\n" \
-       "$ echo $?\n" \
-       "0\n" \
-       "$ [ -d /junk ]\n" \
-       "$ echo $?\n" \
-       "1\n"
-
-#ifdef BB_FEATURE_TFTP_GET
-  #define USAGE_TFTP_GET(a) a
-#else
-  #define USAGE_TFTP_GET(a)
-#endif
-#ifdef BB_FEATURE_TFTP_PUT
-  #define USAGE_TFTP_PUT(a) a
-#else
-  #define USAGE_TFTP_PUT(a)
-#endif
-
-#define tftp_trivial_usage \
-       "[OPTION]... HOST [PORT]"
-#define tftp_full_usage \
-       "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
-       "Options:\n" \
-       "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
-        USAGE_TFTP_GET(        \
-        "\t-g\tGet file.\n" \
-        ) \
-       "\t-l FILE\tTransfer local FILE.\n" \
-        USAGE_TFTP_PUT(        \
-       "\t-p\tPut file.\n" \
-       ) \
-       "\t-r FILE\tTransfer remote FILE.\n"
-
-#define touch_trivial_usage \
-       "[-c] FILE [FILE ...]"
-#define touch_full_usage \
-       "Update the last-modified date on the given FILE[s].\n\n" \
-       "Options:\n" \
-       "\t-c\tDo not create any files"
-#define touch_example_usage \
-       "$ ls -l /tmp/foo\n" \
-       "/bin/ls: /tmp/foo: No such file or directory\n" \
-       "$ touch /tmp/foo\n" \
-       "$ ls -l /tmp/foo\n" \
-       "-rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo\n" 
-
-#define tr_trivial_usage \
-       "[-cds] STRING1 [STRING2]"
-#define tr_full_usage \
-       "Translate, squeeze, and/or delete characters from\n" \
-       "standard input, writing to standard output.\n\n" \
-       "Options:\n" \
-       "\t-c\ttake complement of STRING1\n" \
-       "\t-d\tdelete input characters coded STRING1\n" \
-       "\t-s\tsqueeze multiple output characters of STRING2 into one character"
-#define tr_example_usage \
-       "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
-       "hello world\n" 
-
-#define traceroute_trivial_usage \
-       "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\
-       [-s src_addr] [-t tos] [-w wait] host [data size]"
-#define traceroute_full_usage \
-       "trace the route ip packets follow going to \"host\"\n" \
-       "Options:\n" \
-       "\t-d\tset SO_DEBUG options to socket\n" \
-       "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
-       "\t-r\tBypass the normal routing tables and send directly to a host\n" \
-       "\t-v\tVerbose output\n" \
-       "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \
-       "\t-p port#\tSet the base UDP port number used in probes\n" \
-       "\t\t(default is 33434)\n" \
-       "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \
-       "\t\t(default is 3)\n" \
-       "\t-s src_addr\tUse the following IP address as the source address\n" \
-       "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
-       "\t\t(default 0)\n" \
-       "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
-       "\t\t(default 3 sec.)."
-
-
-#define true_trivial_usage \
-       ""
-#define true_full_usage \
-       "Return an exit code of TRUE (0)."
-#define true_example_usage \
-       "$ true\n" \
-       "$ echo $?\n" \
-       "0\n"
-
-#define tty_trivial_usage \
-       ""
-#define tty_full_usage \
-       "Print the file name of the terminal connected to standard input.\n\n"\
-       "Options:\n" \
-       "\t-s\tprint nothing, only return an exit status"
-#define tty_example_usage \
-       "$ tty\n" \
-       "/dev/tty2\n"
-
-#ifdef BB_FEATURE_MOUNT_FORCE
-  #define USAGE_MOUNT_FORCE(a) a
-#else
-  #define USAGE_MOUNT_FORCE(a)
-#endif
-#define umount_trivial_usage \
-       "[flags] FILESYSTEM|DIRECTORY"
-#define umount_full_usage \
-       "Unmount file systems\n" \
-       "\nFlags:\n" "\t-a\tUnmount all file systems" \
-       USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \
-       "\n\t-r\tTry to remount devices as read-only if mount is busy" \
-       USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \
-       USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)")
-#define umount_example_usage \
-       "$ umount /dev/hdc1 \n"
-
-#define uname_trivial_usage \
-       "[OPTION]..."
-#define uname_full_usage \
-       "Print certain system information.  With no OPTION, same as -s.\n\n" \
-       "Options:\n" \
-       "\t-a\tprint all information\n" \
-       "\t-m\tthe machine (hardware) type\n" \
-       "\t-n\tprint the machine's network node hostname\n" \
-       "\t-r\tprint the operating system release\n" \
-       "\t-s\tprint the operating system name\n" \
-       "\t-p\tprint the host processor type\n" \
-       "\t-v\tprint the operating system version"
-#define uname_example_usage \
-       "$ uname -a\n" \
-       "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" 
-
-#define uniq_trivial_usage \
-       "[OPTION]... [INPUT [OUTPUT]]"
-#define uniq_full_usage \
-       "Discard all but one of successive identical lines from INPUT\n" \
-       "(or standard input), writing to OUTPUT (or standard output).\n\n" \
-       "Options:\n" \
-       "\t-c\tprefix lines by the number of occurrences\n" \
-       "\t-d\tonly print duplicate lines\n" \
-       "\t-u\tonly print unique lines"
-#define uniq_example_usage \
-       "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
-       "a\n" \
-       "b\n" \
-       "c\n"
-
-#define unix2dos_trivial_usage \
-       "[option] [FILE]"
-#define unix2dos_full_usage \
-       "Converts FILE from unix format to dos format.  When no option\n" \
-       "is given, the input is converted to the opposite output format.\n" \
-       "When no file is given, uses stdin for input and stdout for output.\n" \
-       "Options:\n" \
-       "\t-u\toutput will be in UNIX format\n" \
-       "\t-d\toutput will be in DOS format"
-
-#define update_trivial_usage \
-       "[options]"
-#define update_full_usage \
-       "Periodically flushes filesystem buffers.\n\n" \
-       "Options:\n" \
-       "\t-S\tforce use of sync(2) instead of flushing\n" \
-       "\t-s SECS\tcall sync this often (default 30)\n" \
-       "\t-f SECS\tflush some buffers this often (default 5)"
-
-#define uptime_trivial_usage \
-       ""
-#define uptime_full_usage \
-       "Display the time since the last boot."
-#define uptime_example_usage \
-       "$ uptime\n" \
-       "  1:55pm  up  2:30, load average: 0.09, 0.04, 0.00\n" 
-
-#define usleep_trivial_usage \
-       "N" 
-#define usleep_full_usage \
-       "Pause for N microseconds."
-#define usleep_example_usage \
-       "$ usleep 1000000\n" \
-       "[pauses for 1 second]\n"
-
-#define uudecode_trivial_usage \
-       "[FILE]..."
-#define uudecode_full_usage \
-       "Uudecode a file that is uuencoded.\n\n" \
-       "Options:\n" \
-       "\t-o FILE\tdirect output to FILE" 
-#define uudecode_example_usage \
-       "$ uudecode -o busybox busybox.uu\n" \
-       "$ ls -l busybox\n" \
-       "-rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox\n" 
-
-#define uuencode_trivial_usage \
-       "[OPTION] [INFILE] REMOTEFILE"
-#define uuencode_full_usage \
-       "Uuencode a file.\n\n" \
-       "Options:\n" \
-       "\t-m\tuse base64 encoding per RFC1521"
-#define uuencode_example_usage \
-       "$ uuencode busybox busybox\n" \
-       "begin 755 busybox\n" \
-       "<encoded file snipped>\n" \
-       "$ uudecode busybox busybox > busybox.uu\n" \
-       "$\n"
-
-#define vi_trivial_usage \
-       "[OPTION] [FILE]..."
-#define vi_full_usage \
-       "edit FILE.\n\n" \
-       "Options:\n" \
-       "\t-R\tRead-only- do not write to the file." 
-
-#define watchdog_trivial_usage \
-       "DEV"
-#define watchdog_full_usage \
-       "Periodically write to watchdog device DEV"
-
-#define wc_trivial_usage \
-       "[OPTION]... [FILE]..."
-#define wc_full_usage \
-       "Print line, word, and byte counts for each FILE, and a total line if\n" \
-       "more than one FILE is specified.  With no FILE, read standard input.\n\n" \
-       "Options:\n" \
-       "\t-c\tprint the byte counts\n" \
-       "\t-l\tprint the newline counts\n" \
-       "\t-L\tprint the length of the longest line\n" \
-       "\t-w\tprint the word counts"
-#define wc_example_usage \
-       "$ wc /etc/passwd\n" \
-       "     31      46    1365 /etc/passwd\n" 
-
-#define wget_trivial_usage \
-       "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url"
-#define wget_full_usage \
-       "wget retrieves files via HTTP or FTP\n\n" \
-       "Options:\n" \
-       "\t-c\tcontinue retrieval of aborted transfers\n" \
-       "\t-q\tquiet mode - do not print\n" \
-       "\t-P\tSet directory prefix to DIR\n" \
-       "\t-O\tsave to filename ('-' for stdout)"
-
-#define which_trivial_usage \
-       "[COMMAND ...]"
-#define which_full_usage \
-       "Locates a COMMAND."
-#define which_example_usage \
-       "$ which login\n" \
-       "/bin/login\n"
-
-#define whoami_trivial_usage \
-       ""
-#define whoami_full_usage \
-       "Prints the user name associated with the current effective user id."
-
-#define xargs_trivial_usage \
-       "[COMMAND] [ARGS...]"
-#define xargs_full_usage \
-       "Executes COMMAND on every item given by standard input."
-#define xargs_example_usage \
-       "$ ls | xargs gzip\n" \
-       "$ find . -name '*.c' -print | xargs rm\n" 
-
-#define yes_trivial_usage \
-       "[OPTION]... [STRING]..."
-#define yes_full_usage \
-       "Repeatedly outputs a line with all specified STRING(s), or 'y'."
-
-#define zcat_trivial_usage \
-       "FILE"
-#define zcat_full_usage \
-       "Uncompress to stdout."
diff --git a/busybox/usleep.c b/busybox/usleep.c
deleted file mode 100644 (file)
index 6023bf4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini usleep implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int usleep_main(int argc, char **argv)
-{
-       if ((argc < 2) || (**(argv + 1) == '-')) {
-               show_usage();
-       }
-
-       usleep(atoi(*(++argv)));        /* return void */
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/dmesg.c b/busybox/util-linux/dmesg.c
deleted file mode 100644 (file)
index 73de6d1..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/* dmesg.c -- Print out the contents of the kernel ring buffer
- * Created: Sat Oct  9 16:19:47 1993
- * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
- * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
- * This program comes with ABSOLUTELY NO WARRANTY.
- * Modifications by Rick Sladkey (jrs@world.std.com)
- * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
- * by Peeter Joot.  This was also suggested by John Hudson.
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- * from util-linux -- adapted for busybox by 
- * Erik Andersen <andersee@debian.org>. I ripped out Native Language 
- * Support, replaced getopt, added some gotos for redundant stuff.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-
-#if __GNU_LIBRARY__ < 5
-# ifdef __alpha__
-#   define klogctl syslog
-# endif
-#else
-# include <sys/klog.h>
-#endif
-
-#include "busybox.h"
-
-int dmesg_main(int argc, char **argv)
-{
-       char *buf;
-       int c;
-       int bufsize = 8196;
-       int i;
-       int n;
-       int level = 0;
-       int lastc;
-       int cmd = 3;
-
-       while ((c = getopt(argc, argv, "cn:s:")) != EOF) {
-               switch (c) {
-               case 'c':
-                       cmd = 4;
-                       break;
-               case 'n':
-                       cmd = 8;
-                       if (optarg == NULL)
-                               show_usage();
-                       level = atoi(optarg);
-                       break;
-               case 's':
-                       if (optarg == NULL)
-                               show_usage();
-                       bufsize = atoi(optarg);
-                       break;
-               default:
-                       show_usage();
-               }
-       }                       
-
-       if (optind < argc) {
-               show_usage();
-       }
-
-       if (cmd == 8) {
-               if (klogctl(cmd, NULL, level) < 0)
-                       perror_msg_and_die("klogctl");
-               return EXIT_SUCCESS;
-       }
-
-       if (bufsize < 4096)
-               bufsize = 4096;
-       buf = (char *) xmalloc(bufsize);
-       if ((n = klogctl(cmd, buf, bufsize)) < 0)
-               perror_msg_and_die("klogctl");
-
-       lastc = '\n';
-       for (i = 0; i < n; i++) {
-               if (lastc == '\n' && buf[i] == '<') {
-                       i++;
-                       while (buf[i] >= '0' && buf[i] <= '9')
-                               i++;
-                       if (buf[i] == '>')
-                               i++;
-               }
-               lastc = buf[i];
-               putchar(lastc);
-       }
-       if (lastc != '\n')
-               putchar('\n');
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/fbset.c b/busybox/util-linux/fbset.c
deleted file mode 100644 (file)
index 5ccd80e..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini fbset implementation for busybox
- *
- * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This is a from-scratch implementation of fbset; but the de facto fbset
- * implementation was a good reference. fbset (original) is released under
- * the GPL, and is (c) 1995-1999 by: 
- *     Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#define DEFAULTFBDEV  "/dev/fb0"
-#define DEFAULTFBMODE "/etc/fb.modes"
-
-static const int OPT_CHANGE   = (1 << 0);
-static const int OPT_INFO     = (1 << 1);
-static const int OPT_READMODE = (1 << 2);
-
-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_CHANGE = 13,
-
-#ifdef BB_FEATURE_FBSET_FANCY
-       CMD_XRES = 100,
-       CMD_YRES = 101,
-       CMD_VXRES = 102,
-       CMD_VYRES = 103,
-       CMD_DEPTH = 104,
-       CMD_MATCH = 105,
-       CMD_PIXCLOCK = 106,
-       CMD_LEFT = 107,
-       CMD_RIGHT = 108,
-       CMD_UPPER = 109,
-       CMD_LOWER = 110,
-       CMD_HSLEN = 111,
-       CMD_VSLEN = 112,
-       CMD_CSYNC = 113,
-       CMD_GSYNC = 114,
-       CMD_EXTSYNC = 115,
-       CMD_BCAST = 116,
-       CMD_RGBA = 117,
-       CMD_STEP = 118,
-       CMD_MOVE = 119,
-#endif
-};
-
-static unsigned int g_options = 0;
-
-/* Stuff stolen from the kernel's fb.h */
-static const int FBIOGET_VSCREENINFO = 0x4600;
-static const int FBIOPUT_VSCREENINFO = 0x4601;
-#define __u32                  u_int32_t
-struct fb_bitfield {
-       __u32 offset;                   /* beginning of bitfield        */
-       __u32 length;                   /* length of bitfield           */
-       __u32 msb_right;                /* != 0 : Most significant bit is */ 
-                                       /* right */ 
-};
-struct fb_var_screeninfo {
-       __u32 xres;                     /* visible resolution           */
-       __u32 yres;
-       __u32 xres_virtual;             /* virtual resolution           */
-       __u32 yres_virtual;
-       __u32 xoffset;                  /* offset from virtual to visible */
-       __u32 yoffset;                  /* resolution                   */
-
-       __u32 bits_per_pixel;           /* guess what                   */
-       __u32 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                 */      
-
-       __u32 nonstd;                   /* != 0 Non standard pixel format */
-
-       __u32 activate;                 /* see FB_ACTIVATE_*            */
-
-       __u32 height;                   /* height of picture in mm    */
-       __u32 width;                    /* width of picture in mm     */
-
-       __u32 accel_flags;              /* acceleration flags (hints)   */
-
-       /* Timing: All values in pixclocks, except pixclock (of course) */
-       __u32 pixclock;                 /* pixel clock in ps (pico seconds) */
-       __u32 left_margin;              /* time from sync to picture    */
-       __u32 right_margin;             /* time from picture to sync    */
-       __u32 upper_margin;             /* time from sync to picture    */
-       __u32 lower_margin;
-       __u32 hsync_len;                /* length of horizontal sync    */
-       __u32 vsync_len;                /* length of vertical sync      */
-       __u32 sync;                     /* see FB_SYNC_*                */
-       __u32 vmode;                    /* see FB_VMODE_*               */
-       __u32 reserved[6];              /* Reserved for future compatibility */
-};
-
-
-static struct cmdoptions_t {
-       char *name;
-       unsigned char param_count;
-       unsigned char code;
-} g_cmdoptions[] = {
-       {
-       "-fb", 1, CMD_FB}, {
-       "-db", 1, CMD_DB}, {
-       "-a", 0, CMD_ALL}, {
-       "-i", 0, CMD_INFO}, {
-       "-g", 5, CMD_GEOMETRY}, {
-       "-t", 7, CMD_TIMING}, {
-       "-accel", 1, CMD_ACCEL}, {
-       "-hsync", 1, CMD_HSYNC}, {
-       "-vsync", 1, CMD_VSYNC}, {
-       "-laced", 1, CMD_LACED}, {
-       "-double", 1, CMD_DOUBLE}, {
-       "-n", 0, CMD_CHANGE}, {
-#ifdef BB_FEATURE_FBSET_FANCY
-       "-all", 0, CMD_ALL}, {
-       "-xres", 1, CMD_XRES}, {
-       "-yres", 1, CMD_YRES}, {
-       "-vxres", 1, CMD_VXRES}, {
-       "-vyres", 1, CMD_VYRES}, {
-       "-depth", 1, CMD_DEPTH}, {
-       "-match", 0, CMD_MATCH}, {
-       "-geometry", 5, CMD_GEOMETRY}, {
-       "-pixclock", 1, CMD_PIXCLOCK}, {
-       "-left", 1, CMD_LEFT}, {
-       "-right", 1, CMD_RIGHT}, {
-       "-upper", 1, CMD_UPPER}, {
-       "-lower", 1, CMD_LOWER}, {
-       "-hslen", 1, CMD_HSLEN}, {
-       "-vslen", 1, CMD_VSLEN}, {
-       "-timings", 7, CMD_TIMING}, {
-       "-csync", 1, CMD_CSYNC}, {
-       "-gsync", 1, CMD_GSYNC}, {
-       "-extsync", 1, CMD_EXTSYNC}, {
-       "-bcast", 1, CMD_BCAST}, {
-       "-rgba", 1, CMD_RGBA}, {
-       "-step", 1, CMD_STEP}, {
-       "-move", 1, CMD_MOVE}, {
-#endif
-       0, 0, 0}
-};
-
-#ifdef BB_FEATURE_FBSET_READMODE
-/* taken from linux/fb.h */
-static const int FB_VMODE_INTERLACED = 1;      /* interlaced   */
-static const int FB_VMODE_DOUBLE = 2;  /* double scan */
-static const int FB_SYNC_HOR_HIGH_ACT = 1;     /* horizontal sync high active  */
-static const int FB_SYNC_VERT_HIGH_ACT = 2;    /* vertical sync high active    */
-static const int FB_SYNC_EXT = 4;      /* external sync                */
-static const int FB_SYNC_COMP_HIGH_ACT = 8;    /* composite sync high active   */
-#endif
-static int readmode(struct fb_var_screeninfo *base, const char *fn,
-                                       const char *mode)
-{
-#ifdef BB_FEATURE_FBSET_READMODE
-       FILE *f;
-       char buf[256];
-       char *p = buf;
-
-       f = xfopen(fn, "r");
-       while (!feof(f)) {
-               fgets(buf, sizeof(buf), f);
-               if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) {
-                       p += 5;
-                       if ((p = strstr(buf, mode))) {
-                               p += strlen(mode);
-                               if (!isspace(*p) && (*p != 0) && (*p != '"')
-                                       && (*p != '\r') && (*p != '\n'))
-                                       continue;       /* almost, but not quite */
-                               while (!feof(f)) {
-                                       fgets(buf, sizeof(buf), f);
-
-                    if ((p = strstr(buf, "geometry "))) {
-                        p += 9;
-
-                        sscanf(p, "%d %d %d %d %d", 
-                                &(base->xres), &(base->yres), 
-                                &(base->xres_virtual), &(base->yres_virtual), 
-                                &(base->bits_per_pixel));
-                    } else if ((p = strstr(buf, "timings "))) {
-                        p += 8;
-                        
-                        sscanf(p, "%d %d %d %d %d %d %d",
-                                &(base->pixclock),
-                                &(base->left_margin), &(base->right_margin),
-                                &(base->upper_margin), &(base->lower_margin),
-                                &(base->hsync_len), &(base->vsync_len));
-                    } else if ((p = strstr(buf, "laced "))) {
-                        p += 6;
-
-                        if (strstr(buf, "false")) {
-                            base->vmode &= ~FB_VMODE_INTERLACED;
-                        } else {
-                            base->vmode |= FB_VMODE_INTERLACED;
-                        }
-                    } else if ((p = strstr(buf, "double "))) {
-                        p += 7;
-
-                        if (strstr(buf, "false")) {
-                            base->vmode &= ~FB_VMODE_DOUBLE;
-                        } else {
-                            base->vmode |= FB_VMODE_DOUBLE;
-                        }
-                    } else if ((p = strstr(buf, "vsync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_VERT_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "hsync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_HOR_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "csync "))) {
-                        p += 6;
-
-                        if (strstr(buf, "low")) {
-                            base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
-                        } else {
-                            base->sync |= FB_SYNC_COMP_HIGH_ACT;
-                        }
-                    } else if ((p = strstr(buf, "extsync "))) {
-                        p += 8;
-
-                        if (strstr(buf, "false")) {
-                            base->sync &= ~FB_SYNC_EXT;
-                        } else {
-                            base->sync |= FB_SYNC_EXT;
-                        }
-                    }
-                    
-                                       if (strstr(buf, "endmode"))
-                                               return 1;
-                               }
-                       }
-               }
-       }
-#else
-       error_msg( "mode reading not compiled in");
-#endif
-       return 0;
-}
-
-static void setmode(struct fb_var_screeninfo *base,
-                                       struct fb_var_screeninfo *set)
-{
-       if ((int) set->xres > 0)
-               base->xres = set->xres;
-       if ((int) set->yres > 0)
-               base->yres = set->yres;
-       if ((int) set->xres_virtual > 0)
-               base->xres_virtual = set->xres_virtual;
-       if ((int) set->yres_virtual > 0)
-               base->yres_virtual = set->yres_virtual;
-       if ((int) set->bits_per_pixel > 0)
-               base->bits_per_pixel = set->bits_per_pixel;
-}
-
-static 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", v->xres, v->yres, (int) (vrate + 0.5));
-#ifdef BB_FEATURE_FBSET_FANCY
-       printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6,
-                  hrate / 1e3, vrate);
-#endif
-       printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres,
-                  v->xres_virtual, v->yres_virtual, v->bits_per_pixel);
-       printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin,
-                  v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len,
-                  v->vsync_len);
-       printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false"));
-       printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length,
-                  v->red.offset, v->green.length, v->green.offset, v->blue.length,
-                  v->blue.offset, v->transp.length, v->transp.offset);
-       printf("endmode\n\n");
-}
-
-#ifdef STANDALONE
-int main(int argc, char **argv)
-#else
-extern int fbset_main(int argc, char **argv)
-#endif
-{
-       struct fb_var_screeninfo var, varset;
-       int fh, i;
-       char *fbdev = DEFAULTFBDEV;
-       char *modefile = DEFAULTFBMODE;
-       char *thisarg, *mode = NULL;
-
-       memset(&varset, 0xFF, sizeof(varset));
-
-       /* parse cmd args.... why do they have to make things so difficult? */
-       argv++;
-       argc--;
-       for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
-               for (i = 0; g_cmdoptions[i].name; i++) {
-                       if (!strcmp(thisarg, g_cmdoptions[i].name)) {
-                               if (argc - 1 < g_cmdoptions[i].param_count)
-                                       show_usage();
-                               switch (g_cmdoptions[i].code) {
-                               case CMD_FB:
-                                       fbdev = argv[1];
-                                       break;
-                               case CMD_DB:
-                                       modefile = argv[1];
-                                       break;
-                               case CMD_GEOMETRY:
-                                       varset.xres = strtoul(argv[1], 0, 0);
-                                       varset.yres = strtoul(argv[2], 0, 0);
-                                       varset.xres_virtual = strtoul(argv[3], 0, 0);
-                                       varset.yres_virtual = strtoul(argv[4], 0, 0);
-                                       varset.bits_per_pixel = strtoul(argv[5], 0, 0);
-                                       break;
-                               case CMD_TIMING:
-                                       varset.pixclock = strtoul(argv[1], 0, 0);
-                                       varset.left_margin = strtoul(argv[2], 0, 0);
-                                       varset.right_margin = strtoul(argv[3], 0, 0);
-                                       varset.upper_margin = strtoul(argv[4], 0, 0);
-                                       varset.lower_margin = strtoul(argv[5], 0, 0);
-                                       varset.hsync_len = strtoul(argv[6], 0, 0);
-                                       varset.vsync_len = strtoul(argv[7], 0, 0);
-                                       break;
-                case CMD_CHANGE:
-                    g_options |= OPT_CHANGE;
-                    break;
-#ifdef BB_FEATURE_FBSET_FANCY
-                               case CMD_XRES:
-                                       varset.xres = strtoul(argv[1], 0, 0);
-                                       break;
-                               case CMD_YRES:
-                                       varset.yres = strtoul(argv[1], 0, 0);
-                                       break;
-#endif
-                               }
-                               argc -= g_cmdoptions[i].param_count;
-                               argv += g_cmdoptions[i].param_count;
-                               break;
-                       }
-               }
-               if (!g_cmdoptions[i].name) {
-                       if (argc == 1) {
-                               mode = *argv;
-                               g_options |= OPT_READMODE;
-                       } else {
-                               show_usage();
-                       }
-               }
-       }
-
-       if ((fh = open(fbdev, O_RDONLY)) < 0)
-               perror_msg_and_die("fbset(open)");
-       if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
-               perror_msg_and_die("fbset(ioctl)");
-       if (g_options & OPT_READMODE) {
-               if (!readmode(&var, modefile, mode)) {
-                       error_msg("Unknown video mode `%s'", mode);
-                       return EXIT_FAILURE;
-               }
-       }
-
-       setmode(&var, &varset);
-       if (g_options & OPT_CHANGE)
-               if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
-                       perror_msg_and_die("fbset(ioctl)");
-       showmode(&var);
-       /* Don't close the file, as exiting will take care of that */
-       /* close(fh); */
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/fdflush.c b/busybox/util-linux/fdflush.c
deleted file mode 100644 (file)
index 28f5cb6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini fdflush implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-/* From <linux/fd.h> */
-#define FDFLUSH  _IO(2,0x4b)
-
-extern int fdflush_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc <= 1 || **(++argv) == '-')
-               show_usage();
-
-       if ((fd = open(*argv, 0)) < 0)
-               perror_msg_and_die("%s", *argv);
-
-       if (ioctl(fd, FDFLUSH, 0))
-               perror_msg_and_die("%s", *argv);
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/freeramdisk.c b/busybox/util-linux/freeramdisk.c
deleted file mode 100644 (file)
index cf25fae..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * freeramdisk implementation for busybox
- *
- * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
- * Adjusted a bit by Erik Andersen <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-
-/* From linux/fs.h */
-#define BLKFLSBUF  _IO(0x12,97)        /* flush buffer cache */
-
-extern int
-freeramdisk_main(int argc, char **argv)
-{
-       int   f;
-
-       if (argc != 2 || *argv[1] == '-') {
-               show_usage();
-       }
-
-       if ((f = open(argv[1], O_RDWR)) == -1) {
-               perror_msg_and_die("cannot open %s", argv[1]);
-       }
-       if (ioctl(f, BLKFLSBUF) < 0) {
-               perror_msg_and_die("failed ioctl on %s", argv[1]);
-       }
-       /* Don't bother closing.  Exit does
-        * that, so we can save a few bytes */
-       /* close(f); */
-       return EXIT_SUCCESS;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/busybox/util-linux/fsck_minix.c b/busybox/util-linux/fsck_minix.c
deleted file mode 100644 (file)
index 952968d..0000000
+++ /dev/null
@@ -1,1478 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * fsck.c - a file system consistency checker for Linux.
- *
- * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
- * as per the GNU copyleft.
- */
-
-/*
- * 09.11.91  -  made the first rudimetary functions
- *
- * 10.11.91  -  updated, does checking, no repairs yet.
- *             Sent out to the mailing-list for testing.
- *
- * 14.11.91  - Testing seems to have gone well. Added some
- *             correction-code, and changed some functions.
- *
- * 15.11.91  -  More correction code. Hopefully it notices most
- *             cases now, and tries to do something about them.
- *
- * 16.11.91  -  More corrections (thanks to Mika Jalava). Most
- *             things seem to work now. Yeah, sure.
- *
- *
- * 19.04.92  - Had to start over again from this old version, as a
- *             kernel bug ate my enhanced fsck in february.
- *
- * 28.02.93  - added support for different directory entry sizes..
- *
- * Sat Mar  6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
- *                           super-block information
- *
- * Sat Oct  9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
- *                           to that required by fsutil
- *
- * Mon Jan  3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
- *                           Added support for file system valid flag.  Also
- *                           added program_version variable and output of
- *                           program name and version number when program
- *                           is executed.
- *
- * 30.10.94 - added support for v2 filesystem
- *            (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
- *
- * 10.12.94  -  added test to prevent checking of mounted fs adapted
- *              from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
- *              program.  (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 01.07.96  - Fixed the v2 fs stuff to use the right #defines and such
- *            for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
- *
- * 02.07.96  - Added C bit fiddling routines from rmk@ecs.soton.ac.uk 
- *             (Russell King).  He made them for ARM.  It would seem
- *            that the ARM is powerful enough to do this in C whereas
- *             i386 and m64k must use assembly to get it fast >:-)
- *            This should make minix fsck systemindependent.
- *            (janl@math.uio.no, Nicolai Langfeldt)
- *
- * 04.11.96  - Added minor fixes from Andreas Schwab to avoid compiler
- *             warnings.  Added mc68k bitops from 
- *            Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
- *
- * 06.11.96  - Added v2 code submitted by Joerg Dorchain, but written by
- *             Andreas Schwab.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- *
- * I've had no time to add comments - hopefully the function names
- * are comments enough. As with all file system checkers, this assumes
- * the file system is quiescent - don't use it on a mounted device
- * unless you can be sure nobody is writing to it (and remember that the
- * kernel can write to it when it searches for files).
- *
- * Usuage: fsck [-larvsm] device
- *     -l for a listing of all the filenames
- *     -a for automatic repairs (not implemented)
- *     -r for repairs (interactive) (not implemented)
- *     -v for verbose (tells how many files)
- *     -s for super-block info
- *     -m for minix-like "mode not cleared" warnings
- *     -f force filesystem check even if filesystem marked as valid
- *
- * The device may be a block device or a image of one, but this isn't
- * enforced (but it's not much fun on a character device :-). 
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <mntent.h>
-#include <sys/param.h>
-#include "busybox.h"
-
-static const int MINIX_ROOT_INO = 1;
-static const int MINIX_LINK_MAX = 250;
-static const int MINIX2_LINK_MAX = 65530;
-
-static const int MINIX_I_MAP_SLOTS = 8;
-static const int MINIX_Z_MAP_SLOTS = 64;
-static const int MINIX_SUPER_MAGIC = 0x137F;           /* original minix fs */
-static const int MINIX_SUPER_MAGIC2 = 0x138F;          /* minix fs, 30 char names */
-static const int MINIX2_SUPER_MAGIC = 0x2468;          /* minix V2 fs */
-static const int MINIX2_SUPER_MAGIC2 = 0x2478;         /* minix V2 fs, 30 char names */
-static const int MINIX_VALID_FS = 0x0001;              /* Clean fs. */
-static const int MINIX_ERROR_FS = 0x0002;              /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-
-static const int MINIX_V1 = 0x0001;            /* original minix fs */
-static const int MINIX_V2 = 0x0002;            /* minix V2 fs */
-
-#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
-       u_int16_t i_mode;
-       u_int16_t i_uid;
-       u_int32_t i_size;
-       u_int32_t i_time;
-       u_int8_t  i_gid;
-       u_int8_t  i_nlinks;
-       u_int16_t i_zone[9];
-};
-
-/*
- * The new minix inode has all the time entries, as well as
- * long block numbers and a third indirect block (7+1+1+1
- * instead of 7+1+1). Also, some previously 8-bit values are
- * now 16-bit. The inode is now 64 bytes instead of 32.
- */
-struct minix2_inode {
-       u_int16_t i_mode;
-       u_int16_t i_nlinks;
-       u_int16_t i_uid;
-       u_int16_t i_gid;
-       u_int32_t i_size;
-       u_int32_t i_atime;
-       u_int32_t i_mtime;
-       u_int32_t i_ctime;
-       u_int32_t i_zone[10];
-};
-
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
-       u_int16_t s_ninodes;
-       u_int16_t s_nzones;
-       u_int16_t s_imap_blocks;
-       u_int16_t s_zmap_blocks;
-       u_int16_t s_firstdatazone;
-       u_int16_t s_log_zone_size;
-       u_int32_t s_max_size;
-       u_int16_t s_magic;
-       u_int16_t s_state;
-       u_int32_t s_zones;
-};
-
-struct minix_dir_entry {
-       u_int16_t inode;
-       char name[0];
-};
-
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-#define NAME_MAX         255   /* # chars in a file name */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96)    /* return device size */
-#endif
-
-#ifndef __linux__
-#define volatile
-#endif
-
-static const int ROOT_INO = 1;
-
-#define UPPER(size,n) ((size+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef BB_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
-                                   : MINIX_INODES_PER_BLOCK))
-#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
-#endif
-#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
-
-#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *program_version = "1.2 - 11/11/96";
-static char *device_name = NULL;
-static int IN;
-static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
-       0, warn_mode = 0, force = 0;
-static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
-       0, symlinks = 0, total = 0;
-
-static int changed = 0;                        /* flags if the filesystem has been changed */
-static int errors_uncorrected = 0;     /* flag if some error was not corrected */
-static int dirsize = 16;
-static int namelen = 14;
-static int version2 = 0;
-static struct termios termios;
-static int termios_set = 0;
-
-/* File-name data */
-static const int MAX_DEPTH = 32;
-static int name_depth = 0;
-// static char name_list[MAX_DEPTH][BUFSIZ + 1];
-static char **name_list = NULL;
-
-static char *inode_buffer = NULL;
-
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-static char super_block_buffer[BLOCK_SIZE];
-
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef BB_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
-#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned char *inode_count = NULL;
-static unsigned char *zone_count = NULL;
-
-static void recursive_check(unsigned int ino);
-#ifdef BB_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino);
-#endif
-
-static inline int bit(char * a,unsigned int i)
-{
-         return (a[i >> 3] & (1<<(i & 7))) != 0;
-}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-
-#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
-#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
-
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-
-static void leave(int) __attribute__ ((noreturn));
-static void leave(int status)
-{
-       if (termios_set)
-               tcsetattr(0, TCSANOW, &termios);
-       exit(status);
-}
-
-static void die(const char *str)
-{
-       error_msg("%s", str);
-       leave(8);
-}
-
-/*
- * This simply goes through the file-name data and prints out the
- * current file.
- */
-static void print_current_name(void)
-{
-       int i = 0;
-
-       while (i < name_depth)
-               printf("/%.*s", namelen, name_list[i++]);
-       if (i == 0)
-               printf("/");
-}
-
-static int ask(const char *string, int def)
-{
-       int c;
-
-       if (!repair) {
-               printf("\n");
-               errors_uncorrected = 1;
-               return 0;
-       }
-       if (automatic) {
-               printf("\n");
-               if (!def)
-                       errors_uncorrected = 1;
-               return def;
-       }
-       printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
-       for (;;) {
-               fflush(stdout);
-               if ((c = getchar()) == EOF) {
-                       if (!def)
-                               errors_uncorrected = 1;
-                       return def;
-               }
-               c = toupper(c);
-               if (c == 'Y') {
-                       def = 1;
-                       break;
-               } else if (c == 'N') {
-                       def = 0;
-                       break;
-               } else if (c == ' ' || c == '\n')
-                       break;
-       }
-       if (def)
-               printf("y\n");
-       else {
-               printf("n\n");
-               errors_uncorrected = 1;
-       }
-       return def;
-}
-
-/*
- * Make certain that we aren't checking a filesystem that is on a
- * mounted partition.  Code adapted from e2fsck, Copyright (C) 1993,
- * 1994 Theodore Ts'o.  Also licensed under GPL.
- */
-static void check_mount(void)
-{
-       FILE *f;
-       struct mntent *mnt;
-       int cont;
-       int fd;
-
-       if ((f = setmntent(MOUNTED, "r")) == NULL)
-               return;
-       while ((mnt = getmntent(f)) != NULL)
-               if (strcmp(device_name, mnt->mnt_fsname) == 0)
-                       break;
-       endmntent(f);
-       if (!mnt)
-               return;
-
-       /*
-        * If the root is mounted read-only, then /etc/mtab is
-        * probably not correct; so we won't issue a warning based on
-        * it.
-        */
-       fd = open(MOUNTED, O_RDWR);
-       if (fd < 0 && errno == EROFS)
-               return;
-       else
-               close(fd);
-
-       printf("%s is mounted.   ", device_name);
-       if (isatty(0) && isatty(1))
-               cont = ask("Do you really want to continue", 0);
-       else
-               cont = 0;
-       if (!cont) {
-               printf("check aborted.\n");
-               exit(0);
-       }
-       return;
-}
-
-/*
- * 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_nr(unsigned short *nr, int *corrected)
-{
-       if (!*nr)
-               return 0;
-       if (*nr < FIRSTZONE)
-               printf("Zone nr < FIRSTZONE in file `");
-       else if (*nr >= ZONES)
-               printf("Zone nr >= ZONES in file `");
-       else
-               return *nr;
-       print_current_name();
-       printf("'.");
-       if (ask("Remove block", 1)) {
-               *nr = 0;
-               *corrected = 1;
-       }
-       return 0;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int check_zone_nr2(unsigned int *nr, int *corrected)
-{
-       if (!*nr)
-               return 0;
-       if (*nr < FIRSTZONE)
-               printf("Zone nr < FIRSTZONE in file `");
-       else if (*nr >= ZONES)
-               printf("Zone nr >= ZONES in file `");
-       else
-               return *nr;
-       print_current_name();
-       printf("'.");
-       if (ask("Remove block", 1)) {
-               *nr = 0;
-               *corrected = 1;
-       }
-       return 0;
-}
-#endif
-
-/*
- * read-block reads block nr into the buffer at addr.
- */
-static void read_block(unsigned int nr, char *addr)
-{
-       if (!nr) {
-               memset(addr, 0, BLOCK_SIZE);
-               return;
-       }
-       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
-               printf("Read error: unable to seek to block in file '");
-               print_current_name();
-               printf("'\n");
-               memset(addr, 0, BLOCK_SIZE);
-               errors_uncorrected = 1;
-       } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
-               printf("Read error: bad block in file '");
-               print_current_name();
-               printf("'\n");
-               memset(addr, 0, BLOCK_SIZE);
-               errors_uncorrected = 1;
-       }
-}
-
-/*
- * write_block writes block nr to disk.
- */
-static void write_block(unsigned int nr, char *addr)
-{
-       if (!nr)
-               return;
-       if (nr < FIRSTZONE || nr >= ZONES) {
-               printf("Internal error: trying to write bad block\n"
-                          "Write request ignored\n");
-               errors_uncorrected = 1;
-               return;
-       }
-       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
-               die("seek failed in write_block");
-       if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
-               printf("Write error: bad block in file '");
-               print_current_name();
-               printf("'\n");
-               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 minix_inode *inode, unsigned int blknr)
-{
-       unsigned short ind[BLOCK_SIZE >> 1];
-       unsigned short dind[BLOCK_SIZE >> 1];
-       int blk_chg, block, result;
-
-       if (blknr < 7)
-               return check_zone_nr(inode->i_zone + blknr, &changed);
-       blknr -= 7;
-       if (blknr < 512) {
-               block = check_zone_nr(inode->i_zone + 7, &changed);
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr(blknr + ind, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 512;
-       block = check_zone_nr(inode->i_zone + 8, &changed);
-       read_block(block, (char *) dind);
-       blk_chg = 0;
-       result = check_zone_nr(dind + (blknr / 512), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) dind);
-       block = result;
-       read_block(block, (char *) ind);
-       blk_chg = 0;
-       result = check_zone_nr(ind + (blknr % 512), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) ind);
-       return result;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int map_block2(struct minix2_inode *inode, unsigned int blknr)
-{
-       unsigned int ind[BLOCK_SIZE >> 2];
-       unsigned int dind[BLOCK_SIZE >> 2];
-       unsigned int tind[BLOCK_SIZE >> 2];
-       int blk_chg, block, result;
-
-       if (blknr < 7)
-               return check_zone_nr2(inode->i_zone + blknr, &changed);
-       blknr -= 7;
-       if (blknr < 256) {
-               block = check_zone_nr2(inode->i_zone + 7, &changed);
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr2(blknr + ind, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 256;
-       if (blknr >= 256 * 256) {
-               block = check_zone_nr2(inode->i_zone + 8, &changed);
-               read_block(block, (char *) dind);
-               blk_chg = 0;
-               result = check_zone_nr2(dind + blknr / 256, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) dind);
-               block = result;
-               read_block(block, (char *) ind);
-               blk_chg = 0;
-               result = check_zone_nr2(ind + blknr % 256, &blk_chg);
-               if (blk_chg)
-                       write_block(block, (char *) ind);
-               return result;
-       }
-       blknr -= 256 * 256;
-       block = check_zone_nr2(inode->i_zone + 9, &changed);
-       read_block(block, (char *) tind);
-       blk_chg = 0;
-       result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) tind);
-       block = result;
-       read_block(block, (char *) dind);
-       blk_chg = 0;
-       result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) dind);
-       block = result;
-       read_block(block, (char *) ind);
-       blk_chg = 0;
-       result = check_zone_nr2(ind + blknr % 256, &blk_chg);
-       if (blk_chg)
-               write_block(block, (char *) ind);
-       return result;
-}
-#endif
-
-static void write_super_block(void)
-{
-       /*
-        * Set the state of the filesystem based on whether or not there
-        * are uncorrected errors.  The filesystem valid flag is
-        * unconditionally set if we get this far.
-        */
-       Super.s_state |= MINIX_VALID_FS;
-       if (errors_uncorrected)
-               Super.s_state |= MINIX_ERROR_FS;
-       else
-               Super.s_state &= ~MINIX_ERROR_FS;
-
-       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
-               die("seek failed in write_super_block");
-       if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
-               die("unable to write super-block");
-
-       return;
-}
-
-static void write_tables(void)
-{
-       write_super_block();
-
-       if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
-               die("Unable to write inode map");
-       if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
-               die("Unable to write zone map");
-       if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
-               die("Unable to write inodes");
-}
-
-static void get_dirsize(void)
-{
-       int block;
-       char blk[BLOCK_SIZE];
-       int size;
-
-#ifdef BB_FEATURE_MINIX2
-       if (version2)
-               block = Inode2[ROOT_INO].i_zone[0];
-       else
-#endif
-               block = Inode[ROOT_INO].i_zone[0];
-       read_block(block, blk);
-       for (size = 16; size < BLOCK_SIZE; size <<= 1) {
-               if (strcmp(blk + size + 2, "..") == 0) {
-                       dirsize = size;
-                       namelen = size - 2;
-                       return;
-               }
-       }
-       /* use defaults */
-}
-
-static void read_superblock(void)
-{
-       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
-               die("seek failed");
-       if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
-               die("unable to read super block");
-       if (MAGIC == MINIX_SUPER_MAGIC) {
-               namelen = 14;
-               dirsize = 16;
-               version2 = 0;
-       } else if (MAGIC == MINIX_SUPER_MAGIC2) {
-               namelen = 30;
-               dirsize = 32;
-               version2 = 0;
-#ifdef BB_FEATURE_MINIX2
-       } else if (MAGIC == MINIX2_SUPER_MAGIC) {
-               namelen = 14;
-               dirsize = 16;
-               version2 = 1;
-       } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
-               namelen = 30;
-               dirsize = 32;
-               version2 = 1;
-#endif
-       } else
-               die("bad magic number in super-block");
-       if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
-               die("Only 1k blocks/zones supported");
-       if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
-               die("bad s_imap_blocks field in super-block");
-       if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
-               die("bad s_zmap_blocks field in super-block");
-}
-
-static void read_tables(void)
-{
-       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
-       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
-       memset(inode_map, 0, sizeof(inode_map));
-       memset(zone_map, 0, sizeof(zone_map));
-       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
-       inode_count = xmalloc(INODES + 1);
-       zone_count = xmalloc(ZONES);
-       if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
-               die("Unable to read inode map");
-       if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
-               die("Unable to read zone map");
-       if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
-               die("Unable to read inodes");
-       if (NORM_FIRSTZONE != FIRSTZONE) {
-               printf("Warning: Firstzone != Norm_firstzone\n");
-               errors_uncorrected = 1;
-       }
-       get_dirsize();
-       if (show) {
-               printf("%ld inodes\n", INODES);
-               printf("%ld blocks\n", ZONES);
-               printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
-               printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
-               printf("Maxsize=%ld\n", MAXSIZE);
-               printf("Filesystem state=%d\n", Super.s_state);
-               printf("namelen=%d\n\n", namelen);
-       }
-}
-
-static struct minix_inode *get_inode(unsigned int nr)
-{
-       struct minix_inode *inode;
-
-       if (!nr || nr > INODES)
-               return NULL;
-       total++;
-       inode = Inode + nr;
-       if (!inode_count[nr]) {
-               if (!inode_in_use(nr)) {
-                       printf("Inode %d marked not used, but used for file '", nr);
-                       print_current_name();
-                       printf("'\n");
-                       if (repair) {
-                               if (ask("Mark in use", 1))
-                                       mark_inode(nr);
-                       } else {
-                               errors_uncorrected = 1;
-                       }
-               }
-               if (S_ISDIR(inode->i_mode))
-                       directory++;
-               else if (S_ISREG(inode->i_mode))
-                       regular++;
-               else if (S_ISCHR(inode->i_mode))
-                       chardev++;
-               else if (S_ISBLK(inode->i_mode))
-                       blockdev++;
-               else if (S_ISLNK(inode->i_mode))
-                       symlinks++;
-               else if (S_ISSOCK(inode->i_mode));
-               else if (S_ISFIFO(inode->i_mode));
-               else {
-                       print_current_name();
-                       printf(" has mode %05o\n", inode->i_mode);
-               }
-
-       } else
-               links++;
-       if (!++inode_count[nr]) {
-               printf("Warning: inode count too big.\n");
-               inode_count[nr]--;
-               errors_uncorrected = 1;
-       }
-       return inode;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static struct minix2_inode *get_inode2(unsigned int nr)
-{
-       struct minix2_inode *inode;
-
-       if (!nr || nr > INODES)
-               return NULL;
-       total++;
-       inode = Inode2 + nr;
-       if (!inode_count[nr]) {
-               if (!inode_in_use(nr)) {
-                       printf("Inode %d marked not used, but used for file '", nr);
-                       print_current_name();
-                       printf("'\n");
-                       if (repair) {
-                               if (ask("Mark in use", 1))
-                                       mark_inode(nr);
-                               else
-                                       errors_uncorrected = 1;
-                       }
-               }
-               if (S_ISDIR(inode->i_mode))
-                       directory++;
-               else if (S_ISREG(inode->i_mode))
-                       regular++;
-               else if (S_ISCHR(inode->i_mode))
-                       chardev++;
-               else if (S_ISBLK(inode->i_mode))
-                       blockdev++;
-               else if (S_ISLNK(inode->i_mode))
-                       symlinks++;
-               else if (S_ISSOCK(inode->i_mode));
-               else if (S_ISFIFO(inode->i_mode));
-               else {
-                       print_current_name();
-                       printf(" has mode %05o\n", inode->i_mode);
-               }
-       } else
-               links++;
-       if (!++inode_count[nr]) {
-               printf("Warning: inode count too big.\n");
-               inode_count[nr]--;
-               errors_uncorrected = 1;
-       }
-       return inode;
-}
-#endif
-
-static void check_root(void)
-{
-       struct minix_inode *inode = Inode + ROOT_INO;
-
-       if (!inode || !S_ISDIR(inode->i_mode))
-               die("root inode isn't a directory");
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_root2(void)
-{
-       struct minix2_inode *inode = Inode2 + ROOT_INO;
-
-       if (!inode || !S_ISDIR(inode->i_mode))
-               die("root inode isn't a directory");
-}
-#endif
-
-static int add_zone(unsigned short *znr, int *corrected)
-{
-       int result;
-       int block;
-
-       result = 0;
-       block = check_zone_nr(znr, corrected);
-       if (!block)
-               return 0;
-       if (zone_count[block]) {
-               printf("Block has been used before. Now in file `");
-               print_current_name();
-               printf("'.");
-               if (ask("Clear", 1)) {
-                       *znr = 0;
-                       block = 0;
-                       *corrected = 1;
-               }
-       }
-       if (!block)
-               return 0;
-       if (!zone_in_use(block)) {
-               printf("Block %d in file `", block);
-               print_current_name();
-               printf("' is marked not in use.");
-               if (ask("Correct", 1))
-                       mark_zone(block);
-       }
-       if (!++zone_count[block])
-               zone_count[block]--;
-       return block;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static int add_zone2(unsigned int *znr, int *corrected)
-{
-       int result;
-       int block;
-
-       result = 0;
-       block = check_zone_nr2(znr, corrected);
-       if (!block)
-               return 0;
-       if (zone_count[block]) {
-               printf("Block has been used before. Now in file `");
-               print_current_name();
-               printf("'.");
-               if (ask("Clear", 1)) {
-                       *znr = 0;
-                       block = 0;
-                       *corrected = 1;
-               }
-       }
-       if (!block)
-               return 0;
-       if (!zone_in_use(block)) {
-               printf("Block %d in file `", block);
-               print_current_name();
-               printf("' is marked not in use.");
-               if (ask("Correct", 1))
-                       mark_zone(block);
-       }
-       if (!++zone_count[block])
-               zone_count[block]--;
-       return block;
-}
-#endif
-
-static void add_zone_ind(unsigned short *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, chg_blk = 0;
-       int block;
-
-       block = add_zone(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
-               add_zone(i + (unsigned short *) blk, &chg_blk);
-       if (chg_blk)
-               write_block(block, blk);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void add_zone_ind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, chg_blk = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone2(i + (unsigned int *) blk, &chg_blk);
-       if (chg_blk)
-               write_block(block, blk);
-}
-#endif
-
-static void add_zone_dind(unsigned short *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
-               add_zone_ind(i + (unsigned short *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void add_zone_dind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-
-static void add_zone_tind2(unsigned int *znr, int *corrected)
-{
-       static char blk[BLOCK_SIZE];
-       int i, blk_chg = 0;
-       int block;
-
-       block = add_zone2(znr, corrected);
-       if (!block)
-               return;
-       read_block(block, blk);
-       for (i = 0; i < BLOCK_SIZE >> 2; i++)
-               add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
-       if (blk_chg)
-               write_block(block, blk);
-}
-#endif
-
-static void check_zones(unsigned int i)
-{
-       struct minix_inode *inode;
-
-       if (!i || i > INODES)
-               return;
-       if (inode_count[i] > 1)         /* have we counted this file already? */
-               return;
-       inode = Inode + 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);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_zones2(unsigned int 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 minix_inode *dir, unsigned int offset)
-{
-       static char blk[BLOCK_SIZE];
-       struct minix_inode *inode;
-       int ino;
-       char *name;
-       int block;
-
-       block = map_block(dir, offset / BLOCK_SIZE);
-       read_block(block, blk);
-       name = blk + (offset % BLOCK_SIZE) + 2;
-       ino = *(unsigned short *) (name - 2);
-       if (ino > INODES) {
-               print_current_name();
-               printf(" contains a bad inode number for file '");
-               printf("%.*s'.", namelen, name);
-               if (ask(" Remove", 1)) {
-                       *(unsigned short *) (name - 2) = 0;
-                       write_block(block, blk);
-               }
-               ino = 0;
-       }
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       inode = get_inode(ino);
-       name_depth--;
-       if (!offset) {
-               if (!inode || strcmp(".", name)) {
-                       print_current_name();
-                       printf(": bad directory: '.' isn't first\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (offset == dirsize) {
-               if (!inode || strcmp("..", name)) {
-                       print_current_name();
-                       printf(": bad directory: '..' isn't second\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (!inode)
-               return;
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       if (list) {
-               if (verbose)
-                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
-               print_current_name();
-               if (S_ISDIR(inode->i_mode))
-                       printf(":\n");
-               else
-                       printf("\n");
-       }
-       check_zones(ino);
-       if (inode && S_ISDIR(inode->i_mode))
-               recursive_check(ino);
-       name_depth--;
-       return;
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_file2(struct minix2_inode *dir, unsigned int offset)
-{
-       static char blk[BLOCK_SIZE];
-       struct minix2_inode *inode;
-       int ino;
-       char *name;
-       int block;
-
-       block = map_block2(dir, offset / BLOCK_SIZE);
-       read_block(block, blk);
-       name = blk + (offset % BLOCK_SIZE) + 2;
-       ino = *(unsigned short *) (name - 2);
-       if (ino > INODES) {
-               print_current_name();
-               printf(" contains a bad inode number for file '");
-               printf("%.*s'.", namelen, name);
-               if (ask(" Remove", 1)) {
-                       *(unsigned short *) (name - 2) = 0;
-                       write_block(block, blk);
-               }
-               ino = 0;
-       }
-       if (name_depth < MAX_DEPTH)
-               strncpy(name_list[name_depth], name, namelen);
-       name_depth++;
-       inode = get_inode2(ino);
-       name_depth--;
-       if (!offset) {
-               if (!inode || strcmp(".", name)) {
-                       print_current_name();
-                       printf(": bad directory: '.' isn't first\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (offset == dirsize) {
-               if (!inode || strcmp("..", name)) {
-                       print_current_name();
-                       printf(": bad directory: '..' isn't second\n");
-                       errors_uncorrected = 1;
-               } else
-                       return;
-       }
-       if (!inode)
-               return;
-       name_depth++;
-       if (list) {
-               if (verbose)
-                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
-               print_current_name();
-               if (S_ISDIR(inode->i_mode))
-                       printf(":\n");
-               else
-                       printf("\n");
-       }
-       check_zones2(ino);
-       if (inode && S_ISDIR(inode->i_mode))
-               recursive_check2(ino);
-       name_depth--;
-       return;
-}
-#endif
-
-static void recursive_check(unsigned int ino)
-{
-       struct minix_inode *dir;
-       unsigned int offset;
-
-       dir = Inode + ino;
-       if (!S_ISDIR(dir->i_mode))
-               die("internal error");
-       if (dir->i_size < 2 * dirsize) {
-               print_current_name();
-               printf(": bad directory: size<32");
-               errors_uncorrected = 1;
-       }
-       for (offset = 0; offset < dir->i_size; offset += dirsize)
-               check_file(dir, offset);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino)
-{
-       struct minix2_inode *dir;
-       unsigned int offset;
-
-       dir = Inode2 + ino;
-       if (!S_ISDIR(dir->i_mode))
-               die("internal error");
-       if (dir->i_size < 2 * dirsize) {
-               print_current_name();
-               printf(": bad directory: size < 32");
-               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[1024];
-
-       if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
-               die("seek failed in bad_zone");
-       return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
-}
-
-static void check_counts(void)
-{
-       int i;
-
-       for (i = 1; i <= INODES; i++) {
-               if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
-                       printf("Inode %d mode not cleared.", i);
-                       if (ask("Clear", 1)) {
-                               Inode[i].i_mode = 0;
-                               changed = 1;
-                       }
-               }
-               if (!inode_count[i]) {
-                       if (!inode_in_use(i))
-                               continue;
-                       printf("Inode %d not used, marked used in the bitmap.", i);
-                       if (ask("Clear", 1))
-                               unmark_inode(i);
-                       continue;
-               }
-               if (!inode_in_use(i)) {
-                       printf("Inode %d used, marked unused in the bitmap.", i);
-                       if (ask("Set", 1))
-                               mark_inode(i);
-               }
-               if (Inode[i].i_nlinks != inode_count[i]) {
-                       printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
-                                  i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]);
-                       if (ask("Set i_nlinks to count", 1)) {
-                               Inode[i].i_nlinks = inode_count[i];
-                               changed = 1;
-                       }
-               }
-       }
-       for (i = FIRSTZONE; i < ZONES; i++) {
-               if (zone_in_use(i) == zone_count[i])
-                       continue;
-               if (!zone_count[i]) {
-                       if (bad_zone(i))
-                               continue;
-                       printf("Zone %d: marked in use, 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]);
-       }
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check_counts2(void)
-{
-       int i;
-
-       for (i = 1; i <= INODES; i++) {
-               if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
-                       printf("Inode %d mode not cleared.", i);
-                       if (ask("Clear", 1)) {
-                               Inode2[i].i_mode = 0;
-                               changed = 1;
-                       }
-               }
-               if (!inode_count[i]) {
-                       if (!inode_in_use(i))
-                               continue;
-                       printf("Inode %d not used, marked used in the bitmap.", i);
-                       if (ask("Clear", 1))
-                               unmark_inode(i);
-                       continue;
-               }
-               if (!inode_in_use(i)) {
-                       printf("Inode %d used, marked 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) == zone_count[i])
-                       continue;
-               if (!zone_count[i]) {
-                       if (bad_zone(i))
-                               continue;
-                       printf("Zone %d: marked in use, 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(ROOT_INO);
-       recursive_check(ROOT_INO);
-       check_counts();
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void check2(void)
-{
-       memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
-       memset(zone_count, 0, ZONES * sizeof(*zone_count));
-       check_zones2(ROOT_INO);
-       recursive_check2(ROOT_INO);
-       check_counts2();
-}
-#endif
-
-/* Wed Feb  9 15:17:06 MST 2000 */
-/* dynamically allocate name_list (instead of making it static) */
-static void alloc_name_list(void)
-{
-       int i;
-
-       name_list = xmalloc(sizeof(char *) * MAX_DEPTH);
-       for (i = 0; i < MAX_DEPTH; i++)
-               name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
-}
-
-#ifdef BB_FEATURE_CLEAN_UP
-/* execute this atexit() to deallocate name_list[] */
-/* piptigger was here */
-static void free_name_list(void)
-{
-       int i;
-
-       if (name_list) { 
-               for (i = 0; i < MAX_DEPTH; i++) {
-                       if (name_list[i]) {
-                               free(name_list[i]);
-                       }
-               }
-               free(name_list);
-       }
-}
-#endif
-
-extern int fsck_minix_main(int argc, char **argv)
-{
-       struct termios tmp;
-       int count;
-       int retcode = 0;
-
-       alloc_name_list();
-#ifdef BB_FEATURE_CLEAN_UP
-       /* Don't bother to free memory.  Exit does
-        * that automagically, so we can save a few bytes */
-       atexit(free_name_list);
-#endif
-
-       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
-               die("bad inode size");
-#ifdef BB_FEATURE_MINIX2
-       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
-               die("bad v2 inode size");
-#endif
-       while (argc-- > 1) {
-               argv++;
-               if (argv[0][0] != '-') {
-                       if (device_name)
-                               show_usage();
-                       else
-                               device_name = argv[0];
-               } else
-                       while (*++argv[0])
-                               switch (argv[0][0]) {
-                               case 'l':
-                                       list = 1;
-                                       break;
-                               case 'a':
-                                       automatic = 1;
-                                       repair = 1;
-                                       break;
-                               case 'r':
-                                       automatic = 0;
-                                       repair = 1;
-                                       break;
-                               case 'v':
-                                       verbose = 1;
-                                       break;
-                               case 's':
-                                       show = 1;
-                                       break;
-                               case 'm':
-                                       warn_mode = 1;
-                                       break;
-                               case 'f':
-                                       force = 1;
-                                       break;
-                               default:
-                                       show_usage();
-                               }
-       }
-       if (!device_name)
-               show_usage();
-       check_mount();                          /* trying to check a mounted filesystem? */
-       if (repair && !automatic) {
-               if (!isatty(0) || !isatty(1))
-                       die("need terminal for interactive repairs");
-       }
-       IN = open(device_name, repair ? O_RDWR : O_RDONLY);
-       if (IN < 0){
-               fprintf(stderr,"unable to open device '%s'.\n",device_name);
-               leave(8);
-       }
-       for (count = 0; count < 3; count++)
-               sync();
-       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, program_version);
-       if (!(Super.s_state & MINIX_ERROR_FS) &&
-               (Super.s_state & MINIX_VALID_FS) && !force) {
-               if (repair)
-                       printf("%s is clean, no check.\n", device_name);
-               return retcode;
-       } else if (force)
-               printf("Forcing filesystem check on %s.\n", device_name);
-       else if (repair)
-               printf("Filesystem on %s is dirty, needs checking.\n",
-                          device_name);
-
-       read_tables();
-
-       if (repair && !automatic) {
-               tcgetattr(0, &termios);
-               tmp = termios;
-               tmp.c_lflag &= ~(ICANON | ECHO);
-               tcsetattr(0, TCSANOW, &tmp);
-               termios_set = 1;
-       }
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               check_root2();
-               check2();
-       } else
-#endif
-       {
-               check_root();
-               check();
-       }
-       if (verbose) {
-               int i, free_cnt;
-
-               for (i = 1, free_cnt = 0; i <= INODES; i++)
-                       if (!inode_in_use(i))
-                               free_cnt++;
-               printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt),
-                          100 * (INODES - free_cnt) / INODES);
-               for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
-                       if (!zone_in_use(i))
-                               free_cnt++;
-               printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt),
-                          100 * (ZONES - free_cnt) / ZONES);
-               printf("\n%6d regular files\n"
-                          "%6d directories\n"
-                          "%6d character device files\n"
-                          "%6d block device files\n"
-                          "%6d links\n"
-                          "%6d symbolic links\n"
-                          "------\n"
-                          "%6d files\n",
-                          regular, directory, chardev, blockdev,
-                          links - 2 * directory + 1, symlinks,
-                          total - 2 * directory + 1);
-       }
-       if (changed) {
-               write_tables();
-               printf("----------------------------\n"
-                          "FILE SYSTEM HAS BEEN CHANGED\n"
-                          "----------------------------\n");
-               for (count = 0; count < 3; count++)
-                       sync();
-       } else if (repair)
-               write_super_block();
-
-       if (repair && !automatic)
-               tcsetattr(0, TCSANOW, &termios);
-
-       if (changed)
-               retcode += 3;
-       if (errors_uncorrected)
-               retcode += 4;
-       return retcode;
-}
diff --git a/busybox/util-linux/getopt.c b/busybox/util-linux/getopt.c
deleted file mode 100644 (file)
index 95ecba6..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * getopt.c - Enhanced implementation of BSD getopt(1)
- *   Copyright (c) 1997, 1998, 1999, 2000  Frodo Looijaard <frodol@dds.nl>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * Version 1.0-b4: Tue Sep 23 1997. First public release.
- * Version 1.0: Wed Nov 19 1997.
- *   Bumped up the version number to 1.0
- *   Fixed minor typo (CSH instead of TCSH)
- * Version 1.0.1: Tue Jun 3 1998
- *   Fixed sizeof instead of strlen bug
- *   Bumped up the version number to 1.0.1
- * Version 1.0.2: Thu Jun 11 1998 (not present)
- *   Fixed gcc-2.8.1 warnings
- *   Fixed --version/-V option (not present)
- * Version 1.0.5: Tue Jun 22 1999
- *   Make -u option work (not present)
- * Version 1.0.6: Tue Jun 27 2000
- *   No important changes
- * Version 1.1.0: Tue Jun 30 2000
- *   Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
- *     <misiek@misiek.eu.org>)
- * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
- *  Removed --version/-V and --help/-h in
- *  Removed prase_error(), using error_msg() from Busybox instead
- *  Replaced our_malloc with xmalloc and our_realloc with xrealloc
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <getopt.h>
-
-#include "busybox.h"
-
-/* NON_OPT is the code that is returned when a non-option is found in '+'
-   mode */
-static const int NON_OPT = 1;
-/* LONG_OPT is the code that is returned when a long option is found. */
-static const int LONG_OPT = 2;
-
-/* The shells recognized. */
-typedef enum {BASH,TCSH} shell_t;
-
-
-/* Some global variables that tells us how to parse. */
-static shell_t shell=BASH; /* The shell we generate output for. */
-static int quiet_errors=0; /* 0 is not quiet. */
-static int quiet_output=0; /* 0 is not quiet. */
-static int quote=1; /* 1 is do quote. */
-static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
-
-/* Function prototypes */
-static const char *normalize(const char *arg);
-static int generate_output(char * argv[],int argc,const char *optstr,
-                    const struct option *longopts);
-static void add_long_options(char *options);
-static void add_longopt(const char *name,int has_arg);
-static void set_shell(const char *new_shell);
-
-
-/*
- * This function 'normalizes' a single argument: it puts single quotes around
- * it and escapes other special characters. If quote is false, it just
- * returns its argument.
- * Bash only needs special treatment for single quotes; tcsh also recognizes
- * exclamation marks within single quotes, and nukes whitespace.
- * This function returns a pointer to a buffer that is overwritten by
- * each call.
- */
-const char *normalize(const char *arg)
-{
-        static char *BUFFER=NULL;
-        const char *argptr=arg;
-        char *bufptr;
-
-        if (BUFFER != NULL)
-                free(BUFFER);
-
-        if (!quote) { /* Just copy arg */
-                BUFFER=xmalloc(strlen(arg)+1);
-
-                strcpy(BUFFER,arg);
-                return BUFFER;
-        }
-
-        /* Each character in arg may take upto four characters in the result:
-           For a quote we need a closing quote, a backslash, a quote and an
-           opening quote! We need also the global opening and closing quote,
-           and one extra character for '\0'. */
-        BUFFER=xmalloc(strlen(arg)*4+3);
-
-        bufptr=BUFFER;
-        *bufptr++='\'';
-
-        while (*argptr) {
-                if (*argptr == '\'') {
-                        /* Quote: replace it with: '\'' */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++='\'';
-                        *bufptr++='\'';
-                } else if (shell==TCSH && *argptr=='!') {
-                        /* Exclamation mark: replace it with: \! */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++='!';
-                        *bufptr++='\'';
-                } else if (shell==TCSH && *argptr=='\n') {
-                        /* Newline: replace it with: \n */
-                        *bufptr++='\\';
-                        *bufptr++='n';
-                } else if (shell==TCSH && isspace(*argptr)) {
-                        /* Non-newline whitespace: replace it with \<ws> */
-                        *bufptr++='\'';
-                        *bufptr++='\\';
-                        *bufptr++=*argptr;
-                        *bufptr++='\'';
-                } else
-                        /* Just copy */
-                        *bufptr++=*argptr;
-                argptr++;
-        }
-        *bufptr++='\'';
-        *bufptr++='\0';
-        return BUFFER;
-}
-
-/*
- * Generate the output. argv[0] is the program name (used for reporting errors).
- * argv[1..] contains the options to be parsed. argc must be the number of
- * elements in argv (ie. 1 if there are no options, only the program name),
- * optstr must contain the short options, and longopts the long options.
- * Other settings are found in global variables.
- */
-int generate_output(char * argv[],int argc,const char *optstr,
-                    const struct option *longopts)
-{
-        int exit_code = 0; /* We assume everything will be OK */
-        int opt;
-        int longindex;
-        const char *charptr;
-
-        if (quiet_errors) /* No error reporting from getopt(3) */
-                opterr=0;
-        optind=0; /* Reset getopt(3) */
-
-        while ((opt = (alternative?
-                       getopt_long_only(argc,argv,optstr,longopts,&longindex):
-                       getopt_long(argc,argv,optstr,longopts,&longindex)))
-               != EOF)
-                if (opt == '?' || opt == ':' )
-                        exit_code = 1;
-                else if (!quiet_output) {
-                        if (opt == LONG_OPT) {
-                                printf(" --%s",longopts[longindex].name);
-                                if (longopts[longindex].has_arg)
-                                        printf(" %s",
-                                               normalize(optarg?optarg:""));
-                        } else if (opt == NON_OPT)
-                                printf(" %s",normalize(optarg));
-                        else {
-                                printf(" -%c",opt);
-                                charptr = strchr(optstr,opt);
-                                if (charptr != NULL && *++charptr == ':')
-                                        printf(" %s",
-                                               normalize(optarg?optarg:""));
-                        }
-                }
-
-        if (! quiet_output) {
-                printf(" --");
-                while (optind < argc)
-                        printf(" %s",normalize(argv[optind++]));
-                printf("\n");
-        }
-        return exit_code;
-}
-
-static struct option *long_options=NULL;
-static int long_options_length=0; /* Length of array */
-static int long_options_nr=0; /* Nr of used elements in array */
-static const int LONG_OPTIONS_INCR = 10;
-#define init_longopt() add_longopt(NULL,0)
-
-/* Register a long option. The contents of name is copied. */
-void add_longopt(const char *name,int has_arg)
-{
-        char *tmp;
-        if (!name) { /* init */
-                free(long_options);
-                long_options=NULL;
-                long_options_length=0;
-                long_options_nr=0;
-        }
-
-        if (long_options_nr == long_options_length) {
-                long_options_length += LONG_OPTIONS_INCR;
-                long_options=xrealloc(long_options,
-                                         sizeof(struct option) *
-                                         long_options_length);
-        }
-
-        long_options[long_options_nr].name=NULL;
-        long_options[long_options_nr].has_arg=0;
-        long_options[long_options_nr].flag=NULL;
-        long_options[long_options_nr].val=0;
-
-        if (long_options_nr) { /* Not for init! */
-                long_options[long_options_nr-1].has_arg=has_arg;
-                long_options[long_options_nr-1].flag=NULL;
-                long_options[long_options_nr-1].val=LONG_OPT;
-                tmp = xmalloc(strlen(name)+1);
-                strcpy(tmp,name);
-                long_options[long_options_nr-1].name=tmp;
-        }
-        long_options_nr++;
-}
-
-
-/*
- * Register several long options. options is a string of long options,
- * separated by commas or whitespace.
- * This nukes options!
- */
-void add_long_options(char *options)
-{
-        int arg_opt, tlen;
-        char *tokptr=strtok(options,", \t\n");
-        while (tokptr) {
-                arg_opt=no_argument;
-               tlen=strlen(tokptr);
-                if (tlen > 0) {
-                        if (tokptr[tlen-1] == ':') {
-                                if (tlen > 1 && tokptr[tlen-2] == ':') {
-                                        tokptr[tlen-2]='\0';
-                                       tlen -= 2;
-                                        arg_opt=optional_argument;
-                                } else {
-                                        tokptr[tlen-1]='\0';
-                                       tlen -= 1;
-                                        arg_opt=required_argument;
-                                }
-                                if (tlen == 0)
-                                        error_msg("empty long option after -l or --long argument");
-                        }
-                        add_longopt(tokptr,arg_opt);
-                }
-                tokptr=strtok(NULL,", \t\n");
-        }
-}
-
-void set_shell(const char *new_shell)
-{
-        if (!strcmp(new_shell,"bash"))
-                shell=BASH;
-        else if (!strcmp(new_shell,"tcsh"))
-                shell=TCSH;
-        else if (!strcmp(new_shell,"sh"))
-                shell=BASH;
-        else if (!strcmp(new_shell,"csh"))
-                shell=TCSH;
-        else
-                error_msg("unknown shell after -s or --shell argument");
-}
-
-
-/* Exit codes:
- *   0) No errors, succesful operation.
- *   1) getopt(3) returned an error.
- *   2) A problem with parameter parsing for getopt(1).
- *   3) Internal error, out of memory
- *   4) Returned for -T
- */
-
-static struct option longopts[]=
-{
-        {"options",required_argument,NULL,'o'},
-        {"longoptions",required_argument,NULL,'l'},
-        {"quiet",no_argument,NULL,'q'},
-        {"quiet-output",no_argument,NULL,'Q'},
-        {"shell",required_argument,NULL,'s'},
-        {"test",no_argument,NULL,'T'},
-        {"unquoted",no_argument,NULL,'u'},
-        {"alternative",no_argument,NULL,'a'},
-        {"name",required_argument,NULL,'n'},
-        {NULL,0,NULL,0}
-};
-
-/* Stop scanning as soon as a non-option argument is found! */
-static const char *shortopts="+ao:l:n:qQs:Tu";
-
-
-int getopt_main(int argc, char *argv[])
-{
-        char *optstr=NULL;
-        char *name=NULL;
-        int opt;
-        int compatible=0;
-
-        init_longopt();
-
-        if (getenv("GETOPT_COMPATIBLE"))
-                compatible=1;
-
-        if (argc == 1) {
-                if (compatible) {
-                        /* For some reason, the original getopt gave no error
-                           when there were no arguments. */
-                        printf(" --\n");
-                        exit(0);
-                } else
-                        error_msg_and_die("missing optstring argument");
-        }
-
-        if (argv[1][0] != '-' || compatible) {
-                quote=0;
-                optstr=xmalloc(strlen(argv[1])+1);
-                strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
-                argv[1]=argv[0];
-                exit(generate_output(argv+1,argc-1,optstr,long_options));
-        }
-
-        while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
-                switch (opt) {
-                case 'a':
-                        alternative=1;
-                        break;
-                case 'o':
-                        if (optstr)
-                                free(optstr);
-                        optstr=xmalloc(strlen(optarg)+1);
-                        strcpy(optstr,optarg);
-                        break;
-                case 'l':
-                        add_long_options(optarg);
-                        break;
-                case 'n':
-                        if (name)
-                                free(name);
-                        name=xmalloc(strlen(optarg)+1);
-                        strcpy(name,optarg);
-                        break;
-                case 'q':
-                        quiet_errors=1;
-                        break;
-                case 'Q':
-                        quiet_output=1;
-                        break;
-                case 's':
-                        set_shell(optarg);
-                        break;
-                case 'T':
-                        exit(4);
-                case 'u':
-                        quote=0;
-                        break;
-                default:
-                        show_usage();
-                }
-
-        if (!optstr) {
-                if (optind >= argc)
-                        error_msg_and_die("missing optstring argument");
-                else {
-                        optstr=xmalloc(strlen(argv[optind])+1);
-                        strcpy(optstr,argv[optind]);
-                        optind++;
-                }
-        }
-        if (name)
-                argv[optind-1]=name;
-        else
-                argv[optind-1]=argv[0];
-        exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
-}
-
-/*
-  Local Variables:
-  c-file-style: "linux"
-  c-basic-offset: 4
-  tab-width: 4
-  End:
-*/
diff --git a/busybox/util-linux/mkfs_minix.c b/busybox/util-linux/mkfs_minix.c
deleted file mode 100644 (file)
index ccc0e85..0000000
+++ /dev/null
@@ -1,847 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * mkfs.c - make a linux (minix) file-system.
- *
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
- */
-
-/*
- * DD.MM.YY
- *
- * 24.11.91  - Time began. Used the fsck sources to get started.
- *
- * 25.11.91  - Corrected some bugs. Added support for ".badblocks"
- *             The algorithm for ".badblocks" is a bit weird, but
- *             it should work. Oh, well.
- *
- * 25.01.92  - Added the -l option for getting the list of bad blocks
- *             out of a named file. (Dave Rivers, rivers@ponds.uucp)
- *
- * 28.02.92  - Added %-information when using -c.
- *
- * 28.02.93  - Added support for other namelengths than the original
- *             14 characters so that I can test the new kernel routines..
- *
- * 09.10.93  - Make exit status conform to that required by fsutil
- *             (Rik Faith, faith@cs.unc.edu)
- *
- * 31.10.93  - Added inode request feature, for backup floppies: use
- *             32 inodes, for a news partition use more.
- *             (Scott Heavner, sdh@po.cwru.edu)
- *
- * 03.01.94  - Added support for file system valid flag.
- *             (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
- *
- * 30.10.94 - added support for v2 filesystem
- *           (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
- * 
- * 09.11.94  - Added test to prevent overwrite of mounted fs adapted
- *             from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
- *             program.  (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 03.20.95  - Clear first 512 bytes of filesystem to make certain that
- *             the filesystem is not misidentified as a MS-DOS FAT filesystem.
- *             (Daniel Quinlan, quinlan@yggdrasil.com)
- *
- * 02.07.96  -  Added small patch from Russell King to make the program a
- *             good deal more portable (janl@math.uio.no)
- *
- * Usage:  mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
- *
- *     -c for readablility checking (SLOW!)
- *      -l for getting a list of bad blocks from a file.
- *     -n for namelength (currently the kernel only uses 14 or 30)
- *     -i for number of inodes
- *     -v for v2 filesystem
- *
- * The device may be a block device or a image of one, but this isn't
- * enforced (but it's not much fun on a character device :-). 
- *
- * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
- *     removed getopt based parser and added a hand rolled one.
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <mntent.h>
-#include "busybox.h"
-
-#define MINIX_ROOT_INO 1
-#define MINIX_LINK_MAX 250
-#define MINIX2_LINK_MAX        65530
-
-#define MINIX_I_MAP_SLOTS      8
-#define MINIX_Z_MAP_SLOTS      64
-#define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
-#define MINIX2_SUPER_MAGIC     0x2468          /* minix V2 fs */
-#define MINIX2_SUPER_MAGIC2    0x2478          /* minix V2 fs, 30 char names */
-#define MINIX_VALID_FS         0x0001          /* Clean fs. */
-#define MINIX_ERROR_FS         0x0002          /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-
-#define MINIX_V1               0x0001          /* original minix fs */
-#define MINIX_V2               0x0002          /* minix V2 fs */
-
-#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
-       u_int16_t i_mode;
-       u_int16_t i_uid;
-       u_int32_t i_size;
-       u_int32_t i_time;
-       u_int8_t  i_gid;
-       u_int8_t  i_nlinks;
-       u_int16_t i_zone[9];
-};
-
-/*
- * The new minix inode has all the time entries, as well as
- * long block numbers and a third indirect block (7+1+1+1
- * instead of 7+1+1). Also, some previously 8-bit values are
- * now 16-bit. The inode is now 64 bytes instead of 32.
- */
-struct minix2_inode {
-       u_int16_t i_mode;
-       u_int16_t i_nlinks;
-       u_int16_t i_uid;
-       u_int16_t i_gid;
-       u_int32_t i_size;
-       u_int32_t i_atime;
-       u_int32_t i_mtime;
-       u_int32_t i_ctime;
-       u_int32_t i_zone[10];
-};
-
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
-       u_int16_t s_ninodes;
-       u_int16_t s_nzones;
-       u_int16_t s_imap_blocks;
-       u_int16_t s_zmap_blocks;
-       u_int16_t s_firstdatazone;
-       u_int16_t s_log_zone_size;
-       u_int32_t s_max_size;
-       u_int16_t s_magic;
-       u_int16_t s_state;
-       u_int32_t s_zones;
-};
-
-struct minix_dir_entry {
-       u_int16_t inode;
-       char name[0];
-};
-
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-#define NAME_MAX         255   /* # chars in a file name */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-
-#define MINIX_VALID_FS               0x0001          /* Clean fs. */
-#define MINIX_ERROR_FS               0x0002          /* fs has errors. */
-
-#define MINIX_SUPER_MAGIC    0x137F          /* original minix fs */
-#define MINIX_SUPER_MAGIC2   0x138F          /* minix fs, 30 char names */
-
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96)    /* return device size */
-#endif
-
-
-#ifndef __linux__
-#define volatile
-#endif
-
-#define MINIX_ROOT_INO 1
-#define MINIX_BAD_INO 2
-
-#define TEST_BUFFER_BLOCKS 16
-#define MAX_GOOD_BLOCKS 512
-
-#define UPPER(size,n) (((size)+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef BB_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
-                                   : MINIX_INODES_PER_BLOCK))
-#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
-#endif
-#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
-
-#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long BLOCKS = 0;
-static int check = 0;
-static int badblocks = 0;
-static int namelen = 30;               /* default (changed to 30, per Linus's
-
-                                                                  suggestion, Sun Nov 21 08:05:07 1993) */
-static int dirsize = 32;
-static int magic = MINIX_SUPER_MAGIC2;
-static int version2 = 0;
-
-static char root_block[BLOCK_SIZE] = "\0";
-
-static char *inode_buffer = NULL;
-
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#ifdef BB_FEATURE_MINIX2
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-#endif
-static char super_block_buffer[BLOCK_SIZE];
-static char boot_block_buffer[512];
-
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef BB_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
-#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
-static int used_good_blocks = 0;
-static unsigned long req_nr_inodes = 0;
-
-static inline int bit(char * a,unsigned int i)
-{
-         return (a[i >> 3] & (1<<(i & 7))) != 0;
-}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-
-#define mark_inode(x) (setbit(inode_map,(x)))
-#define unmark_inode(x) (clrbit(inode_map,(x)))
-
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
-
-/*
- * Check to make certain that our new filesystem won't be created on
- * an already mounted partition.  Code adapted from mke2fs, Copyright
- * (C) 1994 Theodore Ts'o.  Also licensed under GPL.
- */
-static void check_mount(void)
-{
-       FILE *f;
-       struct mntent *mnt;
-
-       if ((f = setmntent(MOUNTED, "r")) == NULL)
-               return;
-       while ((mnt = getmntent(f)) != NULL)
-               if (strcmp(device_name, mnt->mnt_fsname) == 0)
-                       break;
-       endmntent(f);
-       if (!mnt)
-               return;
-
-       error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
-}
-
-static long valid_offset(int fd, int offset)
-{
-       char ch;
-
-       if (lseek(fd, offset, 0) < 0)
-               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;
-
-       if ((fd = open(file, O_RDWR)) < 0)
-               perror_msg_and_die("%s", file);
-       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
-               close(fd);
-               return (size * 512);
-       }
-
-       size = count_blocks(fd);
-       close(fd);
-       return size;
-}
-
-static void write_tables(void)
-{
-       /* Mark the super block valid. */
-       Super.s_state |= MINIX_VALID_FS;
-       Super.s_state &= ~MINIX_ERROR_FS;
-
-       if (lseek(DEV, 0, SEEK_SET))
-               error_msg_and_die("seek to boot block failed in write_tables");
-       if (512 != write(DEV, boot_block_buffer, 512))
-               error_msg_and_die("unable to clear boot sector");
-       if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
-               error_msg_and_die("seek failed in write_tables");
-       if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
-               error_msg_and_die("unable to write super-block");
-       if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
-               error_msg_and_die("unable to write inode map");
-       if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
-               error_msg_and_die("unable to write zone map");
-       if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
-               error_msg_and_die("unable to write inodes");
-
-}
-
-static void write_block(int blk, char *buffer)
-{
-       if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
-               error_msg_and_die("seek failed in write_block");
-       if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
-               error_msg_and_die("write failed in write_block");
-}
-
-static int get_free_block(void)
-{
-       int blk;
-
-       if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
-               error_msg_and_die("too many bad blocks");
-       if (used_good_blocks)
-               blk = good_blocks_table[used_good_blocks - 1] + 1;
-       else
-               blk = FIRSTZONE;
-       while (blk < ZONES && zone_in_use(blk))
-               blk++;
-       if (blk >= ZONES)
-               error_msg_and_die("not enough good blocks");
-       good_blocks_table[used_good_blocks] = blk;
-       used_good_blocks++;
-       return blk;
-}
-
-static void mark_good_blocks(void)
-{
-       int blk;
-
-       for (blk = 0; blk < used_good_blocks; blk++)
-               mark_zone(good_blocks_table[blk]);
-}
-
-static int next(int zone)
-{
-       if (!zone)
-               zone = FIRSTZONE - 1;
-       while (++zone < ZONES)
-               if (zone_in_use(zone))
-                       return zone;
-       return 0;
-}
-
-static void make_bad_inode(void)
-{
-       struct minix_inode *inode = &Inode[MINIX_BAD_INO];
-       int i, j, zone;
-       int ind = 0, dind = 0;
-       unsigned short ind_block[BLOCK_SIZE >> 1];
-       unsigned short dind_block[BLOCK_SIZE >> 1];
-
-#define NEXT_BAD (zone = next(zone))
-
-       if (!badblocks)
-               return;
-       mark_inode(MINIX_BAD_INO);
-       inode->i_nlinks = 1;
-       inode->i_time = time(NULL);
-       inode->i_mode = S_IFREG + 0000;
-       inode->i_size = 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;
-               }
-       }
-       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);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void make_bad_inode2(void)
-{
-       struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
-       int i, j, zone;
-       int ind = 0, dind = 0;
-       unsigned long ind_block[BLOCK_SIZE >> 2];
-       unsigned long dind_block[BLOCK_SIZE >> 2];
-
-       if (!badblocks)
-               return;
-       mark_inode(MINIX_BAD_INO);
-       inode->i_nlinks = 1;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
-       inode->i_mode = S_IFREG + 0000;
-       inode->i_size = 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 */
-       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);
-}
-#endif
-
-static void make_root_inode(void)
-{
-       struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
-
-       mark_inode(MINIX_ROOT_INO);
-       inode->i_zone[0] = get_free_block();
-       inode->i_nlinks = 2;
-       inode->i_time = time(NULL);
-       if (badblocks)
-               inode->i_size = 3 * dirsize;
-       else {
-               root_block[2 * dirsize] = '\0';
-               root_block[2 * dirsize + 1] = '\0';
-               inode->i_size = 2 * 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], root_block);
-}
-
-#ifdef BB_FEATURE_MINIX2
-static void make_root_inode2(void)
-{
-       struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
-
-       mark_inode(MINIX_ROOT_INO);
-       inode->i_zone[0] = get_free_block();
-       inode->i_nlinks = 2;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
-       if (badblocks)
-               inode->i_size = 3 * dirsize;
-       else {
-               root_block[2 * dirsize] = '\0';
-               root_block[2 * dirsize + 1] = '\0';
-               inode->i_size = 2 * 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], root_block);
-}
-#endif
-
-static void setup_tables(void)
-{
-       int i;
-       unsigned long inodes;
-
-       memset(super_block_buffer, 0, BLOCK_SIZE);
-       memset(boot_block_buffer, 0, 512);
-       MAGIC = magic;
-       ZONESIZE = 0;
-       MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
-       ZONES = BLOCKS;
-/* some magic nrs: 1 inode / 3 blocks */
-       if (req_nr_inodes == 0)
-               inodes = BLOCKS / 3;
-       else
-               inodes = req_nr_inodes;
-       /* Round up inode count to fill block size */
-#ifdef BB_FEATURE_MINIX2
-       if (version2)
-               inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
-                                 ~(MINIX2_INODES_PER_BLOCK - 1));
-       else
-#endif
-               inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
-                                 ~(MINIX_INODES_PER_BLOCK - 1));
-       if (inodes > 65535)
-               inodes = 65535;
-       INODES = inodes;
-       IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
-       ZMAPS = 0;
-       i = 0;
-       while (ZMAPS !=
-                  UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
-                                BITS_PER_BLOCK) && i < 1000) {
-               ZMAPS =
-                       UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
-                                 BITS_PER_BLOCK);
-               i++;
-       }
-       /* Real bad hack but overwise mkfs.minix can be thrown
-        * in infinite loop...
-        * try:
-        * dd if=/dev/zero of=test.fs count=10 bs=1024
-        * /sbin/mkfs.minix -i 200 test.fs
-        * */
-       if (i >= 999) {
-               error_msg_and_die("unable to allocate buffers for maps");
-       }
-       FIRSTZONE = NORM_FIRSTZONE;
-       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
-       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
-       memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
-       memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
-       for (i = FIRSTZONE; i < ZONES; i++)
-               unmark_zone(i);
-       for (i = MINIX_ROOT_INO; i <= INODES; i++)
-               unmark_inode(i);
-       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
-       memset(inode_buffer, 0, INODE_BUFFER_SIZE);
-       printf("%ld inodes\n", INODES);
-       printf("%ld blocks\n", ZONES);
-       printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
-       printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
-       printf("Maxsize=%ld\n\n", MAXSIZE);
-}
-
-/*
- * Perform a test of a block; return the number of
- * blocks readable/writeable.
- */
-static long do_check(char *buffer, int try, unsigned int current_block)
-{
-       long got;
-
-       /* Seek to the correct loc. */
-       if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
-               current_block * BLOCK_SIZE) {
-               error_msg_and_die("seek failed during testing of blocks");
-       }
-
-
-       /* Try the read */
-       got = read(DEV, buffer, try * BLOCK_SIZE);
-       if (got < 0)
-               got = 0;
-       if (got & (BLOCK_SIZE - 1)) {
-               printf("Weird values in do_check: probably bugs\n");
-       }
-       got /= BLOCK_SIZE;
-       return got;
-}
-
-static unsigned int currently_testing = 0;
-
-static void alarm_intr(int alnum)
-{
-       if (currently_testing >= ZONES)
-               return;
-       signal(SIGALRM, alarm_intr);
-       alarm(5);
-       if (!currently_testing)
-               return;
-       printf("%d ...", currently_testing);
-       fflush(stdout);
-}
-
-static void check_blocks(void)
-{
-       int try, got;
-       static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
-
-       currently_testing = 0;
-       signal(SIGALRM, alarm_intr);
-       alarm(5);
-       while (currently_testing < ZONES) {
-               if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
-                       currently_testing * BLOCK_SIZE)
-                       error_msg_and_die("seek failed in check_blocks");
-               try = TEST_BUFFER_BLOCKS;
-               if (currently_testing + try > ZONES)
-                       try = ZONES - currently_testing;
-               got = do_check(buffer, try, currently_testing);
-               currently_testing += got;
-               if (got == try)
-                       continue;
-               if (currently_testing < FIRSTZONE)
-                       error_msg_and_die("bad blocks before data-area: cannot make fs");
-               mark_zone(currently_testing);
-               badblocks++;
-               currently_testing++;
-       }
-       if (badblocks > 1)
-               printf("%d bad blocks\n", badblocks);
-       else if (badblocks == 1)
-               printf("one bad block\n");
-}
-
-static void get_list_blocks(filename)
-char *filename;
-
-{
-       FILE *listfile;
-       unsigned long blockno;
-
-       listfile = xfopen(filename, "r");
-       while (!feof(listfile)) {
-               fscanf(listfile, "%ld\n", &blockno);
-               mark_zone(blockno);
-               badblocks++;
-       }
-       if (badblocks > 1)
-               printf("%d bad blocks\n", badblocks);
-       else if (badblocks == 1)
-               printf("one bad block\n");
-}
-
-extern int mkfs_minix_main(int argc, char **argv)
-{
-       int i=1;
-       char *tmp;
-       struct stat statbuf;
-       char *listfile = NULL;
-       int stopIt=FALSE;
-
-       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
-               error_msg_and_die("bad inode size");
-#ifdef BB_FEATURE_MINIX2
-       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
-               error_msg_and_die("bad inode size");
-#endif
-       
-       /* Parse options */
-       argv++;
-       while (--argc >= 0 && *argv && **argv) {
-               if (**argv == '-') {
-                       stopIt=FALSE;
-                       while (i > 0 && *++(*argv) && stopIt==FALSE) {
-                               switch (**argv) {
-                                       case 'c':
-                                               check = 1;
-                                               break;
-                                       case 'i':
-                                               {
-                                                       char *cp=NULL;
-                                                       if (*(*argv+1) != 0) {
-                                                               cp = ++(*argv);
-                                                       } else {
-                                                               if (--argc == 0) {
-                                                                       goto goodbye;
-                                                               }
-                                                               cp = *(++argv);
-                                                       }
-                                                       req_nr_inodes = strtoul(cp, &tmp, 0);
-                                                       if (*tmp)
-                                                               show_usage();
-                                                       stopIt=TRUE;
-                                                       break;
-                                               }
-                                       case 'l':
-                                               if (--argc == 0) {
-                                                       goto goodbye;
-                                               }
-                                               listfile = *(++argv);
-                                               break;
-                                       case 'n':
-                                               {
-                                                       char *cp=NULL;
-
-                                                       if (*(*argv+1) != 0) {
-                                                               cp = ++(*argv);
-                                                       } else {
-                                                               if (--argc == 0) {
-                                                                       goto goodbye;
-                                                               }
-                                                               cp = *(++argv);
-                                                       }
-                                                       i = strtoul(cp, &tmp, 0);
-                                                       if (*tmp)
-                                                               show_usage();
-                                                       if (i == 14)
-                                                               magic = MINIX_SUPER_MAGIC;
-                                                       else if (i == 30)
-                                                               magic = MINIX_SUPER_MAGIC2;
-                                                       else 
-                                                               show_usage();
-                                                       namelen = i;
-                                                       dirsize = i + 2;
-                                                       stopIt=TRUE;
-                                                       break;
-                                               }
-                                       case 'v':
-#ifdef BB_FEATURE_MINIX2
-                                               version2 = 1;
-#else
-                                               error_msg("%s: not compiled with minix v2 support",
-                                                               device_name);
-                                               exit(-1);
-#endif
-                                               break;
-                                       case '-':
-                                       case 'h':
-                                       default:
-goodbye:
-                                               show_usage();
-                               }
-                       }
-               } else {
-                       if (device_name == NULL)
-                               device_name = *argv;
-                       else if (BLOCKS == 0)
-                               BLOCKS = strtol(*argv, &tmp, 0);
-                       else {
-                               goto goodbye;
-                       }
-               }
-               argv++;
-       }
-
-       if (device_name && !BLOCKS)
-               BLOCKS = get_size(device_name) / 1024;
-       if (!device_name || BLOCKS < 10) {
-               show_usage();
-       }
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               if (namelen == 14)
-                       magic = MINIX2_SUPER_MAGIC;
-               else
-                       magic = MINIX2_SUPER_MAGIC2;
-       } else
-#endif
-       if (BLOCKS > 65535)
-               BLOCKS = 65535;
-       check_mount();                          /* is it already mounted? */
-       tmp = root_block;
-       *(short *) tmp = 1;
-       strcpy(tmp + 2, ".");
-       tmp += dirsize;
-       *(short *) tmp = 1;
-       strcpy(tmp + 2, "..");
-       tmp += dirsize;
-       *(short *) tmp = 2;
-       strcpy(tmp + 2, ".badblocks");
-       DEV = open(device_name, O_RDWR);
-       if (DEV < 0)
-               error_msg_and_die("unable to open %s", device_name);
-       if (fstat(DEV, &statbuf) < 0)
-               error_msg_and_die("unable to stat %s", device_name);
-       if (!S_ISBLK(statbuf.st_mode))
-               check = 0;
-       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
-               error_msg_and_die("will not try to make filesystem on '%s'", device_name);
-       setup_tables();
-       if (check)
-               check_blocks();
-       else if (listfile)
-               get_list_blocks(listfile);
-#ifdef BB_FEATURE_MINIX2
-       if (version2) {
-               make_root_inode2();
-               make_bad_inode2();
-       } else
-#endif
-       {
-               make_root_inode();
-               make_bad_inode();
-       }
-       mark_good_blocks();
-       write_tables();
-       return( 0);
-
-}
diff --git a/busybox/util-linux/mkswap.c b/busybox/util-linux/mkswap.c
deleted file mode 100644 (file)
index f72c700..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * mkswap.c - set up a linux swap device
- *
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
- */
-
-/*
- * 20.12.91  - time began. Got VM working yesterday by doing this by hand.
- *
- * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
- *
- *     -c   for readability checking. (Use it unless you are SURE!)
- *     -vN  for swap areas version N. (Only N=0,1 known today.)
- *      -f   for forcing swap creation even if it would smash partition table.
- *
- * The device may be a block device or an image of one, but this isn't
- * enforced (but it's not much fun on a character device :-).
- *
- * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
- * size-in-blocks parameter optional added Wed Feb  8 10:33:43 1995.
- *
- * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
- *
- * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
- * V1_MAX_PAGES fixes, jj, 990325.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- *
- *  from util-linux -- adapted for busybox by
- *  Erik Andersen <andersee@debian.org>. I ripped out Native Language
- *  Support, made some stuff smaller, and fitted for life in busybox.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>                 /* for _IO */
-#include <sys/utsname.h>
-#include <asm/page.h>                  /* for PAGE_SIZE and PAGE_SHIFT */
-                               /* we also get PAGE_SIZE via getpagesize() */
-#include "busybox.h"
-
-#ifndef _IO
-/* pre-1.3.45 */
-static const int BLKGETSIZE = 0x1260;
-#else
-/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
-#define BLKGETSIZE _IO(0x12,96)
-#endif
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long PAGES = 0;
-static int check = 0;
-static int badpages = 0;
-static int version = -1;
-
-#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
-
-/*
- * The definition of the union swap_header uses the constant PAGE_SIZE.
- * Unfortunately, on some architectures this depends on the hardware model,
- * and can only be found at run time -- we use getpagesize().
- */
-
-static int pagesize;
-static int *signature_page;
-
-static struct swap_header_v1 {
-       char bootbits[1024];            /* Space for disklabel etc. */
-       unsigned int version;
-       unsigned int last_page;
-       unsigned int nr_badpages;
-       unsigned int padding[125];
-       unsigned int badpages[1];
-} *p;
-
-static void init_signature_page()
-{
-       pagesize = getpagesize();
-
-#ifdef PAGE_SIZE
-       if (pagesize != PAGE_SIZE)
-               error_msg("Assuming pages of size %d", pagesize);
-#endif
-       signature_page = (int *) xmalloc(pagesize);
-       memset(signature_page, 0, pagesize);
-       p = (struct swap_header_v1 *) signature_page;
-}
-
-static void write_signature(char *sig)
-{
-       char *sp = (char *) signature_page;
-
-       strncpy(sp + pagesize - 10, sig, 10);
-}
-
-#define V0_MAX_PAGES   (8 * (pagesize - 10))
-/* Before 2.2.0pre9 */
-#define V1_OLD_MAX_PAGES       ((0x7fffffff / pagesize) - 1)
-/* Since 2.2.0pre9:
-   error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
-   with variations on
-       #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
-       #define SWP_OFFSET(entry) ((entry) >> 8)
-   on the various architectures. Below the result - yuk.
-
-   Machine     pagesize        SWP_ENTRY       SWP_OFFSET      bound+1 oldbound+2
-   i386                2^12            o<<8            e>>8            1<<24   1<<19
-   mips                2^12            o<<15           e>>15           1<<17   1<<19
-   alpha       2^13            o<<40           e>>40           1<<24   1<<18
-   m68k                2^12            o<<12           e>>12           1<<20   1<<19
-   sparc       2^{12,13}       (o&0x3ffff)<<9  (e>>9)&0x3ffff  1<<18   1<<{19,18}
-   sparc64     2^13            o<<13           e>>13           1<<51   1<<18
-   ppc         2^12            o<<8            e>>8            1<<24   1<<19
-   armo                2^{13,14,15}    o<<8            e>>8            1<<24   1<<{18,17,16}
-   armv                2^12            o<<9            e>>9            1<<23   1<<19
-
-   assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
-
-   The bad part is that we need to know this since the kernel will
-   refuse a swap space if it is too large.
-*/
-/* patch from jj - why does this differ from the above? */
-#if defined(__alpha__)
-#define V1_MAX_PAGES           ((1 << 24) - 1)
-#elif defined(__mips__)
-#define V1_MAX_PAGES           ((1 << 17) - 1)
-#elif defined(__sparc_v9__)
-#define V1_MAX_PAGES           ((3 << 29) - 1)
-#elif defined(__sparc__)
-#define V1_MAX_PAGES           (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
-#else
-#define V1_MAX_PAGES           V1_OLD_MAX_PAGES
-#endif
-/* man page now says:
-The maximum useful size of a swap area now depends on the architecture.
-It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
-128GB on alpha and 3TB on sparc64.
-*/
-
-#define MAX_BADPAGES   ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
-
-static void bit_set(unsigned int *addr, unsigned int nr)
-{
-       unsigned int r, m;
-
-       addr += nr / (8 * sizeof(int));
-
-       r = *addr;
-       m = 1 << (nr & (8 * sizeof(int) - 1));
-
-       *addr = r | m;
-}
-
-static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
-{
-       unsigned int r, m;
-
-       addr += nr / (8 * sizeof(int));
-
-       r = *addr;
-       m = 1 << (nr & (8 * sizeof(int) - 1));
-
-       *addr = r & ~m;
-       return (r & m) != 0;
-}
-
-
-static void page_ok(int page)
-{
-       if (version == 0)
-               bit_set(signature_page, page);
-}
-
-static void page_bad(int page)
-{
-       if (version == 0)
-               bit_test_and_clear(signature_page, page);
-       else {
-               if (badpages == MAX_BADPAGES)
-                       error_msg_and_die("too many bad pages");
-               p->badpages[badpages] = page;
-       }
-       badpages++;
-}
-
-static void check_blocks(void)
-{
-       unsigned int current_page;
-       int do_seek = 1;
-       char *buffer;
-
-       buffer = xmalloc(pagesize);
-       current_page = 0;
-       while (current_page < PAGES) {
-               if (!check) {
-                       page_ok(current_page++);
-                       continue;
-               }
-               if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
-                       current_page * pagesize)
-                       error_msg_and_die("seek failed in check_blocks");
-               if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
-                       page_bad(current_page++);
-                       continue;
-               }
-               page_ok(current_page++);
-       }
-       if (badpages == 1)
-               printf("one bad page\n");
-       else if (badpages > 1)
-               printf("%d bad pages\n", badpages);
-}
-
-static long valid_offset(int fd, int offset)
-{
-       char ch;
-
-       if (lseek(fd, offset, 0) < 0)
-               return 0;
-       if (read(fd, &ch, 1) < 1)
-               return 0;
-       return 1;
-}
-
-static int find_size(int fd)
-{
-       unsigned int high, low;
-
-       low = 0;
-       for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
-               low = high;
-       while (low < high - 1) {
-               const int mid = (low + high) / 2;
-
-               if (valid_offset(fd, mid))
-                       low = mid;
-               else
-                       high = mid;
-       }
-       return (low + 1);
-}
-
-/* return size in pages, to avoid integer overflow */
-static long get_size(const char *file)
-{
-       int fd;
-       long size;
-
-       if ((fd = open(file, O_RDONLY)) < 0)
-               perror_msg_and_die("%s", file);
-       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
-               int sectors_per_page = pagesize / 512;
-
-               size /= sectors_per_page;
-       } else {
-               size = find_size(fd) / pagesize;
-       }
-       close(fd);
-       return size;
-}
-
-int mkswap_main(int argc, char **argv)
-{
-       char *tmp;
-       struct stat statbuf;
-       int sz;
-       int maxpages;
-       int goodpages;
-       int offset;
-       int force = 0;
-
-       init_signature_page();          /* get pagesize */
-
-       while (argc-- > 1) {
-               argv++;
-               if (argv[0][0] != '-') {
-                       if (device_name) {
-                               int blocks_per_page = pagesize / 1024;
-
-                               PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
-                               if (*tmp)
-                                       show_usage();
-                       } else
-                               device_name = argv[0];
-               } else {
-                       switch (argv[0][1]) {
-                       case 'c':
-                               check = 1;
-                               break;
-                       case 'f':
-                               force = 1;
-                               break;
-                       case 'v':
-                               version = atoi(argv[0] + 2);
-                               break;
-                       default:
-                               show_usage();
-                       }
-               }
-       }
-       if (!device_name) {
-               error_msg("error: Nowhere to set up swap on?");
-               show_usage();
-       }
-       sz = get_size(device_name);
-       if (!PAGES) {
-               PAGES = sz;
-       } else if (PAGES > sz && !force) {
-               error_msg("error: size %ld is larger than device size %d",
-                               PAGES * (pagesize / 1024), sz * (pagesize / 1024));
-               return EXIT_FAILURE;
-       }
-
-       if (version == -1) {
-               if (PAGES <= V0_MAX_PAGES)
-                       version = 0;
-               else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
-                       version = 0;
-               else if (pagesize < 2048)
-                       version = 0;
-               else
-                       version = 1;
-       }
-       if (version != 0 && version != 1) {
-               error_msg("error: unknown version %d", version);
-               show_usage();
-       }
-       if (PAGES < 10) {
-               error_msg("error: swap area needs to be at least %ldkB",
-                               (long) (10 * pagesize / 1024));
-               show_usage();
-       }
-#if 0
-       maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
-#else
-       if (!version)
-               maxpages = V0_MAX_PAGES;
-       else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
-               maxpages = V1_MAX_PAGES;
-       else {
-               maxpages = V1_OLD_MAX_PAGES;
-               if (maxpages > V1_MAX_PAGES)
-                       maxpages = V1_MAX_PAGES;
-       }
-#endif
-       if (PAGES > maxpages) {
-               PAGES = maxpages;
-               error_msg("warning: truncating swap area to %ldkB",
-                               PAGES * pagesize / 1024);
-       }
-
-       DEV = open(device_name, O_RDWR);
-       if (DEV < 0 || fstat(DEV, &statbuf) < 0)
-               perror_msg_and_die("%s", device_name);
-       if (!S_ISBLK(statbuf.st_mode))
-               check = 0;
-       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
-               error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
-
-#ifdef __sparc__
-       if (!force && version == 0) {
-               /* Don't overwrite partition table unless forced */
-               unsigned char *buffer = (unsigned char *) signature_page;
-               unsigned short *q, sum;
-
-               if (read(DEV, buffer, 512) != 512)
-                       error_msg_and_die("fatal: first page unreadable");
-               if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
-                       q = (unsigned short *) (buffer + 510);
-                       for (sum = 0; q >= (unsigned short *) buffer;)
-                               sum ^= *q--;
-                       if (!sum) {
-                               error_msg("Device '%s' contains a valid Sun disklabel.\n"
-"This probably means creating v0 swap would destroy your partition table\n"
-"No swap created. If you really want to create swap v0 on that device, use\n"
-"the -f option to force it.", device_name);
-                               return EXIT_FAILURE;
-                       }
-               }
-       }
-#endif
-
-       if (version == 0 || check)
-               check_blocks();
-       if (version == 0 && !bit_test_and_clear(signature_page, 0))
-               error_msg_and_die("fatal: first page unreadable");
-       if (version == 1) {
-               p->version = version;
-               p->last_page = PAGES - 1;
-               p->nr_badpages = badpages;
-       }
-
-       goodpages = PAGES - badpages - 1;
-       if (goodpages <= 0)
-               error_msg_and_die("Unable to set up swap-space: unreadable");
-       printf("Setting up swapspace version %d, size = %ld bytes\n",
-                  version, (long) (goodpages * pagesize));
-       write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
-
-       offset = ((version == 0) ? 0 : 1024);
-       if (lseek(DEV, offset, SEEK_SET) != offset)
-               error_msg_and_die("unable to rewind swap-device");
-       if (write(DEV, (char *) signature_page + offset, pagesize - offset)
-               != pagesize - offset)
-               error_msg_and_die("unable to write signature page");
-
-       /*
-        * A subsequent swapon() will fail if the signature
-        * is not actually on disk. (This is a kernel bug.)
-        */
-       if (fsync(DEV))
-               error_msg_and_die("fsync failed");
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/more.c b/busybox/util-linux/more.c
deleted file mode 100644 (file)
index 780cddf..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini more implementation for busybox
- *
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * Latest version blended together by Erik Andersen <andersen@lineo.com>,
- * based on the original more implementation by Bruce, and code from the 
- * Debian boot-floppies team.
- *
- * Termios corrects by Vladimir Oleynik <vodz@usa.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-static FILE *cin;
-
-#ifdef BB_FEATURE_USE_TERMIOS
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
-#define getTermSettings(fd,argp) tcgetattr(fd, argp);
-
-static struct termios initial_settings, new_settings;
-
-static void set_tty_to_initial_mode(void)
-{
-       setTermSettings(fileno(cin), &initial_settings);
-}
-
-static void gotsig(int sig)
-{
-       putchar('\n');
-       exit(EXIT_FAILURE);
-}
-#endif /* BB_FEATURE_USE_TERMIOS */
-
-
-static int terminal_width = 79;        /* not 80 in case terminal has linefold bug */
-static int terminal_height = 24;
-
-
-extern int more_main(int argc, char **argv)
-{
-       int c, lines, input = 0;
-       int please_display_more_prompt = -1;
-       struct stat st;
-       FILE *file;
-       int len, page_height;
-
-#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
-       struct winsize win = { 0, 0, 0, 0 };
-#endif
-
-       argc--;
-       argv++;
-
-
-       /* not use inputing from terminal if usage: more > outfile */
-       if(isatty(fileno(stdout))) {
-               cin = fopen(CURRENT_TTY, "r");
-               if (!cin)
-                       cin = xfopen(CONSOLE_DEV, "r");
-               please_display_more_prompt = 0;
-#ifdef BB_FEATURE_USE_TERMIOS
-               getTermSettings(fileno(cin), &initial_settings);
-               new_settings = initial_settings;
-               new_settings.c_lflag &= ~ICANON;
-               new_settings.c_lflag &= ~ECHO;
-#ifndef linux
-                /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
-               new_settings.c_cc[VMIN] = 1;
-               new_settings.c_cc[VTIME] = 0;
-#endif
-               setTermSettings(fileno(cin), &new_settings);
-               atexit(set_tty_to_initial_mode);
-               (void) signal(SIGINT, gotsig);
-               (void) signal(SIGQUIT, gotsig);
-               (void) signal(SIGTERM, gotsig);
-#endif
-       }
-
-       do {
-               if (argc == 0) {
-                       file = stdin;
-               } else
-                       file = wfopen(*argv, "r");
-               if(file==0)
-                       goto loop;
-                       
-               fstat(fileno(file), &st);
-
-               if(please_display_more_prompt>0)
-                       please_display_more_prompt = 0;
-
-#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
-               ioctl(fileno(stdout), TIOCGWINSZ, &win);
-               if (win.ws_row > 4)
-                       terminal_height = win.ws_row - 2;
-               if (win.ws_col > 0)
-                       terminal_width = win.ws_col - 1;
-#endif
-               len=0;
-               lines = 0;
-               page_height = terminal_height;
-               while ((c = getc(file)) != EOF) {
-
-                       if (please_display_more_prompt>0) {
-                               len = printf("--More-- ");
-                               if (file != stdin) {
-#if _FILE_OFFSET_BITS == 64
-                                       len += printf("(%d%% of %lld bytes)",
-                                                  (int) (100 * ((double) ftell(file) /
-                                                  (double) st.st_size)), (long long)st.st_size);
-#else
-                                       len += printf("(%d%% of %ld bytes)",
-                                                  (int) (100 * ((double) ftell(file) /
-                                                  (double) st.st_size)), (long)st.st_size);
-#endif
-                               }
-
-                               fflush(stdout);
-
-                               /*
-                                * We've just displayed the "--More--" prompt, so now we need
-                                * to get input from the user.
-                                */
-                               input = getc(cin);
-#ifndef BB_FEATURE_USE_TERMIOS
-                               printf("\033[A"); /* up cursor */
-#endif
-                               /* Erase the "More" message */
-                               putc('\r', stdout);
-                               while (--len >= 0)
-                                       putc(' ', stdout);
-                               putc('\r', stdout);
-                               fflush(stdout);
-                               len=0;
-                               lines = 0;
-                               page_height = terminal_height;
-                               please_display_more_prompt = 0;
-
-                               if (input == 'q')
-                                       goto end;
-                       }
-
-                       /* 
-                        * There are two input streams to worry about here:
-                        *
-                        * c     : the character we are reading from the file being "mored"
-                        * input : a character received from the keyboard
-                        *
-                        * If we hit a newline in the _file_ stream, we want to test and
-                        * see if any characters have been hit in the _input_ stream. This
-                        * allows the user to quit while in the middle of a file.
-                        */
-                       if (c == '\n') {
-                               /* increment by just one line if we are at
-                                * the end of this line */
-                               if (input == '\n')
-                                       if(please_display_more_prompt==0)
-                                       please_display_more_prompt = 1;
-                               /* Adjust the terminal height for any overlap, so that
-                                * no lines get lost off the top. */
-                               if (len >= terminal_width) {
-                                       int quot, rem;
-                                       quot = len / terminal_width;
-                                       rem  = len - (quot * terminal_width);
-                                       if (quot) {
-                                               if (rem)
-                                                       page_height-=quot;
-                                               else
-                                                       page_height-=(quot-1);
-                                       }
-                               }
-                               if (++lines >= page_height) {
-                                       if(please_display_more_prompt==0)
-                                       please_display_more_prompt = 1;
-                               }
-                               len=0;
-                       }
-                       /*
-                        * If we just read a newline from the file being 'mored' and any
-                        * key other than a return is hit, scroll by one page
-                        */
-                       putc(c, stdout);
-                       len++;
-               }
-               fclose(file);
-               fflush(stdout);
-loop:
-               argv++;
-       } while (--argc > 0);
-  end:
-       return 0;
-}
diff --git a/busybox/util-linux/mount.c b/busybox/util-linux/mount.c
deleted file mode 100644 (file)
index af57a76..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini mount implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 3/21/1999   Charles P. Wright <cpwright@cpwright.com>
- *             searches through fstab when -a is passed
- *             will try mounting stuff with all fses when passed -t auto
- *
- * 1999-04-17  Dave Cinege...Rewrote -t auto. Fixed ro mtab.
- *
- * 1999-10-07  Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
- *              Rewrite of a lot of code. Removed mtab usage (I plan on
- *              putting it back as a compile-time option some time), 
- *              major adjustments to option parsing, and some serious 
- *              dieting all around.
- *
- * 1999-11-06  mtab suppport is back - andersee
- *
- * 2000-01-12   Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
- *              mount to add loop support.
- *
- * 2000-04-30  Dave Cinege <dcinege@psychosis.com>
- *             Rewrote fstab while loop and lower mount section. Can now do
- *             single mounts from fstab. Can override fstab options for single
- *             mount. Common mount_one call for single mounts and 'all'. Fixed
- *             mtab updating and stale entries. Removed 'remount' default. 
- *     
- */
-
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <ctype.h>
-#include "busybox.h"
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-#      include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */
-#endif
-
-enum {
-       MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
-       MS_RDONLY = 1,      /* Mount read-only */
-       MS_NOSUID = 2,      /* Ignore suid and sgid bits */
-       MS_NODEV = 4,      /* Disallow access to device special files */
-       MS_NOEXEC = 8,      /* Disallow program execution */
-       MS_SYNCHRONOUS = 16,      /* Writes are synced at once */
-       MS_REMOUNT = 32,      /* Alter flags of a mounted FS */
-       MS_MANDLOCK = 64,      /* Allow mandatory locks on an FS */
-       S_QUOTA = 128,     /* Quota initialized for file/directory/symlink */
-       S_APPEND = 256,     /* Append-only file */
-       S_IMMUTABLE = 512,     /* Immutable file */
-       MS_NOATIME = 1024,    /* Do not update access times. */
-       MS_NODIRATIME = 2048,    /* Do not update directory access times */
-       MS_BIND = 4096,    /* Use the new linux 2.4.x "mount --bind" feature */
-};
-
-
-#if defined BB_FEATURE_MOUNT_LOOP
-#include <fcntl.h>
-#include <sys/ioctl.h>
-static int use_loop = FALSE;
-#endif
-
-extern int mount (__const char *__special_file, __const char *__dir,
-                       __const char *__fstype, unsigned long int __rwflag,
-                       __const void *__data);
-extern int umount (__const char *__special_file);
-extern int umount2 (__const char *__special_file, int __flags);
-
-extern int sysfs( int option, unsigned int fs_index, char * buf);
-
-extern const char mtab_file[]; /* Defined in utility.c */
-
-struct mount_options {
-       const char *name;
-       unsigned long and;
-       unsigned long or;
-};
-
-static const struct mount_options mount_options[] = {
-       {"async", ~MS_SYNCHRONOUS, 0},
-       {"atime", ~0, ~MS_NOATIME},
-       {"defaults", ~0, 0},
-       {"dev", ~MS_NODEV, 0},
-       {"diratime", ~0, ~MS_NODIRATIME},
-       {"exec", ~MS_NOEXEC, 0},
-       {"noatime", ~0, MS_NOATIME},
-       {"nodev", ~0, MS_NODEV},
-       {"nodiratime", ~0, MS_NODIRATIME},
-       {"noexec", ~0, MS_NOEXEC},
-       {"nosuid", ~0, MS_NOSUID},
-       {"remount", ~0, MS_REMOUNT},
-       {"ro", ~0, MS_RDONLY},
-       {"rw", ~MS_RDONLY, 0},
-       {"suid", ~MS_NOSUID, 0},
-       {"sync", ~0, MS_SYNCHRONOUS},
-       {"bind", ~0, MS_BIND},
-       {0, 0, 0}
-};
-
-static int
-do_mount(char *specialfile, char *dir, char *filesystemtype,
-                long flags, void *string_flags, int useMtab, int fakeIt,
-                char *mtab_opts, int mount_all)
-{
-       int status = 0;
-#if defined BB_FEATURE_MOUNT_LOOP
-       char *lofile = NULL;
-#endif
-
-       if (fakeIt == FALSE)
-       {
-#if defined BB_FEATURE_MOUNT_LOOP
-               if (use_loop==TRUE) {
-                       int loro = flags & MS_RDONLY;
-                       
-                       lofile = specialfile;
-
-                       specialfile = find_unused_loop_device();
-                       if (specialfile == NULL) {
-                               error_msg_and_die("Could not find a spare loop device");
-                       }
-                       if (set_loop(specialfile, lofile, 0, &loro)) {
-                               error_msg_and_die("Could not setup loop device");
-                       }
-                       if (!(flags & MS_RDONLY) && loro) {     /* loop is ro, but wanted rw */
-                               error_msg("WARNING: loop device is read-only");
-                               flags |= MS_RDONLY;
-                       }
-               }
-#endif
-               status = mount(specialfile, dir, filesystemtype, flags, string_flags);
-               if (status < 0 && errno == EROFS) {
-                       error_msg("%s is write-protected, mounting read-only", specialfile);
-                       status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags);
-               }
-               /* Don't whine about already mounted filesystems when mounting all. */
-               if (status < 0 && errno == EBUSY && mount_all)
-                       return TRUE;
-       }
-
-
-       /* If the mount was sucessful, do anything needed, then return TRUE */
-       if (status == 0 || fakeIt==TRUE) {
-
-#if defined BB_FEATURE_MTAB_SUPPORT
-               if (useMtab == TRUE) {
-                       erase_mtab(specialfile);        // Clean any stale entries
-                       write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
-               }
-#endif
-               return (TRUE);
-       }
-
-       /* Bummer.  mount failed.  Clean up */
-#if defined BB_FEATURE_MOUNT_LOOP
-       if (lofile != NULL) {
-               del_loop(specialfile);
-       }
-#endif
-
-       if (errno == EPERM) {
-               error_msg_and_die("permission denied. Are you root?");
-       }
-
-       return (FALSE);
-}
-
-
-
-/* Seperate standard mount options from the nonstandard string options */
-static void
-parse_mount_options(char *options, int *flags, char *strflags)
-{
-       while (options) {
-               int gotone = FALSE;
-               char *comma = strchr(options, ',');
-               const struct mount_options *f = mount_options;
-
-               if (comma)
-                       *comma = '\0';
-
-               while (f->name != 0) {
-                       if (strcasecmp(f->name, options) == 0) {
-
-                               *flags &= f->and;
-                               *flags |= f->or;
-                               gotone = TRUE;
-                               break;
-                       }
-                       f++;
-               }
-#if defined BB_FEATURE_MOUNT_LOOP
-               if (gotone == FALSE && !strcasecmp("loop", options)) {  /* loop device support */
-                       use_loop = TRUE;
-                       gotone = TRUE;
-               }
-#endif
-               if (*strflags && strflags != '\0' && gotone == FALSE) {
-                       char *temp = strflags;
-
-                       temp += strlen(strflags);
-                       *temp++ = ',';
-                       *temp++ = '\0';
-               }
-               if (gotone == FALSE)
-                       strcat(strflags, options);
-               if (comma) {
-                       *comma = ',';
-                       options = ++comma;
-               } else {
-                       break;
-               }
-       }
-}
-
-static int
-mount_one(char *blockDevice, char *directory, char *filesystemType,
-                 unsigned long flags, char *string_flags, int useMtab, int fakeIt,
-                 char *mtab_opts, int whineOnErrors, int mount_all)
-{
-       int status = 0;
-
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-       if (strcmp(filesystemType, "auto") == 0) {
-               static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 };
-               const char **noauto_fstype;
-               const int num_of_filesystems = sysfs(3, 0, 0);
-               char buf[255];
-               int i=0;
-
-               filesystemType=buf;
-
-               while(i < num_of_filesystems) {
-                       sysfs(2, i++, filesystemType);
-                       for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) {
-                               if (!strcmp(filesystemType, *noauto_fstype)) {
-                                       break;
-                               }
-                       }
-                       if (!*noauto_fstype) {
-                               status = do_mount(blockDevice, directory, filesystemType,
-                                       flags | MS_MGC_VAL, string_flags,
-                                       useMtab, fakeIt, mtab_opts, mount_all);
-                               if (status == TRUE)
-                                       break;
-                       }
-               }
-       } 
-#else
-       if (strcmp(filesystemType, "auto") == 0) {
-               char buf[255];
-               FILE *f = xfopen("/proc/filesystems", "r");
-
-               while (fgets(buf, sizeof(buf), f) != NULL) {
-                       filesystemType = buf;
-                       if (*filesystemType == '\t') {  // Not a nodev filesystem
-
-                               // Add NULL termination to each line
-                               while (*filesystemType && *filesystemType != '\n')
-                                       filesystemType++;
-                               *filesystemType = '\0';
-
-                               filesystemType = buf;
-                               filesystemType++;       // hop past tab
-
-                               status = do_mount(blockDevice, directory, filesystemType,
-                                                                 flags | MS_MGC_VAL, string_flags,
-                                                                 useMtab, fakeIt, mtab_opts, mount_all);
-                               if (status == TRUE)
-                                       break;
-                       }
-               }
-               fclose(f);
-       }
-#endif
-       else {
-               status = do_mount(blockDevice, directory, filesystemType,
-                               flags | MS_MGC_VAL, string_flags, useMtab,
-                               fakeIt, mtab_opts, mount_all);
-       }
-
-       if (status == FALSE) {
-               if (whineOnErrors == TRUE) {
-                       perror_msg("Mounting %s on %s failed", blockDevice, directory);
-               }
-               return (FALSE);
-       }
-       return (TRUE);
-}
-
-void show_mounts(void)
-{
-#if defined BB_FEATURE_USE_DEVPS_PATCH
-       int fd, i, numfilesystems;
-       char device[] = "/dev/mtab";
-       struct k_mntent *mntentlist;
-
-       /* open device */ 
-       fd = open(device, O_RDONLY);
-       if (fd < 0)
-               perror_msg_and_die("open failed for `%s'", device);
-
-       /* How many mounted filesystems?  We need to know to 
-        * allocate enough space for later... */
-       numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
-       if (numfilesystems<0)
-               perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS");
-       mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent));
-               
-       /* Grab the list of mounted filesystems */
-       if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
-               perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS");
-
-       for( i = 0 ; i < numfilesystems ; i++) {
-               printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
-                               mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
-                               mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
-                               mntentlist[i].mnt_passno);
-       }
-#ifdef BB_FEATURE_CLEAN_UP
-       /* Don't bother to close files or free memory.  Exit 
-        * does that automagically, so we can save a few bytes */
-       free( mntentlist);
-       close(fd);
-#endif
-       exit(EXIT_SUCCESS);
-#else
-       FILE *mountTable = setmntent(mtab_file, "r");
-
-       if (mountTable) {
-               struct mntent *m;
-
-               while ((m = getmntent(mountTable)) != 0) {
-                       char *blockDevice = m->mnt_fsname;
-                       if (strcmp(blockDevice, "/dev/root") == 0) {
-                               blockDevice = find_real_root_device_name(blockDevice);
-                       }
-                       printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
-                                  m->mnt_type, m->mnt_opts);
-#ifdef BB_FEATURE_CLEAN_UP
-                       if(blockDevice != m->mnt_fsname)
-                               free(blockDevice);
-#endif
-               }
-               endmntent(mountTable);
-       } else {
-               perror_msg_and_die("%s", mtab_file);
-       }
-       exit(EXIT_SUCCESS);
-#endif
-}
-
-extern int mount_main(int argc, char **argv)
-{
-       struct stat statbuf;
-       char string_flags_buf[1024] = "";
-       char *string_flags = string_flags_buf;
-       char *extra_opts = string_flags_buf;
-       int flags = 0;
-       char *filesystemType = "auto";
-       char *device = xmalloc(PATH_MAX);
-       char *directory = xmalloc(PATH_MAX);
-       int all = FALSE;
-       int fakeIt = FALSE;
-       int useMtab = TRUE;
-       int rc = EXIT_FAILURE;
-       int fstabmount = FALSE; 
-       int opt;
-
-       /* Parse options */
-       while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
-               switch (opt) {
-               case 'o':
-                       parse_mount_options(optarg, &flags, string_flags);
-                       break;
-               case 'r':
-                       flags |= MS_RDONLY;
-                       break;
-               case 't':
-                       filesystemType = optarg;
-                       break;
-               case 'w':
-                       flags &= ~MS_RDONLY;
-                       break;
-               case 'a':
-                       all = TRUE;
-                       break;
-               case 'f':
-                       fakeIt = TRUE;
-                       break;
-#ifdef BB_FEATURE_MTAB_SUPPORT
-               case 'n':
-                       useMtab = FALSE;
-                       break;
-#endif
-               case 'v':
-                       break; /* ignore -v */
-               }
-       }
-
-       if (!all && optind == argc)
-               show_mounts();
-
-       if (optind < argc) {
-               /* if device is a filename get its real path */
-               if (stat(argv[optind], &statbuf) == 0) {
-                       device = simplify_path(argv[optind]);
-               } else {
-                       safe_strncpy(device, argv[optind], PATH_MAX);
-               }
-       }
-
-       if (optind + 1 < argc)
-               directory = simplify_path(argv[optind + 1]);
-
-       if (all == TRUE || optind + 1 == argc) {
-               struct mntent *m = NULL;
-               FILE *f = setmntent("/etc/fstab", "r");
-               fstabmount = TRUE;
-
-               if (f == NULL)
-                       perror_msg_and_die( "\nCannot read /etc/fstab");
-
-               while ((m = getmntent(f)) != NULL) {
-                       if (all == FALSE && optind + 1 == argc && (
-                               (strcmp(device, m->mnt_fsname) != 0) &&
-                               (strcmp(device, m->mnt_dir) != 0) ) ) {
-                               continue;
-                       }
-                       
-                       if (all == TRUE && (                            // If we're mounting 'all'
-                               (strstr(m->mnt_opts, "noauto")) ||      // and the file system isn't noauto,
-                               (strstr(m->mnt_type, "swap")) ||        // and isn't swap or nfs, then mount it
-                               (strstr(m->mnt_type, "nfs")) ) ) {
-                               continue;
-                       }
-                       
-                       if (all == TRUE || flags == 0) {        // Allow single mount to override fstab flags
-                               flags = 0;
-                               *string_flags = '\0';
-                               parse_mount_options(m->mnt_opts, &flags, string_flags);
-                       }
-                       
-                       strcpy(device, m->mnt_fsname);
-                       strcpy(directory, m->mnt_dir);
-                       filesystemType = strdup(m->mnt_type);
-singlemount:                   
-                       string_flags = strdup(string_flags);
-                       rc = EXIT_SUCCESS;
-#ifdef BB_NFSMOUNT
-                       if (strchr(device, ':') != NULL)
-                               filesystemType = "nfs";
-                       if (strcmp(filesystemType, "nfs") == 0) {
-                               if (nfsmount (device, directory, &flags, &extra_opts,
-                                                       &string_flags, 1)) {
-                                       perror_msg("nfsmount failed");
-                                       rc = EXIT_FAILURE;
-                               }
-                       }
-#endif
-                       if (!mount_one(device, directory, filesystemType, flags,
-                                       string_flags, useMtab, fakeIt, extra_opts, TRUE, all))
-                               rc = EXIT_FAILURE;
-                               
-                       if (all == FALSE)
-                               break;
-               }
-               if (fstabmount == TRUE)
-                       endmntent(f);
-                       
-               if (all == FALSE && fstabmount == TRUE && m == NULL)
-                       fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
-       
-               return rc;
-       }
-       
-       goto singlemount;
-}
diff --git a/busybox/util-linux/nfsmount.c b/busybox/util-linux/nfsmount.c
deleted file mode 100644 (file)
index cd722ac..0000000
+++ /dev/null
@@ -1,977 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * nfsmount.c -- Linux NFS mount
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
- * numbers to be specified on the command line.
- *
- * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
- * Omit the call to connect() for Linux version 1.3.11 or later.
- *
- * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
- * Implemented the "bg", "fg" and "retry" mount options for NFS.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
- * 
- * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
- * plus NFSv3 stuff.
- */
-
-/*
- * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <sys/utsname.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include "busybox.h"
-#undef TRUE
-#undef FALSE
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
-#include <linux/nfs.h>  /* For the kernels nfs stuff */
-#include "nfsmount.h"
-
-#ifndef NFS_FHSIZE
-static const int NFS_FHSIZE = 32;
-#endif
-#ifndef NFS_PORT
-static const int NFS_PORT = 2049;
-#endif
-
-/* Disable the nls stuff */
-# undef bindtextdomain
-# define bindtextdomain(Domain, Directory) /* empty */
-# undef textdomain
-# define textdomain(Domain) /* empty */
-# define _(Text) (Text)
-# define N_(Text) (Text)
-
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_RDONLY = 1;      /* Mount read-only */
-static const int MS_NOSUID = 2;      /* Ignore suid and sgid bits */
-static const int MS_NODEV = 4;      /* Disallow access to device special files */
-static const int MS_NOEXEC = 8;      /* Disallow program execution */
-static const int MS_SYNCHRONOUS = 16;      /* Writes are synced at once */
-static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS */
-static const int MS_MANDLOCK = 64;      /* Allow mandatory locks on an FS */
-static const int S_QUOTA = 128;     /* Quota initialized for file/directory/symlink */
-static const int S_APPEND = 256;     /* Append-only file */
-static const int S_IMMUTABLE = 512;     /* Immutable file */
-static const int MS_NOATIME = 1024;    /* Do not update access times. */
-static const int MS_NODIRATIME = 2048;    /* Do not update directory access times */
-
-
-/*
- * We want to be able to compile mount on old kernels in such a way
- * that the binary will work well on more recent kernels.
- * Thus, if necessary we teach nfsmount.c the structure of new fields
- * that will come later.
- *
- * Moreover, the new kernel includes conflict with glibc includes
- * so it is easiest to ignore the kernel altogether (at compile time).
- */
-
-/* NOTE: Do not make this into a 'static const int' because the pre-processor
- * needs to test this value in some #if statements. */
-#define NFS_MOUNT_VERSION 4
-
-struct nfs2_fh {
-        char                    data[32];
-};
-struct nfs3_fh {
-        unsigned short          size;
-        unsigned char           data[64];
-};
-
-struct nfs_mount_data {
-       int             version;                /* 1 */
-       int             fd;                     /* 1 */
-       struct nfs2_fh  old_root;               /* 1 */
-       int             flags;                  /* 1 */
-       int             rsize;                  /* 1 */
-       int             wsize;                  /* 1 */
-       int             timeo;                  /* 1 */
-       int             retrans;                /* 1 */
-       int             acregmin;               /* 1 */
-       int             acregmax;               /* 1 */
-       int             acdirmin;               /* 1 */
-       int             acdirmax;               /* 1 */
-       struct sockaddr_in addr;                /* 1 */
-       char            hostname[256];          /* 1 */
-       int             namlen;                 /* 2 */
-       unsigned int    bsize;                  /* 3 */
-       struct nfs3_fh  root;                   /* 4 */
-};
-
-/* bits in the flags field */
-
-static const int NFS_MOUNT_SOFT = 0x0001;      /* 1 */
-static const int NFS_MOUNT_INTR = 0x0002;      /* 1 */
-static const int NFS_MOUNT_SECURE = 0x0004;    /* 1 */
-static const int NFS_MOUNT_POSIX = 0x0008;     /* 1 */
-static const int NFS_MOUNT_NOCTO = 0x0010;     /* 1 */
-static const int NFS_MOUNT_NOAC = 0x0020;      /* 1 */
-static const int NFS_MOUNT_TCP = 0x0040;       /* 2 */
-static const int NFS_MOUNT_VER3 = 0x0080;      /* 3 */
-static const int NFS_MOUNT_KERBEROS = 0x0100;  /* 3 */
-static const int NFS_MOUNT_NONLM = 0x0200;     /* 3 */
-
-
-#define UTIL_LINUX_VERSION "2.10m"
-#define util_linux_version "util-linux-2.10m"
-
-#define HAVE_inet_aton
-#define HAVE_scsi_h
-#define HAVE_blkpg_h
-#define HAVE_kd_h
-#define HAVE_termcap
-#define HAVE_locale_h
-#define HAVE_libintl_h
-#define ENABLE_NLS
-#define HAVE_langinfo_h
-#define HAVE_progname
-#define HAVE_openpty
-#define HAVE_nanosleep
-#define HAVE_personality
-#define HAVE_tm_gmtoff
-
-static char *nfs_strerror(int status);
-
-#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
-#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
-
-static const int EX_FAIL = 32;       /* mount failure */
-static const int EX_BG = 256;       /* retry in background (internal only) */
-
-
-/*
- * nfs_mount_version according to the sources seen at compile time.
- */
-static int nfs_mount_version;
-
-/*
- * Unfortunately, the kernel prints annoying console messages
- * in case of an unexpected nfs mount version (instead of
- * just returning some error).  Therefore we'll have to try
- * and figure out what version the kernel expects.
- *
- * Variables:
- *     KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
- *     NFS_MOUNT_VERSION: these nfsmount sources at compile time
- *     nfs_mount_version: version this source and running kernel can handle
- */
-static void
-find_kernel_nfs_mount_version(void)
-{
-       static int kernel_version = 0;
-
-       if (kernel_version)
-               return;
-
-       nfs_mount_version = NFS_MOUNT_VERSION; /* default */
-
-       kernel_version = get_kernel_revision();
-       if (kernel_version) {
-               if (kernel_version < MAKE_VERSION(2,1,32))
-                       nfs_mount_version = 1;
-               else if (kernel_version < MAKE_VERSION(2,2,18) ||
-                               (kernel_version >=   MAKE_VERSION(2,3,0) &&
-                                kernel_version < MAKE_VERSION(2,3,99)))
-                       nfs_mount_version = 3;
-               else
-                       nfs_mount_version = 4; /* since 2.3.99pre4 */
-       }
-       if (nfs_mount_version > NFS_MOUNT_VERSION)
-               nfs_mount_version = NFS_MOUNT_VERSION;
-}
-
-static struct pmap *
-get_mountport(struct sockaddr_in *server_addr,
-      long unsigned prog,
-      long unsigned version,
-      long unsigned proto,
-      long unsigned port)
-{
-struct pmaplist *pmap;
-static struct pmap p = {0, 0, 0, 0};
-
-server_addr->sin_port = PMAPPORT;
-pmap = pmap_getmaps(server_addr);
-
-if (version > MAX_NFSPROT)
-       version = MAX_NFSPROT;
-if (!prog)
-       prog = MOUNTPROG;
-p.pm_prog = prog;
-p.pm_vers = version;
-p.pm_prot = proto;
-p.pm_port = port;
-
-while (pmap) {
-       if (pmap->pml_map.pm_prog != prog)
-               goto next;
-       if (!version && p.pm_vers > pmap->pml_map.pm_vers)
-               goto next;
-       if (version > 2 && pmap->pml_map.pm_vers != version)
-               goto next;
-       if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
-               goto next;
-       if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
-           (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
-           (port && pmap->pml_map.pm_port != port))
-               goto next;
-       memcpy(&p, &pmap->pml_map, sizeof(p));
-next:
-       pmap = pmap->pml_next;
-}
-if (!p.pm_vers)
-       p.pm_vers = MOUNTVERS;
-if (!p.pm_port)
-       p.pm_port = MOUNTPORT;
-if (!p.pm_prot)
-       p.pm_prot = IPPROTO_TCP;
-return &p;
-}
-
-int nfsmount(const char *spec, const char *node, int *flags,
-            char **extra_opts, char **mount_opts, int running_bg)
-{
-       static char *prev_bg_host;
-       char hostdir[1024];
-       CLIENT *mclient;
-       char *hostname;
-       char *pathname;
-       char *old_opts;
-       char *mounthost=NULL;
-       char new_opts[1024];
-       struct timeval total_timeout;
-       enum clnt_stat clnt_stat;
-       static struct nfs_mount_data data;
-       char *opt, *opteq;
-       int val;
-       struct hostent *hp;
-       struct sockaddr_in server_addr;
-       struct sockaddr_in mount_server_addr;
-       struct pmap* pm_mnt;
-       int msock, fsock;
-       struct timeval retry_timeout;
-       union {
-               struct fhstatus nfsv2;
-               struct mountres3 nfsv3;
-       } status;
-       struct stat statbuf;
-       char *s;
-       int port;
-       int mountport;
-       int proto;
-       int bg;
-       int soft;
-       int intr;
-       int posix;
-       int nocto;
-       int noac;
-       int nolock;
-       int retry;
-       int tcp;
-       int mountprog;
-       int mountvers;
-       int nfsprog;
-       int nfsvers;
-       int retval;
-       time_t t;
-       time_t prevt;
-       time_t timeout;
-
-       find_kernel_nfs_mount_version();
-
-       retval = EX_FAIL;
-       msock = fsock = -1;
-       mclient = NULL;
-       if (strlen(spec) >= sizeof(hostdir)) {
-               error_msg("excessively long host:dir argument");
-               goto fail;
-       }
-       strcpy(hostdir, spec);
-       if ((s = strchr(hostdir, ':'))) {
-               hostname = hostdir;
-               pathname = s + 1;
-               *s = '\0';
-               /* Ignore all but first hostname in replicated mounts
-                  until they can be fully supported. (mack@sgi.com) */
-               if ((s = strchr(hostdir, ','))) {
-                       *s = '\0';
-                       error_msg("warning: multiple hostnames not supported");
-               }
-       } else {
-               error_msg("directory to mount not in host:dir format");
-               goto fail;
-       }
-
-       server_addr.sin_family = AF_INET;
-#ifdef HAVE_inet_aton
-       if (!inet_aton(hostname, &server_addr.sin_addr))
-#endif
-       {
-               if ((hp = gethostbyname(hostname)) == NULL) {
-                       herror_msg("%s", hostname);
-                       goto fail;
-               } else {
-                       if (hp->h_length > sizeof(struct in_addr)) {
-                               error_msg("got bad hp->h_length");
-                               hp->h_length = sizeof(struct in_addr);
-                       }
-                       memcpy(&server_addr.sin_addr,
-                              hp->h_addr, hp->h_length);
-               }
-       }
-
-       memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
-
-       /* add IP address to mtab options for use when unmounting */
-
-       s = inet_ntoa(server_addr.sin_addr);
-       old_opts = *extra_opts;
-       if (!old_opts)
-               old_opts = "";
-       if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
-               error_msg("excessively long option argument");
-               goto fail;
-       }
-       sprintf(new_opts, "%s%saddr=%s",
-               old_opts, *old_opts ? "," : "", s);
-       *extra_opts = xstrdup(new_opts);
-
-       /* Set default options.
-        * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
-        * let the kernel decide.
-        * timeo is filled in after we know whether it'll be TCP or UDP. */
-       memset(&data, 0, sizeof(data));
-       data.retrans    = 3;
-       data.acregmin   = 3;
-       data.acregmax   = 60;
-       data.acdirmin   = 30;
-       data.acdirmax   = 60;
-#if NFS_MOUNT_VERSION >= 2
-       data.namlen     = NAME_MAX;
-#endif
-
-       bg = 0;
-       soft = 0;
-       intr = 0;
-       posix = 0;
-       nocto = 0;
-       nolock = 0;
-       noac = 0;
-       retry = 10000;          /* 10000 minutes ~ 1 week */
-       tcp = 0;
-
-       mountprog = MOUNTPROG;
-       mountvers = 0;
-       port = 0;
-       mountport = 0;
-       nfsprog = NFS_PROGRAM;
-       nfsvers = 0;
-
-       /* parse options */
-
-       for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
-               if ((opteq = strchr(opt, '='))) {
-                       val = atoi(opteq + 1);  
-                       *opteq = '\0';
-                       if (!strcmp(opt, "rsize"))
-                               data.rsize = val;
-                       else if (!strcmp(opt, "wsize"))
-                               data.wsize = val;
-                       else if (!strcmp(opt, "timeo"))
-                               data.timeo = val;
-                       else if (!strcmp(opt, "retrans"))
-                               data.retrans = val;
-                       else if (!strcmp(opt, "acregmin"))
-                               data.acregmin = val;
-                       else if (!strcmp(opt, "acregmax"))
-                               data.acregmax = val;
-                       else if (!strcmp(opt, "acdirmin"))
-                               data.acdirmin = val;
-                       else if (!strcmp(opt, "acdirmax"))
-                               data.acdirmax = val;
-                       else if (!strcmp(opt, "actimeo")) {
-                               data.acregmin = val;
-                               data.acregmax = val;
-                               data.acdirmin = val;
-                               data.acdirmax = val;
-                       }
-                       else if (!strcmp(opt, "retry"))
-                               retry = val;
-                       else if (!strcmp(opt, "port"))
-                               port = val;
-                       else if (!strcmp(opt, "mountport"))
-                               mountport = val;
-                       else if (!strcmp(opt, "mounthost"))
-                               mounthost=xstrndup(opteq+1,
-                                                 strcspn(opteq+1," \t\n\r,"));
-                       else if (!strcmp(opt, "mountprog"))
-                               mountprog = val;
-                       else if (!strcmp(opt, "mountvers"))
-                               mountvers = val;
-                       else if (!strcmp(opt, "nfsprog"))
-                               nfsprog = val;
-                       else if (!strcmp(opt, "nfsvers") ||
-                                !strcmp(opt, "vers"))
-                               nfsvers = val;
-                       else if (!strcmp(opt, "proto")) {
-                               if (!strncmp(opteq+1, "tcp", 3))
-                                       tcp = 1;
-                               else if (!strncmp(opteq+1, "udp", 3))
-                                       tcp = 0;
-                               else
-                                       printf(_("Warning: Unrecognized proto= option.\n"));
-                       } else if (!strcmp(opt, "namlen")) {
-#if NFS_MOUNT_VERSION >= 2
-                               if (nfs_mount_version >= 2)
-                                       data.namlen = val;
-                               else
-#endif
-                               printf(_("Warning: Option namlen is not supported.\n"));
-                       } else if (!strcmp(opt, "addr"))
-                               /* ignore */;
-                       else {
-                               printf(_("unknown nfs mount parameter: "
-                                      "%s=%d\n"), opt, val);
-                               goto fail;
-                       }
-               }
-               else {
-                       val = 1;
-                       if (!strncmp(opt, "no", 2)) {
-                               val = 0;
-                               opt += 2;
-                       }
-                       if (!strcmp(opt, "bg")) 
-                               bg = val;
-                       else if (!strcmp(opt, "fg")) 
-                               bg = !val;
-                       else if (!strcmp(opt, "soft"))
-                               soft = val;
-                       else if (!strcmp(opt, "hard"))
-                               soft = !val;
-                       else if (!strcmp(opt, "intr"))
-                               intr = val;
-                       else if (!strcmp(opt, "posix"))
-                               posix = val;
-                       else if (!strcmp(opt, "cto"))
-                               nocto = !val;
-                       else if (!strcmp(opt, "ac"))
-                               noac = !val;
-                       else if (!strcmp(opt, "tcp"))
-                               tcp = val;
-                       else if (!strcmp(opt, "udp"))
-                               tcp = !val;
-                       else if (!strcmp(opt, "lock")) {
-                               if (nfs_mount_version >= 3)
-                                       nolock = !val;
-                               else
-                                       printf(_("Warning: option nolock is not supported.\n"));
-                       } else {
-                               printf(_("unknown nfs mount option: "
-                                          "%s%s\n"), val ? "" : "no", opt);
-                               goto fail;
-                       }
-               }
-       }
-       proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
-
-       data.flags = (soft ? NFS_MOUNT_SOFT : 0)
-               | (intr ? NFS_MOUNT_INTR : 0)
-               | (posix ? NFS_MOUNT_POSIX : 0)
-               | (nocto ? NFS_MOUNT_NOCTO : 0)
-               | (noac ? NFS_MOUNT_NOAC : 0);
-#if NFS_MOUNT_VERSION >= 2
-       if (nfs_mount_version >= 2)
-               data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
-#endif
-#if NFS_MOUNT_VERSION >= 3
-       if (nfs_mount_version >= 3)
-               data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
-#endif
-       if (nfsvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!", nfsvers);
-               return 0;
-       }
-       if (mountvers > MAX_NFSPROT) {
-               error_msg("NFSv%d not supported!", nfsvers);
-               return 0;
-       }
-       if (nfsvers && !mountvers)
-               mountvers = (nfsvers < 3) ? 1 : nfsvers;
-       if (nfsvers && nfsvers < mountvers) {
-               mountvers = nfsvers;
-       }
-
-       /* Adjust options if none specified */
-       if (!data.timeo)
-               data.timeo = tcp ? 70 : 7;
-
-#ifdef NFS_MOUNT_DEBUG
-       printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
-               data.rsize, data.wsize, data.timeo, data.retrans);
-       printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
-               data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
-       printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
-               port, bg, retry, data.flags);
-       printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
-               mountprog, mountvers, nfsprog, nfsvers);
-       printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
-               (data.flags & NFS_MOUNT_SOFT) != 0,
-               (data.flags & NFS_MOUNT_INTR) != 0,
-               (data.flags & NFS_MOUNT_POSIX) != 0,
-               (data.flags & NFS_MOUNT_NOCTO) != 0,
-               (data.flags & NFS_MOUNT_NOAC) != 0);
-#if NFS_MOUNT_VERSION >= 2
-       printf("tcp = %d\n",
-               (data.flags & NFS_MOUNT_TCP) != 0);
-#endif
-#endif
-
-       data.version = nfs_mount_version;
-       *mount_opts = (char *) &data;
-
-       if (*flags & MS_REMOUNT)
-               return 0;
-
-       /*
-        * If the previous mount operation on the same host was
-        * backgrounded, and the "bg" for this mount is also set,
-        * give up immediately, to avoid the initial timeout.
-        */
-       if (bg && !running_bg &&
-           prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
-               if (retry > 0)
-                       retval = EX_BG;
-               return retval;
-       }
-
-       /* create mount deamon client */
-       /* See if the nfs host = mount host. */
-       if (mounthost) {
-         if (mounthost[0] >= '0' && mounthost[0] <= '9') {
-           mount_server_addr.sin_family = AF_INET;
-           mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
-         } else {
-                 if ((hp = gethostbyname(mounthost)) == NULL) {
-                         herror_msg("%s", mounthost);
-                         goto fail;
-                 } else {
-                         if (hp->h_length > sizeof(struct in_addr)) {
-                                 error_msg("got bad hp->h_length?");
-                                 hp->h_length = sizeof(struct in_addr);
-                         }
-                         mount_server_addr.sin_family = AF_INET;
-                         memcpy(&mount_server_addr.sin_addr,
-                                hp->h_addr, hp->h_length);
-                 }
-         }
-       }
-
-       /*
-        * The following loop implements the mount retries. On the first
-        * call, "running_bg" is 0. When the mount times out, and the
-        * "bg" option is set, the exit status EX_BG will be returned.
-        * For a backgrounded mount, there will be a second call by the
-        * child process with "running_bg" set to 1.
-        *
-        * The case where the mount point is not present and the "bg"
-        * option is set, is treated as a timeout. This is done to
-        * support nested mounts.
-        *
-        * The "retry" count specified by the user is the number of
-        * minutes to retry before giving up.
-        *
-        * Only the first error message will be displayed.
-        */
-       retry_timeout.tv_sec = 3;
-       retry_timeout.tv_usec = 0;
-       total_timeout.tv_sec = 20;
-       total_timeout.tv_usec = 0;
-       timeout = time(NULL) + 60 * retry;
-       prevt = 0;
-       t = 30;
-       val = 1;
-       for (;;) {
-               if (bg && stat(node, &statbuf) == -1) {
-                       if (running_bg) {
-                               sleep(val);     /* 1, 2, 4, 8, 16, 30, ... */
-                               val *= 2;
-                               if (val > 30)
-                                       val = 30;
-                       }
-               } else {
-                       /* be careful not to use too many CPU cycles */
-                       if (t - prevt < 30)
-                               sleep(30);
-
-                       pm_mnt = get_mountport(&mount_server_addr,
-                                      mountprog,
-                                      mountvers,
-                                      proto,
-                                      mountport);
-
-                       /* contact the mount daemon via TCP */
-                       mount_server_addr.sin_port = htons(pm_mnt->pm_port);
-                       msock = RPC_ANYSOCK;
-
-                       switch (pm_mnt->pm_prot) {
-                       case IPPROTO_UDP:
-                               mclient = clntudp_create(&mount_server_addr,
-                                                pm_mnt->pm_prog,
-                                                pm_mnt->pm_vers,
-                                                retry_timeout,
-                                                &msock);
-                 if (mclient)
-                         break;
-                 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
-                 msock = RPC_ANYSOCK;
-               case IPPROTO_TCP:
-                       mclient = clnttcp_create(&mount_server_addr,
-                                                pm_mnt->pm_prog,
-                                                pm_mnt->pm_vers,
-                                                &msock, 0, 0);
-                       break;
-               default:
-                       mclient = 0;
-                       }
-                       if (mclient) {
-                               /* try to mount hostname:pathname */
-                               mclient->cl_auth = authunix_create_default();
-
-                       /* make pointers in xdr_mountres3 NULL so
-                        * that xdr_array allocates memory for us
-                        */
-                       memset(&status, 0, sizeof(status));
-
-                       if (pm_mnt->pm_vers == 3)
-                               clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
-                                                     (xdrproc_t) xdr_dirpath,
-                                                     (caddr_t) &pathname,
-                                                     (xdrproc_t) xdr_mountres3,
-                                                     (caddr_t) &status,
-                                       total_timeout);
-                       else
-                               clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
-                                                     (xdrproc_t) xdr_dirpath,
-                                                     (caddr_t) &pathname,
-                                                     (xdrproc_t) xdr_fhstatus,
-                                                     (caddr_t) &status,
-                                                     total_timeout);
-
-                               if (clnt_stat == RPC_SUCCESS)
-                                       break;          /* we're done */
-                               if (errno != ECONNREFUSED) {
-                                       clnt_perror(mclient, "mount");
-                                       goto fail;      /* don't retry */
-                               }
-                               if (!running_bg && prevt == 0)
-                                       clnt_perror(mclient, "mount");
-                               auth_destroy(mclient->cl_auth);
-                               clnt_destroy(mclient);
-                               mclient = 0;
-                               close(msock);
-                       } else {
-                               if (!running_bg && prevt == 0)
-                                       clnt_pcreateerror("mount");
-                       }
-                       prevt = t;
-               }
-               if (!bg)
-                       goto fail;
-               if (!running_bg) {
-                       prev_bg_host = xstrdup(hostname);
-                       if (retry > 0)
-                               retval = EX_BG;
-                       goto fail;
-               }
-               t = time(NULL);
-               if (t >= timeout)
-                       goto fail;
-       }
-       nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
-
-       if (nfsvers == 2) {
-               if (status.nfsv2.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s",
-                               hostname, pathname,
-                               nfs_strerror(status.nfsv2.fhs_status));
-                       goto fail;
-               }
-               memcpy(data.root.data,
-                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
-                      NFS_FHSIZE);
-#if NFS_MOUNT_VERSION >= 4
-               data.root.size = NFS_FHSIZE;
-               memcpy(data.old_root.data,
-                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
-                      NFS_FHSIZE);
-#endif
-       } else {
-#if NFS_MOUNT_VERSION >= 4
-               fhandle3 *my_fhandle;
-               if (status.nfsv3.fhs_status != 0) {
-                       error_msg("%s:%s failed, reason given by server: %s",
-                               hostname, pathname,
-                               nfs_strerror(status.nfsv3.fhs_status));
-                       goto fail;
-               }
-               my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
-               memset(data.old_root.data, 0, NFS_FHSIZE);
-               memset(&data.root, 0, sizeof(data.root));
-               data.root.size = my_fhandle->fhandle3_len;
-               memcpy(data.root.data,
-                      (char *) my_fhandle->fhandle3_val,
-                      my_fhandle->fhandle3_len);
-
-               data.flags |= NFS_MOUNT_VER3;
-#endif
-       }
-
-       /* create nfs socket for kernel */
-
-       if (tcp) {
-               if (nfs_mount_version < 3) {
-                       printf(_("NFS over TCP is not supported.\n"));
-                       goto fail;
-               }
-               fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       } else
-               fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (fsock < 0) {
-               perror(_("nfs socket"));
-               goto fail;
-       }
-       if (bindresvport(fsock, 0) < 0) {
-               perror(_("nfs bindresvport"));
-               goto fail;
-       }
-       if (port == 0) {
-               server_addr.sin_port = PMAPPORT;
-               port = pmap_getport(&server_addr, nfsprog, nfsvers,
-                       tcp ? IPPROTO_TCP : IPPROTO_UDP);
-               if (port == 0)
-                       port = NFS_PORT;
-#ifdef NFS_MOUNT_DEBUG
-               else
-                       printf(_("used portmapper to find NFS port\n"));
-#endif
-       }
-#ifdef NFS_MOUNT_DEBUG
-       printf(_("using port %d for nfs deamon\n"), port);
-#endif
-       server_addr.sin_port = htons(port);
-        /*
-         * connect() the socket for kernels 1.3.10 and below only,
-         * to avoid problems with multihomed hosts.
-         * --Swen
-         */
-       if (get_kernel_revision() <= 66314
-           && connect(fsock, (struct sockaddr *) &server_addr,
-                      sizeof (server_addr)) < 0) {
-               perror(_("nfs connect"));
-               goto fail;
-       }
-
-       /* prepare data structure for kernel */
-
-       data.fd = fsock;
-       memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
-       strncpy(data.hostname, hostname, sizeof(data.hostname));
-
-       /* clean up */
-
-       auth_destroy(mclient->cl_auth);
-       clnt_destroy(mclient);
-       close(msock);
-       return 0;
-
-       /* abort */
-
-fail:
-       if (msock != -1) {
-               if (mclient) {
-                       auth_destroy(mclient->cl_auth);
-                       clnt_destroy(mclient);
-               }
-               close(msock);
-       }
-       if (fsock != -1)
-               close(fsock);
-       return retval;
-}      
-
-/*
- * We need to translate between nfs status return values and
- * the local errno values which may not be the same.
- *
- * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
- * "after #include <errno.h> the symbol errno is reserved for any use,
- *  it cannot even be used as a struct tag or field name".
- */
-
-#ifndef EDQUOT
-#define EDQUOT ENOSPC
-#endif
-
-static struct {
-       enum nfs_stat stat;
-       int errnum;
-} nfs_errtbl[] = {
-       { NFS_OK,               0               },
-       { NFSERR_PERM,          EPERM           },
-       { NFSERR_NOENT,         ENOENT          },
-       { NFSERR_IO,            EIO             },
-       { NFSERR_NXIO,          ENXIO           },
-       { NFSERR_ACCES,         EACCES          },
-       { NFSERR_EXIST,         EEXIST          },
-       { NFSERR_NODEV,         ENODEV          },
-       { NFSERR_NOTDIR,        ENOTDIR         },
-       { NFSERR_ISDIR,         EISDIR          },
-#ifdef NFSERR_INVAL
-       { NFSERR_INVAL,         EINVAL          },      /* that Sun forgot */
-#endif
-       { NFSERR_FBIG,          EFBIG           },
-       { NFSERR_NOSPC,         ENOSPC          },
-       { NFSERR_ROFS,          EROFS           },
-       { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
-       { NFSERR_NOTEMPTY,      ENOTEMPTY       },
-       { NFSERR_DQUOT,         EDQUOT          },
-       { NFSERR_STALE,         ESTALE          },
-#ifdef EWFLUSH
-       { NFSERR_WFLUSH,        EWFLUSH         },
-#endif
-       /* Throw in some NFSv3 values for even more fun (HP returns these) */
-       { 71,                   EREMOTE         },
-
-       { -1,                   EIO             }
-};
-
-static char *nfs_strerror(int status)
-{
-       int i;
-       static char buf[256];
-
-       for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-               if (nfs_errtbl[i].stat == status)
-                       return strerror(nfs_errtbl[i].errnum);
-       }
-       sprintf(buf, _("unknown nfs status return value: %d"), status);
-       return buf;
-}
-
-static bool_t
-xdr_fhandle (XDR *xdrs, fhandle objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_opaque (xdrs, objp, FHSIZE))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_fhstatus (XDR *xdrs, fhstatus *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_u_int (xdrs, &objp->fhs_status))
-                return FALSE;
-       switch (objp->fhs_status) {
-       case 0:
-                if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
-                        return FALSE;
-               break;
-       default:
-               break;
-       }
-       return TRUE;
-}
-
-bool_t
-xdr_dirpath (XDR *xdrs, dirpath *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_string (xdrs, objp, MNTPATHLEN))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_fhandle3 (xdrs, &objp->fhandle))
-                return FALSE;
-        if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
-               sizeof (int), (xdrproc_t) xdr_int))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_enum (xdrs, (enum_t *) objp))
-                return FALSE;
-       return TRUE;
-}
-
-bool_t
-xdr_mountres3 (XDR *xdrs, mountres3 *objp)
-{
-       //register int32_t *buf;
-
-        if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
-                return FALSE;
-       switch (objp->fhs_status) {
-       case MNT_OK:
-                if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
-                        return FALSE;
-               break;
-       default:
-               break;
-       }
-       return TRUE;
-}
-
diff --git a/busybox/util-linux/nfsmount.h b/busybox/util-linux/nfsmount.h
deleted file mode 100644 (file)
index b3d5a51..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * This file was originally generated using rpcgen.
- * But now we edit it by hand as needed to make it
- * shut up...
- */
-
-#ifndef _NFSMOUNT_H_RPCGEN
-#define _NFSMOUNT_H_RPCGEN
-
-#include <rpc/rpc.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
- * unrestricted use provided that this legend is included on all tape
- * media and as a part of the software program in whole or part.  Users
- * may copy or modify Sun RPC without charge, but are not authorized
- * to license or distribute it to anyone else except as part of a product or
- * program developed by the user or with the express written consent of
- * Sun Microsystems, Inc.
- *
- * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
- * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * Sun RPC is provided with no support and without any obligation on the
- * part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
- *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
- * OR ANY PART THEREOF.
- *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
- *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California  94043
- */
-/*
- * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
- */
-
-/* from @(#)mount.x    1.3 91/03/11 TIRPC 1.0 */
-#ifndef _rpcsvc_mount_h
-#define _rpcsvc_mount_h
-#include <asm/types.h>
-#define MOUNTPORT 635
-#define MNTPATHLEN 1024
-#define MNTNAMLEN 255
-#define FHSIZE 32
-#define FHSIZE3 64
-
-typedef char fhandle[FHSIZE];
-
-typedef struct {
-       u_int fhandle3_len;
-       char *fhandle3_val;
-} fhandle3;
-
-enum mountstat3 {
-       MNT_OK = 0,
-       MNT3ERR_PERM = 1,
-       MNT3ERR_NOENT = 2,
-       MNT3ERR_IO = 5,
-       MNT3ERR_ACCES = 13,
-       MNT3ERR_NOTDIR = 20,
-       MNT3ERR_INVAL = 22,
-       MNT3ERR_NAMETOOLONG = 63,
-       MNT3ERR_NOTSUPP = 10004,
-       MNT3ERR_SERVERFAULT = 10006,
-};
-typedef enum mountstat3 mountstat3;
-
-struct fhstatus {
-       u_int fhs_status;
-       union {
-               fhandle fhs_fhandle;
-       } fhstatus_u;
-};
-typedef struct fhstatus fhstatus;
-
-struct mountres3_ok {
-       fhandle3 fhandle;
-       struct {
-               u_int auth_flavours_len;
-               int *auth_flavours_val;
-       } auth_flavours;
-};
-typedef struct mountres3_ok mountres3_ok;
-
-struct mountres3 {
-       mountstat3 fhs_status;
-       union {
-               mountres3_ok mountinfo;
-       } mountres3_u;
-};
-typedef struct mountres3 mountres3;
-
-typedef char *dirpath;
-
-typedef char *name;
-
-typedef struct mountbody *mountlist;
-
-struct mountbody {
-       name ml_hostname;
-       dirpath ml_directory;
-       mountlist ml_next;
-};
-typedef struct mountbody mountbody;
-
-typedef struct groupnode *groups;
-
-struct groupnode {
-       name gr_name;
-       groups gr_next;
-};
-typedef struct groupnode groupnode;
-
-typedef struct exportnode *exports;
-
-struct exportnode {
-       dirpath ex_dir;
-       groups ex_groups;
-       exports ex_next;
-};
-typedef struct exportnode exportnode;
-
-struct ppathcnf {
-       int pc_link_max;
-       short pc_max_canon;
-       short pc_max_input;
-       short pc_name_max;
-       short pc_path_max;
-       short pc_pipe_buf;
-       u_char pc_vdisable;
-       char pc_xxx;
-       short pc_mask[2];
-};
-typedef struct ppathcnf ppathcnf;
-#endif /*!_rpcsvc_mount_h*/
-
-#define MOUNTPROG 100005
-#define MOUNTVERS 1
-
-#define MOUNTPROC_NULL 0
-extern  void * mountproc_null_1(void *, CLIENT *);
-extern  void * mountproc_null_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_MNT 1
-extern  fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
-extern  fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_DUMP 2
-extern  mountlist * mountproc_dump_1(void *, CLIENT *);
-extern  mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_UMNT 3
-extern  void * mountproc_umnt_1(dirpath *, CLIENT *);
-extern  void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_UMNTALL 4
-extern  void * mountproc_umntall_1(void *, CLIENT *);
-extern  void * mountproc_umntall_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORT 5
-extern  exports * mountproc_export_1(void *, CLIENT *);
-extern  exports * mountproc_export_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORTALL 6
-extern  exports * mountproc_exportall_1(void *, CLIENT *);
-extern  exports * mountproc_exportall_1_svc(void *, struct svc_req *);
-extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNTVERS_POSIX 2
-
-extern  void * mountproc_null_2(void *, CLIENT *);
-extern  void * mountproc_null_2_svc(void *, struct svc_req *);
-extern  fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
-extern  fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
-extern  mountlist * mountproc_dump_2(void *, CLIENT *);
-extern  mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
-extern  void * mountproc_umnt_2(dirpath *, CLIENT *);
-extern  void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
-extern  void * mountproc_umntall_2(void *, CLIENT *);
-extern  void * mountproc_umntall_2_svc(void *, struct svc_req *);
-extern  exports * mountproc_export_2(void *, CLIENT *);
-extern  exports * mountproc_export_2_svc(void *, struct svc_req *);
-extern  exports * mountproc_exportall_2(void *, CLIENT *);
-extern  exports * mountproc_exportall_2_svc(void *, struct svc_req *);
-#define MOUNTPROC_PATHCONF 7
-extern  ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
-extern  ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
-extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNT_V3 3
-
-#define MOUNTPROC3_NULL 0
-extern  void * mountproc3_null_3(void *, CLIENT *);
-extern  void * mountproc3_null_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_MNT 1
-extern  mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
-extern  mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_DUMP 2
-extern  mountlist * mountproc3_dump_3(void *, CLIENT *);
-extern  mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_UMNT 3
-extern  void * mountproc3_umnt_3(dirpath *, CLIENT *);
-extern  void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_UMNTALL 4
-extern  void * mountproc3_umntall_3(void *, CLIENT *);
-extern  void * mountproc3_umntall_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_EXPORT 5
-extern  exports * mountproc3_export_3(void *, CLIENT *);
-extern  exports * mountproc3_export_3_svc(void *, struct svc_req *);
-extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-/* the xdr functions */
-
-static  bool_t xdr_fhandle (XDR *, fhandle);
-extern  bool_t xdr_fhandle3 (XDR *, fhandle3*);
-extern  bool_t xdr_mountstat3 (XDR *, mountstat3*);
-extern  bool_t xdr_fhstatus (XDR *, fhstatus*);
-extern  bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
-extern  bool_t xdr_mountres3 (XDR *, mountres3*);
-extern  bool_t xdr_dirpath (XDR *, dirpath*);
-extern  bool_t xdr_name (XDR *, name*);
-extern  bool_t xdr_mountlist (XDR *, mountlist*);
-extern  bool_t xdr_mountbody (XDR *, mountbody*);
-extern  bool_t xdr_groups (XDR *, groups*);
-extern  bool_t xdr_groupnode (XDR *, groupnode*);
-extern  bool_t xdr_exports (XDR *, exports*);
-extern  bool_t xdr_exportnode (XDR *, exportnode*);
-extern  bool_t xdr_ppathcnf (XDR *, ppathcnf*);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_NFSMOUNT_H_RPCGEN */
diff --git a/busybox/util-linux/pivot_root.c b/busybox/util-linux/pivot_root.c
deleted file mode 100644 (file)
index ba26b9c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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. 
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include "busybox.h"
-
-extern int pivot_root(const char * new_root,const char * put_old);
-
-int pivot_root_main(int argc, char **argv)
-{
-    if (argc != 3)
-        show_usage();
-
-       if (pivot_root(argv[1],argv[2]) < 0)
-               perror_msg_and_die("pivot_root");
-
-    return EXIT_SUCCESS;
-
-}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/util-linux/rdate.c b/busybox/util-linux/rdate.c
deleted file mode 100644 (file)
index 50be4de..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* 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>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-
-static const int RFC_868_BIAS = 2208988800UL;
-
-static time_t askremotedate(const char *host)
-{
-       struct hostent *h;
-       struct sockaddr_in s_in;
-       struct servent *tserv;
-       unsigned long int nett, localt;
-       int fd;
-
-       h = xgethostbyname(host);         /* get the IP addr */
-
-       if ((tserv = getservbyname("time", "tcp")) == NULL)   /* find port # */
-               perror_msg_and_die("time");
-
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    /* get net connection */
-               perror_msg_and_die("socket");
-
-       memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr));
-       s_in.sin_port= tserv->s_port;
-       s_in.sin_family = AF_INET;
-
-       if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)      /* connect to time server */
-               perror_msg_and_die("%s", host);
-
-       if (read(fd, (void *)&nett, 4) != 4)    /* read time from server */
-               error_msg_and_die("%s did not send the complete time", host);
-
-       close(fd);
-
-       /* convert from network byte order to local byte order.
-        * RFC 868 time is the number of seconds
-        *  since 00:00 (midnight) 1 January 1900 GMT
-        *  the RFC 868 time 2,208,988,800 corresponds to 00:00  1 Jan 1970 GMT
-        * Subtract the RFC 868 time  to get Linux epoch
-        */
-       localt= ntohl(nett) - RFC_868_BIAS;
-
-       return(localt);
-}
-
-int rdate_main(int argc, char **argv)
-{
-       time_t remote_time;
-       int opt;
-       int setdate = 1;
-       int printdate = 1;
-
-       /* Interpret command line args */
-       while ((opt = getopt(argc, argv, "sp")) > 0) {
-               switch (opt) {
-                       case 's':
-                               printdate = 0;
-                               setdate = 1;
-                               break;
-                       case 'p':
-                               printdate = 1;
-                               setdate = 0;
-                               break;
-                       default:
-                               show_usage();
-               }
-       }
-
-       if (optind == argc)
-               show_usage();
-
-       remote_time = askremotedate(argv[optind]);
-
-       if (setdate) {
-               if (stime(&remote_time) < 0)
-                       perror_msg_and_die("Could not set time of day");
-       }
-
-       if (printdate)
-               printf("%s", ctime(&remote_time));
-
-       return EXIT_SUCCESS;
-}
diff --git a/busybox/util-linux/swaponoff.c b/busybox/util-linux/swaponoff.c
deleted file mode 100644 (file)
index ce0e2c6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini swapon/swapoff implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <mntent.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/mount.h>
-
-#if __GNU_LIBRARY__ < 5
-/* libc5 doesn't have sys/swap.h, define these here. */ 
-extern int swapon (__const char *__path, int __flags);
-extern int swapoff (__const char *__path);
-#else
-#include <sys/swap.h>
-#endif
-
-#include "busybox.h"
-
-static int whichApp;
-
-static const int SWAPON_APP = 1;
-static const int SWAPOFF_APP = 2;
-
-
-static void swap_enable_disable(char *device)
-{
-       int status;
-
-       if (whichApp == SWAPON_APP)
-               status = swapon(device, 0);
-       else
-               status = swapoff(device);
-
-       if (status != 0)
-               perror_msg_and_die(applet_name);
-}
-
-static void do_em_all()
-{
-       struct mntent *m;
-       FILE *f = setmntent("/etc/fstab", "r");
-
-       if (f == NULL)
-               perror_msg_and_die("/etc/fstab");
-       while ((m = getmntent(f)) != NULL) {
-               if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) {
-                       swap_enable_disable(m->mnt_fsname);
-               }
-       }
-       endmntent(f);
-       exit(EXIT_SUCCESS);
-}
-
-
-extern int swap_on_off_main(int argc, char **argv)
-{
-       if (strcmp(applet_name, "swapon") == 0) {
-               whichApp = SWAPON_APP;
-       } else {
-               whichApp = SWAPOFF_APP;
-       }
-
-       if (argc != 2) {
-               goto usage_and_exit;
-       }
-       argc--;
-       argv++;
-
-       /* Parse any options */
-       while (**argv == '-') {
-               while (*++(*argv))
-                       switch (**argv) {
-                       case 'a':
-                               {
-                                       struct stat statBuf;
-
-                                       if (stat("/etc/fstab", &statBuf) < 0)
-                                               error_msg_and_die("/etc/fstab file missing");
-                               }
-                               do_em_all();
-                               break;
-                       default:
-                               goto usage_and_exit;
-                       }
-       }
-       swap_enable_disable(*argv);
-       return EXIT_SUCCESS;
-
-  usage_and_exit:
-       show_usage();
-}
diff --git a/busybox/util-linux/umount.c b/busybox/util-linux/umount.c
deleted file mode 100644 (file)
index 74638d2..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini umount implementation for busybox
- *
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-/* Teach libc5 about realpath -- it includes it but the 
- * prototype is missing... */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-extern char *realpath(const char *path, char *resolved_path);
-#endif
-
-static const int MNT_FORCE = 1;
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS.  */
-static const int MS_RDONLY = 1;        /* Mount read-only.  */
-
-extern int mount (__const char *__special_file, __const char *__dir,
-                       __const char *__fstype, unsigned long int __rwflag,
-                       __const void *__data);
-extern int umount (__const char *__special_file);
-extern int umount2 (__const char *__special_file, int __flags);
-
-struct _mtab_entry_t {
-       char *device;
-       char *mountpt;
-       struct _mtab_entry_t *next;
-};
-
-static struct _mtab_entry_t *mtab_cache = NULL;
-
-
-
-#if defined BB_FEATURE_MOUNT_FORCE
-static int doForce = FALSE;
-#endif
-#if defined BB_FEATURE_MOUNT_LOOP
-static int freeLoop = TRUE;
-#endif
-#if defined BB_FEATURE_MTAB_SUPPORT
-static int useMtab = TRUE;
-#endif
-static int umountAll = FALSE;
-static int doRemount = FALSE;
-extern const char mtab_file[]; /* Defined in utility.c */
-
-
-
-/* These functions are here because the getmntent functions do not appear
- * to be re-entrant, which leads to all sorts of problems when we try to
- * use them recursively - randolph
- *
- * TODO: Perhaps switch to using Glibc's getmntent_r
- *        -Erik
- */
-static void mtab_read(void)
-{
-       struct _mtab_entry_t *entry = NULL;
-       struct mntent *e;
-       FILE *fp;
-
-       if (mtab_cache != NULL)
-               return;
-
-       if ((fp = setmntent(mtab_file, "r")) == NULL) {
-               error_msg("Cannot open %s", mtab_file);
-               return;
-       }
-       while ((e = getmntent(fp))) {
-               entry = xmalloc(sizeof(struct _mtab_entry_t));
-               entry->device = strdup(e->mnt_fsname);
-               entry->mountpt = strdup(e->mnt_dir);
-               entry->next = mtab_cache;
-               mtab_cache = entry;
-       }
-       endmntent(fp);
-}
-
-static char *mtab_getinfo(const char *match, const char which)
-{
-       struct _mtab_entry_t *cur = mtab_cache;
-
-       while (cur) {
-               if (strcmp(cur->mountpt, match) == 0 ||
-                       strcmp(cur->device, match) == 0) {
-                       if (which == MTAB_GETMOUNTPT) {
-                               return cur->mountpt;
-                       } else {
-#if !defined BB_FEATURE_MTAB_SUPPORT
-                               if (strcmp(cur->device, "/dev/root") == 0) {
-                                       /* Adjusts device to be the real root device,
-                                        * or leaves device alone if it can't find it */
-                                       cur->device = find_real_root_device_name(cur->device);
-                               }
-#endif
-                               return cur->device;
-                       }
-               }
-               cur = cur->next;
-       }
-       return NULL;
-}
-
-static char *mtab_next(void **iter)
-{
-       char *mp;
-
-       if (iter == NULL || *iter == NULL)
-               return NULL;
-       mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
-       *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
-       return mp;
-}
-
-static char *mtab_first(void **iter)
-{
-       struct _mtab_entry_t *mtab_iter;
-
-       if (!iter)
-               return NULL;
-       mtab_iter = mtab_cache;
-       *iter = (void *) mtab_iter;
-       return mtab_next(iter);
-}
-
-/* Don't bother to clean up, since exit() does that 
- * automagically, so we can save a few bytes */
-#ifdef BB_FEATURE_CLEAN_UP
-static void mtab_free(void)
-{
-       struct _mtab_entry_t *this, *next;
-
-       this = mtab_cache;
-       while (this) {
-               next = this->next;
-               if (this->device)
-                       free(this->device);
-               if (this->mountpt)
-                       free(this->mountpt);
-               free(this);
-               this = next;
-       }
-}
-#endif
-
-static int do_umount(const char *name)
-{
-       int status;
-       char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
-
-       if (blockDevice && strcmp(blockDevice, name) == 0)
-               name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
-
-       status = umount(name);
-
-#if defined BB_FEATURE_MOUNT_LOOP
-       if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
-               /* this was a loop device, delete it */
-               del_loop(blockDevice);
-#endif
-#if defined BB_FEATURE_MOUNT_FORCE
-       if (status != 0 && doForce == TRUE) {
-               status = umount2(blockDevice, MNT_FORCE);
-               if (status != 0) {
-                       error_msg_and_die("forced umount of %s failed!", blockDevice);
-               }
-       }
-#endif
-       if (status != 0 && doRemount == TRUE && errno == EBUSY) {
-               status = mount(blockDevice, name, NULL,
-                                          MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
-               if (status == 0) {
-                       error_msg("%s busy - remounted read-only", blockDevice);
-               } else {
-                       error_msg("Cannot remount %s read-only", blockDevice);
-               }
-       }
-       if (status == 0) {
-#if defined BB_FEATURE_MTAB_SUPPORT
-               if (useMtab == TRUE)
-                       erase_mtab(name);
-#endif
-               return (TRUE);
-       }
-       return (FALSE);
-}
-
-static int umount_all(void)
-{
-       int status = TRUE;
-       char *mountpt;
-       void *iter;
-
-       for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
-               /* Never umount /proc on a umount -a */
-               if (strstr(mountpt, "proc")!= NULL)
-                       continue;
-               if (!do_umount(mountpt)) {
-                       /* Don't bother retrying the umount on busy devices */
-                       if (errno == EBUSY) {
-                               perror_msg("%s", mountpt);
-                               status = FALSE;
-                               continue;
-                       }
-                       if (!do_umount(mountpt)) {
-                               printf("Couldn't umount %s on %s: %s\n",
-                                          mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
-                                          strerror(errno));
-                               status = FALSE;
-                       }
-               }
-       }
-       return (status);
-}
-
-extern int umount_main(int argc, char **argv)
-{
-       char path[PATH_MAX];
-
-       if (argc < 2) {
-               show_usage();
-       }
-#ifdef BB_FEATURE_CLEAN_UP
-       atexit(mtab_free);
-#endif
-
-       /* Parse any options */
-       while (--argc > 0 && **(++argv) == '-') {
-               while (*++(*argv))
-                       switch (**argv) {
-                       case 'a':
-                               umountAll = TRUE;
-                               break;
-#if defined BB_FEATURE_MOUNT_LOOP
-                       case 'l':
-                               freeLoop = FALSE;
-                               break;
-#endif
-#ifdef BB_FEATURE_MTAB_SUPPORT
-                       case 'n':
-                               useMtab = FALSE;
-                               break;
-#endif
-#ifdef BB_FEATURE_MOUNT_FORCE
-                       case 'f':
-                               doForce = TRUE;
-                               break;
-#endif
-                       case 'r':
-                               doRemount = TRUE;
-                               break;
-                       case 'v':
-                               break; /* ignore -v */
-                       default:
-                               show_usage();
-                       }
-       }
-
-       mtab_read();
-       if (umountAll == TRUE) {
-               if (umount_all() == TRUE)
-                       return EXIT_SUCCESS;
-               else
-                       return EXIT_FAILURE;
-       }
-       if (realpath(*argv, path) == NULL)
-               perror_msg_and_die("%s", path);
-       if (do_umount(path) == TRUE)
-               return EXIT_SUCCESS;
-       perror_msg_and_die("%s", *argv);
-}
-
diff --git a/busybox/uudecode.c b/busybox/uudecode.c
deleted file mode 100644 (file)
index a4059dd..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/* uudecode.c -- uudecode utility.
- * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
- *
- * This product is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This product is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this product; see the file COPYING.  If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
- *
- * Original copyright notice is retained at the end of this file.
- */
-
-
-
-#include <stdio.h>
-#include <errno.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-#include "pwd_grp/pwd.h"
-#include "pwd_grp/grp.h"
-
-/*struct passwd *getpwnam();*/
-
-/* Single character decode.  */
-#define        DEC(Char) (((Char) - ' ') & 077)
-
-static int read_stduu (const char *inname)
-{
-  char buf[2 * BUFSIZ];
-
-  while (1) {
-    int n;
-    char *p;
-
-    if (fgets (buf, sizeof(buf), stdin) == NULL) {
-      error_msg("%s: Short file", inname);
-      return FALSE;
-    }
-    p = buf;
-
-    /* N is used to avoid writing out all the characters at the end of
-       the file.  */
-    n = DEC (*p);
-    if (n <= 0)
-      break;
-    for (++p; n > 0; p += 4, n -= 3) {
-      char ch;
-
-      if (n >= 3) {
-        ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
-        putchar (ch);
-        ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
-        putchar (ch);
-        ch = DEC (p[2]) << 6 | DEC (p[3]);
-        putchar (ch);
-      } else {
-        if (n >= 1) {
-          ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
-          putchar (ch);
-        }
-        if (n >= 2) {
-          ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
-          putchar (ch);
-        }
-      }
-    }
-  }
-
-  if (fgets (buf, sizeof(buf), stdin) == NULL
-      || strcmp (buf, "end\n")) {
-    error_msg("%s: No `end' line", inname);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static int read_base64 (const char *inname)
-{
-  static const char b64_tab[256] = {
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
-    '\177', '\177', '\177', '\76',  '\177', '\177', '\177', '\77',  /*050-057*/
-    '\64',  '\65',  '\66',  '\67',  '\70',  '\71',  '\72',  '\73',  /*060-067*/
-    '\74',  '\75',  '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
-    '\177', '\0',   '\1',   '\2',   '\3',   '\4',   '\5',   '\6',   /*100-107*/
-    '\7',   '\10',  '\11',  '\12',  '\13',  '\14',  '\15',  '\16',  /*110-117*/
-    '\17',  '\20',  '\21',  '\22',  '\23',  '\24',  '\25',  '\26',  /*120-127*/
-    '\27',  '\30',  '\31',  '\177', '\177', '\177', '\177', '\177', /*130-137*/
-    '\177', '\32',  '\33',  '\34',  '\35',  '\36',  '\37',  '\40',  /*140-147*/
-    '\41',  '\42',  '\43',  '\44',  '\45',  '\46',  '\47',  '\50',  /*150-157*/
-    '\51',  '\52',  '\53',  '\54',  '\55',  '\56',  '\57',  '\60',  /*160-167*/
-    '\61',  '\62',  '\63',  '\177', '\177', '\177', '\177', '\177', /*170-177*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
-    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
-  };
-  unsigned char buf[2 * BUFSIZ];
-
-  while (1) {
-    int last_data = 0;
-    unsigned char *p;
-
-    if (fgets (buf, sizeof(buf), stdin) == NULL) {
-      error_msg("%s: Short file", inname);
-      return FALSE;
-    }
-    p = buf;
-
-    if (memcmp (buf, "====", 4) == 0)
-      break;
-    if (last_data != 0) {
-      error_msg("%s: data following `=' padding character", inname);
-      return FALSE;
-    }
-
-    /* The following implementation of the base64 decoding might look
-       a bit clumsy but I only try to follow the POSIX standard:
-       ``All line breaks or other characters not found in the table
-       [with base64 characters] shall be ignored by decoding
-       software.''  */
-    while (*p != '\n') {
-      char c1, c2, c3;
-
-      while ((b64_tab[*p] & '\100') != 0)
-        if (*p == '\n' || *p++ == '=')
-          break;
-      if (*p == '\n')
-        /* This leaves the loop.  */
-        continue;
-      c1 = b64_tab[*p++];
-
-      while ((b64_tab[*p] & '\100') != 0)
-        if (*p == '\n' || *p++ == '=') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      c2 = b64_tab[*p++];
-
-      while (b64_tab[*p] == '\177')
-        if (*p++ == '\n') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      if (*p == '=') {
-        putchar (c1 << 2 | c2 >> 4);
-        last_data = 1;
-        break;
-      }
-      c3 = b64_tab[*p++];
-
-      while (b64_tab[*p] == '\177')
-        if (*p++ == '\n') {
-          error_msg("%s: illegal line", inname);
-          return FALSE;
-        }
-      putchar (c1 << 2 | c2 >> 4);
-      putchar (c2 << 4 | c3 >> 2);
-      if (*p == '=') {
-        last_data = 1;
-        break;
-      }
-      else
-        putchar (c3 << 6 | b64_tab[*p++]);
-    }
-  }
-
-  return TRUE;
-}
-
-static int decode (const char *inname,
-                   const char *forced_outname)
-{
-  struct passwd *pw;
-  register char *p;
-  int mode;
-  char buf[2 * BUFSIZ];
-  char *outname;
-  int do_base64 = 0;
-  int res;
-  int dofre;
-
-  /* Search for header line.  */
-
-  while (1) {
-    if (fgets (buf, sizeof (buf), stdin) == NULL) {
-      error_msg("%s: No `begin' line", inname);
-      return FALSE;
-    }
-
-    if (strncmp (buf, "begin", 5) == 0) {
-      if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
-        do_base64 = 1;
-        break;
-      } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
-        break;
-    }
-  }
-
-  /* If the output file name is given on the command line this rules.  */
-  dofre = FALSE;
-  if (forced_outname != NULL)
-    outname = (char *) forced_outname;
-  else {
-    /* Handle ~user/file format.  */
-    if (buf[0] != '~')
-      outname = buf;
-    else {
-      p = buf + 1;
-      while (*p != '/')
-        ++p;
-      if (*p == '\0') {
-        error_msg("%s: Illegal ~user", inname);
-        return FALSE;
-      }
-      *p++ = '\0';
-      pw = getpwnam (buf + 1);
-      if (pw == NULL) {
-        error_msg("%s: No user `%s'", inname, buf + 1);
-        return FALSE;
-      }
-      outname = concat_path_file(pw->pw_dir, p);
-      dofre = TRUE;
-    }
-  }
-
-  /* Create output file and set mode.  */
-  if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
-      && (freopen (outname, "w", stdout) == NULL
-         || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
-         )) {
-    perror_msg("%s", outname); /* */
-    if (dofre)
-       free(outname);
-    return FALSE;
-  }
-
-  /* We differenciate decoding standard UU encoding and base64.  A
-     common function would only slow down the program.  */
-
-  /* For each input line:  */
-  if (do_base64)
-      res = read_base64 (inname);
-  else
-       res = read_stduu (inname);
-  if (dofre)
-      free(outname);
-  return res;
-}
-
-int uudecode_main (int argc,
-                   char **argv)
-{
-  int opt;
-  int exit_status;
-  const char *outname;
-  outname = NULL;
-
-  while ((opt = getopt(argc, argv, "o:")) != EOF) {
-    switch (opt) {
-     case 0:
-      break;
-
-     case 'o':
-      outname = optarg;
-      break;
-
-     default:
-      show_usage();
-    }
-  }
-
-  if (optind == argc)
-    exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-  else {
-    exit_status = EXIT_SUCCESS;
-    do {
-      if (freopen (argv[optind], "r", stdin) != NULL) {
-        if (decode (argv[optind], outname) != 0)
-          exit_status = FALSE;
-      } else {
-        perror_msg("%s", argv[optind]);
-        exit_status = EXIT_FAILURE;
-      }
-      optind++;
-    }
-    while (optind < argc);
-  }
-  return(exit_status);
-}
-
-/* Copyright (c) 1983 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- */
-
-
diff --git a/busybox/uuencode.c b/busybox/uuencode.c
deleted file mode 100644 (file)
index fc03740..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- *  Copyright (C) 2000 by Glenn McGrath
- *
- *  based on the function base64_encode from http.c in wget v1.6
- *  Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU Library General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* Conversion table.  for base 64 */
-static char tbl_base64[64] = {
-       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-       'w', 'x', 'y', 'z', '0', '1', '2', '3',
-       '4', '5', '6', '7', '8', '9', '+', '/'
-};
-
-static char tbl_std[64] = {
-       '`', '!', '"', '#', '$', '%', '&', '\'',
-       '(', ')', '*', '+', ',', '-', '.', '/',
-       '0', '1', '2', '3', '4', '5', '6', '7',
-       '8', '9', ':', ';', '<', '=', '>', '?',
-       '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
-       'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-       'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-       'X', 'Y', 'Z', '[', '\\', ']', '^', '_'
-};
-
-/*
- * Encode the string S of length LENGTH to base64 format and place it
- * to STORE.  STORE will be 0-terminated, and must point to a writable
- * buffer of at least 1+BASE64_LENGTH(length) bytes.
- * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
- */
-static void uuencode (const char *s, const char *store, const int length, const char *tbl)
-{
-       int i;
-       unsigned char *p = (unsigned char *)store;
-
-       /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
-       for (i = 0; i < length; i += 3) {
-               *p++ = tbl[s[0] >> 2];
-               *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
-               *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
-               *p++ = tbl[s[2] & 0x3f];
-               s += 3;
-       }
-       /* Pad the result if necessary...  */
-       if (i == length + 1) {
-               *(p - 1) = '=';
-       }
-       else if (i == length + 2) {
-               *(p - 1) = *(p - 2) = '=';
-       }
-       /* ...and zero-terminate it.  */
-       *p = '\0';
-}
-
-int uuencode_main(int argc, char **argv)
-{
-       const int src_buf_size = 60;    // This *MUST* be a multiple of 3
-       const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
-       RESERVE_BB_BUFFER(src_buf, src_buf_size + 1);
-       RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1);
-       struct stat stat_buf;
-       FILE *src_stream = stdin;
-       char *tbl = tbl_std;
-       size_t size;
-       mode_t mode;
-       int opt;
-       int column = 0;
-       int write_size = 0;
-       int remaining;
-       int buffer_offset = 0;
-
-       while ((opt = getopt(argc, argv, "m")) != -1) {
-               switch (opt) {
-               case 'm':
-                       tbl = tbl_base64;
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       switch (argc - optind) {
-               case 2:
-                       src_stream = xfopen(argv[optind], "r");
-                       stat(argv[optind], &stat_buf);
-                       mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
-                       if (src_stream == stdout) {
-                               printf("NULL\n");
-                       }
-                       break;
-               case 1:
-                       mode = 0666 & ~umask(0666);
-                       break;
-               default:
-                       show_usage();
-       }
-
-       printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
-
-       while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
-               /* Encode the buffer we just read in */
-               uuencode(src_buf, dst_buf, size, tbl);
-
-               /* Write the buffer to stdout, wrapping at 60 chars.
-                * This looks overly complex, but it gets tricky as
-                * the line has to continue to wrap correctly if we
-                * have to refill the buffer
-                *
-                * Improvments most welcome
-                */
-
-               /* Initialise values for the new buffer */
-               remaining = 4 * ((size + 2) / 3);
-               buffer_offset = 0;
-
-               /* Write the buffer to stdout, wrapping at 60 chars
-                * starting from the column the last buffer ran out
-                */
-               do {
-                       if (remaining > (60 - column)) {
-                               write_size = 60 - column;
-                       }
-                       else if (remaining < 60) {
-                               write_size = remaining;
-                       } else {
-                               write_size = 60;
-                       }
-
-                       /* Setup a new row if required */
-                       if (column == 0) {
-                               putchar('\n');
-                               if (tbl == tbl_std) {
-                                       putchar('M');
-                               }
-                       }
-                       /* Write to the 60th column */
-                       if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) {
-                               perror("Couldnt finish writing");
-                       }
-                       /* Update variables based on last write */
-                       buffer_offset += write_size;
-                       remaining -= write_size;
-                       column += write_size;
-                       if (column % 60 == 0) {
-                               column = 0;
-                       }
-               } while (remaining > 0);
-       }
-       printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
-
-       return(EXIT_SUCCESS);
-}
diff --git a/busybox/vi.c b/busybox/vi.c
deleted file mode 100644 (file)
index 8d7506d..0000000
+++ /dev/null
@@ -1,3947 +0,0 @@
-/* vi: set sw=8 ts=8: */
-/*
- * tiny vi.c: A small 'vi' clone
- * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-static const char vi_Version[] =
-       "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $";
-
-/*
- * To compile for standalone use:
- *     gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
- *       or
- *     gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c                # include testing features
- *     strip vi
- */
-
-/*
- * Things To Do:
- *     EXINIT
- *     $HOME/.exrc  and  ./.exrc
- *     add magic to search     /foo.*bar
- *     add :help command
- *     :map macros
- *     how about mode lines:   vi: set sw=8 ts=8:
- *     if mark[] values were line numbers rather than pointers
- *        it would be easier to change the mark when add/delete lines
- *     More intelligence in refresh()
- *     ":r !cmd"  and  "!cmd"  to filter text through an external command
- *     A true "undo" facility
- *     An "ex" line oriented mode- maybe using "cmdedit"
- */
-
-//----  Feature --------------  Bytes to immplement
-#ifdef STANDALONE
-#define vi_main                        main
-#define BB_FEATURE_VI_COLON    // 4288
-#define BB_FEATURE_VI_YANKMARK // 1408
-#define BB_FEATURE_VI_SEARCH   // 1088
-#define BB_FEATURE_VI_USE_SIGNALS      // 1056
-#define BB_FEATURE_VI_DOT_CMD  //  576
-#define BB_FEATURE_VI_READONLY //  128
-#define BB_FEATURE_VI_SETOPTS  //  576
-#define BB_FEATURE_VI_SET      //  224
-#define BB_FEATURE_VI_WIN_RESIZE       //  256  WIN_RESIZE
-// To test editor using CRASHME:
-//    vi -C filename
-// To stop testing, wait until all to text[] is deleted, or
-//    Ctrl-Z and kill -9 %1
-// while in the editor Ctrl-T will toggle the crashme function on and off.
-//#define BB_FEATURE_VI_CRASHME                // randomly pick commands to execute
-#endif                                                 /* STANDALONE */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <regex.h>
-#include <ctype.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#ifndef STANDALONE
-#include "busybox.h"
-#endif                                                 /* STANDALONE */
-
-#ifndef TRUE
-#define TRUE                   ((int)1)
-#define FALSE                  ((int)0)
-#endif                                                 /* TRUE */
-#define MAX_SCR_COLS           BUFSIZ
-
-// Misc. non-Ascii keys that report an escape sequence
-#define VI_K_UP                        128     // cursor key Up
-#define VI_K_DOWN              129     // cursor key Down
-#define VI_K_RIGHT             130     // Cursor Key Right
-#define VI_K_LEFT              131     // cursor key Left
-#define VI_K_HOME              132     // Cursor Key Home
-#define VI_K_END               133     // Cursor Key End
-#define VI_K_INSERT            134     // Cursor Key Insert
-#define VI_K_PAGEUP            135     // Cursor Key Page Up
-#define VI_K_PAGEDOWN          136     // Cursor Key Page Down
-#define VI_K_FUN1              137     // Function Key F1
-#define VI_K_FUN2              138     // Function Key F2
-#define VI_K_FUN3              139     // Function Key F3
-#define VI_K_FUN4              140     // Function Key F4
-#define VI_K_FUN5              141     // Function Key F5
-#define VI_K_FUN6              142     // Function Key F6
-#define VI_K_FUN7              143     // Function Key F7
-#define VI_K_FUN8              144     // Function Key F8
-#define VI_K_FUN9              145     // Function Key F9
-#define VI_K_FUN10             146     // Function Key F10
-#define VI_K_FUN11             147     // Function Key F11
-#define VI_K_FUN12             148     // Function Key F12
-
-static const int YANKONLY = FALSE;
-static const int YANKDEL = TRUE;
-static const int FORWARD = 1;  // code depends on "1"  for array index
-static const int BACK = -1;    // code depends on "-1" for array index
-static const int LIMITED = 0;  // how much of text[] in char_search
-static const int FULL = 1;     // how much of text[] in char_search
-
-static const int S_BEFORE_WS = 1;      // used in skip_thing() for moving "dot"
-static const int S_TO_WS = 2;          // used in skip_thing() for moving "dot"
-static const int S_OVER_WS = 3;                // used in skip_thing() for moving "dot"
-static const int S_END_PUNCT = 4;      // used in skip_thing() for moving "dot"
-static const int S_END_ALNUM = 5;      // used in skip_thing() for moving "dot"
-
-typedef unsigned char Byte;
-
-
-static int editing;            // >0 while we are editing a file
-static int cmd_mode;           // 0=command  1=insert
-static int file_modified;      // buffer contents changed
-static int err_method;         // indicate error with beep or flash
-static int fn_start;           // index of first cmd line file name
-static int save_argc;          // how many file names on cmd line
-static int cmdcnt;             // repetition count
-static fd_set rfds;            // use select() for small sleeps
-static struct timeval tv;      // use select() for small sleeps
-static char erase_char;                // the users erase character
-static int rows, columns;      // the terminal screen is this size
-static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
-static char *SOs, *SOn;                // terminal standout start/normal ESC sequence
-static char *bell;             // terminal bell sequence
-static char *Ceol, *Ceos;      // Clear-end-of-line and Clear-end-of-screen ESC sequence
-static char *CMrc;             // Cursor motion arbitrary destination ESC sequence
-static char *CMup, *CMdown;    // Cursor motion up and down ESC sequence
-static Byte *status_buffer;    // mesages to the user
-static Byte last_input_char;   // last char read from user
-static Byte last_forward_char; // last char searched for with 'f'
-static Byte *cfn;              // previous, current, and next file name
-static Byte *text, *end, *textend;     // pointers to the user data in memory
-static Byte *screen;           // pointer to the virtual screen buffer
-static int screensize;         //            and its size
-static Byte *screenbegin;      // index into text[], of top line on the screen
-static Byte *dot;              // where all the action takes place
-static int tabstop;
-static struct termios term_orig, term_vi;      // remember what the cooked mode was
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-static int last_row;           // where the cursor was last moved to
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static jmp_buf restart;                // catch_sig()
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-static struct winsize winsize; // remember the window size
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-#ifdef BB_FEATURE_VI_DOT_CMD
-static int adding2q;           // are we currently adding user input to q
-static Byte *last_modifying_cmd;       // last modifying cmd for "."
-static Byte *ioq, *ioq_start;  // pointer to string for get_one_char to "read"
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#if    defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)
-static Byte *modifying_cmds;   // cmds that modify text[]
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_READONLY
-static int vi_readonly, readonly;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SETOPTS
-static int autoindent;
-static int showmatch;
-static int ignorecase;
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
-static int YDreg, Ureg;                // default delete register and orig line for "U"
-static Byte *mark[28];         // user marks points somewhere in text[]-  a-z and previous context ''
-static Byte *context_start, *context_end;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-static Byte *last_search_pattern;      // last pattern from a '/' or '?' search
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-
-static void edit_file(Byte *); // edit one file
-static void do_cmd(Byte);      // execute a command
-static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot
-static Byte *begin_line(Byte *);       // return pointer to cur line B-o-l
-static Byte *end_line(Byte *); // return pointer to cur line E-o-l
-static Byte *dollar_line(Byte *);      // return pointer to just before NL
-static Byte *prev_line(Byte *);        // return pointer to prev line B-o-l
-static Byte *next_line(Byte *);        // return pointer to next line B-o-l
-static Byte *end_screen(void); // get pointer to last char on screen
-static int count_lines(Byte *, Byte *);        // count line from start to stop
-static Byte *find_line(int);   // find begining of line #li
-static Byte *move_to_col(Byte *, int); // move "p" to column l
-static int isblnk(Byte);       // is the char a blank or tab
-static void dot_left(void);    // move dot left- dont leave line
-static void dot_right(void);   // move dot right- dont leave line
-static void dot_begin(void);   // move dot to B-o-l
-static void dot_end(void);     // move dot to E-o-l
-static void dot_next(void);    // move dot to next line B-o-l
-static void dot_prev(void);    // move dot to prev line B-o-l
-static void dot_scroll(int, int);      // move the screen up or down
-static void dot_skip_over_ws(void);    // move dot pat WS
-static void dot_delete(void);  // delete the char at 'dot'
-static Byte *bound_dot(Byte *);        // make sure  text[0] <= P < "end"
-static Byte *new_screen(int, int);     // malloc virtual screen memory
-static Byte *new_text(int);    // malloc memory for text[] buffer
-static Byte *char_insert(Byte *, Byte);        // insert the char c at 'p'
-static Byte *stupid_insert(Byte *, Byte);      // stupidly insert the char c at 'p'
-static Byte find_range(Byte **, Byte **, Byte);        // return pointers for an object
-static int st_test(Byte *, int, int, Byte *);  // helper for skip_thing()
-static Byte *skip_thing(Byte *, int, int, int);        // skip some object
-static Byte *find_pair(Byte *, Byte);  // find matching pair ()  []  {}
-static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole
-static Byte *text_hole_make(Byte *, int);      // at "p", make a 'size' byte hole
-static Byte *yank_delete(Byte *, Byte *, int, int);    // yank text[] into register then delete
-static void show_help(void);   // display some help info
-static void print_literal(Byte *, Byte *);     // copy s to buf, convert unprintable
-static void rawmode(void);     // set "raw" mode on tty
-static void cookmode(void);    // return to "cooked" mode on tty
-static int mysleep(int);       // sleep for 'h' 1/100 seconds
-static Byte readit(void);      // read (maybe cursor) key from stdin
-static Byte get_one_char(void);        // read 1 char from stdin
-static int file_size(Byte *);  // what is the byte size of "fn"
-static int file_insert(Byte *, Byte *, int);
-static int file_write(Byte *, Byte *, Byte *);
-static void place_cursor(int, int, int);
-static void screen_erase();
-static void clear_to_eol(void);
-static void clear_to_eos(void);
-static void standout_start(void);      // send "start reverse video" sequence
-static void standout_end(void);        // send "end reverse video" sequence
-static void flash(int);                // flash the terminal screen
-static void beep(void);                // beep the terminal
-static void indicate_error(char);      // use flash or beep to indicate error
-static void show_status_line(void);    // put a message on the bottom line
-static void psb(char *, ...);  // Print Status Buf
-static void psbs(char *, ...); // Print Status Buf in standout mode
-static void ni(Byte *);                // display messages
-static void edit_status(void); // show file status on status line
-static void redraw(int);       // force a full screen refresh
-static void format_line(Byte*, Byte*, int);
-static void refresh(int);      // update the terminal from screen[]
-
-#ifdef BB_FEATURE_VI_SEARCH
-static Byte *char_search(Byte *, Byte *, int, int);    // search for pattern starting at p
-static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-#ifdef BB_FEATURE_VI_COLON
-static void Hit_Return(void);
-static Byte *get_one_address(Byte *, int *);   // get colon addr, if present
-static Byte *get_address(Byte *, int *, int *);        // get two colon addrs, if present
-static void colon(Byte *);     // execute the "colon" mode cmds
-#endif                                                 /* BB_FEATURE_VI_COLON */
-static Byte *get_input_line(Byte *);   // get input line- use "status line"
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static void winch_sig(int);    // catch window size changes
-static void suspend_sig(int);  // catch ctrl-Z
-static void alarm_sig(int);    // catch alarm time-outs
-static void catch_sig(int);    // catch ctrl-C
-static void core_sig(int);     // catch a core dump signal
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_DOT_CMD
-static void start_new_cmd_q(Byte);     // new queue for command
-static void end_cmd_q();       // stop saving input chars
-#else                                                  /* BB_FEATURE_VI_DOT_CMD */
-#define end_cmd_q()
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-static void window_size_get(int);      // find out what size the window is
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-#ifdef BB_FEATURE_VI_SETOPTS
-static void showmatching(Byte *);      // show the matching pair ()  []  {}
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
-static Byte *string_insert(Byte *, Byte *);    // insert the string at 'p'
-#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *text_yank(Byte *, Byte *, int);   // save copy of "p" into a register
-static Byte what_reg(void);            // what is letter of current YDreg
-static void check_context(Byte);       // remember context for '' command
-static Byte *swap_context(Byte *);     // goto new context for '' command
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_CRASHME
-static void crash_dummy();
-static void crash_test();
-static int crashme = 0;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-
-
-extern int vi_main(int argc, char **argv)
-{
-       int c;
-
-#ifdef BB_FEATURE_VI_YANKMARK
-       int i;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       CMrc= "\033[%d;%dH";    // Terminal Crusor motion ESC sequence
-       CMup= "\033[A";         // move cursor up one line, same col
-       CMdown="\n";            // move cursor down one line, same col
-       Ceol= "\033[0K";        // Clear from cursor to end of line
-       Ceos= "\033[0J";        // Clear from cursor to end of screen
-       SOs = "\033[7m";        // Terminal standout mode on
-       SOn = "\033[0m";        // Terminal standout mode off
-       bell= "\007";           // Terminal bell sequence
-#ifdef BB_FEATURE_VI_CRASHME
-       (void) srand((long) getpid());
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       status_buffer = (Byte *) malloc(200);   // hold messages to user
-#ifdef BB_FEATURE_VI_READONLY
-       vi_readonly = readonly = FALSE;
-       if (strncmp(argv[0], "view", 4) == 0) {
-               readonly = TRUE;
-               vi_readonly = TRUE;
-       }
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SETOPTS
-       autoindent = 1;
-       ignorecase = 1;
-       showmatch = 1;
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_YANKMARK
-       for (i = 0; i < 28; i++) {
-               reg[i] = 0;
-       }                                       // init the yank regs
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_DOT_CMD
-       modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~";      // cmds modifying text[]
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-
-       //  1-  process $HOME/.exrc file
-       //  2-  process EXINIT variable from environment
-       //  3-  process command line args
-       while ((c = getopt(argc, argv, "hCR")) != -1) {
-               switch (c) {
-#ifdef BB_FEATURE_VI_CRASHME
-               case 'C':
-                       crashme = 1;
-                       break;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-#ifdef BB_FEATURE_VI_READONLY
-               case 'R':               // Read-only flag
-                       readonly = TRUE;
-                       break;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       //case 'r':     // recover flag-  ignore- we don't use tmp file
-                       //case 'x':     // encryption flag- ignore
-                       //case 'c':     // execute command first
-                       //case 'h':     // help -- just use default
-               default:
-                       show_help();
-                       return 1;
-               }
-       }
-
-       // The argv array can be used by the ":next"  and ":rewind" commands
-       // save optind.
-       fn_start = optind;      // remember first file name for :next and :rew
-       save_argc = argc;
-
-       //----- This is the main file handling loop --------------
-       if (optind >= argc) {
-               editing = 1;    // 0= exit,  1= one file,  2= multiple files
-               edit_file(0);
-       } else {
-               for (; optind < argc; optind++) {
-                       editing = 1;    // 0=exit, 1=one file, 2+ =many files
-                       if (cfn != 0)
-                               free(cfn);
-                       cfn = (Byte *) strdup(argv[optind]);
-                       edit_file(cfn);
-               }
-       }
-       //-----------------------------------------------------------
-
-       return (0);
-}
-
-static void edit_file(Byte * fn)
-{
-       char c;
-       int cnt, size, ch;
-
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       char *msg;
-       int sig;
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_YANKMARK
-       static Byte *cur_line;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       rawmode();
-       rows = 24;
-       columns = 80;
-       ch= -1;
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       new_screen(rows, columns);      // get memory for virtual screen
-
-       cnt = file_size(fn);    // file size
-       size = 2 * cnt;         // 200% of file size
-       new_text(size);         // get a text[] buffer
-       screenbegin = dot = end = text;
-       if (fn != 0) {
-               ch= file_insert(fn, text, cnt);
-       }
-       if (ch < 1) {
-               (void) char_insert(text, '\n'); // start empty buf with dummy line
-       }
-       file_modified = FALSE;
-#ifdef BB_FEATURE_VI_YANKMARK
-       YDreg = 26;                     // default Yank/Delete reg
-       Ureg = 27;                      // hold orig line for "U" cmd
-       for (cnt = 0; cnt < 28; cnt++) {
-               mark[cnt] = 0;
-       }                                       // init the marks
-       mark[26] = mark[27] = text;     // init "previous context"
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       err_method = 1;         // flash
-       last_forward_char = last_input_char = '\0';
-       crow = 0;
-       ccol = 0;
-       edit_status();
-
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       signal(SIGHUP, catch_sig);
-       signal(SIGINT, catch_sig);
-       signal(SIGALRM, alarm_sig);
-       signal(SIGTERM, catch_sig);
-       signal(SIGQUIT, core_sig);
-       signal(SIGILL, core_sig);
-       signal(SIGTRAP, core_sig);
-       signal(SIGIOT, core_sig);
-       signal(SIGABRT, core_sig);
-       signal(SIGFPE, core_sig);
-       signal(SIGBUS, core_sig);
-       signal(SIGSEGV, core_sig);
-#ifdef SIGSYS
-       signal(SIGSYS, core_sig);
-#endif 
-       signal(SIGWINCH, winch_sig);
-       signal(SIGTSTP, suspend_sig);
-       sig = setjmp(restart);
-       if (sig != 0) {
-               msg = "";
-               if (sig == SIGWINCH)
-                       msg = "(window resize)";
-               if (sig == SIGHUP)
-                       msg = "(hangup)";
-               if (sig == SIGINT)
-                       msg = "(interrupt)";
-               if (sig == SIGTERM)
-                       msg = "(terminate)";
-               if (sig == SIGBUS)
-                       msg = "(bus error)";
-               if (sig == SIGSEGV)
-                       msg = "(I tried to touch invalid memory)";
-               if (sig == SIGALRM)
-                       msg = "(alarm)";
-
-               psbs("-- caught signal %d %s--", sig, msg);
-               screenbegin = dot = text;
-       }
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-
-       editing = 1;
-       cmd_mode = 0;           // 0=command  1=insert  2='R'eplace
-       cmdcnt = 0;
-       tabstop = 8;
-       offset = 0;                     // no horizontal offset
-       c = '\0';
-#ifdef BB_FEATURE_VI_DOT_CMD
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
-       if (ioq_start != NULL)
-               free(ioq_start);
-       ioq = ioq_start = last_modifying_cmd = 0;
-       adding2q = 0;
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-       redraw(FALSE);                  // dont force every col re-draw
-       show_status_line();
-
-       //------This is the main Vi cmd handling loop -----------------------
-       while (editing > 0) {
-#ifdef BB_FEATURE_VI_CRASHME
-               if (crashme > 0) {
-                       if ((end - text) > 1) {
-                               crash_dummy();  // generate a random command
-                       } else {
-                               crashme = 0;
-                               dot =
-                                       string_insert(text, (Byte *) "\n\n#####  Ran out of text to work on.  #####\n\n");      // insert the string
-                               refresh(FALSE);
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-               last_input_char = c = get_one_char();   // get a cmd from user
-#ifdef BB_FEATURE_VI_YANKMARK
-               // save a copy of the current line- for the 'U" command
-               if (begin_line(dot) != cur_line) {
-                       cur_line = begin_line(dot);
-                       text_yank(begin_line(dot), end_line(dot), Ureg);
-               }
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_DOT_CMD
-               // These are commands that change text[].
-               // Remember the input for the "." command
-               if (!adding2q && ioq_start == 0
-                       && strchr((char *) modifying_cmds, c) != NULL) {
-                       start_new_cmd_q(c);
-               }
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               do_cmd(c);              // execute the user command
-               //
-               // poll to see if there is input already waiting. if we are
-               // not able to display output fast enough to keep up, skip
-               // the display update until we catch up with input.
-               if (mysleep(0) == 0) {
-                       // no input pending- so update output
-                       refresh(FALSE);
-                       show_status_line();
-               }
-#ifdef BB_FEATURE_VI_CRASHME
-               if (crashme > 0)
-                       crash_test();   // test editor variables
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       }
-       //-------------------------------------------------------------------
-
-       place_cursor(rows, 0, FALSE);   // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
-       cookmode();
-}
-
-static Byte readbuffer[BUFSIZ];
-
-#ifdef BB_FEATURE_VI_CRASHME
-static int totalcmds = 0;
-static int Mp = 85;            // Movement command Probability
-static int Np = 90;            // Non-movement command Probability
-static int Dp = 96;            // Delete command Probability
-static int Ip = 97;            // Insert command Probability
-static int Yp = 98;            // Yank command Probability
-static int Pp = 99;            // Put command Probability
-static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
-char chars[20] = "\t012345 abcdABCD-=.$";
-char *words[20] = { "this", "is", "a", "test",
-       "broadcast", "the", "emergency", "of",
-       "system", "quick", "brown", "fox",
-       "jumped", "over", "lazy", "dogs",
-       "back", "January", "Febuary", "March"
-};
-char *lines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-char *multilines[20] = {
-       "You should have received a copy of the GNU General Public License\n",
-       "char c, cm, *cmd, *cmd1;\n",
-       "generate a command by percentages\n",
-       "Numbers may be typed as a prefix to some commands.\n",
-       "Quit, discarding changes!\n",
-       "Forced write, if permission originally not valid.\n",
-       "In general, any ex or ed command (such as substitute or delete).\n",
-       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
-       "Please get w/ me and I will go over it with you.\n",
-       "The following is a list of scheduled, committed changes.\n",
-       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
-       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
-       "Any question about transactions please contact Sterling Huxley.\n",
-       "I will try to get back to you by Friday, December 31.\n",
-       "This Change will be implemented on Friday.\n",
-       "Let me know if you have problems accessing this;\n",
-       "Sterling Huxley recently added you to the access list.\n",
-       "Would you like to go to lunch?\n",
-       "The last command will be automatically run.\n",
-       "This is too much english for a computer geek.\n",
-};
-
-// create a random command to execute
-static void crash_dummy()
-{
-       static int sleeptime;   // how long to pause between commands
-       char c, cm, *cmd, *cmd1;
-       int i, cnt, thing, rbi, startrbi, percent;
-
-       // "dot" movement commands
-       cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
-
-       // is there already a command running?
-       if (strlen((char *) readbuffer) > 0)
-               goto cd1;
-  cd0:
-       startrbi = rbi = 0;
-       sleeptime = 0;          // how long to pause between commands
-       memset(readbuffer, '\0', BUFSIZ - 1);   // clear the read buffer
-       // generate a command by percentages
-       percent = (int) lrand48() % 100;        // get a number from 0-99
-       if (percent < Mp) {     //  Movement commands
-               // available commands
-               cmd = cmd1;
-               M++;
-       } else if (percent < Np) {      //  non-movement commands
-               cmd = "mz<>\'\"";       // available commands
-               N++;
-       } else if (percent < Dp) {      //  Delete commands
-               cmd = "dx";             // available commands
-               D++;
-       } else if (percent < Ip) {      //  Inset commands
-               cmd = "iIaAsrJ";        // available commands
-               I++;
-       } else if (percent < Yp) {      //  Yank commands
-               cmd = "yY";             // available commands
-               Y++;
-       } else if (percent < Pp) {      //  Put commands
-               cmd = "pP";             // available commands
-               P++;
-       } else {
-               // We do not know how to handle this command, try again
-               U++;
-               goto cd0;
-       }
-       // randomly pick one of the available cmds from "cmd[]"
-       i = (int) lrand48() % strlen(cmd);
-       cm = cmd[i];
-       if (strchr(":\024", cm))
-               goto cd0;               // dont allow colon or ctrl-T commands
-       readbuffer[rbi++] = cm; // put cmd into input buffer
-
-       // now we have the command-
-       // there are 1, 2, and multi char commands
-       // find out which and generate the rest of command as necessary
-       if (strchr("dmryz<>\'\"", cm)) {        // 2-char commands
-               cmd1 = " \n\r0$^-+wWeEbBhjklHL";
-               if (cm == 'm' || cm == '\'' || cm == '\"') {    // pick a reg[]
-                       cmd1 = "abcdefghijklmnopqrstuvwxyz";
-               }
-               thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-               c = cmd1[thing];
-               readbuffer[rbi++] = c;  // add movement to input buffer
-       }
-       if (strchr("iIaAsc", cm)) {     // multi-char commands
-               if (cm == 'c') {
-                       // change some thing
-                       thing = (int) lrand48() % strlen(cmd1); // pick a movement command
-                       c = cmd1[thing];
-                       readbuffer[rbi++] = c;  // add movement to input buffer
-               }
-               thing = (int) lrand48() % 4;    // what thing to insert
-               cnt = (int) lrand48() % 10;     // how many to insert
-               for (i = 0; i < cnt; i++) {
-                       if (thing == 0) {       // insert chars
-                               readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
-                       } else if (thing == 1) {        // insert words
-                               strcat((char *) readbuffer, words[(int) lrand48() % 20]);
-                               strcat((char *) readbuffer, " ");
-                               sleeptime = 0;  // how fast to type
-                       } else if (thing == 2) {        // insert lines
-                               strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       } else {        // insert multi-lines
-                               strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
-                               sleeptime = 0;  // how fast to type
-                       }
-               }
-               strcat((char *) readbuffer, "\033");
-       }
-  cd1:
-       totalcmds++;
-       if (sleeptime > 0)
-               (void) mysleep(sleeptime);      // sleep 1/100 sec
-}
-
-// test to see if there are any errors
-static void crash_test()
-{
-       static time_t oldtim;
-       time_t tim;
-       char d[2], buf[BUFSIZ], msg[BUFSIZ];
-
-       msg[0] = '\0';
-       if (end < text) {
-               strcat((char *) msg, "end<text ");
-       }
-       if (end > textend) {
-               strcat((char *) msg, "end>textend ");
-       }
-       if (dot < text) {
-               strcat((char *) msg, "dot<text ");
-       }
-       if (dot > end) {
-               strcat((char *) msg, "dot>end ");
-       }
-       if (screenbegin < text) {
-               strcat((char *) msg, "screenbegin<text ");
-       }
-       if (screenbegin > end - 1) {
-               strcat((char *) msg, "screenbegin>end-1 ");
-       }
-
-       if (strlen(msg) > 0) {
-               alarm(0);
-               sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
-                       totalcmds, last_input_char, msg, SOs, SOn);
-               write(1, buf, strlen(buf));
-               while (read(0, d, 1) > 0) {
-                       if (d[0] == '\n' || d[0] == '\r')
-                               break;
-               }
-               alarm(3);
-       }
-       tim = (time_t) time((time_t *) 0);
-       if (tim >= (oldtim + 3)) {
-               sprintf((char *) status_buffer,
-                               "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
-                               totalcmds, M, N, I, D, Y, P, U, end - text + 1);
-               oldtim = tim;
-       }
-       return;
-}
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-
-//---------------------------------------------------------------------
-//----- the Ascii Chart -----------------------------------------------
-//
-//  00 nul   01 soh   02 stx   03 etx   04 eot   05 enq   06 ack   07 bel
-//  08 bs    09 ht    0a nl    0b vt    0c np    0d cr    0e so    0f si
-//  10 dle   11 dc1   12 dc2   13 dc3   14 dc4   15 nak   16 syn   17 etb
-//  18 can   19 em    1a sub   1b esc   1c fs    1d gs    1e rs    1f us
-//  20 sp    21 !     22 "     23 #     24 $     25 %     26 &     27 '
-//  28 (     29 )     2a *     2b +     2c ,     2d -     2e .     2f /
-//  30 0     31 1     32 2     33 3     34 4     35 5     36 6     37 7
-//  38 8     39 9     3a :     3b ;     3c <     3d =     3e >     3f ?
-//  40 @     41 A     42 B     43 C     44 D     45 E     46 F     47 G
-//  48 H     49 I     4a J     4b K     4c L     4d M     4e N     4f O
-//  50 P     51 Q     52 R     53 S     54 T     55 U     56 V     57 W
-//  58 X     59 Y     5a Z     5b [     5c \     5d ]     5e ^     5f _
-//  60 `     61 a     62 b     63 c     64 d     65 e     66 f     67 g
-//  68 h     69 i     6a j     6b k     6c l     6d m     6e n     6f o
-//  70 p     71 q     72 r     73 s     74 t     75 u     76 v     77 w
-//  78 x     79 y     7a z     7b {     7c |     7d }     7e ~     7f del
-//---------------------------------------------------------------------
-
-//----- Execute a Vi Command -----------------------------------
-static void do_cmd(Byte c)
-{
-       Byte c1, *p, *q, *msg, buf[9], *save_dot;
-       int cnt, i, j, dir, yf;
-
-       c1 = c;                         // quiet the compiler
-       cnt = yf = dir = 0;     // quiet the compiler
-       p = q = save_dot = msg = buf;   // quiet the compiler
-       memset(buf, '\0', 9);   // clear buf
-       if (cmd_mode == 2) {
-               // we are 'R'eplacing the current *dot with new char
-               if (*dot == '\n') {
-                       // don't Replace past E-o-l
-                       cmd_mode = 1;   // convert to insert
-               } else {
-                       if (1 <= c && c <= 127) {       // only ASCII chars
-                               if (c != 27)
-                                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
-                               dot = char_insert(dot, c);      // insert new char
-                       }
-                       goto dc1;
-               }
-       }
-       if (cmd_mode == 1) {
-               //  hitting "Insert" twice means "R" replace mode
-               if (c == VI_K_INSERT) goto dc5;
-               // insert the char c at "dot"
-               if (1 <= c && c <= 127) {
-                       dot = char_insert(dot, c);      // only ASCII chars
-               }
-               goto dc1;
-       }
-
-       switch (c) {
-               //case 0x01:    // soh
-               //case 0x09:    // ht
-               //case 0x0b:    // vt
-               //case 0x0e:    // so
-               //case 0x0f:    // si
-               //case 0x10:    // dle
-               //case 0x11:    // dc1
-               //case 0x13:    // dc3
-#ifdef BB_FEATURE_VI_CRASHME
-       case 0x14:                      // dc4  ctrl-T
-               crashme = (crashme == 0) ? 1 : 0;
-               break;
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-               //case 0x16:    // syn
-               //case 0x17:    // etb
-               //case 0x18:    // can
-               //case 0x1c:    // fs
-               //case 0x1d:    // gs
-               //case 0x1e:    // rs
-               //case 0x1f:    // us
-               //case '!':     // !- 
-               //case '#':     // #- 
-               //case '&':     // &- 
-               //case '(':     // (- 
-               //case ')':     // )- 
-               //case '*':     // *- 
-               //case ',':     // ,- 
-               //case '=':     // =- 
-               //case '@':     // @- 
-               //case 'F':     // F- 
-               //case 'K':     // K- 
-               //case 'Q':     // Q- 
-               //case 'S':     // S- 
-               //case 'T':     // T- 
-               //case 'V':     // V- 
-               //case '[':     // [- 
-               //case '\\':    // \- 
-               //case ']':     // ]- 
-               //case '_':     // _- 
-               //case '`':     // `- 
-               //case 'g':     // g- 
-               //case 'u':     // u- FIXME- there is no undo
-               //case 'v':     // v- 
-       default:                        // unrecognised command
-               buf[0] = c;
-               buf[1] = '\0';
-               if (c <= ' ') {
-                       buf[0] = '^';
-                       buf[1] = c + '@';
-                       buf[2] = '\0';
-               }
-               ni((Byte *) buf);
-               end_cmd_q();    // stop adding to q
-       case 0x00:                      // nul- ignore
-               break;
-       case 2:                 // ctrl-B  scroll up   full screen
-       case VI_K_PAGEUP:       // Cursor Key Page Up
-               dot_scroll(rows - 2, -1);
-               break;
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       case 0x03:                      // ctrl-C   interrupt
-               longjmp(restart, 1);
-               break;
-       case 26:                        // ctrl-Z suspend
-               suspend_sig(SIGTSTP);
-               break;
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-       case 4:                 // ctrl-D  scroll down half screen
-               dot_scroll((rows - 2) / 2, 1);
-               break;
-       case 5:                 // ctrl-E  scroll down one line
-               dot_scroll(1, 1);
-               break;
-       case 6:                 // ctrl-F  scroll down full screen
-       case VI_K_PAGEDOWN:     // Cursor Key Page Down
-               dot_scroll(rows - 2, 1);
-               break;
-       case 7:                 // ctrl-G  show current status
-               edit_status();
-               break;
-       case 'h':                       // h- move left
-       case VI_K_LEFT: // cursor key Left
-       case 8:                 // ctrl-H- move left    (This may be ERASE char)
-       case 127:                       // DEL- move left   (This may be ERASE char)
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_left();
-               break;
-       case 10:                        // Newline ^J
-       case 'j':                       // j- goto next line, same col
-       case VI_K_DOWN: // cursor key Down
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_next();             // go to next B-o-l
-               dot = move_to_col(dot, ccol + offset);  // try stay in same col
-               break;
-       case 12:                        // ctrl-L  force redraw whole screen
-       case 18:                        // ctrl-R  force redraw
-               place_cursor(0, 0, FALSE);      // put cursor in correct place
-               clear_to_eos(); // tel terminal to erase display
-               (void) mysleep(10);
-               screen_erase(); // erase the internal screen buffer
-               refresh(TRUE);  // this will redraw the entire display
-               break;
-       case 13:                        // Carriage Return ^M
-       case '+':                       // +- goto next line
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_next();
-               dot_skip_over_ws();
-               break;
-       case 21:                        // ctrl-U  scroll up   half screen
-               dot_scroll((rows - 2) / 2, -1);
-               break;
-       case 25:                        // ctrl-Y  scroll up one line
-               dot_scroll(1, -1);
-               break;
-       case 27:                        // esc
-               if (cmd_mode == 0)
-                       indicate_error(c);
-               cmd_mode = 0;   // stop insrting
-               end_cmd_q();
-               *status_buffer = '\0';  // clear status buffer
-               break;
-       case ' ':                       // move right
-       case 'l':                       // move right
-       case VI_K_RIGHT:        // Cursor Key Right
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_right();
-               break;
-#ifdef BB_FEATURE_VI_YANKMARK
-       case '"':                       // "- name a register to use for Delete/Yank
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       YDreg = c1 - 'a';
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case '\'':                      // '- goto a specific mark
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
-                       // get the b-o-l
-                       q = mark[(int) c1];
-                       if (text <= q && q < end) {
-                               dot = q;
-                               dot_begin();    // go to B-o-l
-                               dot_skip_over_ws();
-                       }
-               } else if (c1 == '\'') {        // goto previous context
-                       dot = swap_context(dot);        // swap current and previous context
-                       dot_begin();    // go to B-o-l
-                       dot_skip_over_ws();
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case 'm':                       // m- Mark a line
-               // this is really stupid.  If there are any inserts or deletes
-               // between text[0] and dot then this mark will not point to the
-               // correct location! It could be off by many lines!
-               // Well..., at least its quick and dirty.
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
-                       // remember the line
-                       mark[(int) c1] = dot;
-               } else {
-                       indicate_error(c);
-               }
-               break;
-       case 'P':                       // P- Put register before
-       case 'p':                       // p- put register after
-               p = reg[YDreg];
-               if (p == 0) {
-                       psbs("Nothing in register %c", what_reg());
-                       break;
-               }
-               // are we putting whole lines or strings
-               if (strchr((char *) p, '\n') != NULL) {
-                       if (c == 'P') {
-                               dot_begin();    // putting lines- Put above
-                       }
-                       if (c == 'p') {
-                               // are we putting after very last line?
-                               if (end_line(dot) == (end - 1)) {
-                                       dot = end;      // force dot to end of text[]
-                               } else {
-                                       dot_next();     // next line, then put before
-                               }
-                       }
-               } else {
-                       if (c == 'p')
-                               dot_right();    // move to right, can move to NL
-               }
-               dot = string_insert(dot, p);    // insert the string
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'U':                       // U- Undo; replace current line with original version
-               if (reg[Ureg] != 0) {
-                       p = begin_line(dot);
-                       q = end_line(dot);
-                       p = text_hole_delete(p, q);     // delete cur line
-                       p = string_insert(p, reg[Ureg]);        // insert orig line
-                       dot = p;
-                       dot_skip_over_ws();
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       case '$':                       // $- goto end of line
-       case VI_K_END:          // Cursor Key End
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot = end_line(dot + 1);
-               break;
-       case '%':                       // %- find matching char of pair () [] {}
-               for (q = dot; q < end && *q != '\n'; q++) {
-                       if (strchr("()[]{}", *q) != NULL) {
-                               // we found half of a pair
-                               p = find_pair(q, *q);
-                               if (p == NULL) {
-                                       indicate_error(c);
-                               } else {
-                                       dot = p;
-                               }
-                               break;
-                       }
-               }
-               if (*q == '\n')
-                       indicate_error(c);
-               break;
-       case 'f':                       // f- forward to a user specified char
-               last_forward_char = get_one_char();     // get the search char
-               //
-               // dont seperate these two commands. 'f' depends on ';'
-               //
-               //**** fall thru to ... 'i'
-       case ';':                       // ;- look at rest of line for last forward char
-               if (cmdcnt-- > 1) {
-                       do_cmd(';');
-               }                               // repeat cnt
-               if (last_forward_char == 0) break;
-               q = dot + 1;
-               while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
-                       q++;
-               }
-               if (*q == last_forward_char)
-                       dot = q;
-               break;
-       case '-':                       // -- goto prev line
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_prev();
-               dot_skip_over_ws();
-               break;
-#ifdef BB_FEATURE_VI_DOT_CMD
-       case '.':                       // .- repeat the last modifying command
-               // Stuff the last_modifying_cmd back into stdin
-               // and let it be re-executed.
-               if (last_modifying_cmd != 0) {
-                       ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd);
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_SEARCH
-       case '?':                       // /- search for a pattern
-       case '/':                       // /- search for a pattern
-               buf[0] = c;
-               buf[1] = '\0';
-               q = get_input_line(buf);        // get input line- use "status line"
-               if (strlen((char *) q) == 1)
-                       goto dc3;       // if no pat re-use old pat
-               if (strlen((char *) q) > 1) {   // new pat- save it and find
-                       // there is a new pat
-                       if (last_search_pattern != 0) {
-                               free(last_search_pattern);
-                       }
-                       last_search_pattern = (Byte *) strdup((char *) q);
-                       goto dc3;       // now find the pattern
-               }
-               // user changed mind and erased the "/"-  do nothing
-               break;
-       case 'N':                       // N- backward search for last pattern
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = BACK;             // assume BACKWARD search
-               p = dot - 1;
-               if (last_search_pattern[0] == '?') {
-                       dir = FORWARD;
-                       p = dot + 1;
-               }
-               goto dc4;               // now search for pattern
-               break;
-       case 'n':                       // n- repeat search for last pattern
-               // search rest of text[] starting at next char
-               // if search fails return orignal "p" not the "p+1" address
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-         dc3:
-               if (last_search_pattern == 0) {
-                       msg = (Byte *) "No previous regular expression";
-                       goto dc2;
-               }
-               if (last_search_pattern[0] == '/') {
-                       dir = FORWARD;  // assume FORWARD search
-                       p = dot + 1;
-               }
-               if (last_search_pattern[0] == '?') {
-                       dir = BACK;
-                       p = dot - 1;
-               }
-         dc4:
-               q = char_search(p, last_search_pattern + 1, dir, FULL);
-               if (q != NULL) {
-                       dot = q;        // good search, update "dot"
-                       msg = (Byte *) "";
-                       goto dc2;
-               }
-               // no pattern found between "dot" and "end"- continue at top
-               p = text;
-               if (dir == BACK) {
-                       p = end - 1;
-               }
-               q = char_search(p, last_search_pattern + 1, dir, FULL);
-               if (q != NULL) {        // found something
-                       dot = q;        // found new pattern- goto it
-                       msg = (Byte *) "search hit BOTTOM, continuing at TOP";
-                       if (dir == BACK) {
-                               msg = (Byte *) "search hit TOP, continuing at BOTTOM";
-                       }
-               } else {
-                       msg = (Byte *) "Pattern not found";
-               }
-         dc2:
-               psbs("%s", msg);
-               break;
-       case '{':                       // {- move backward paragraph
-               q = char_search(dot, (Byte *) "\n\n", BACK, FULL);
-               if (q != NULL) {        // found blank line
-                       dot = next_line(q);     // move to next blank line
-               }
-               break;
-       case '}':                       // }- move forward paragraph
-               q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL);
-               if (q != NULL) {        // found blank line
-                       dot = next_line(q);     // move to next blank line
-               }
-               break;
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       case '0':                       // 0- goto begining of line
-       case '1':                       // 1- 
-       case '2':                       // 2- 
-       case '3':                       // 3- 
-       case '4':                       // 4- 
-       case '5':                       // 5- 
-       case '6':                       // 6- 
-       case '7':                       // 7- 
-       case '8':                       // 8- 
-       case '9':                       // 9- 
-               if (c == '0' && cmdcnt < 1) {
-                       dot_begin();    // this was a standalone zero
-               } else {
-                       cmdcnt = cmdcnt * 10 + (c - '0');       // this 0 is part of a number
-               }
-               break;
-       case ':':                       // :- the colon mode commands
-               p = get_input_line((Byte *) ":");       // get input line- use "status line"
-#ifdef BB_FEATURE_VI_COLON
-               colon(p);               // execute the command
-#else                                                  /* BB_FEATURE_VI_COLON */
-               if (*p == ':')
-                       p++;                            // move past the ':'
-               cnt = strlen((char *) p);
-               if (cnt <= 0)
-                       break;
-               if (strncasecmp((char *) p, "quit", cnt) == 0 ||
-                       strncasecmp((char *) p, "q!", cnt) == 0) {      // delete lines
-                       if (file_modified == TRUE && p[1] != '!') {
-                               psbs("No write since last change (:quit! overrides)");
-                       } else {
-                               editing = 0;
-                       }
-               } else if (strncasecmp((char *) p, "write", cnt) == 0 ||
-                                  strncasecmp((char *) p, "wq", cnt) == 0) {
-                       cnt = file_write(cfn, text, end - 1);
-                       file_modified = FALSE;
-                       psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
-                       if (p[1] == 'q') {
-                               editing = 0;
-                       }
-               } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
-                       edit_status();                  // show current file status
-               } else if (sscanf((char *) p, "%d", &j) > 0) {
-                       dot = find_line(j);             // go to line # j
-                       dot_skip_over_ws();
-               } else {                // unrecognised cmd
-                       ni((Byte *) p);
-               }
-#endif                                                 /* BB_FEATURE_VI_COLON */
-               break;
-       case '<':                       // <- Left  shift something
-       case '>':                       // >- Right shift something
-               cnt = count_lines(text, dot);   // remember what line we are on
-               c1 = get_one_char();    // get the type of thing to delete
-               find_range(&p, &q, c1);
-               (void) yank_delete(p, q, 1, YANKONLY);  // save copy before change
-               p = begin_line(p);
-               q = end_line(q);
-               i = count_lines(p, q);  // # of lines we are shifting
-               for ( ; i > 0; i--, p = next_line(p)) {
-                       if (c == '<') {
-                               // shift left- remove tab or 8 spaces
-                               if (*p == '\t') {
-                                       // shrink buffer 1 char
-                                       (void) text_hole_delete(p, p);
-                               } else if (*p == ' ') {
-                                       // we should be calculating columns, not just SPACE
-                                       for (j = 0; *p == ' ' && j < tabstop; j++) {
-                                               (void) text_hole_delete(p, p);
-                                       }
-                               }
-                       } else if (c == '>') {
-                               // shift right -- add tab or 8 spaces
-                               (void) char_insert(p, '\t');
-                       }
-               }
-               dot = find_line(cnt);   // what line were we on
-               dot_skip_over_ws();
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'A':                       // A- append at e-o-l
-               dot_end();              // go to e-o-l
-               //**** fall thru to ... 'a'
-       case 'a':                       // a- append after current char
-               if (*dot != '\n')
-                       dot++;
-               goto dc_i;
-               break;
-       case 'B':                       // B- back a blank-delimited Word
-       case 'E':                       // E- end of a blank-delimited word
-       case 'W':                       // W- forward a blank-delimited word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = FORWARD;
-               if (c == 'B')
-                       dir = BACK;
-               if (c == 'W' || isspace(dot[dir])) {
-                       dot = skip_thing(dot, 1, dir, S_TO_WS);
-                       dot = skip_thing(dot, 2, dir, S_OVER_WS);
-               }
-               if (c != 'W')
-                       dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
-               break;
-       case 'C':                       // C- Change to e-o-l
-       case 'D':                       // D- delete to e-o-l
-               save_dot = dot;
-               dot = dollar_line(dot); // move to before NL
-               // copy text into a register and delete
-               dot = yank_delete(save_dot, dot, 0, YANKDEL);   // delete to e-o-l
-               if (c == 'C')
-                       goto dc_i;      // start inserting
-#ifdef BB_FEATURE_VI_DOT_CMD
-               if (c == 'D')
-                       end_cmd_q();    // stop adding to q
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               break;
-       case 'G':               // G- goto to a line number (default= E-O-F)
-               dot = end - 1;                          // assume E-O-F
-               if (cmdcnt > 0) {
-                       dot = find_line(cmdcnt);        // what line is #cmdcnt
-               }
-               dot_skip_over_ws();
-               break;
-       case 'H':                       // H- goto top line on screen
-               dot = screenbegin;
-               if (cmdcnt > (rows - 1)) {
-                       cmdcnt = (rows - 1);
-               }
-               if (cmdcnt-- > 1) {
-                       do_cmd('+');
-               }                               // repeat cnt
-               dot_skip_over_ws();
-               break;
-       case 'I':                       // I- insert before first non-blank
-               dot_begin();    // 0
-               dot_skip_over_ws();
-               //**** fall thru to ... 'i'
-       case 'i':                       // i- insert before current char
-       case VI_K_INSERT:       // Cursor Key Insert
-         dc_i:
-               cmd_mode = 1;   // start insrting
-               psb("-- Insert --");
-               break;
-       case 'J':                       // J- join current and next lines together
-               if (cmdcnt-- > 2) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_end();              // move to NL
-               if (dot < end - 1) {    // make sure not last char in text[]
-                       *dot++ = ' ';   // replace NL with space
-                       while (isblnk(*dot)) {  // delete leading WS
-                               dot_delete();
-                       }
-               }
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'L':                       // L- goto bottom line on screen
-               dot = end_screen();
-               if (cmdcnt > (rows - 1)) {
-                       cmdcnt = (rows - 1);
-               }
-               if (cmdcnt-- > 1) {
-                       do_cmd('-');
-               }                               // repeat cnt
-               dot_begin();
-               dot_skip_over_ws();
-               break;
-       case 'M':                       // M- goto middle line on screen
-               dot = screenbegin;
-               for (cnt = 0; cnt < (rows-1) / 2; cnt++)
-                       dot = next_line(dot);
-               break;
-       case 'O':                       // O- open a empty line above
-               //    0i\n ESC -i
-               p = begin_line(dot);
-               if (p[-1] == '\n') {
-                       dot_prev();
-       case 'o':                       // o- open a empty line below; Yes, I know it is in the middle of the "if (..."
-                       dot_end();
-                       dot = char_insert(dot, '\n');
-               } else {
-                       dot_begin();    // 0
-                       dot = char_insert(dot, '\n');   // i\n ESC
-                       dot_prev();     // -
-               }
-               goto dc_i;
-               break;
-       case 'R':                       // R- continuous Replace char
-         dc5:
-               cmd_mode = 2;
-               psb("-- Replace --");
-               break;
-       case 'X':                       // X- delete char before dot
-       case 'x':                       // x- delete the current char
-       case 's':                       // s- substitute the current char
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = 0;
-               if (c == 'X')
-                       dir = -1;
-               if (dot[dir] != '\n') {
-                       if (c == 'X')
-                               dot--;  // delete prev char
-                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
-               }
-               if (c == 's')
-                       goto dc_i;      // start insrting
-               end_cmd_q();    // stop adding to q
-               break;
-       case 'Z':                       // Z- if modified, {write}; exit
-               // ZZ means to save file (if necessary), then exit
-               c1 = get_one_char();
-               if (c1 != 'Z') {
-                       indicate_error(c);
-                       break;
-               }
-               if (file_modified == TRUE
-#ifdef BB_FEATURE_VI_READONLY
-                       && vi_readonly == FALSE
-                       && readonly == FALSE
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       ) {
-                       cnt = file_write(cfn, text, end - 1);
-                       if (cnt == (end - 1 - text + 1)) {
-                               editing = 0;
-                       }
-               } else {
-                       editing = 0;
-               }
-               break;
-       case '^':                       // ^- move to first non-blank on line
-               dot_begin();
-               dot_skip_over_ws();
-               break;
-       case 'b':                       // b- back a word
-       case 'e':                       // e- end of word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dir = FORWARD;
-               if (c == 'b')
-                       dir = BACK;
-               if ((dot + dir) < text || (dot + dir) > end - 1)
-                       break;
-               dot += dir;
-               if (isspace(*dot)) {
-                       dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
-               }
-               if (isalnum(*dot) || *dot == '_') {
-                       dot = skip_thing(dot, 1, dir, S_END_ALNUM);
-               } else if (ispunct(*dot)) {
-                       dot = skip_thing(dot, 1, dir, S_END_PUNCT);
-               }
-               break;
-       case 'c':                       // c- change something
-       case 'd':                       // d- delete something
-#ifdef BB_FEATURE_VI_YANKMARK
-       case 'y':                       // y- yank   something
-       case 'Y':                       // Y- Yank a line
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               yf = YANKDEL;   // assume either "c" or "d"
-#ifdef BB_FEATURE_VI_YANKMARK
-               if (c == 'y' || c == 'Y')
-                       yf = YANKONLY;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               c1 = 'y';
-               if (c != 'Y')
-                       c1 = get_one_char();    // get the type of thing to delete
-               find_range(&p, &q, c1);
-               if (c1 == 27) { // ESC- user changed mind and wants out
-                       c = c1 = 27;    // Escape- do nothing
-               } else if (strchr("wW", c1)) {
-                       if (c == 'c') {
-                               // don't include trailing WS as part of word
-                               while (isblnk(*q)) {
-                                       if (q <= text || q[-1] == '\n')
-                                               break;
-                                       q--;
-                               }
-                       }
-                       dot = yank_delete(p, q, 0, yf); // delete word
-               } else if (strchr("^0bBeEft$", c1)) {
-                       // single line copy text into a register and delete
-                       dot = yank_delete(p, q, 0, yf); // delete word
-               } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
-                       // multiple line copy text into a register and delete
-                       dot = yank_delete(p, q, 1, yf); // delete lines
-                       if (c == 'c') {
-                               dot = char_insert(dot, '\n');
-                               // on the last line of file don't move to prev line
-                               if (dot != (end-1)) {
-                                       dot_prev();
-                               }
-                       } else if (c == 'd') {
-                               dot_begin();
-                               dot_skip_over_ws();
-                       }
-               } else {
-                       // could not recognize object
-                       c = c1 = 27;    // error-
-                       indicate_error(c);
-               }
-               if (c1 != 27) {
-                       // if CHANGING, not deleting, start inserting after the delete
-                       if (c == 'c') {
-                               strcpy((char *) buf, "Change");
-                               goto dc_i;      // start inserting
-                       }
-                       if (c == 'd') {
-                               strcpy((char *) buf, "Delete");
-                       }
-#ifdef BB_FEATURE_VI_YANKMARK
-                       if (c == 'y' || c == 'Y') {
-                               strcpy((char *) buf, "Yank");
-                       }
-                       p = reg[YDreg];
-                       q = p + strlen((char *) p);
-                       for (cnt = 0; p <= q; p++) {
-                               if (*p == '\n')
-                                       cnt++;
-                       }
-                       psb("%s %d lines (%d chars) using [%c]",
-                               buf, cnt, strlen((char *) reg[YDreg]), what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-                       end_cmd_q();    // stop adding to q
-               }
-               break;
-       case 'k':                       // k- goto prev line, same col
-       case VI_K_UP:           // cursor key Up
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               dot_prev();
-               dot = move_to_col(dot, ccol + offset);  // try stay in same col
-               break;
-       case 'r':                       // r- replace the current char with user input
-               c1 = get_one_char();    // get the replacement char
-               if (*dot != '\n') {
-                       *dot = c1;
-                       file_modified = TRUE;   // has the file been modified
-               }
-               end_cmd_q();    // stop adding to q
-               break;
-       case 't':                       // t- move to char prior to next x
-                last_forward_char = get_one_char();
-                do_cmd(';');
-                if (*dot == last_forward_char)
-                        dot_left();
-                last_forward_char= 0;
-               break;
-       case 'w':                       // w- forward a word
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               if (isalnum(*dot) || *dot == '_') {     // we are on ALNUM
-                       dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
-               } else if (ispunct(*dot)) {     // we are on PUNCT
-                       dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
-               }
-               if (dot < end - 1)
-                       dot++;          // move over word
-               if (isspace(*dot)) {
-                       dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
-               }
-               break;
-       case 'z':                       // z-
-               c1 = get_one_char();    // get the replacement char
-               cnt = 0;
-               if (c1 == '.')
-                       cnt = (rows - 2) / 2;   // put dot at center
-               if (c1 == '-')
-                       cnt = rows - 2; // put dot at bottom
-               screenbegin = begin_line(dot);  // start dot at top
-               dot_scroll(cnt, -1);
-               break;
-       case '|':                       // |- move to column "cmdcnt"
-               dot = move_to_col(dot, cmdcnt - 1);     // try to move to column
-               break;
-       case '~':                       // ~- flip the case of letters   a-z -> A-Z
-               if (cmdcnt-- > 1) {
-                       do_cmd(c);
-               }                               // repeat cnt
-               if (islower(*dot)) {
-                       *dot = toupper(*dot);
-                       file_modified = TRUE;   // has the file been modified
-               } else if (isupper(*dot)) {
-                       *dot = tolower(*dot);
-                       file_modified = TRUE;   // has the file been modified
-               }
-               dot_right();
-               end_cmd_q();    // stop adding to q
-               break;
-               //----- The Cursor and Function Keys -----------------------------
-       case VI_K_HOME: // Cursor Key Home
-               dot_begin();
-               break;
-               // The Fn keys could point to do_macro which could translate them
-       case VI_K_FUN1: // Function Key F1
-       case VI_K_FUN2: // Function Key F2
-       case VI_K_FUN3: // Function Key F3
-       case VI_K_FUN4: // Function Key F4
-       case VI_K_FUN5: // Function Key F5
-       case VI_K_FUN6: // Function Key F6
-       case VI_K_FUN7: // Function Key F7
-       case VI_K_FUN8: // Function Key F8
-       case VI_K_FUN9: // Function Key F9
-       case VI_K_FUN10:        // Function Key F10
-       case VI_K_FUN11:        // Function Key F11
-       case VI_K_FUN12:        // Function Key F12
-               break;
-       }
-
-  dc1:
-       // if text[] just became empty, add back an empty line
-       if (end == text) {
-               (void) char_insert(text, '\n'); // start empty buf with dummy line
-               dot = text;
-       }
-       // it is OK for dot to exactly equal to end, otherwise check dot validity
-       if (dot != end) {
-               dot = bound_dot(dot);   // make sure "dot" is valid
-       }
-#ifdef BB_FEATURE_VI_YANKMARK
-       check_context(c);       // update the current context
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-       if (!isdigit(c))
-               cmdcnt = 0;             // cmd was not a number, reset cmdcnt
-       cnt = dot - begin_line(dot);
-       // Try to stay off of the Newline
-       if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
-               dot--;
-}
-
-//----- The Colon commands -------------------------------------
-#ifdef BB_FEATURE_VI_COLON
-static Byte *get_one_address(Byte * p, int *addr)      // get colon addr, if present
-{
-       int st;
-       Byte *q;
-
-#ifdef BB_FEATURE_VI_YANKMARK
-       Byte c;
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-       Byte *pat, buf[BUFSIZ];
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-       *addr = -1;                     // assume no addr
-       if (*p == '.') {        // the current line
-               p++;
-               q = begin_line(dot);
-               *addr = count_lines(text, q);
-#ifdef BB_FEATURE_VI_YANKMARK
-       } else if (*p == '\'') {        // is this a mark addr
-               p++;
-               c = tolower(*p);
-               p++;
-               if (c >= 'a' && c <= 'z') {
-                       // we have a mark
-                       c = c - 'a';
-                       q = mark[(int) c];
-                       if (q != NULL) {        // is mark valid
-                               *addr = count_lines(text, q);   // count lines
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_SEARCH
-       } else if (*p == '/') { // a search pattern
-               q = buf;
-               for (p++; *p; p++) {
-                       if (*p == '/')
-                               break;
-                       *q++ = *p;
-                       *q = '\0';
-               }
-               pat = (Byte *) strdup((char *) buf);    // save copy of pattern
-               if (*p == '/')
-                       p++;
-               q = char_search(dot, pat, FORWARD, FULL);
-               if (q != NULL) {
-                       *addr = count_lines(text, q);
-               }
-               free(pat);
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       } else if (*p == '$') { // the last line in file
-               p++;
-               q = begin_line(end - 1);
-               *addr = count_lines(text, q);
-       } else if (isdigit(*p)) {       // specific line number
-               sscanf((char *) p, "%d%n", addr, &st);
-               p += st;
-       } else {                        // I don't reconise this
-               // unrecognised address- assume -1
-               *addr = -1;
-       }
-       return (p);
-}
-
-static Byte *get_address(Byte *p, int *b, int *e)      // get two colon addrs, if present
-{
-       //----- get the address' i.e., 1,3   'a,'b  -----
-       // get FIRST addr, if present
-       while (isblnk(*p))
-               p++;                            // skip over leading spaces
-       if (*p == '%') {                        // alias for 1,$
-               p++;
-               *b = 1;
-               *e = count_lines(text, end-1);
-               goto ga0;
-       }
-       p = get_one_address(p, b);
-       while (isblnk(*p))
-               p++;
-       if (*p == ',') {                        // is there a address seperator
-               p++;
-               while (isblnk(*p))
-                       p++;
-               // get SECOND addr, if present
-               p = get_one_address(p, e);
-       }
-ga0:
-       while (isblnk(*p))
-               p++;                            // skip over trailing spaces
-       return (p);
-}
-
-static void colon(Byte * buf)
-{
-       Byte c, *orig_buf, *buf1, *q, *r;
-       Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
-       int i, l, li, ch, st, b, e;
-       int useforce, forced;
-       struct stat st_buf;
-
-       // :3154        // if (-e line 3154) goto it  else stay put
-       // :4,33w! foo  // write a portion of buffer to file "foo"
-       // :w           // write all of buffer to current file
-       // :q           // quit
-       // :q!          // quit- dont care about modified file
-       // :'a,'z!sort -u   // filter block through sort
-       // :'f          // goto mark "f"
-       // :'fl         // list literal the mark "f" line
-       // :.r bar      // read file "bar" into buffer before dot
-       // :/123/,/abc/d    // delete lines from "123" line to "abc" line
-       // :/xyz/       // goto the "xyz" line
-       // :s/find/replace/ // substitute pattern "find" with "replace"
-       // :!<cmd>      // run <cmd> then return
-       //
-       if (strlen((char *) buf) <= 0)
-               goto vc1;
-       if (*buf == ':')
-               buf++;                  // move past the ':'
-
-       forced = useforce = FALSE;
-       li = st = ch = i = 0;
-       b = e = -1;
-       q = text;                       // assume 1,$ for the range
-       r = end - 1;
-       li = count_lines(text, end - 1);
-       fn = cfn;                       // default to current file
-       memset(cmd, '\0', BUFSIZ);      // clear cmd[]
-       memset(args, '\0', BUFSIZ);     // clear args[]
-
-       // look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
-       buf = get_address(buf, &b, &e);
-
-       // remember orig command line
-       orig_buf = buf;
-
-       // get the COMMAND into cmd[]
-       buf1 = cmd;
-       while (*buf != '\0') {
-               if (isspace(*buf))
-                       break;
-               *buf1++ = *buf++;
-       }
-       // get any ARGuments
-       while (isblnk(*buf))
-               buf++;
-       strcpy((char *) args, (char *) buf);
-       buf1 = last_char_is((char *)cmd, '!');
-       if (buf1) {
-               useforce = TRUE;
-               *buf1 = '\0';   // get rid of !
-       }
-       if (b >= 0) {
-               // if there is only one addr, then the addr
-               // is the line number of the single line the
-               // user wants. So, reset the end
-               // pointer to point at end of the "b" line
-               q = find_line(b);       // what line is #b
-               r = end_line(q);
-               li = 1;
-       }
-       if (e >= 0) {
-               // we were given two addrs.  change the
-               // end pointer to the addr given by user.
-               r = find_line(e);       // what line is #e
-               r = end_line(r);
-               li = e - b + 1;
-       }
-       // ------------ now look for the command ------------
-       i = strlen((char *) cmd);
-       if (i == 0) {           // :123CR goto line #123
-               if (b >= 0) {
-                       dot = find_line(b);     // what line is #b
-                       dot_skip_over_ws();
-               }
-       } else if (strncmp((char *) cmd, "!", 1) == 0) {        // run a cmd
-               // :!ls   run the <cmd>
-               (void) alarm(0);                // wait for input- no alarms
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line
-               clear_to_eol();                 // clear the line
-               cookmode();
-               system(orig_buf+1);             // run the cmd
-               rawmode();
-               Hit_Return();                   // let user see results
-               (void) alarm(3);                // done waiting for input
-       } else if (strncmp((char *) cmd, "=", i) == 0) {        // where is the address
-               if (b < 0) {    // no addr given- use defaults
-                       b = e = count_lines(text, dot);
-               }
-               psb("%d", b);
-       } else if (strncasecmp((char *) cmd, "delete", i) == 0) {       // delete lines
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               dot = yank_delete(q, r, 1, YANKDEL);    // save, then delete lines
-               dot_skip_over_ws();
-       } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
-               int sr;
-               sr= 0;
-               // don't edit, if the current file has been modified
-               if (file_modified == TRUE && useforce != TRUE) {
-                       psbs("No write since last change (:edit! overrides)");
-                       goto vc1;
-               }
-               if (strlen(args) > 0) {
-                       // the user supplied a file name
-                       fn= args;
-               } else if (cfn != 0 && strlen(cfn) > 0) {
-                       // no user supplied name- use the current filename
-                       fn= cfn;
-                       goto vc5;
-               } else {
-                       // no user file name, no current name- punt
-                       psbs("No current filename");
-                       goto vc1;
-               }
-
-               // see if file exists- if not, its just a new file request
-               if ((sr=stat((char*)fn, &st_buf)) < 0) {
-                       // This is just a request for a new file creation.
-                       // The file_insert below will fail but we get
-                       // an empty buffer with a file name.  Then the "write"
-                       // command can do the create.
-               } else {
-                       if ((st_buf.st_mode & (S_IFREG)) == 0) {
-                               // This is not a regular file
-                               psbs("\"%s\" is not a regular file", fn);
-                               goto vc1;
-                       }
-                       if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
-                               // dont have any read permissions
-                               psbs("\"%s\" is not readable", fn);
-                               goto vc1;
-                       }
-               }
-
-               // There is a read-able regular file
-               // make this the current file
-               q = (Byte *) strdup((char *) fn);       // save the cfn
-               if (cfn != 0)
-                       free(cfn);              // free the old name
-               cfn = q;                        // remember new cfn
-
-         vc5:
-               // delete all the contents of text[]
-               new_text(2 * file_size(fn));
-               screenbegin = dot = end = text;
-
-               // insert new file
-               ch = file_insert(fn, text, file_size(fn));
-
-               if (ch < 1) {
-                       // start empty buf with dummy line
-                       (void) char_insert(text, '\n');
-                       ch= 1;
-               }
-               file_modified = FALSE;
-#ifdef BB_FEATURE_VI_YANKMARK
-               if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
-                       free(reg[Ureg]);        //   free orig line reg- for 'U'
-                       reg[Ureg]= 0;
-               }
-               if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
-                       free(reg[YDreg]);       //   free default yank/delete register
-                       reg[YDreg]= 0;
-               }
-               for (li = 0; li < 28; li++) {
-                       mark[li] = 0;
-               }                               // init the marks
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-               // how many lines in text[]?
-               li = count_lines(text, end - 1);
-               psb("\"%s\"%s"
-#ifdef BB_FEATURE_VI_READONLY
-                       "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       " %dL, %dC", cfn,
-                       (sr < 0 ? " [New file]" : ""),
-#ifdef BB_FEATURE_VI_READONLY
-                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       li, ch);
-       } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
-               if (b != -1 || e != -1) {
-                       ni((Byte *) "No address allowed on this command");
-                       goto vc1;
-               }
-               if (strlen((char *) args) > 0) {
-                       // user wants a new filename
-                       if (cfn != NULL)
-                               free(cfn);
-                       cfn = (Byte *) strdup((char *) args);
-               } else {
-                       // user wants file status info
-                       edit_status();
-               }
-       } else if (strncasecmp((char *) cmd, "features", i) == 0) {     // what features are available
-               // print out values of all features
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
-               cookmode();
-               show_help();
-               rawmode();
-               Hit_Return();
-       } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
-               write(1, "\r\n", 2);
-               for (; q <= r; q++) {
-                       c = *q;
-                       if (c > '~')
-                               standout_start();
-                       if (c == '\n') {
-                               write(1, "$\r", 2);
-                       } else if (*q < ' ') {
-                               write(1, "^", 1);
-                               c += '@';
-                       }
-                       write(1, &c, 1);
-                       if (c > '~')
-                               standout_end();
-               }
-#ifdef BB_FEATURE_VI_SET
-         vc2:
-#endif                                                 /* BB_FEATURE_VI_SET */
-               Hit_Return();
-       } else if ((strncasecmp((char *) cmd, "quit", i) == 0) ||       // Quit
-                          (strncasecmp((char *) cmd, "next", i) == 0)) {       // edit next file
-               if (useforce == TRUE) {
-                       // force end of argv list
-                       if (*cmd == 'q') {
-                               optind = save_argc;
-                       }
-                       editing = 0;
-                       goto vc1;
-               }
-               // don't exit if the file been modified
-               if (file_modified == TRUE) {
-                       psbs("No write since last change (:%s! overrides)",
-                                (*cmd == 'q' ? "quit" : "next"));
-                       goto vc1;
-               }
-               // are there other file to edit
-               if (*cmd == 'q' && optind < save_argc - 1) {
-                       psbs("%d more file to edit", (save_argc - optind - 1));
-                       goto vc1;
-               }
-               if (*cmd == 'n' && optind >= save_argc - 1) {
-                       psbs("No more files to edit");
-                       goto vc1;
-               }
-               editing = 0;
-       } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[]
-               fn = args;
-               if (strlen((char *) fn) <= 0) {
-                       psbs("No filename given");
-                       goto vc1;
-               }
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume "dot"
-               }
-               // read after current line- unless user said ":0r foo"
-               if (b != 0)
-                       q = next_line(q);
-#ifdef BB_FEATURE_VI_READONLY
-               l= readonly;                    // remember current files' status
-#endif
-               ch = file_insert(fn, q, file_size(fn));
-#ifdef BB_FEATURE_VI_READONLY
-               readonly= l;
-#endif
-               if (ch < 0)
-                       goto vc1;       // nothing was inserted
-               // how many lines in text[]?
-               li = count_lines(q, q + ch - 1);
-               psb("\"%s\""
-#ifdef BB_FEATURE_VI_READONLY
-                       "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       " %dL, %dC", fn,
-#ifdef BB_FEATURE_VI_READONLY
-                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-                       li, ch);
-               if (ch > 0) {
-                       // if the insert is before "dot" then we need to update
-                       if (q <= dot)
-                               dot += ch;
-                       file_modified = TRUE;
-               }
-       } else if (strncasecmp((char *) cmd, "rewind", i) == 0) {       // rewind cmd line args
-               if (file_modified == TRUE && useforce != TRUE) {
-                       psbs("No write since last change (:rewind! overrides)");
-               } else {
-                       // reset the filenames to edit
-                       optind = fn_start - 1;
-                       editing = 0;
-               }
-#ifdef BB_FEATURE_VI_SET
-       } else if (strncasecmp((char *) cmd, "set", i) == 0) {  // set or clear features
-               i = 0;                  // offset into args
-               if (strlen((char *) args) == 0) {
-                       // print out values of all options
-                       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-                       clear_to_eol(); // clear the line
-                       printf("----------------------------------------\r\n");
-#ifdef BB_FEATURE_VI_SETOPTS
-                       if (!autoindent)
-                               printf("no");
-                       printf("autoindent ");
-                       if (!err_method)
-                               printf("no");
-                       printf("flash ");
-                       if (!ignorecase)
-                               printf("no");
-                       printf("ignorecase ");
-                       if (!showmatch)
-                               printf("no");
-                       printf("showmatch ");
-                       printf("tabstop=%d ", tabstop);
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-                       printf("\r\n");
-                       goto vc2;
-               }
-               if (strncasecmp((char *) args, "no", 2) == 0)
-                       i = 2;          // ":set noautoindent"
-#ifdef BB_FEATURE_VI_SETOPTS
-               if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ai", 2) == 0) {
-                       autoindent = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
-                       strncasecmp((char *) args + i, "fl", 2) == 0) {
-                       err_method = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
-                       strncasecmp((char *) args + i, "ic", 2) == 0) {
-                       ignorecase = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "showmatch", 9) == 0 ||
-                       strncasecmp((char *) args + i, "sm", 2) == 0) {
-                       showmatch = (i == 2) ? 0 : 1;
-               }
-               if (strncasecmp((char *) args + i, "tabstop", 7) == 0) {
-                       sscanf(strchr((char *) args + i, '='), "=%d", &ch);
-                       if (ch > 0 && ch < columns - 1)
-                               tabstop = ch;
-               }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#endif                                                 /* BB_FEATURE_VI_SET */
-#ifdef BB_FEATURE_VI_SEARCH
-       } else if (strncasecmp((char *) cmd, "s", 1) == 0) {    // substitute a pattern with a replacement pattern
-               Byte *ls, *F, *R;
-               int gflag;
-
-               // F points to the "find" pattern
-               // R points to the "replace" pattern
-               // replace the cmd line delimiters "/" with NULLs
-               gflag = 0;              // global replace flag
-               c = orig_buf[1];        // what is the delimiter
-               F = orig_buf + 2;       // start of "find"
-               R = (Byte *) strchr((char *) F, c);     // middle delimiter
-               if (!R) goto colon_s_fail;
-               *R++ = '\0';    // terminate "find"
-               buf1 = (Byte *) strchr((char *) R, c);
-               if (!buf1) goto colon_s_fail;
-               *buf1++ = '\0'; // terminate "replace"
-               if (*buf1 == 'g') {     // :s/foo/bar/g
-                       buf1++;
-                       gflag++;        // turn on gflag
-               }
-               q = begin_line(q);
-               if (b < 0) {    // maybe :s/foo/bar/
-                       q = begin_line(dot);    // start with cur line
-                       b = count_lines(text, q);       // cur line number
-               }
-               if (e < 0)
-                       e = b;          // maybe :.s/foo/bar/
-               for (i = b; i <= e; i++) {      // so, :20,23 s \0 find \0 replace \0
-                       ls = q;         // orig line start
-                 vc4:
-                       buf1 = char_search(q, F, FORWARD, LIMITED);     // search cur line only for "find"
-                       if (buf1 != NULL) {
-                               // we found the "find" pattern- delete it
-                               (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1);
-                               // inset the "replace" patern
-                               (void) string_insert(buf1, R);  // insert the string
-                               // check for "global"  :s/foo/bar/g
-                               if (gflag == 1) {
-                                       if ((buf1 + strlen((char *) R)) < end_line(ls)) {
-                                               q = buf1 + strlen((char *) R);
-                                               goto vc4;       // don't let q move past cur line
-                                       }
-                               }
-                       }
-                       q = next_line(ls);
-               }
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-       } else if (strncasecmp((char *) cmd, "version", i) == 0) {      // show software version
-               psb("%s", vi_Version);
-       } else if ((strncasecmp((char *) cmd, "write", i) == 0) ||      // write text to file
-                          (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file
-               // is there a file name to write to?
-               if (strlen((char *) args) > 0) {
-                       fn = args;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-               if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
-                       psbs("\"%s\" File is read only", fn);
-                       goto vc3;
-               }
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               // how many lines in text[]?
-               li = count_lines(q, r);
-               ch = r - q + 1;
-               // see if file exists- if not, its just a new file request
-               if (useforce == TRUE) {
-                       // if "fn" is not write-able, chmod u+w
-                       // sprintf(syscmd, "chmod u+w %s", fn);
-                       // system(syscmd);
-                       forced = TRUE;
-               }
-               l = file_write(fn, q, r);
-               if (useforce == TRUE && forced == TRUE) {
-                       // chmod u-w
-                       // sprintf(syscmd, "chmod u-w %s", fn);
-                       // system(syscmd);
-                       forced = FALSE;
-               }
-               psb("\"%s\" %dL, %dC", fn, li, l);
-               if (q == text && r == end - 1 && l == ch)
-                       file_modified = FALSE;
-               if (cmd[1] == 'q' && l == ch) {
-                       editing = 0;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-         vc3:;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_YANKMARK
-       } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
-               if (b < 0) {    // no addr given- use defaults
-                       q = begin_line(dot);    // assume .,. for the range
-                       r = end_line(dot);
-               }
-               text_yank(q, r, YDreg);
-               li = count_lines(q, r);
-               psb("Yank %d lines (%d chars) into [%c]",
-                       li, strlen((char *) reg[YDreg]), what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       } else {
-               // cmd unknown
-               ni((Byte *) cmd);
-       }
-  vc1:
-       dot = bound_dot(dot);   // make sure "dot" is valid
-       return;
-#ifdef BB_FEATURE_VI_SEARCH
-colon_s_fail:
-       psb(":s expression missing delimiters");
-       return;
-#endif
-
-}
-
-static void Hit_Return(void)
-{
-       char c;
-
-       standout_start();       // start reverse video
-       write(1, "[Hit return to continue]", 24);
-       standout_end();         // end reverse video
-       while ((c = get_one_char()) != '\n' && c != '\r')       /*do nothing */
-               ;
-       redraw(TRUE);           // force redraw all
-}
-#endif                                                 /* BB_FEATURE_VI_COLON */
-
-//----- Synchronize the cursor to Dot --------------------------
-static void sync_cursor(Byte * d, int *row, int *col)
-{
-       Byte *beg_cur, *end_cur;        // begin and end of "d" line
-       Byte *beg_scr, *end_scr;        // begin and end of screen
-       Byte *tp;
-       int cnt, ro, co;
-
-       beg_cur = begin_line(d);        // first char of cur line
-       end_cur = end_line(d);  // last char of cur line
-
-       beg_scr = end_scr = screenbegin;        // first char of screen
-       end_scr = end_screen(); // last char of screen
-
-       if (beg_cur < screenbegin) {
-               // "d" is before  top line on screen
-               // how many lines do we have to move
-               cnt = count_lines(beg_cur, screenbegin);
-         sc1:
-               screenbegin = beg_cur;
-               if (cnt > (rows - 1) / 2) {
-                       // we moved too many lines. put "dot" in middle of screen
-                       for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
-                               screenbegin = prev_line(screenbegin);
-                       }
-               }
-       } else if (beg_cur > end_scr) {
-               // "d" is after bottom line on screen
-               // how many lines do we have to move
-               cnt = count_lines(end_scr, beg_cur);
-               if (cnt > (rows - 1) / 2)
-                       goto sc1;       // too many lines
-               for (ro = 0; ro < cnt - 1; ro++) {
-                       // move screen begin the same amount
-                       screenbegin = next_line(screenbegin);
-                       // now, move the end of screen
-                       end_scr = next_line(end_scr);
-                       end_scr = end_line(end_scr);
-               }
-       }
-       // "d" is on screen- find out which row
-       tp = screenbegin;
-       for (ro = 0; ro < rows - 1; ro++) {     // drive "ro" to correct row
-               if (tp == beg_cur)
-                       break;
-               tp = next_line(tp);
-       }
-
-       // find out what col "d" is on
-       co = 0;
-       do {                            // drive "co" to correct column
-               if (*tp == '\n' || *tp == '\0')
-                       break;
-               if (*tp == '\t') {
-                       //         7       - (co %    8  )
-                       co += ((tabstop - 1) - (co % tabstop));
-               } else if (*tp < ' ') {
-                       co++;           // display as ^X, use 2 columns
-               }
-       } while (tp++ < d && ++co);
-
-       // "co" is the column where "dot" is.
-       // The screen has "columns" columns.
-       // The currently displayed columns are  0+offset -- columns+ofset
-       // |-------------------------------------------------------------|
-       //               ^ ^                                ^
-       //        offset | |------- columns ----------------|
-       //
-       // If "co" is already in this range then we do not have to adjust offset
-       //      but, we do have to subtract the "offset" bias from "co".
-       // If "co" is outside this range then we have to change "offset".
-       // If the first char of a line is a tab the cursor will try to stay
-       //  in column 7, but we have to set offset to 0.
-
-       if (co < 0 + offset) {
-               offset = co;
-       }
-       if (co >= columns + offset) {
-               offset = co - columns + 1;
-       }
-       // if the first char of the line is a tab, and "dot" is sitting on it
-       //  force offset to 0.
-       if (d == beg_cur && *d == '\t') {
-               offset = 0;
-       }
-       co -= offset;
-
-       *row = ro;
-       *col = co;
-}
-
-//----- Text Movement Routines ---------------------------------
-static Byte *begin_line(Byte * p) // return pointer to first char cur line
-{
-       while (p > text && p[-1] != '\n')
-               p--;                    // go to cur line B-o-l
-       return (p);
-}
-
-static Byte *end_line(Byte * p) // return pointer to NL of cur line line
-{
-       while (p < end - 1 && *p != '\n')
-               p++;                    // go to cur line E-o-l
-       return (p);
-}
-
-static Byte *dollar_line(Byte * p) // return pointer to just before NL line
-{
-       while (p < end - 1 && *p != '\n')
-               p++;                    // go to cur line E-o-l
-       // Try to stay off of the Newline
-       if (*p == '\n' && (p - begin_line(p)) > 0)
-               p--;
-       return (p);
-}
-
-static Byte *prev_line(Byte * p) // return pointer first char prev line
-{
-       p = begin_line(p);      // goto begining of cur line
-       if (p[-1] == '\n' && p > text)
-               p--;                    // step to prev line
-       p = begin_line(p);      // goto begining of prev line
-       return (p);
-}
-
-static Byte *next_line(Byte * p) // return pointer first char next line
-{
-       p = end_line(p);
-       if (*p == '\n' && p < end - 1)
-               p++;                    // step to next line
-       return (p);
-}
-
-//----- Text Information Routines ------------------------------
-static Byte *end_screen(void)
-{
-       Byte *q;
-       int cnt;
-
-       // find new bottom line
-       q = screenbegin;
-       for (cnt = 0; cnt < rows - 2; cnt++)
-               q = next_line(q);
-       q = end_line(q);
-       return (q);
-}
-
-static int count_lines(Byte * start, Byte * stop) // count line from start to stop
-{
-       Byte *q;
-       int cnt;
-
-       if (stop < start) {     // start and stop are backwards- reverse them
-               q = start;
-               start = stop;
-               stop = q;
-       }
-       cnt = 0;
-       stop = end_line(stop);  // get to end of this line
-       for (q = start; q <= stop && q <= end - 1; q++) {
-               if (*q == '\n')
-                       cnt++;
-       }
-       return (cnt);
-}
-
-static Byte *find_line(int li) // find begining of line #li
-{
-       Byte *q;
-
-       for (q = text; li > 1; li--) {
-               q = next_line(q);
-       }
-       return (q);
-}
-
-//----- Dot Movement Routines ----------------------------------
-static void dot_left(void)
-{
-       if (dot > text && dot[-1] != '\n')
-               dot--;
-}
-
-static void dot_right(void)
-{
-       if (dot < end - 1 && *dot != '\n')
-               dot++;
-}
-
-static void dot_begin(void)
-{
-       dot = begin_line(dot);  // return pointer to first char cur line
-}
-
-static void dot_end(void)
-{
-       dot = end_line(dot);    // return pointer to last char cur line
-}
-
-static Byte *move_to_col(Byte * p, int l)
-{
-       int co;
-
-       p = begin_line(p);
-       co = 0;
-       do {
-               if (*p == '\n' || *p == '\0')
-                       break;
-               if (*p == '\t') {
-                       //         7       - (co %    8  )
-                       co += ((tabstop - 1) - (co % tabstop));
-               } else if (*p < ' ') {
-                       co++;           // display as ^X, use 2 columns
-               }
-       } while (++co <= l && p++ < end);
-       return (p);
-}
-
-static void dot_next(void)
-{
-       dot = next_line(dot);
-}
-
-static void dot_prev(void)
-{
-       dot = prev_line(dot);
-}
-
-static void dot_scroll(int cnt, int dir)
-{
-       Byte *q;
-
-       for (; cnt > 0; cnt--) {
-               if (dir < 0) {
-                       // scroll Backwards
-                       // ctrl-Y  scroll up one line
-                       screenbegin = prev_line(screenbegin);
-               } else {
-                       // scroll Forwards
-                       // ctrl-E  scroll down one line
-                       screenbegin = next_line(screenbegin);
-               }
-       }
-       // make sure "dot" stays on the screen so we dont scroll off
-       if (dot < screenbegin)
-               dot = screenbegin;
-       q = end_screen();       // find new bottom line
-       if (dot > q)
-               dot = begin_line(q);    // is dot is below bottom line?
-       dot_skip_over_ws();
-}
-
-static void dot_skip_over_ws(void)
-{
-       // skip WS
-       while (isspace(*dot) && *dot != '\n' && dot < end - 1)
-               dot++;
-}
-
-static void dot_delete(void)   // delete the char at 'dot'
-{
-       (void) text_hole_delete(dot, dot);
-}
-
-static Byte *bound_dot(Byte * p) // make sure  text[0] <= P < "end"
-{
-       if (p >= end && end > text) {
-               p = end - 1;
-               indicate_error('1');
-       }
-       if (p < text) {
-               p = text;
-               indicate_error('2');
-       }
-       return (p);
-}
-
-//----- Helper Utility Routines --------------------------------
-
-//----------------------------------------------------------------
-//----- Char Routines --------------------------------------------
-/* Chars that are part of a word-
- *    0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
- * Chars that are Not part of a word (stoppers)
- *    !"#$%&'()*+,-./:;<=>?@[\]^`{|}~
- * Chars that are WhiteSpace
- *    TAB NEWLINE VT FF RETURN SPACE
- * DO NOT COUNT NEWLINE AS WHITESPACE
- */
-
-static Byte *new_screen(int ro, int co)
-{
-       int li;
-
-       if (screen != 0)
-               free(screen);
-       screensize = ro * co + 8;
-       screen = (Byte *) malloc(screensize);
-       // initialize the new screen. assume this will be a empty file.
-       screen_erase();
-       //   non-existant text[] lines start with a tilde (~).
-       for (li = 1; li < ro - 1; li++) {
-               screen[(li * co) + 0] = '~';
-       }
-       return (screen);
-}
-
-static Byte *new_text(int size)
-{
-       if (size < 10240)
-               size = 10240;   // have a minimum size for new files
-       if (text != 0) {
-               //text -= 4;
-               free(text);
-       }
-       text = (Byte *) malloc(size + 8);
-       memset(text, '\0', size);       // clear new text[]
-       //text += 4;            // leave some room for "oops"
-       textend = text + size - 1;
-       //textend -= 4;         // leave some root for "oops"
-       return (text);
-}
-
-#ifdef BB_FEATURE_VI_SEARCH
-static int mycmp(Byte * s1, Byte * s2, int len)
-{
-       int i;
-
-       i = strncmp((char *) s1, (char *) s2, len);
-#ifdef BB_FEATURE_VI_SETOPTS
-       if (ignorecase) {
-               i = strncasecmp((char *) s1, (char *) s2, len);
-       }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-       return (i);
-}
-
-static Byte *char_search(Byte * p, Byte * pat, int dir, int range)     // search for pattern starting at p
-{
-#ifndef REGEX_SEARCH
-       Byte *start, *stop;
-       int len;
-
-       len = strlen((char *) pat);
-       if (dir == FORWARD) {
-               stop = end - 1; // assume range is p - end-1
-               if (range == LIMITED)
-                       stop = next_line(p);    // range is to next line
-               for (start = p; start < stop; start++) {
-                       if (mycmp(start, pat, len) == 0) {
-                               return (start);
-                       }
-               }
-       } else if (dir == BACK) {
-               stop = text;    // assume range is text - p
-               if (range == LIMITED)
-                       stop = prev_line(p);    // range is to prev line
-               for (start = p - len; start >= stop; start--) {
-                       if (mycmp(start, pat, len) == 0) {
-                               return (start);
-                       }
-               }
-       }
-       // pattern not found
-       return (NULL);
-#else                                                  /*REGEX_SEARCH */
-       char *q;
-       struct re_pattern_buffer preg;
-       int i;
-       int size, range;
-
-       re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
-       preg.translate = 0;
-       preg.fastmap = 0;
-       preg.buffer = 0;
-       preg.allocated = 0;
-
-       // assume a LIMITED forward search
-       q = next_line(p);
-       q = end_line(q);
-       q = end - 1;
-       if (dir == BACK) {
-               q = prev_line(p);
-               q = text;
-       }
-       // count the number of chars to search over, forward or backward
-       size = q - p;
-       if (size < 0)
-               size = p - q;
-       // RANGE could be negative if we are searching backwards
-       range = q - p;
-
-       q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg);
-       if (q != 0) {
-               // The pattern was not compiled
-               psbs("bad search pattern: \"%s\": %s", pat, q);
-               i = 0;                  // return p if pattern not compiled
-               goto cs1;
-       }
-
-       q = p;
-       if (range < 0) {
-               q = p - size;
-               if (q < text)
-                       q = text;
-       }
-       // search for the compiled pattern, preg, in p[]
-       // range < 0-  search backward
-       // range > 0-  search forward
-       // 0 < start < size
-       // re_search() < 0  not found or error
-       // re_search() > 0  index of found pattern
-       //            struct pattern    char     int    int    int     struct reg
-       // re_search (*pattern_buffer,  *string, size,  start, range,  *regs)
-       i = re_search(&preg, q, size, 0, range, 0);
-       if (i == -1) {
-               p = 0;
-               i = 0;                  // return NULL if pattern not found
-       }
-  cs1:
-       if (dir == FORWARD) {
-               p = p + i;
-       } else {
-               p = p - i;
-       }
-       return (p);
-#endif                                                 /*REGEX_SEARCH */
-}
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-
-static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
-{
-       if (c == 22) {          // Is this an ctrl-V?
-               p = stupid_insert(p, '^');      // use ^ to indicate literal next
-               p--;                    // backup onto ^
-               refresh(FALSE); // show the ^
-               c = get_one_char();
-               *p = c;
-               p++;
-               file_modified = TRUE;   // has the file been modified
-       } else if (c == 27) {   // Is this an ESC?
-               cmd_mode = 0;
-               cmdcnt = 0;
-               end_cmd_q();    // stop adding to q
-               strcpy((char *) status_buffer, " ");    // clear the status buffer
-               if ((p[-1] != '\n') && (dot>text)) {
-                       p--;
-               }
-       } else if (c == erase_char) {   // Is this a BS
-               //     123456789
-               if ((p[-1] != '\n') && (dot>text)) {
-                       p--;
-                       p = text_hole_delete(p, p);     // shrink buffer 1 char
-#ifdef BB_FEATURE_VI_DOT_CMD
-                       // also rmove char from last_modifying_cmd
-                       if (strlen((char *) last_modifying_cmd) > 0) {
-                               Byte *q;
-
-                               q = last_modifying_cmd;
-                               q[strlen((char *) q) - 1] = '\0';       // erase BS
-                               q[strlen((char *) q) - 1] = '\0';       // erase prev char
-                       }
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-               }
-       } else {
-               // insert a char into text[]
-               Byte *sp;               // "save p"
-
-               if (c == 13)
-                       c = '\n';       // translate \r to \n
-               sp = p;                 // remember addr of insert
-               p = stupid_insert(p, c);        // insert the char
-#ifdef BB_FEATURE_VI_SETOPTS
-               if (showmatch && strchr(")]}", *sp) != NULL) {
-                       showmatching(sp);
-               }
-               if (autoindent && c == '\n') {  // auto indent the new line
-                       Byte *q;
-
-                       q = prev_line(p);       // use prev line as templet
-                       for (; isblnk(*q); q++) {
-                               p = stupid_insert(p, *q);       // insert the char
-                       }
-               }
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-       }
-       return (p);
-}
-
-static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p'
-{
-       p = text_hole_make(p, 1);
-       if (p != 0) {
-               *p = c;
-               file_modified = TRUE;   // has the file been modified
-               p++;
-       }
-       return (p);
-}
-
-static Byte find_range(Byte ** start, Byte ** stop, Byte c)
-{
-       Byte *save_dot, *p, *q;
-       int cnt;
-
-       save_dot = dot;
-       p = q = dot;
-
-       if (strchr("cdy><", c)) {
-               // these cmds operate on whole lines
-               p = q = begin_line(p);
-               for (cnt = 1; cnt < cmdcnt; cnt++) {
-                       q = next_line(q);
-               }
-               q = end_line(q);
-       } else if (strchr("^%$0bBeEft", c)) {
-               // These cmds operate on char positions
-               do_cmd(c);              // execute movement cmd
-               q = dot;
-       } else if (strchr("wW", c)) {
-               do_cmd(c);              // execute movement cmd
-               if (dot > text)
-                       dot--;          // move back off of next word
-               if (dot > text && *dot == '\n')
-                       dot--;          // stay off NL
-               q = dot;
-       } else if (strchr("H-k{", c)) {
-               // these operate on multi-lines backwards
-               q = end_line(dot);      // find NL
-               do_cmd(c);              // execute movement cmd
-               dot_begin();
-               p = dot;
-       } else if (strchr("L+j}\r\n", c)) {
-               // these operate on multi-lines forwards
-               p = begin_line(dot);
-               do_cmd(c);              // execute movement cmd
-               dot_end();              // find NL
-               q = dot;
-       } else {
-               c = 27;                 // error- return an ESC char
-               //break;
-       }
-       *start = p;
-       *stop = q;
-       if (q < p) {
-               *start = q;
-               *stop = p;
-       }
-       dot = save_dot;
-       return (c);
-}
-
-static int st_test(Byte * p, int type, int dir, Byte * tested)
-{
-       Byte c, c0, ci;
-       int test, inc;
-
-       inc = dir;
-       c = c0 = p[0];
-       ci = p[inc];
-       test = 0;
-
-       if (type == S_BEFORE_WS) {
-               c = ci;
-               test = ((!isspace(c)) || c == '\n');
-       }
-       if (type == S_TO_WS) {
-               c = c0;
-               test = ((!isspace(c)) || c == '\n');
-       }
-       if (type == S_OVER_WS) {
-               c = c0;
-               test = ((isspace(c)));
-       }
-       if (type == S_END_PUNCT) {
-               c = ci;
-               test = ((ispunct(c)));
-       }
-       if (type == S_END_ALNUM) {
-               c = ci;
-               test = ((isalnum(c)) || c == '_');
-       }
-       *tested = c;
-       return (test);
-}
-
-static Byte *skip_thing(Byte * p, int linecnt, int dir, int type)
-{
-       Byte c;
-
-       while (st_test(p, type, dir, &c)) {
-               // make sure we limit search to correct number of lines
-               if (c == '\n' && --linecnt < 1)
-                       break;
-               if (dir >= 0 && p >= end - 1)
-                       break;
-               if (dir < 0 && p <= text)
-                       break;
-               p += dir;               // move to next char
-       }
-       return (p);
-}
-
-// find matching char of pair  ()  []  {}
-static Byte *find_pair(Byte * p, Byte c)
-{
-       Byte match, *q;
-       int dir, level;
-
-       match = ')';
-       level = 1;
-       dir = 1;                        // assume forward
-       switch (c) {
-       case '(':
-               match = ')';
-               break;
-       case '[':
-               match = ']';
-               break;
-       case '{':
-               match = '}';
-               break;
-       case ')':
-               match = '(';
-               dir = -1;
-               break;
-       case ']':
-               match = '[';
-               dir = -1;
-               break;
-       case '}':
-               match = '{';
-               dir = -1;
-               break;
-       }
-       for (q = p + dir; text <= q && q < end; q += dir) {
-               // look for match, count levels of pairs  (( ))
-               if (*q == c)
-                       level++;        // increase pair levels
-               if (*q == match)
-                       level--;        // reduce pair level
-               if (level == 0)
-                       break;          // found matching pair
-       }
-       if (level != 0)
-               q = NULL;               // indicate no match
-       return (q);
-}
-
-#ifdef BB_FEATURE_VI_SETOPTS
-// show the matching char of a pair,  ()  []  {}
-static void showmatching(Byte * p)
-{
-       Byte *q, *save_dot;
-
-       // we found half of a pair
-       q = find_pair(p, *p);   // get loc of matching char
-       if (q == NULL) {
-               indicate_error('3');    // no matching char
-       } else {
-               // "q" now points to matching pair
-               save_dot = dot; // remember where we are
-               dot = q;                // go to new loc
-               refresh(FALSE); // let the user see it
-               (void) mysleep(40);     // give user some time
-               dot = save_dot; // go back to old loc
-               refresh(FALSE);
-       }
-}
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-
-//  open a hole in text[]
-static Byte *text_hole_make(Byte * p, int size)        // at "p", make a 'size' byte hole
-{
-       Byte *src, *dest;
-       int cnt;
-
-       if (size <= 0)
-               goto thm0;
-       src = p;
-       dest = p + size;
-       cnt = end - src;        // the rest of buffer
-       if (memmove(dest, src, cnt) != dest) {
-               psbs("can't create room for new characters");
-       }
-       memset(p, ' ', size);   // clear new hole
-       end = end + size;       // adjust the new END
-       file_modified = TRUE;   // has the file been modified
-  thm0:
-       return (p);
-}
-
-//  close a hole in text[]
-static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive
-{
-       Byte *src, *dest;
-       int cnt, hole_size;
-
-       // move forwards, from beginning
-       // assume p <= q
-       src = q + 1;
-       dest = p;
-       if (q < p) {            // they are backward- swap them
-               src = p + 1;
-               dest = q;
-       }
-       hole_size = q - p + 1;
-       cnt = end - src;
-       if (src < text || src > end)
-               goto thd0;
-       if (dest < text || dest >= end)
-               goto thd0;
-       if (src >= end)
-               goto thd_atend; // just delete the end of the buffer
-       if (memmove(dest, src, cnt) != dest) {
-               psbs("can't delete the character");
-       }
-  thd_atend:
-       end = end - hole_size;  // adjust the new END
-       if (dest >= end)
-               dest = end - 1; // make sure dest in below end-1
-       if (end <= text)
-               dest = end = text;      // keep pointers valid
-       file_modified = TRUE;   // has the file been modified
-  thd0:
-       return (dest);
-}
-
-// copy text into register, then delete text.
-// if dist <= 0, do not include, or go past, a NewLine
-//
-static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
-{
-       Byte *p;
-
-       // make sure start <= stop
-       if (start > stop) {
-               // they are backwards, reverse them
-               p = start;
-               start = stop;
-               stop = p;
-       }
-       if (dist <= 0) {
-               // we can not cross NL boundaries
-               p = start;
-               if (*p == '\n')
-                       return (p);
-               // dont go past a NewLine
-               for (; p + 1 <= stop; p++) {
-                       if (p[1] == '\n') {
-                               stop = p;       // "stop" just before NewLine
-                               break;
-                       }
-               }
-       }
-       p = start;
-#ifdef BB_FEATURE_VI_YANKMARK
-       text_yank(start, stop, YDreg);
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       if (yf == YANKDEL) {
-               p = text_hole_delete(start, stop);
-       }                                       // delete lines
-       return (p);
-}
-
-static void show_help(void)
-{
-       puts("These features are available:"
-#ifdef BB_FEATURE_VI_SEARCH
-       "\n\tPattern searches with / and ?"
-#endif                                                 /* BB_FEATURE_VI_SEARCH */
-#ifdef BB_FEATURE_VI_DOT_CMD
-       "\n\tLast command repeat with \'.\'"
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-#ifdef BB_FEATURE_VI_YANKMARK
-       "\n\tLine marking with  'x"
-       "\n\tNamed buffers with  \"x"
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-#ifdef BB_FEATURE_VI_READONLY
-       "\n\tReadonly if vi is called as \"view\""
-       "\n\tReadonly with -R command line arg"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-#ifdef BB_FEATURE_VI_SET
-       "\n\tSome colon mode commands with \':\'"
-#endif                                                 /* BB_FEATURE_VI_SET */
-#ifdef BB_FEATURE_VI_SETOPTS
-       "\n\tSettable options with \":set\""
-#endif                                                 /* BB_FEATURE_VI_SETOPTS */
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-       "\n\tSignal catching- ^C"
-       "\n\tJob suspend and resume with ^Z"
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       "\n\tAdapt to window re-sizes"
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       );
-}
-
-static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
-{
-       Byte c, b[2];
-
-       b[1] = '\0';
-       strcpy((char *) buf, "");       // init buf
-       if (strlen((char *) s) <= 0)
-               s = (Byte *) "(NULL)";
-       for (; *s > '\0'; s++) {
-               c = *s;
-               if (*s > '~') {
-                       strcat((char *) buf, SOs);
-                       c = *s - 128;
-               }
-               if (*s < ' ') {
-                       strcat((char *) buf, "^");
-                       c += '@';
-               }
-               b[0] = c;
-               strcat((char *) buf, (char *) b);
-               if (*s > '~')
-                       strcat((char *) buf, SOn);
-               if (*s == '\n') {
-                       strcat((char *) buf, "$");
-               }
-       }
-}
-
-#ifdef BB_FEATURE_VI_DOT_CMD
-static void start_new_cmd_q(Byte c)
-{
-       // release old cmd
-       if (last_modifying_cmd != 0)
-               free(last_modifying_cmd);
-       // get buffer for new cmd
-       last_modifying_cmd = (Byte *) malloc(BUFSIZ);
-       memset(last_modifying_cmd, '\0', BUFSIZ);       // clear new cmd queue
-       // if there is a current cmd count put it in the buffer first
-       if (cmdcnt > 0)
-               sprintf((char *) last_modifying_cmd, "%d", cmdcnt);
-       // save char c onto queue
-       last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
-       adding2q = 1;
-       return;
-}
-
-static void end_cmd_q()
-{
-#ifdef BB_FEATURE_VI_YANKMARK
-       YDreg = 26;                     // go back to default Yank/Delete reg
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       adding2q = 0;
-       return;
-}
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-
-#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
-static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
-{
-       int cnt, i;
-
-       i = strlen((char *) s);
-       p = text_hole_make(p, i);
-       strncpy((char *) p, (char *) s, i);
-       for (cnt = 0; *s != '\0'; s++) {
-               if (*s == '\n')
-                       cnt++;
-       }
-#ifdef BB_FEATURE_VI_YANKMARK
-       psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-       return (p);
-}
-#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
-
-#ifdef BB_FEATURE_VI_YANKMARK
-static Byte *text_yank(Byte * p, Byte * q, int dest)   // copy text into a register
-{
-       Byte *t;
-       int cnt;
-
-       if (q < p) {            // they are backwards- reverse them
-               t = q;
-               q = p;
-               p = t;
-       }
-       cnt = q - p + 1;
-       t = reg[dest];
-       if (t != 0) {           // if already a yank register
-               free(t);                //   free it
-       }
-       t = (Byte *) malloc(cnt + 1);   // get a new register
-       memset(t, '\0', cnt + 1);       // clear new text[]
-       strncpy((char *) t, (char *) p, cnt);   // copy text[] into bufer
-       reg[dest] = t;
-       return (p);
-}
-
-static Byte what_reg(void)
-{
-       Byte c;
-       int i;
-
-       i = 0;
-       c = 'D';                        // default to D-reg
-       if (0 <= YDreg && YDreg <= 25)
-               c = 'a' + (Byte) YDreg;
-       if (YDreg == 26)
-               c = 'D';
-       if (YDreg == 27)
-               c = 'U';
-       return (c);
-}
-
-static void check_context(Byte cmd)
-{
-       // A context is defined to be "modifying text"
-       // Any modifying command establishes a new context.
-
-       if (dot < context_start || dot > context_end) {
-               if (strchr((char *) modifying_cmds, cmd) != NULL) {
-                       // we are trying to modify text[]- make this the current context
-                       mark[27] = mark[26];    // move cur to prev
-                       mark[26] = dot; // move local to cur
-                       context_start = prev_line(prev_line(dot));
-                       context_end = next_line(next_line(dot));
-                       //loiter= start_loiter= now;
-               }
-       }
-       return;
-}
-
-static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
-{
-       Byte *tmp;
-
-       // the current context is in mark[26]
-       // the previous context is in mark[27]
-       // only swap context if other context is valid
-       if (text <= mark[27] && mark[27] <= end - 1) {
-               tmp = mark[27];
-               mark[27] = mark[26];
-               mark[26] = tmp;
-               p = mark[26];   // where we are going- previous context
-               context_start = prev_line(prev_line(prev_line(p)));
-               context_end = next_line(next_line(next_line(p)));
-       }
-       return (p);
-}
-#endif                                                 /* BB_FEATURE_VI_YANKMARK */
-
-static int isblnk(Byte c) // is the char a blank or tab
-{
-       return (c == ' ' || c == '\t');
-}
-
-//----- Set terminal attributes --------------------------------
-static void rawmode(void)
-{
-       tcgetattr(0, &term_orig);
-       term_vi = term_orig;
-       term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG ON- allow intr's
-       term_vi.c_iflag &= (~IXON & ~ICRNL);
-       term_vi.c_oflag &= (~ONLCR);
-#ifndef linux
-       term_vi.c_cc[VMIN] = 1;
-       term_vi.c_cc[VTIME] = 0;
-#endif
-       erase_char = term_vi.c_cc[VERASE];
-       tcsetattr(0, TCSANOW, &term_vi);
-}
-
-static void cookmode(void)
-{
-       tcsetattr(0, TCSANOW, &term_orig);
-}
-
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-//----- See what the window size currently is --------------------
-static void window_size_get(int sig)
-{
-       int i;
-
-       i = ioctl(0, TIOCGWINSZ, &winsize);
-       if (i != 0) {
-               // force 24x80
-               winsize.ws_row = 24;
-               winsize.ws_col = 80;
-       }
-       if (winsize.ws_row <= 1) {
-               winsize.ws_row = 24;
-       }
-       if (winsize.ws_col <= 1) {
-               winsize.ws_col = 80;
-       }
-       rows = (int) winsize.ws_row;
-       columns = (int) winsize.ws_col;
-}
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-
-//----- Come here when we get a window resize signal ---------
-#ifdef BB_FEATURE_VI_USE_SIGNALS
-static void winch_sig(int sig)
-{
-       signal(SIGWINCH, winch_sig);
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       new_screen(rows, columns);      // get memory for virtual screen
-       redraw(TRUE);           // re-draw the screen
-}
-
-//----- Come here when we get a continue signal -------------------
-static void cont_sig(int sig)
-{
-       rawmode();                      // terminal to "raw"
-       *status_buffer = '\0';  // clear the status buffer
-       redraw(TRUE);           // re-draw the screen
-
-       signal(SIGTSTP, suspend_sig);
-       signal(SIGCONT, SIG_DFL);
-       kill(getpid(), SIGCONT);
-}
-
-//----- Come here when we get a Suspend signal -------------------
-static void suspend_sig(int sig)
-{
-       place_cursor(rows - 1, 0, FALSE);       // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
-       cookmode();                     // terminal to "cooked"
-
-       signal(SIGCONT, cont_sig);
-       signal(SIGTSTP, SIG_DFL);
-       kill(getpid(), SIGTSTP);
-}
-
-//----- Come here when we get a signal ---------------------------
-static void catch_sig(int sig)
-{
-       signal(SIGHUP, catch_sig);
-       signal(SIGINT, catch_sig);
-       signal(SIGTERM, catch_sig);
-       longjmp(restart, sig);
-}
-
-static void alarm_sig(int sig)
-{
-       signal(SIGALRM, catch_sig);
-       longjmp(restart, sig);
-}
-
-//----- Come here when we get a core dump signal -----------------
-static void core_sig(int sig)
-{
-       signal(SIGQUIT, core_sig);
-       signal(SIGILL, core_sig);
-       signal(SIGTRAP, core_sig);
-       signal(SIGIOT, core_sig);
-       signal(SIGABRT, core_sig);
-       signal(SIGFPE, core_sig);
-       signal(SIGBUS, core_sig);
-       signal(SIGSEGV, core_sig);
-#ifdef SIGSYS
-       signal(SIGSYS, core_sig);
-#endif
-
-       dot = bound_dot(dot);   // make sure "dot" is valid
-
-       longjmp(restart, sig);
-}
-#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
-
-static int mysleep(int hund)   // sleep for 'h' 1/100 seconds
-{
-       // Don't hang- Wait 5/100 seconds-  1 Sec= 1000000
-       FD_ZERO(&rfds);
-       FD_SET(0, &rfds);
-       tv.tv_sec = 0;
-       tv.tv_usec = hund * 10000;
-       select(1, &rfds, NULL, NULL, &tv);
-       return (FD_ISSET(0, &rfds));
-}
-
-//----- IO Routines --------------------------------------------
-static Byte readit(void)       // read (maybe cursor) key from stdin
-{
-       Byte c;
-       int i, bufsiz, cnt, cmdindex;
-       struct esc_cmds {
-               Byte *seq;
-               Byte val;
-       };
-
-       static struct esc_cmds esccmds[] = {
-               {(Byte *) "\eOA", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\eOB", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\eOC", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\eOD", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\eOH", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\eOF", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[A", (Byte) VI_K_UP},       // cursor key Up
-               {(Byte *) "\e[B", (Byte) VI_K_DOWN},     // cursor key Down
-               {(Byte *) "\e[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
-               {(Byte *) "\e[D", (Byte) VI_K_LEFT},     // cursor key Left
-               {(Byte *) "\e[H", (Byte) VI_K_HOME},     // Cursor Key Home
-               {(Byte *) "\e[F", (Byte) VI_K_END},      // Cursor Key End
-               {(Byte *) "\e[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
-               {(Byte *) "\e[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
-               {(Byte *) "\e[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
-               {(Byte *) "\eOP", (Byte) VI_K_FUN1},     // Function Key F1
-               {(Byte *) "\eOQ", (Byte) VI_K_FUN2},     // Function Key F2
-               {(Byte *) "\eOR", (Byte) VI_K_FUN3},     // Function Key F3
-               {(Byte *) "\eOS", (Byte) VI_K_FUN4},     // Function Key F4
-               {(Byte *) "\e[15~", (Byte) VI_K_FUN5},   // Function Key F5
-               {(Byte *) "\e[17~", (Byte) VI_K_FUN6},   // Function Key F6
-               {(Byte *) "\e[18~", (Byte) VI_K_FUN7},   // Function Key F7
-               {(Byte *) "\e[19~", (Byte) VI_K_FUN8},   // Function Key F8
-               {(Byte *) "\e[20~", (Byte) VI_K_FUN9},   // Function Key F9
-               {(Byte *) "\e[21~", (Byte) VI_K_FUN10},  // Function Key F10
-               {(Byte *) "\e[23~", (Byte) VI_K_FUN11},  // Function Key F11
-               {(Byte *) "\e[24~", (Byte) VI_K_FUN12},  // Function Key F12
-               {(Byte *) "\e[11~", (Byte) VI_K_FUN1},   // Function Key F1
-               {(Byte *) "\e[12~", (Byte) VI_K_FUN2},   // Function Key F2
-               {(Byte *) "\e[13~", (Byte) VI_K_FUN3},   // Function Key F3
-               {(Byte *) "\e[14~", (Byte) VI_K_FUN4},   // Function Key F4
-       };
-
-#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
-
-       (void) alarm(0);        // turn alarm OFF while we wait for input
-       // get input from User- are there already input chars in Q?
-       bufsiz = strlen((char *) readbuffer);
-       if (bufsiz <= 0) {
-         ri0:
-               // the Q is empty, wait for a typed char
-               bufsiz = read(0, readbuffer, BUFSIZ - 1);
-               if (bufsiz < 0) {
-                       if (errno == EINTR)
-                               goto ri0;       // interrupted sys call
-                       if (errno == EBADF)
-                               editing = 0;
-                       if (errno == EFAULT)
-                               editing = 0;
-                       if (errno == EINVAL)
-                               editing = 0;
-                       if (errno == EIO)
-                               editing = 0;
-                       errno = 0;
-                       bufsiz = 0;
-               }
-               readbuffer[bufsiz] = '\0';
-       }
-       // return char if it is not part of ESC sequence
-       if (readbuffer[0] != 27)
-               goto ri1;
-
-       // This is an ESC char. Is this Esc sequence?
-       // Could be bare Esc key. See if there are any
-       // more chars to read after the ESC. This would
-       // be a Function or Cursor Key sequence.
-       FD_ZERO(&rfds);
-       FD_SET(0, &rfds);
-       tv.tv_sec = 0;
-       tv.tv_usec = 50000;     // Wait 5/100 seconds- 1 Sec=1000000
-
-       // keep reading while there are input chars and room in buffer
-       while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
-               // read the rest of the ESC string
-               i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz);
-               if (i > 0) {
-                       bufsiz += i;
-                       readbuffer[bufsiz] = '\0';      // Terminate the string
-               }
-       }
-       // Maybe cursor or function key?
-       for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) {
-               cnt = strlen((char *) esccmds[cmdindex].seq);
-               i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt);
-               if (i == 0) {
-                       // is a Cursor key- put derived value back into Q
-                       readbuffer[0] = esccmds[cmdindex].val;
-                       // squeeze out the ESC sequence
-                       for (i = 1; i < cnt; i++) {
-                               memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2);
-                               readbuffer[BUFSIZ - 1] = '\0';
-                       }
-                       break;
-               }
-       }
-  ri1:
-       c = readbuffer[0];
-       // remove one char from Q
-       memmove(readbuffer, readbuffer + 1, BUFSIZ - 1);
-       readbuffer[BUFSIZ - 1] = '\0';
-       (void) alarm(3);        // we are done waiting for input, turn alarm ON
-       return (c);
-}
-
-//----- IO Routines --------------------------------------------
-static Byte get_one_char()
-{
-       static Byte c;
-
-#ifdef BB_FEATURE_VI_DOT_CMD
-       // ! adding2q  && ioq == 0  read()
-       // ! adding2q  && ioq != 0  *ioq
-       // adding2q         *last_modifying_cmd= read()
-       if (!adding2q) {
-               // we are not adding to the q.
-               // but, we may be reading from a q
-               if (ioq == 0) {
-                       // there is no current q, read from STDIN
-                       c = readit();   // get the users input
-               } else {
-                       // there is a queue to get chars from first
-                       c = *ioq++;
-                       if (c == '\0') {
-                               // the end of the q, read from STDIN
-                               free(ioq_start);
-                               ioq_start = ioq = 0;
-                               c = readit();   // get the users input
-                       }
-               }
-       } else {
-               // adding STDIN chars to q
-               c = readit();   // get the users input
-               if (last_modifying_cmd != 0) {
-                       // add new char to q
-                       last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
-               }
-       }
-#else                                                  /* BB_FEATURE_VI_DOT_CMD */
-       c = readit();           // get the users input
-#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
-       return (c);                     // return the char, where ever it came from
-}
-
-static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
-{
-       Byte buf[BUFSIZ];
-       Byte c;
-       int i;
-       static Byte *obufp = NULL;
-
-       strcpy((char *) buf, (char *) prompt);
-       *status_buffer = '\0';  // clear the status buffer
-       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-       clear_to_eol();         // clear the line
-       write(1, prompt, strlen((char *) prompt));      // write out the :, /, or ? prompt
-
-       for (i = strlen((char *) buf); i < BUFSIZ;) {
-               c = get_one_char();     // read user input
-               if (c == '\n' || c == '\r' || c == 27)
-                       break;          // is this end of input
-               if (c == erase_char) {  // user wants to erase prev char
-                       i--;            // backup to prev char
-                       buf[i] = '\0';  // erase the char
-                       buf[i + 1] = '\0';      // null terminate buffer
-                       write(1, "\b \b", 3);     // erase char on screen
-                       if (i <= 0) {   // user backs up before b-o-l, exit
-                               break;
-                       }
-               } else {
-                       buf[i] = c;     // save char in buffer
-                       buf[i + 1] = '\0';      // make sure buffer is null terminated
-                       write(1, buf + i, 1);   // echo the char back to user
-                       i++;
-               }
-       }
-       refresh(FALSE);
-       if (obufp != NULL)
-               free(obufp);
-       obufp = (Byte *) strdup((char *) buf);
-       return (obufp);
-}
-
-static int file_size(Byte * fn) // what is the byte size of "fn"
-{
-       struct stat st_buf;
-       int cnt, sr;
-
-       if (fn == 0 || strlen(fn) <= 0)
-               return (-1);
-       cnt = -1;
-       sr = stat((char *) fn, &st_buf);        // see if file exists
-       if (sr >= 0) {
-               cnt = (int) st_buf.st_size;
-       }
-       return (cnt);
-}
-
-static int file_insert(Byte * fn, Byte * p, int size)
-{
-       int fd, cnt;
-
-       cnt = -1;
-#ifdef BB_FEATURE_VI_READONLY
-       readonly = FALSE;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-       if (fn == 0 || strlen((char*) fn) <= 0) {
-               psbs("No filename given");
-               goto fi0;
-       }
-       if (size == 0) {
-               // OK- this is just a no-op
-               cnt = 0;
-               goto fi0;
-       }
-       if (size < 0) {
-               psbs("Trying to insert a negative number (%d) of characters", size);
-               goto fi0;
-       }
-       if (p < text || p > end) {
-               psbs("Trying to insert file outside of memory");
-               goto fi0;
-       }
-
-       // see if we can open the file
-#ifdef BB_FEATURE_VI_READONLY
-       if (vi_readonly == TRUE) goto fi1;              // do not try write-mode
-#endif
-       fd = open((char *) fn, O_RDWR);                 // assume read & write
-       if (fd < 0) {
-               // could not open for writing- maybe file is read only
-#ifdef BB_FEATURE_VI_READONLY
-  fi1:
-#endif
-               fd = open((char *) fn, O_RDONLY);       // try read-only
-               if (fd < 0) {
-                       psbs("\"%s\" %s", fn, "could not open file");
-                       goto fi0;
-               }
-#ifdef BB_FEATURE_VI_READONLY
-               // got the file- read-only
-               readonly = TRUE;
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-       }
-       p = text_hole_make(p, size);
-       cnt = read(fd, p, size);
-       close(fd);
-       if (cnt < 0) {
-               cnt = -1;
-               p = text_hole_delete(p, p + size - 1);  // un-do buffer insert
-               psbs("could not read file \"%s\"", fn);
-       } else if (cnt < size) {
-               // There was a partial read, shrink unused space text[]
-               p = text_hole_delete(p + cnt, p + (size - cnt) - 1);    // un-do buffer insert
-               psbs("could not read all of file \"%s\"", fn);
-       }
-       if (cnt >= size)
-               file_modified = TRUE;
-  fi0:
-       return (cnt);
-}
-
-static int file_write(Byte * fn, Byte * first, Byte * last)
-{
-       int fd, cnt, charcnt;
-
-       if (fn == 0) {
-               psbs("No current filename");
-               return (-1);
-       }
-       charcnt = 0;
-       // FIXIT- use the correct umask()
-       fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
-       if (fd < 0)
-               return (-1);
-       cnt = last - first + 1;
-       charcnt = write(fd, first, cnt);
-       if (charcnt == cnt) {
-               // good write
-               //file_modified= FALSE; // the file has not been modified
-       } else {
-               charcnt = 0;
-       }
-       close(fd);
-       return (charcnt);
-}
-
-//----- Terminal Drawing ---------------------------------------
-// The terminal is made up of 'rows' line of 'columns' columns.
-// classicly this would be 24 x 80.
-//  screen coordinates
-//  0,0     ...     0,79
-//  1,0     ...     1,79
-//  .       ...     .
-//  .       ...     .
-//  22,0    ...     22,79
-//  23,0    ...     23,79   status line
-//
-
-//----- Move the cursor to row x col (count from 0, not 1) -------
-static void place_cursor(int row, int col, int opti)
-{
-       char cm1[BUFSIZ];
-       char *cm;
-       int l;
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       char cm2[BUFSIZ];
-       Byte *screenp;
-       // char cm3[BUFSIZ];
-       int Rrow= last_row;
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-       
-       memset(cm1, '\0', BUFSIZ - 1);  // clear the buffer
-
-       if (row < 0) row = 0;
-       if (row >= rows) row = rows - 1;
-       if (col < 0) col = 0;
-       if (col >= columns) col = columns - 1;
-       
-       //----- 1.  Try the standard terminal ESC sequence
-       sprintf((char *) cm1, CMrc, row + 1, col + 1);
-       cm= cm1;
-       if (opti == FALSE) goto pc0;
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       //----- find the minimum # of chars to move cursor -------------
-       //----- 2.  Try moving with discreet chars (Newline, [back]space, ...)
-       memset(cm2, '\0', BUFSIZ - 1);  // clear the buffer
-       
-       // move to the correct row
-       while (row < Rrow) {
-               // the cursor has to move up
-               strcat(cm2, CMup);
-               Rrow--;
-       }
-       while (row > Rrow) {
-               // the cursor has to move down
-               strcat(cm2, CMdown);
-               Rrow++;
-       }
-       
-       // now move to the correct column
-       strcat(cm2, "\r");                      // start at col 0
-       // just send out orignal source char to get to correct place
-       screenp = &screen[row * columns];       // start of screen line
-       strncat(cm2, screenp, col);
-
-       //----- 3.  Try some other way of moving cursor
-       //---------------------------------------------
-
-       // pick the shortest cursor motion to send out
-       cm= cm1;
-       if (strlen(cm2) < strlen(cm)) {
-               cm= cm2;
-       }  /* else if (strlen(cm3) < strlen(cm)) {
-               cm= cm3;
-       } */
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-  pc0:
-       l= strlen(cm);
-       if (l) write(1, cm, l);                 // move the cursor
-}
-
-//----- Erase from cursor to end of line -----------------------
-static void clear_to_eol()
-{
-       write(1, Ceol, strlen(Ceol));   // Erase from cursor to end of line
-}
-
-//----- Erase from cursor to end of screen -----------------------
-static void clear_to_eos()
-{
-       write(1, Ceos, strlen(Ceos));   // Erase from cursor to end of screen
-}
-
-//----- Start standout mode ------------------------------------
-static void standout_start() // send "start reverse video" sequence
-{
-       write(1, SOs, strlen(SOs));     // Start reverse video mode
-}
-
-//----- End standout mode --------------------------------------
-static void standout_end() // send "end reverse video" sequence
-{
-       write(1, SOn, strlen(SOn));     // End reverse video mode
-}
-
-//----- Flash the screen  --------------------------------------
-static void flash(int h)
-{
-       standout_start();       // send "start reverse video" sequence
-       redraw(TRUE);
-       (void) mysleep(h);
-       standout_end();         // send "end reverse video" sequence
-       redraw(TRUE);
-}
-
-static void beep()
-{
-       write(1, bell, strlen(bell));   // send out a bell character
-}
-
-static void indicate_error(char c)
-{
-#ifdef BB_FEATURE_VI_CRASHME
-       if (crashme > 0)
-               return;                 // generate a random command
-#endif                                                 /* BB_FEATURE_VI_CRASHME */
-       if (err_method == 0) {
-               beep();
-       } else {
-               flash(10);
-       }
-}
-
-//----- Screen[] Routines --------------------------------------
-//----- Erase the Screen[] memory ------------------------------
-static void screen_erase()
-{
-       memset(screen, ' ', screensize);        // clear new screen
-}
-
-//----- Draw the status line at bottom of the screen -------------
-static void show_status_line(void)
-{
-       static int last_cksum;
-       int l, cnt, cksum;
-
-       cnt = strlen((char *) status_buffer);
-       for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
-       // don't write the status line unless it changes
-       if (cnt > 0 && last_cksum != cksum) {
-               last_cksum= cksum;              // remember if we have seen this line
-               place_cursor(rows - 1, 0, FALSE);       // put cursor on status line
-               write(1, status_buffer, cnt);
-               clear_to_eol();
-               place_cursor(crow, ccol, FALSE);        // put cursor back in correct place
-       }
-}
-
-//----- format the status buffer, the bottom line of screen ------
-// print status buffer, with STANDOUT mode
-static void psbs(char *format, ...)
-{
-       va_list args;
-
-       va_start(args, format);
-       strcpy((char *) status_buffer, SOs);    // Terminal standout mode on
-       vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
-                        args);
-       strcat((char *) status_buffer, SOn);    // Terminal standout mode off
-       va_end(args);
-
-       return;
-}
-
-// print status buffer
-static void psb(char *format, ...)
-{
-       va_list args;
-
-       va_start(args, format);
-       vsprintf((char *) status_buffer, format, args);
-       va_end(args);
-       return;
-}
-
-static void ni(Byte * s) // display messages
-{
-       Byte buf[BUFSIZ];
-
-       print_literal(buf, s);
-       psbs("\'%s\' is not implemented", buf);
-}
-
-static void edit_status(void)  // show file status on status line
-{
-       int cur, tot, percent;
-
-       cur = count_lines(text, dot);
-       tot = count_lines(text, end - 1);
-       //    current line         percent
-       //   -------------    ~~ ----------
-       //    total lines            100
-       if (tot > 0) {
-               percent = (100 * cur) / tot;
-       } else {
-               cur = tot = 0;
-               percent = 100;
-       }
-       psb("\"%s\""
-#ifdef BB_FEATURE_VI_READONLY
-               "%s"
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               "%s line %d of %d --%d%%--",
-               (cfn != 0 ? (char *) cfn : "No file"),
-#ifdef BB_FEATURE_VI_READONLY
-               ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
-#endif                                                 /* BB_FEATURE_VI_READONLY */
-               (file_modified == TRUE ? " [modified]" : ""),
-               cur, tot, percent);
-}
-
-//----- Force refresh of all Lines -----------------------------
-static void redraw(int full_screen)
-{
-       place_cursor(0, 0, FALSE);      // put cursor in correct place
-       clear_to_eos();         // tel terminal to erase display
-       screen_erase();         // erase the internal screen buffer
-       refresh(full_screen);   // this will redraw the entire display
-}
-
-//----- Format a text[] line into a buffer ---------------------
-static void format_line(Byte *dest, Byte *src, int li)
-{
-       int co;
-       Byte c;
-       
-       for (co= 0; co < MAX_SCR_COLS; co++) {
-               c= ' ';         // assume blank
-               if (li > 0 && co == 0) {
-                       c = '~';        // not first line, assume Tilde
-               }
-               // are there chars in text[] and have we gone past the end
-               if (text < end && src < end) {
-                       c = *src++;
-               }
-               if (c == '\n')
-                       break;
-               if (c < ' ' || c > '~') {
-                       if (c == '\t') {
-                               c = ' ';
-                               //       co %    8     !=     7
-                               for (; (co % tabstop) != (tabstop - 1); co++) {
-                                       dest[co] = c;
-                               }
-                       } else {
-                               dest[co++] = '^';
-                               c |= '@';       // make it visible
-                               c &= 0x7f;      // get rid of hi bit
-                       }
-               }
-               // the co++ is done here so that the column will
-               // not be overwritten when we blank-out the rest of line
-               dest[co] = c;
-               if (src >= end)
-                       break;
-       }
-}
-
-//----- Refresh the changed screen lines -----------------------
-// Copy the source line from text[] into the buffer and note
-// if the current screenline is different from the new buffer.
-// If they differ then that line needs redrawing on the terminal.
-//
-static void refresh(int full_screen)
-{
-       static int old_offset;
-       int li, changed;
-       Byte buf[MAX_SCR_COLS];
-       Byte *tp, *sp;          // pointer into text[] and screen[]
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       int last_li= -2;                                // last line that changed- for optimizing cursor movement
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-
-#ifdef BB_FEATURE_VI_WIN_RESIZE
-       window_size_get(0);
-#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
-       sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
-       tp = screenbegin;       // index into text[] of top line
-
-       // compare text[] to screen[] and mark screen[] lines that need updating
-       for (li = 0; li < rows - 1; li++) {
-               int cs, ce;                             // column start & end
-               memset(buf, ' ', MAX_SCR_COLS);         // blank-out the buffer
-               buf[MAX_SCR_COLS-1] = 0;                // NULL terminate the buffer
-               // format current text line into buf
-               format_line(buf, tp, li);
-
-               // skip to the end of the current text[] line
-               while (tp < end && *tp++ != '\n') /*no-op*/ ;
-
-               // see if there are any changes between vitual screen and buf
-               changed = FALSE;        // assume no change
-               cs= 0;
-               ce= columns-1;
-               sp = &screen[li * columns];     // start of screen line
-               if (full_screen == TRUE) {
-                       // force re-draw of every single column from 0 - columns-1
-                       goto re0;
-               }
-               // compare newly formatted buffer with virtual screen
-               // look forward for first difference between buf and screen
-               for ( ; cs <= ce; cs++) {
-                       if (buf[cs + offset] != sp[cs]) {
-                               changed = TRUE; // mark for redraw
-                               break;
-                       }
-               }
-
-               // look backward for last difference between buf and screen
-               for ( ; ce >= cs; ce--) {
-                       if (buf[ce + offset] != sp[ce]) {
-                               changed = TRUE; // mark for redraw
-                               break;
-                       }
-               }
-               // now, cs is index of first diff, and ce is index of last diff
-
-               // if horz offset has changed, force a redraw
-               if (offset != old_offset) {
-  re0:
-                       changed = TRUE;
-               }
-
-               // make a sanity check of columns indexes
-               if (cs < 0) cs= 0;
-               if (ce > columns-1) ce= columns-1;
-               if (cs > ce) {  cs= 0;  ce= columns-1;  }
-               // is there a change between vitual screen and buf
-               if (changed == TRUE) {
-                       //  copy changed part of buffer to virtual screen
-                       memmove(sp+cs, buf+(cs+offset), ce-cs+1);
-
-                       // move cursor to column of first change
-                       if (offset != old_offset) {
-                               // opti_cur_move is still too stupid
-                               // to handle offsets correctly
-                               place_cursor(li, cs, FALSE);
-                       } else {
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-                               // if this just the next line
-                               //  try to optimize cursor movement
-                               //  otherwise, use standard ESC sequence
-                               place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
-                               last_li= li;
-#else                                                  /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-                               place_cursor(li, cs, FALSE);    // use standard ESC sequence
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-                       }
-
-                       // write line out to terminal
-                       write(1, sp+cs, ce-cs+1);
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-                       last_row = li;
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-               }
-       }
-
-#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
-       place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
-       last_row = crow;
-#else
-       place_cursor(crow, ccol, FALSE);
-#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
-       
-       if (offset != old_offset)
-               old_offset = offset;
-}
diff --git a/busybox/watchdog.c b/busybox/watchdog.c
deleted file mode 100644 (file)
index f0b0ebd..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini watchdog implementation for busybox
- *
- * Copyright (C) 2000  spoon <spoon@ix.netcom.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int watchdog_main(int argc, char **argv)
-{
-       int fd;
-
-       if (argc != 2) {
-               show_usage();
-       }
-
-       if ((fd=open(argv[1], O_WRONLY)) == -1) {
-               perror_msg_and_die(argv[1]);
-       }
-
-       while (1) {
-               sleep(30);
-               write(fd, "\0", 1);
-       }
-
-       return EXIT_FAILURE;
-}
diff --git a/busybox/wc.c b/busybox/wc.c
deleted file mode 100644 (file)
index 695e7e7..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini wc implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-static int total_lines, total_words, total_chars, max_length;
-static int print_lines, print_words, print_chars, print_length;
-
-static void print_counts(int lines, int words, int chars, int length,
-                                                const char *name)
-{
-       char const *space = "";
-
-       if (print_lines) {
-               printf("%7d", lines);
-               space = " ";
-       }
-       if (print_words) {
-               printf("%s%7d", space, words);
-               space = " ";
-       }
-       if (print_chars) {
-               printf("%s%7d", space, chars);
-               space = " ";
-       }
-       if (print_length)
-               printf("%s%7d", space, length);
-       if (*name)
-               printf(" %s", name);
-       putchar('\n');
-}
-
-static void wc_file(FILE * file, const char *name)
-{
-       int lines, words, chars, length;
-       int in_word = 0, linepos = 0;
-       int c;
-
-       lines = words = chars = length = 0;
-       while ((c = getc(file)) != EOF) {
-               chars++;
-               switch (c) {
-               case '\n':
-                       lines++;
-               case '\r':
-               case '\f':
-                       if (linepos > length)
-                               length = linepos;
-                       linepos = 0;
-                       goto word_separator;
-               case '\t':
-                       linepos += 8 - (linepos % 8);
-                       goto word_separator;
-               case ' ':
-                       linepos++;
-               case '\v':
-                 word_separator:
-                       if (in_word) {
-                               in_word = 0;
-                               words++;
-                       }
-                       break;
-               default:
-                       linepos++;
-                       in_word = 1;
-                       break;
-               }
-       }
-       if (linepos > length)
-               length = linepos;
-       if (in_word)
-               words++;
-       print_counts(lines, words, chars, length, name);
-       total_lines += lines;
-       total_words += words;
-       total_chars += chars;
-       if (length > max_length)
-               max_length = length;
-       fclose(file);
-       fflush(stdout);
-}
-
-int wc_main(int argc, char **argv)
-{
-       FILE *file;
-       unsigned int num_files_counted = 0;
-       int opt, status = EXIT_SUCCESS;
-
-       total_lines = total_words = total_chars = max_length = 0;
-       print_lines = print_words = print_chars = print_length = 0;
-
-       while ((opt = getopt(argc, argv, "clLw")) > 0) {
-                       switch (opt) {
-                       case 'c':
-                               print_chars = 1;
-                               break;
-                       case 'l':
-                               print_lines = 1;
-                               break;
-                       case 'L':
-                               print_length = 1;
-                               break;
-                       case 'w':
-                               print_words = 1;
-                               break;
-                       default:
-                               show_usage();
-                       }
-       }
-
-       if (!print_lines && !print_words && !print_chars && !print_length)
-               print_lines = print_words = print_chars = 1;
-
-       if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
-               wc_file(stdin, "");
-               return EXIT_SUCCESS;
-       } else {
-               while (optind < argc) {
-                       if ((file = wfopen(argv[optind], "r")) != NULL)
-                               wc_file(file, argv[optind]);
-                       else
-                               status = EXIT_FAILURE;
-                       num_files_counted++;
-                       optind++;
-               }
-       }
-
-       if (num_files_counted > 1)
-               print_counts(total_lines, total_words, total_chars,
-                                        max_length, "total");
-
-       return status;
-}
diff --git a/busybox/wget.c b/busybox/wget.c
deleted file mode 100644 (file)
index 59373d1..0000000
+++ /dev/null
@@ -1,834 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * wget - retrieve a file using HTTP or FTP
- *
- * Chip Rosenthal Covad Communications <chip@laserlink.net>
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <getopt.h>
-
-#include "busybox.h"
-
-/* Stupid libc5 doesn't define this... */
-#ifndef timersub
-#define        timersub(a, b, result)                                                \
-  do {                                                                       \
-    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                            \
-    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                         \
-    if ((result)->tv_usec < 0) {                                             \
-      --(result)->tv_sec;                                                    \
-      (result)->tv_usec += 1000000;                                          \
-    }                                                                        \
-  } while (0)
-#endif 
-
-struct host_info {
-       char *host;
-       int port;
-       char *path;
-       int is_ftp;
-       char *user;
-};
-
-static void parse_url(char *url, struct host_info *h);
-static FILE *open_socket(char *host, int port);
-static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
-static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
-
-/* Globals (can be accessed from signal handlers */
-static off_t filesize = 0;             /* content-length of the file */
-static int chunked = 0;                        /* chunked transfer encoding */
-#ifdef BB_FEATURE_WGET_STATUSBAR
-static void progressmeter(int flag);
-static char *curfile;                  /* Name of current file being transferred. */
-static struct timeval start;   /* Time a transfer started. */
-static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */
-/* For progressmeter() -- number of seconds before xfer considered "stalled" */
-static const int STALLTIME = 5;
-#endif
-               
-static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
-{
-       if (output != stdout && do_continue==0) {
-               fclose(output);
-               unlink(fname_out);
-       }
-}
-
-/* Read NMEMB elements of SIZE bytes into PTR from STREAM.  Returns the
- * number of elements read, and a short count if an eof or non-interrupt
- * error is encountered.  */
-static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-       size_t ret = 0;
-
-       do {
-               clearerr(stream);
-               ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
-       } while (ret < nmemb && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-/* Write NMEMB elements of SIZE bytes from PTR to STREAM.  Returns the
- * number of elements written, and a short count if an eof or non-interrupt
- * error is encountered.  */
-static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
-       size_t ret = 0;
-
-       do {
-               clearerr(stream);
-               ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
-       } while (ret < nmemb && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
- * Returns S, or NULL if an eof or non-interrupt error is encountered.  */
-static char *safe_fgets(char *s, int size, FILE *stream)
-{
-       char *ret;
-
-       do {
-               clearerr(stream);
-               ret = fgets(s, size, stream);
-       } while (ret == NULL && ferror(stream) && errno == EINTR);
-
-       return ret;
-}
-
-#define close_delete_and_die(s...) { \
-       close_and_delete_outfile(output, fname_out, do_continue); \
-       error_msg_and_die(s); }
-
-
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
-/*
- *  Base64-encode character string
- *  oops... isn't something similar in uuencode.c?
- *  It would be better to use already existing code
- */
-char *base64enc(char *p, char *buf, int len) {
-
-        char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-                    "0123456789+/";
-               char *s = buf;
-
-        while(*p) {
-                               if (s >= buf+len-4)
-                                       error_msg_and_die("buffer overflow");
-                *(s++) = al[(*p >> 2) & 0x3F];
-                *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
-                *s = *(s+1) = '=';
-                *(s+2) = 0;
-                if (! *(++p)) break;
-                *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
-                if (! *(++p)) break;
-                *(s++) = al[*(p++) & 0x3F];
-        }
-
-               return buf;
-}
-#endif
-
-int wget_main(int argc, char **argv)
-{
-       int n, try=5, status;
-       int port;
-       char *proxy;
-       char *dir_prefix=NULL;
-       char *s, buf[512];
-       struct stat sbuf;
-       char extra_headers[1024];
-       char *extra_headers_ptr = extra_headers;
-       int extra_headers_left = sizeof(extra_headers);
-       int which_long_opt = 0, option_index = -1;
-       struct host_info server, target;
-
-       FILE *sfp = NULL;                       /* socket to web/ftp server                     */
-       FILE *dfp = NULL;                       /* socket to ftp server (data)          */
-       char *fname_out = NULL;         /* where to direct output (-O)          */
-       int do_continue = 0;            /* continue a prev transfer (-c)        */
-       long beg_range = 0L;            /*   range at which continue begins     */
-       int got_clen = 0;                       /* got content-length: from server      */
-       FILE *output;                           /* socket to web server                         */
-       int quiet_flag = FALSE;         /* Be verry, verry quiet...                     */
-
-#define LONG_HEADER    1
-       struct option long_options[] = {
-               { "continue",           0, NULL, 'c' },
-               { "quiet",              0, NULL, 'q' },
-               { "output-document",    1, NULL, 'O' },
-               { "header",             1, &which_long_opt, LONG_HEADER },
-               { 0,                    0, 0, 0 }
-       };
-       /*
-        * Crack command line.
-        */
-       while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) {
-               switch (n) {
-               case 'c':
-                       ++do_continue;
-                       break;
-               case 'P':
-                       dir_prefix = optarg;
-                       break;
-               case 'q':
-                       quiet_flag = TRUE;
-                       break;
-               case 'O':
-                       /* can't set fname_out to NULL if outputting to stdout, because
-                        * this gets interpreted as the auto-gen output filename
-                        * case below  - tausq@debian.org
-                        */
-                       fname_out = optarg;
-                       break;
-               case 0:
-                       switch (which_long_opt) {
-                               case LONG_HEADER: {
-                                       int arglen = strlen(optarg);
-                                       if(extra_headers_left - arglen - 2 <= 0)
-                                               error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
-                                       strcpy(extra_headers_ptr, optarg);
-                                       extra_headers_ptr += arglen;
-                                       extra_headers_left -= ( arglen + 2 );
-                                       *extra_headers_ptr++ = '\r';
-                                       *extra_headers_ptr++ = '\n';
-                                       *(extra_headers_ptr + 1) = 0;
-                                       break;
-                               }
-                       }
-                       break;
-               default:
-                       show_usage();
-               }
-       }
-
-       if (argc - optind != 1)
-                       show_usage();
-
-       parse_url(argv[optind], &target);
-       server.host = target.host;
-       server.port = target.port;
-
-       /*
-        * Use the proxy if necessary.
-        */
-       proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
-       if (proxy)
-               parse_url(xstrdup(proxy), &server);
-       
-       /* Guess an output filename */
-       if (!fname_out) {
-               fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
-                       curfile = 
-#endif
-                       get_last_path_component(target.path);
-               if (fname_out==NULL || strlen(fname_out)<1) {
-                       fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
-                               curfile = 
-#endif
-                               "index.html";
-               }
-               if (dir_prefix != NULL)
-                       fname_out = concat_path_file(dir_prefix, fname_out);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       } else {
-               curfile = get_last_path_component(fname_out);
-#endif
-       }
-       if (do_continue && !fname_out)
-               error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
-
-
-       /*
-        * Open the output file stream.
-        */
-       if (strcmp(fname_out, "-") == 0) {
-               output = stdout;
-               quiet_flag = TRUE;
-       } else {
-               output = xfopen(fname_out, (do_continue ? "a" : "w"));
-       }
-
-       /*
-        * Determine where to start transfer.
-        */
-       if (do_continue) {
-               if (fstat(fileno(output), &sbuf) < 0)
-                       perror_msg_and_die("fstat()");
-               if (sbuf.st_size > 0)
-                       beg_range = sbuf.st_size;
-               else
-                       do_continue = 0;
-       }
-
-       if (proxy || !target.is_ftp) {
-               /*
-                *  HTTP session
-                */
-               do {
-                       if (! --try)
-                               close_delete_and_die("too many redirections");
-
-                       /*
-                        * Open socket to http server
-                        */
-                       if (sfp) fclose(sfp);
-                       sfp = open_socket(server.host, server.port);
-                       
-                       /*
-                        * Send HTTP request.
-                        */
-                       if (proxy) {
-                               fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n",
-                                       target.is_ftp ? "f" : "ht", target.host,
-                                       target.port, target.path);
-                       } else {
-                               fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
-                       }
-
-                       fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
-
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
-                       if (target.user) {
-                               fprintf(sfp, "Authorization: Basic %s\r\n",
-                                       base64enc(target.user, buf, sizeof(buf)));
-                       }
-                       if (proxy && server.user) {
-                               fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
-                                       base64enc(server.user, buf, sizeof(buf)));
-                       }
-#endif
-
-                       if (do_continue)
-                               fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
-                       if(extra_headers_left < sizeof(extra_headers))
-                               fputs(extra_headers,sfp);
-                       fprintf(sfp,"Connection: close\r\n\r\n");
-
-                       /*
-                       * Retrieve HTTP response line and check for "200" status code.
-                       */
-read_response:         if (fgets(buf, sizeof(buf), sfp) == NULL)
-                               close_delete_and_die("no response from server");
-                               
-                       for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
-                       ;
-                       for ( ; isspace(*s) ; ++s)
-                       ;
-                       switch (status = atoi(s)) {
-                               case 0:
-                               case 100:
-                                       while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
-                                       goto read_response;
-                               case 200:
-                                       if (do_continue && output != stdout)
-                                               output = freopen(fname_out, "w", output);
-                                       do_continue = 0;
-                                       break;
-                               case 300:       /* redirection */
-                               case 301:
-                               case 302:
-                               case 303:
-                                       break;
-                               case 206:
-                                       if (do_continue)
-                                               break;
-                                       /*FALLTHRU*/
-                               default:
-                                       chomp(buf);
-                                       close_delete_and_die("server returned error %d: %s", atoi(s), buf);
-                       }
-               
-                       /*
-                        * Retrieve HTTP headers.
-                        */
-                       while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
-                               if (strcasecmp(buf, "content-length") == 0) {
-                                       filesize = atol(s);
-                                       got_clen = 1;
-                                       continue;
-                               }
-                               if (strcasecmp(buf, "transfer-encoding") == 0) {
-                                       if (strcasecmp(s, "chunked") == 0) {
-                                               chunked = got_clen = 1;
-                                       } else {
-                                       close_delete_and_die("server wants to do %s transfer encoding", s);
-                                       }
-                               }
-                               if (strcasecmp(buf, "location") == 0) {
-                                       if (s[0] == '/')
-                                               target.path = xstrdup(s+1);
-                                       else {
-                                               parse_url(xstrdup(s), &target);
-                                               if (!proxy) {
-                                                       server.host = target.host;
-                                                       server.port = target.port;
-                                               }
-                                       }
-                               }
-                       }
-               } while(status >= 300);
-               
-               dfp = sfp;
-       }
-       else
-       {
-               /*
-                *  FTP session
-                */
-               if (! target.user)
-                       target.user = xstrdup("anonymous:busybox@");
-
-               sfp = open_socket(server.host, server.port);
-               if (ftpcmd(NULL, NULL, sfp, buf) != 220)
-                       close_delete_and_die("%s", buf+4);
-
-               /* 
-                * Splitting username:password pair,
-                * trying to log in
-                */
-               s = strchr(target.user, ':');
-               if (s)
-                       *(s++) = '\0';
-               switch(ftpcmd("USER ", target.user, sfp, buf)) {
-                       case 230:
-                               break;
-                       case 331:
-                               if (ftpcmd("PASS ", s, sfp, buf) == 230)
-                                       break;
-                               /* FALLTHRU (failed login) */
-                       default:
-                               close_delete_and_die("ftp login: %s", buf+4);
-               }
-               
-               ftpcmd("CDUP", NULL, sfp, buf);
-               ftpcmd("TYPE I", NULL, sfp, buf);
-               
-               /*
-                * Querying file size
-                */
-               if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) {
-                       filesize = atol(buf+4);
-                       got_clen = 1;
-               }
-               
-               /*
-                * Entering passive mode
-                */
-               if (ftpcmd("PASV", NULL, sfp, buf) !=  227)
-                       close_delete_and_die("PASV: %s", buf+4);
-               s = strrchr(buf, ',');
-               *s = 0;
-               port = atoi(s+1);
-               s = strrchr(buf, ',');
-               port += atoi(s+1) * 256;
-               dfp = open_socket(server.host, port);
-
-               if (do_continue) {
-                       sprintf(buf, "REST %ld", beg_range);
-                       if (ftpcmd(buf, NULL, sfp, buf) != 350) {
-                               if (output != stdout)
-                                       output = freopen(fname_out, "w", output);
-                               do_continue = 0;
-                       } else
-                               filesize -= beg_range;
-               }
-               
-               if (ftpcmd("RETR /", target.path, sfp, buf) > 150)
-                       close_delete_and_die("RETR: %s", buf+4);
-
-       }
-
-
-       /*
-        * Retrieve file
-        */
-       if (chunked) {
-               fgets(buf, sizeof(buf), dfp);
-               filesize = strtol(buf, (char **) NULL, 16);
-       }
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       if (quiet_flag==FALSE)
-               progressmeter(-1);
-#endif
-       do {
-               while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
-               safe_fwrite(buf, 1, n, output);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-               statbytes+=n;
-#endif
-               if (got_clen)
-                       filesize -= n;
-       }
-
-               if (chunked) {
-                       safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
-                       safe_fgets(buf, sizeof(buf), dfp);
-                       filesize = strtol(buf, (char **) NULL, 16);
-                       if (filesize==0) chunked = 0; /* all done! */
-               }
-
-       if (n == 0 && ferror(dfp))
-               perror_msg_and_die("network read error");
-       } while (chunked);
-#ifdef BB_FEATURE_WGET_STATUSBAR
-       if (quiet_flag==FALSE)
-               progressmeter(1);
-#endif
-       if (!proxy && target.is_ftp) {
-               fclose(dfp);
-               if (ftpcmd(NULL, NULL, sfp, buf) != 226)
-                       error_msg_and_die("ftp error: %s", buf+4);
-               ftpcmd("QUIT", NULL, sfp, buf);
-       }
-       exit(EXIT_SUCCESS);
-}
-
-
-void parse_url(char *url, struct host_info *h)
-{
-       char *cp, *sp, *up;
-
-       if (strncmp(url, "http://", 7) == 0) {
-               h->port = 80;
-               h->host = url + 7;
-               h->is_ftp = 0;
-       } else if (strncmp(url, "ftp://", 6) == 0) {
-               h->port = 21;
-               h->host = url + 6;
-               h->is_ftp = 1;
-       } else
-               error_msg_and_die("not an http or ftp url: %s", url);
-
-       sp = strchr(h->host, '/');
-       if (sp != NULL) {
-               *sp++ = '\0';
-               h->path = sp;
-       } else
-               h->path = "";
-
-       up = strrchr(h->host, '@');
-       if (up != NULL) {
-               h->user = h->host;
-               *up++ = '\0';
-               h->host = up;
-       } else
-               h->user = NULL;
-
-       cp = strchr(h->host, ':');
-       if (cp != NULL) {
-               *cp++ = '\0';
-               h->port = atoi(cp);
-       }
-
-}
-
-
-FILE *open_socket(char *host, int port)
-{
-       struct sockaddr_in s_in;
-       struct hostent *hp;
-       int fd;
-       FILE *fp;
-
-       memset(&s_in, 0, sizeof(s_in));
-       s_in.sin_family = AF_INET;
-       hp = xgethostbyname(host);
-       memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length);
-       s_in.sin_port = htons(port);
-
-       /*
-        * Get the server onto a stdio stream.
-        */
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die("socket()");
-       if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0)
-               perror_msg_and_die("connect(%s)", host);
-       if ((fp = fdopen(fd, "r+")) == NULL)
-               perror_msg_and_die("fdopen()");
-
-       return fp;
-}
-
-
-char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
-{
-       char *s, *hdrval;
-       int c;
-
-       *istrunc = 0;
-
-       /* retrieve header line */
-       if (fgets(buf, bufsiz, fp) == NULL)
-               return NULL;
-
-       /* see if we are at the end of the headers */
-       for (s = buf ; *s == '\r' ; ++s)
-               ;
-       if (s[0] == '\n')
-               return NULL;
-
-       /* convert the header name to lower case */
-       for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
-               *s = tolower(*s);
-
-       /* verify we are at the end of the header name */
-       if (*s != ':')
-               error_msg_and_die("bad header line: %s", buf);
-
-       /* locate the start of the header value */
-       for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
-               ;
-       hdrval = s;
-
-       /* locate the end of header */
-       while (*s != '\0' && *s != '\r' && *s != '\n')
-               ++s;
-
-       /* end of header found */
-       if (*s != '\0') {
-               *s = '\0';
-               return hdrval;
-       }
-
-       /* Rats!  The buffer isn't big enough to hold the entire header value. */
-       while (c = getc(fp), c != EOF && c != '\n')
-               ;
-       *istrunc = 1;
-       return hdrval;
-}
-
-static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
-{
-       char *p;
-       
-       if (s1) {
-               if (!s2) s2="";
-               fprintf(fp, "%s%s\n", s1, s2);
-               fflush(fp);
-       }
-       
-       do {
-               p = fgets(buf, 510, fp);
-               if (!p)
-                       perror_msg_and_die("fgets()");
-       } while (! isdigit(buf[0]) || buf[3] != ' ');
-       
-       return atoi(buf);
-}
-
-#ifdef BB_FEATURE_WGET_STATUSBAR
-/* Stuff below is from BSD rcp util.c, as added to openshh. 
- * Original copyright notice is retained at the end of this file.
- * 
- */ 
-
-
-static int
-getttywidth(void)
-{
-       struct winsize winsize;
-
-       if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
-               return (winsize.ws_col ? winsize.ws_col : 80);
-       else
-               return (80);
-}
-
-static void
-updateprogressmeter(int ignore)
-{
-       int save_errno = errno;
-
-       progressmeter(0);
-       errno = save_errno;
-}
-
-static void
-alarmtimer(int wait)
-{
-       struct itimerval itv;
-
-       itv.it_value.tv_sec = wait;
-       itv.it_value.tv_usec = 0;
-       itv.it_interval = itv.it_value;
-       setitimer(ITIMER_REAL, &itv, NULL);
-}
-
-
-static void
-progressmeter(int flag)
-{
-       static const char prefixes[] = " KMGTP";
-       static struct timeval lastupdate;
-       static off_t lastsize, totalsize;
-       struct timeval now, td, wait;
-       off_t cursize, abbrevsize;
-       double elapsed;
-       int ratio, barlength, i, remaining;
-       char buf[256];
-
-       if (flag == -1) {
-               (void) gettimeofday(&start, (struct timezone *) 0);
-               lastupdate = start;
-               lastsize = 0;
-               totalsize = filesize; /* as filesize changes.. */
-       }
-
-       (void) gettimeofday(&now, (struct timezone *) 0);
-       cursize = statbytes;
-       if (totalsize != 0 && !chunked) {
-               ratio = 100.0 * cursize / totalsize;
-               ratio = MAX(ratio, 0);
-               ratio = MIN(ratio, 100);
-       } else
-               ratio = 100;
-
-       snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
-
-       barlength = getttywidth() - 51;
-       if (barlength > 0) {
-               i = barlength * ratio / 100;
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "|%.*s%*s|", i,
-                        "*****************************************************************************"
-                        "*****************************************************************************",
-                        barlength - i, "");
-       }
-       i = 0;
-       abbrevsize = cursize;
-       while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
-               i++;
-               abbrevsize >>= 10;
-       }
-       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ",
-            (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
-                'B');
-
-       timersub(&now, &lastupdate, &wait);
-       if (cursize > lastsize) {
-               lastupdate = now;
-               lastsize = cursize;
-               if (wait.tv_sec >= STALLTIME) {
-                       start.tv_sec += wait.tv_sec;
-                       start.tv_usec += wait.tv_usec;
-               }
-               wait.tv_sec = 0;
-       }
-       timersub(&now, &start, &td);
-       elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
-
-       if (wait.tv_sec >= STALLTIME) {
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        " - stalled -");
-       } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) {
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "   --:-- ETA");
-       } else {
-               remaining = (int) (totalsize / (statbytes / elapsed) - elapsed);
-               i = remaining / 3600;
-               if (i)
-                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                "%2d:", i);
-               else
-                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                "   ");
-               i = remaining % 3600;
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "%02d:%02d ETA", i / 60, i % 60);
-       }
-       write(fileno(stderr), buf, strlen(buf));
-
-       if (flag == -1) {
-               struct sigaction sa;
-               sa.sa_handler = updateprogressmeter;
-               sigemptyset(&sa.sa_mask);
-               sa.sa_flags = SA_RESTART;
-               sigaction(SIGALRM, &sa, NULL);
-               alarmtimer(1);
-       } else if (flag == 1) {
-               alarmtimer(0);
-               statbytes = 0;
-               putc('\n', stderr);
-       }
-}
-#endif
-
-/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff,
- * much of which was blatently stolen from openssh.  */
-/*-
- * Copyright (c) 1992, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
- *
- * 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.
- *
- *     $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $
- */
-
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
-
-
diff --git a/busybox/which.c b/busybox/which.c
deleted file mode 100644 (file)
index c460ffd..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Which implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int which_main(int argc, char **argv)
-{
-       char *path_list, *path_n;
-       struct stat filestat;
-       int i, count=1, found, status = EXIT_SUCCESS;
-
-       if (argc <= 1 || **(argv + 1) == '-')
-               show_usage();
-       argc--;
-
-       path_list = getenv("PATH");
-       if (!path_list)
-               path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
-
-       /* Replace colons with zeros in path_parsed and count them */
-       for(i=strlen(path_list); i > 0; i--) 
-               if (path_list[i]==':') {
-                       path_list[i]=0;
-                       count++;
-               }
-
-       while(argc-- > 0) { 
-               path_n = path_list;
-               argv++;
-               found = 0;
-               for (i = 0; i < count; i++) {
-                       char *buf;
-                       buf = concat_path_file(path_n, *argv);
-                       if (stat (buf, &filestat) == 0
-                           && filestat.st_mode & S_IXUSR)
-                       {
-                               puts(buf);
-                               found = 1;
-                               break;
-                       }
-                       free(buf);
-                       path_n += (strlen(path_n) + 1);
-               }
-               if (!found)
-                       status = EXIT_FAILURE;
-       }
-       return status;
-}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/busybox/whoami.c b/busybox/whoami.c
deleted file mode 100644 (file)
index c3b1140..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini whoami implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-extern int whoami_main(int argc, char **argv)
-{
-       char user[9];
-       uid_t uid = geteuid();
-
-       if (argc > 1)
-               show_usage();
-
-       my_getpwuid(user, uid);
-       if (*user) {
-               puts(user);
-               return EXIT_SUCCESS;
-       }
-       error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
-}
diff --git a/busybox/xargs.c b/busybox/xargs.c
deleted file mode 100644 (file)
index 48adae9..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Mini xargs implementation for busybox
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * Remixed by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
-
-int xargs_main(int argc, char **argv)
-{
-       char *cmd_to_be_executed = NULL;
-       char *file_to_act_on = NULL;
-
-       /*
-        * No options are supported in this version of xargs; no getopt.
-        *
-        * Re: The missing -t flag: Most programs that produce output also print
-        * the filename, so xargs doesn't really need to do it again. Supporting
-        * the -t flag =greatly= bloats up the size of this app and the memory it
-        * uses because you have to buffer all the input file strings in memory. If
-        * you really want to see the filenames that xargs will act on, just run it
-        * once with no args and xargs will echo the filename. Simple.
-        */
-
-       /* Store the command to be executed (taken from the command line) */
-       if (argc == 1) {
-               /* default behavior is to echo all the filenames */
-               cmd_to_be_executed = xstrdup("/bin/echo ");
-       } else {
-               /* concatenate all the arguments passed to xargs together */
-               int i;
-               int len = 1; /* for the '\0' */
-               for (i = 1; i < argc; i++) {
-                       len += strlen(argv[i]);
-                       len += 1;  /* for the space between the args */
-                       cmd_to_be_executed = xrealloc(cmd_to_be_executed, len);
-                       strcat(cmd_to_be_executed, argv[i]);
-                       strcat(cmd_to_be_executed, " ");
-               }
-       }
-
-       /* Now, read in one line at a time from stdin, and store this 
-        * line to be used later as an argument to the command */
-       while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) {
-
-               FILE *cmd_output = NULL;
-               char *output_line = NULL;
-               char *execstr = NULL;
-
-               /* eat the newline off the filename. */
-               chomp(file_to_act_on);
-
-               /* eat blank lines */
-               if (strlen(file_to_act_on) == 0)
-                       continue;
-
-               /* assemble the command and execute it */
-               execstr = xcalloc(strlen(cmd_to_be_executed) +
-                               strlen(file_to_act_on) + 1, sizeof(char));
-               strcat(execstr, cmd_to_be_executed);
-               strcat(execstr, file_to_act_on);
-               cmd_output = popen(execstr, "r");
-               if (cmd_output == NULL)
-                       perror_msg_and_die("popen");
-
-               /* harvest the output */
-               while ((output_line = get_line_from_file(cmd_output)) != NULL) {
-                       fputs(output_line, stdout);
-                       free(output_line);
-               }
-
-               /* clean up */
-               pclose(cmd_output);
-               free(execstr);
-               free(file_to_act_on);
-       }
-
-#ifdef BB_FEATURE_CLEAN_UP
-       free(cmd_to_be_executed);
-#endif
-
-       return 0;
-}
-
-/* vi: set sw=4 ts=4: */
diff --git a/busybox/yes.c b/busybox/yes.c
deleted file mode 100644 (file)
index 7d9596d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini yes implementation for busybox
- *
- * Copyright (C) 2000  Edward Betts <edward@debian.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* getopt not needed */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-extern int yes_main(int argc, char **argv)
-{
-       int i;
-
-       if (argc >= 2 && *argv[1] == '-')
-               show_usage();
-
-       if (argc == 1) {
-               while (1)
-                       if (puts("y") == EOF) {
-                               perror("yes");
-                               return EXIT_FAILURE;
-                       }
-       }
-
-       while (1)
-               for (i = 1; i < argc; i++)
-                       if (fputs(argv[i], stdout) == EOF
-                               || putchar(i == argc - 1 ? '\n' : ' ') == EOF) {
-                               perror("yes");
-                               return EXIT_FAILURE;
-                       }
-
-       return EXIT_SUCCESS;
-}
diff --git a/cat.c b/cat.c
new file mode 100644 (file)
index 0000000..820b634
--- /dev/null
+++ b/cat.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini Cat implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "busybox.h"
+
+extern int cat_main(int argc, char **argv)
+{
+       int status = EXIT_SUCCESS;
+
+       if (argc == 1) {
+               print_file(stdin);
+               return status;
+       }
+
+       while (--argc > 0) {
+               if(!(strcmp(*++argv, "-"))) {
+                       print_file(stdin);
+               } else if (print_file_by_name(*argv) == FALSE) {
+                       status = EXIT_FAILURE;
+               }
+       }
+       return status;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chgrp.c b/chgrp.c
new file mode 100644 (file)
index 0000000..b8ec8fd
--- /dev/null
+++ b/chgrp.c
@@ -0,0 +1,91 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chown/chmod/chgrp implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+/* Don't use lchown for libc5 or glibc older then 2.1.x */
+#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
+#define lchown chown
+#endif
+
+
+static long gid;
+
+static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+       if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
+               return (TRUE);
+       }
+       perror(fileName);
+       return (FALSE);
+}
+
+int chgrp_main(int argc, char **argv)
+{
+       int opt;
+       int recursiveFlag = FALSE;
+       char *p=NULL;
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "R")) > 0) {
+               switch (opt) {
+                       case 'R':
+                               recursiveFlag = TRUE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (argc > optind && argc > 2 && argv[optind]) {
+               /* Find the selected group */
+               gid = strtoul(argv[optind], &p, 10);    /* maybe it's already numeric */
+               if (argv[optind] == p)
+                       gid = my_getgrnam(argv[optind]);
+       } else {
+               error_msg_and_die(too_few_args);
+       }
+
+       /* Ok, ready to do the deed now */
+       while (++optind < argc) {
+               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
+                                       fileAction, fileAction, NULL) == FALSE) {
+                       return EXIT_FAILURE;
+               }
+       }
+       return EXIT_SUCCESS;
+
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chmod.c b/chmod.c
new file mode 100644 (file)
index 0000000..1d3f33b
--- /dev/null
+++ b/chmod.c
@@ -0,0 +1,97 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chown/chmod/chgrp implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "busybox.h"
+
+static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+       if (!parse_mode((char *)junk, &(statbuf->st_mode)))
+               error_msg_and_die("internal error");
+       if (chmod(fileName, statbuf->st_mode) == 0)
+               return (TRUE);
+       perror(fileName);
+       return (FALSE);
+}
+
+int chmod_main(int argc, char **argv)
+{
+       int i;
+       int opt;
+       int recursiveFlag = FALSE;
+       int opt_eq_modeFlag = FALSE;
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "Rrwxst")) > 0) {
+               switch (opt) {
+                       case 'R':
+                               recursiveFlag = TRUE;
+                               break;
+                       case 'r':
+                       case 'w':
+                       case 'x':
+                       case 's':
+                       case 't': 
+                               opt_eq_modeFlag = TRUE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (opt_eq_modeFlag == TRUE) {          
+               optind--;
+       }
+
+       if (argc > optind && argc > 2 && argv[optind]) {
+               /* Parse the specified mode */
+               mode_t mode;
+               if (parse_mode(argv[optind], &mode) == FALSE) {
+                       error_msg_and_die( "unknown mode: %s", argv[optind]);
+               }
+       } else {
+               error_msg_and_die(too_few_args);
+       }
+
+       /* Ok, ready to do the deed now */
+       for (i = optind + 1; i < argc; i++) {
+               if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction,
+                                       fileAction, argv[optind]) == FALSE) {
+                       return EXIT_FAILURE;
+               }
+       }
+       return EXIT_SUCCESS;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chown.c b/chown.c
new file mode 100644 (file)
index 0000000..ae41ec0
--- /dev/null
+++ b/chown.c
@@ -0,0 +1,113 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chown/chmod/chgrp implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+/* Don't use lchown for libc5 or glibc older then 2.1.x */
+#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
+#define lchown chown
+#endif
+
+static long uid;
+static long gid;
+
+static int (*chown_func)(const char *, __uid_t, __gid_t) = chown;
+
+static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+       if (chown_func(fileName, uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
+               return (TRUE);
+       }
+       perror(fileName);
+       return (FALSE);
+}
+
+int chown_main(int argc, char **argv)
+{
+       int opt;
+       int recursiveFlag = FALSE,
+               noderefFlag = FALSE;
+       char *groupName=NULL;
+       char *p=NULL;
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "Rh")) > 0) {
+               switch (opt) {
+                       case 'R':
+                               recursiveFlag = TRUE;
+                               break;
+                       case 'h':
+                               noderefFlag = TRUE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (noderefFlag) chown_func = lchown;
+
+       if (argc > optind && argc > 2 && argv[optind]) {
+               /* First, check if there is a group name here */
+               groupName = strchr(argv[optind], '.');
+               if (groupName == NULL)
+                       groupName = strchr(argv[optind], ':');
+               if (groupName) {
+                       *groupName++ = '\0';
+                       gid = strtoul(groupName, &p, 10);
+                       if (groupName == p)
+                               gid = my_getgrnam(groupName);
+               } else {
+                       gid = -1;
+               }
+               /* Now check for the username */
+               uid = strtoul(argv[optind], &p, 10);    /* Is is numeric? */
+               if (argv[optind] == p) {
+                       uid = my_getpwnam(argv[optind]);
+               }
+       } else {
+               error_msg_and_die(too_few_args);
+       }
+
+       /* Ok, ready to do the deed now */
+       while (++optind < argc) {
+               if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, 
+                                       fileAction, fileAction, NULL) == FALSE) {
+                       return EXIT_FAILURE;
+               }
+       }
+       return EXIT_SUCCESS;
+
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chroot.c b/chroot.c
new file mode 100644 (file)
index 0000000..338d9f4
--- /dev/null
+++ b/chroot.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini chroot implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include "busybox.h"
+
+int chroot_main(int argc, char **argv)
+{
+       char *prog;
+
+       if ((argc < 2) || (**(argv + 1) == '-')) {
+               show_usage();
+       }
+       argc--;
+       argv++;
+
+       if (chroot(*argv) || (chdir("/"))) {
+               perror_msg_and_die("cannot change root directory to %s", *argv);
+       }
+
+       argc--;
+       argv++;
+       if (argc >= 1) {
+               prog = *argv;
+               execvp(*argv, argv);
+       } else {
+#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL
+               char shell[] = "/bin/sh";
+               char *shell_argv[2] = { shell, NULL };
+               applet_name = shell;
+               shell_main(1, shell_argv);
+               return EXIT_SUCCESS;
+#else
+               prog = getenv("SHELL");
+               if (!prog)
+                       prog = "/bin/sh";
+               execlp(prog, prog, NULL);
+#endif
+       }
+       perror_msg_and_die("cannot execute %s", prog);
+
+}
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chvt.c b/chvt.c
new file mode 100644 (file)
index 0000000..8136f1c
--- /dev/null
+++ b/chvt.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * chvt.c - aeb - 940227 - Change virtual terminal
+ *
+ * busyboxed by Erik Andersen
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+/* From <linux/vt.h> */
+static const int VT_ACTIVATE = 0x5606;  /* make vt active */
+static const int VT_WAITACTIVE = 0x5607;  /* wait for vt active */
+
+int chvt_main(int argc, char **argv)
+{
+       int fd, num;
+
+       if ((argc != 2) || (**(argv + 1) == '-'))
+               show_usage();
+       fd = get_console_fd();
+       num = atoi(argv[1]);
+       if (ioctl(fd, VT_ACTIVATE, num))
+               perror_msg_and_die("VT_ACTIVATE");
+       if (ioctl(fd, VT_WAITACTIVE, num))
+               perror_msg_and_die("VT_WAITACTIVE");
+       return EXIT_SUCCESS;
+}
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/clear.c b/clear.c
new file mode 100644 (file)
index 0000000..ac32c32
--- /dev/null
+++ b/clear.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini clear implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+
+extern int clear_main(int argc, char **argv)
+{
+       printf("\033[H\033[J");
+       return EXIT_SUCCESS;
+}
diff --git a/cmdedit.c b/cmdedit.c
new file mode 100644 (file)
index 0000000..d0dff11
--- /dev/null
+++ b/cmdedit.c
@@ -0,0 +1,1657 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Termios command line History and Editting.
+ *
+ * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
+ * Written by:   Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Used ideas:
+ *      Adam Rogoyski    <rogoyski@cs.utexas.edu>
+ *      Dave Cinege      <dcinege@psychosis.com>
+ *      Jakub Jelinek (c) 1995
+ *      Erik Andersen    <andersen@codepoet.org> (Majorly adjusted for busybox)
+ *
+ * This code is 'as is' with no warranty.
+ *
+ *
+ */
+
+/*
+   Usage and Known bugs:
+   Terminal key codes are not extensive, and more will probably
+   need to be added. This version was created on Debian GNU/Linux 2.x.
+   Delete, Backspace, Home, End, and the arrow keys were tested
+   to work in an Xterm and console. Ctrl-A also works as Home.
+   Ctrl-E also works as End.
+
+   Small bugs (simple effect):
+   - not true viewing if terminal size (x*y symbols) less
+     size (prompt + editor`s line + 2 symbols)
+   - not true viewing if length prompt less terminal width
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <signal.h>
+#include <limits.h>
+
+#include "busybox.h"
+
+
+#define BB_FEATURE_COMMAND_SAVEHISTORY
+#define BB_FEATURE_COMMAND_HISTORY     15
+
+
+#ifdef BB_LOCALE_SUPPORT
+#define Isprint(c) isprint((c))
+#else
+#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
+#endif
+
+#ifndef TEST
+#define D(x)
+#else
+/* pretect redefined for test */
+#define BB_FEATURE_COMMAND_EDITING
+#define BB_FEATURE_COMMAND_TAB_COMPLETION
+#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#define BB_FEATURE_CLEAN_UP
+#define D(x)  x
+#endif /* TEST */
+
+#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#include <dirent.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef BB_FEATURE_COMMAND_EDITING
+
+#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION
+#undef  BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#endif
+
+#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT)
+#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#endif
+
+#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#       ifndef TEST
+#               include "pwd_grp/pwd.h"
+#       else
+#               include <pwd.h>
+#       endif  /* TEST */
+#endif                                                  /* advanced FEATURES */
+
+
+/* Maximum length of the linked list for the command line history */
+#ifndef BB_FEATURE_COMMAND_HISTORY
+#define MAX_HISTORY   15
+#else
+#define MAX_HISTORY   BB_FEATURE_COMMAND_HISTORY
+#endif
+
+#if MAX_HISTORY < 1
+#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off.
+#else
+static char *history[MAX_HISTORY+1]; /* history + current */
+/* saved history lines */
+static int n_history;
+/* current pointer to history line */
+static int cur_history;
+#endif
+
+#include <termios.h>
+#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
+#define getTermSettings(fd,argp) tcgetattr(fd, argp);
+
+/* Current termio and the previous termio before starting sh */
+static struct termios initial_settings, new_settings;
+
+
+static
+volatile int cmdedit_termw = 80;        /* actual terminal width */
+static
+volatile int handlers_sets = 0; /* Set next bites: */
+
+enum {
+       SET_ATEXIT = 1,         /* when atexit() has been called
+                                  and get euid,uid,gid to fast compare */
+       SET_WCHG_HANDLERS = 2,  /* winchg signal handler */
+       SET_RESET_TERM = 4,     /* if the terminal needs to be reset upon exit */
+};
+
+
+static int cmdedit_x;           /* real x terminal position */
+static int cmdedit_y;           /* pseudoreal y terminal position */
+static int cmdedit_prmt_len;    /* lenght prompt without colores string */
+
+static int cursor;              /* required global for signal handler */
+static int len;                 /* --- "" - - "" - -"- --""-- --""--- */
+static char *command_ps;        /* --- "" - - "" - -"- --""-- --""--- */
+static
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       const
+#endif
+char *cmdedit_prompt;           /* --- "" - - "" - -"- --""-- --""--- */
+
+#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+static char *user_buf = "";
+static char *home_pwd_buf = "";
+static int my_euid;
+#endif
+
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+static char *hostname_buf;
+static int num_ok_lines = 1;
+#endif
+
+
+#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
+
+#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+static int my_euid;
+#endif
+
+static int my_uid;
+static int my_gid;
+
+#endif  /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+
+static void cmdedit_setwidth(int w, int redraw_flg);
+
+/* It is perfectly ok to pass in a NULL for either width or for
+ * height, in which case that value will not be set.  It is also
+ * perfectly ok to have CONFIG_FEATURE_AUTOWIDTH disabled, in 
+ * which case you will always get 80x24 */
+void get_terminal_width_height(int fd, int *width, int *height)
+{
+       struct winsize win = { 0, 0, 0, 0 };
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+       if (ioctl(0, TIOCGWINSZ, &win) != 0) {
+               win.ws_row = 24;
+               win.ws_col = 80;
+       }
+#endif
+       if (win.ws_row <= 1) {
+               win.ws_row = 24;
+       }
+       if (win.ws_col <= 1) {
+               win.ws_col = 80;
+       }
+       if (height) {
+               *height = (int) win.ws_row;
+       }
+       if (width) {
+               *width = (int) win.ws_col;
+       }
+}
+
+static void win_changed(int nsig)
+{
+       static sighandler_t previous_SIGWINCH_handler;  /* for reset */
+
+       /*   emulate      || signal call */
+       if (nsig == -SIGWINCH || nsig == SIGWINCH) {
+               int width = 0;
+               get_terminal_width_height(0, &width, NULL);
+               cmdedit_setwidth(width, nsig == SIGWINCH);
+       }
+       /* Unix not all standart in recall signal */
+
+       if (nsig == -SIGWINCH)          /* save previous handler   */
+               previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
+       else if (nsig == SIGWINCH)      /* signaled called handler */
+               signal(SIGWINCH, win_changed);  /* set for next call       */
+       else                                            /* nsig == 0 */
+               /* set previous handler    */
+               signal(SIGWINCH, previous_SIGWINCH_handler);    /* reset    */
+}
+
+static void cmdedit_reset_term(void)
+{
+       if ((handlers_sets & SET_RESET_TERM) != 0) {
+/* sparc and other have broken termios support: use old termio handling. */
+               setTermSettings(fileno(stdin), (void *) &initial_settings);
+               handlers_sets &= ~SET_RESET_TERM;
+       }
+       if ((handlers_sets & SET_WCHG_HANDLERS) != 0) {
+               /* reset SIGWINCH handler to previous (default) */
+               win_changed(0);
+               handlers_sets &= ~SET_WCHG_HANDLERS;
+       }
+       fflush(stdout);
+}
+
+
+/* special for recount position for scroll and remove terminal margin effect */
+static void cmdedit_set_out_char(int next_char)
+{
+
+       int c = (int)((unsigned char) command_ps[cursor]);
+
+       if (c == 0)
+               c = ' ';        /* destroy end char? */
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+       if (!Isprint(c)) {      /* Inverse put non-printable characters */
+               if (c >= 128)
+                       c -= 128;
+               if (c < ' ')
+                       c += '@';
+               if (c == 127)
+                       c = '?';
+               printf("\033[7m%c\033[0m", c);
+       } else
+#endif
+               putchar(c);
+       if (++cmdedit_x >= cmdedit_termw) {
+               /* terminal is scrolled down */
+               cmdedit_y++;
+               cmdedit_x = 0;
+
+               if (!next_char)
+                       next_char = ' ';
+               /* destroy "(auto)margin" */
+               putchar(next_char);
+               putchar('\b');
+       }
+       cursor++;
+}
+
+/* Move to end line. Bonus: rewrite line from cursor */
+static void input_end(void)
+{
+       while (cursor < len)
+               cmdedit_set_out_char(0);
+}
+
+/* Go to the next line */
+static void goto_new_line(void)
+{
+       input_end();
+       if (cmdedit_x)
+               putchar('\n');
+}
+
+
+static inline void out1str(const char *s)
+{
+       if ( s )
+               fputs(s, stdout);
+}
+
+static inline void beep(void)
+{
+       putchar('\007');
+}
+
+/* Move back one charactor */
+/* special for slow terminal */
+static void input_backward(int num)
+{
+       if (num > cursor)
+               num = cursor;
+       cursor -= num;          /* new cursor (in command, not terminal) */
+
+       if (cmdedit_x >= num) {         /* no to up line */
+               cmdedit_x -= num;
+               if (num < 4)
+                       while (num-- > 0)
+                               putchar('\b');
+
+               else
+                       printf("\033[%dD", num);
+       } else {
+               int count_y;
+
+               if (cmdedit_x) {
+                       putchar('\r');          /* back to first terminal pos.  */
+                       num -= cmdedit_x;       /* set previous backward        */
+               }
+               count_y = 1 + num / cmdedit_termw;
+               printf("\033[%dA", count_y);
+               cmdedit_y -= count_y;
+               /*  require  forward  after  uping   */
+               cmdedit_x = cmdedit_termw * count_y - num;
+               printf("\033[%dC", cmdedit_x);  /* set term cursor   */
+       }
+}
+
+static void put_prompt(void)
+{
+       out1str(cmdedit_prompt);
+       cmdedit_x = cmdedit_prmt_len;   /* count real x terminal position */
+       cursor = 0;
+       cmdedit_y = 0;                  /* new quasireal y */
+}
+
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+static void parse_prompt(const char *prmt_ptr)
+{
+       cmdedit_prompt = prmt_ptr;
+       cmdedit_prmt_len = strlen(prmt_ptr);
+       put_prompt();
+}
+#else
+char bb_process_escape_sequence(const char **ptr)
+{
+       static const char charmap[] = {
+               'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
+               '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
+
+       const char *p;
+       const char *q;
+       unsigned int num_digits;
+       unsigned int r;
+       unsigned int n;
+       
+       n = 0;
+       q = *ptr;
+
+       num_digits = 0;
+       do {
+               if (((unsigned int)(*q - '0')) <= 7) {
+                       r = n * 8 + (*q - '0');
+                       if (r <= UCHAR_MAX) {
+                               n = r;
+                               ++q;
+                               if (++num_digits < 3) {
+                                       continue;
+                               }
+                       }
+               }
+               break;
+       } while (1);
+
+       if (num_digits == 0) {  /* mnemonic escape sequence? */
+               p = charmap;
+               do {
+                       if (*p == *q) {
+                               q++;
+                               break;
+                       }
+               } while (*++p);
+               n = *(p+(sizeof(charmap)/2));
+       }
+
+       *ptr = q;
+       return (char) n;
+}
+
+static void parse_prompt(const char *prmt_ptr)
+{
+       int prmt_len = 0;
+       int sub_len = 0;
+       char  flg_not_length = '[';
+       char *prmt_mem_ptr = xcalloc(1, 1);
+       char *pwd_buf = xgetcwd(0);
+       char  buf2[PATH_MAX + 1];
+       char  buf[2];
+       char  c;
+       char *pbuf;
+
+       if (!pwd_buf) {
+               pwd_buf=(char *)unknown;
+       }
+
+       while (*prmt_ptr) {
+               pbuf    = buf;
+               pbuf[1] = 0;
+               c = *prmt_ptr++;
+               if (c == '\\') {
+                       const char *cp = prmt_ptr;
+                       int l;
+
+                       c = bb_process_escape_sequence(&prmt_ptr);
+                       if(prmt_ptr==cp) {
+                         if (*cp == 0)
+                               break;
+                         c = *prmt_ptr++;
+                         switch (c) {
+#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+                         case 'u':
+                               pbuf = user_buf;
+                               break;
+#endif
+                         case 'h':
+                               pbuf = hostname_buf;
+                               if (pbuf == 0) {
+                                       pbuf = xcalloc(256, 1);
+                                       if (gethostname(pbuf, 255) < 0) {
+                                               strcpy(pbuf, "?");
+                                       } else {
+                                               char *s = strchr(pbuf, '.');
+
+                                               if (s)
+                                                       *s = 0;
+                                       }
+                                       hostname_buf = pbuf;
+                               }
+                               break;
+                         case '$':
+                               c = my_euid == 0 ? '#' : '$';
+                               break;
+#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+                         case 'w':
+                               pbuf = pwd_buf;
+                               l = strlen(home_pwd_buf);
+                               if (home_pwd_buf[0] != 0 &&
+                                   strncmp(home_pwd_buf, pbuf, l) == 0 &&
+                                   (pbuf[l]=='/' || pbuf[l]=='\0') &&
+                                   strlen(pwd_buf+l)<PATH_MAX) {
+                                       pbuf = buf2;
+                                       *pbuf = '~';
+                                       strcpy(pbuf+1, pwd_buf+l);
+                                       }
+                               break;
+#endif
+                         case 'W':
+                               pbuf = pwd_buf;
+                               cp = strrchr(pbuf,'/');
+                               if ( (cp != NULL) && (cp != pbuf) )
+                                       pbuf += (cp-pbuf)+1;
+                               break;
+                         case '!':
+                               snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
+                               break;
+                         case 'e': case 'E':     /* \e \E = \033 */
+                               c = '\033';
+                               break;
+                         case 'x': case 'X':
+                               for (l = 0; l < 3;) {
+                                       int h;
+                                       buf2[l++] = *prmt_ptr;
+                                       buf2[l] = 0;
+                                       h = strtol(buf2, &pbuf, 16);
+                                       if (h > UCHAR_MAX || (pbuf - buf2) < l) {
+                                               l--;
+                                               break;
+                                       }
+                                       prmt_ptr++;
+                               }
+                               buf2[l] = 0;
+                               c = (char)strtol(buf2, 0, 16);
+                               if(c==0)
+                                       c = '?';
+                               pbuf = buf;
+                               break;
+                         case '[': case ']':
+                               if (c == flg_not_length) {
+                                       flg_not_length = flg_not_length == '[' ? ']' : '[';
+                                       continue;
+                               }
+                               break;
+                         }
+                       }
+               }
+               if(pbuf == buf)
+                       *pbuf = c;
+               prmt_len += strlen(pbuf);
+               prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
+               if (flg_not_length == ']')
+                       sub_len++;
+       }
+       if(pwd_buf!=(char *)unknown)
+               free(pwd_buf);
+       cmdedit_prompt = prmt_mem_ptr;
+       cmdedit_prmt_len = prmt_len - sub_len;
+       put_prompt();
+}
+#endif
+
+
+/* draw promt, editor line, and clear tail */
+static void redraw(int y, int back_cursor)
+{
+       if (y > 0)                              /* up to start y */
+               printf("\033[%dA", y);
+       putchar('\r');
+       put_prompt();
+       input_end();                            /* rewrite */
+       printf("\033[J");                       /* destroy tail after cursor */
+       input_backward(back_cursor);
+}
+
+/* Delete the char in front of the cursor */
+static void input_delete(void)
+{
+       int j = cursor;
+
+       if (j == len)
+               return;
+
+       strcpy(command_ps + j, command_ps + j + 1);
+       len--;
+       input_end();                    /* rewtite new line */
+       cmdedit_set_out_char(0);        /* destroy end char */
+       input_backward(cursor - j);     /* back to old pos cursor */
+}
+
+/* Delete the char in back of the cursor */
+static void input_backspace(void)
+{
+       if (cursor > 0) {
+               input_backward(1);
+               input_delete();
+       }
+}
+
+
+/* Move forward one charactor */
+static void input_forward(void)
+{
+       if (cursor < len)
+               cmdedit_set_out_char(command_ps[cursor + 1]);
+}
+
+
+static void cmdedit_setwidth(int w, int redraw_flg)
+{
+       cmdedit_termw = cmdedit_prmt_len + 2;
+       if (w <= cmdedit_termw) {
+               cmdedit_termw = cmdedit_termw % w;
+       }
+       if (w > cmdedit_termw) {
+               cmdedit_termw = w;
+
+               if (redraw_flg) {
+                       /* new y for current cursor */
+                       int new_y = (cursor + cmdedit_prmt_len) / w;
+
+                       /* redraw */
+                       redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
+                       fflush(stdout);
+               }
+       }
+}
+
+static void cmdedit_init(void)
+{
+       cmdedit_prmt_len = 0;
+       if ((handlers_sets & SET_WCHG_HANDLERS) == 0) {
+               /* emulate usage handler to set handler and call yours work */
+               win_changed(-SIGWINCH);
+               handlers_sets |= SET_WCHG_HANDLERS;
+       }
+
+       if ((handlers_sets & SET_ATEXIT) == 0) {
+#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+               struct passwd *entry;
+
+               my_euid = geteuid();
+               entry = getpwuid(my_euid);
+               if (entry) {
+                       user_buf = xstrdup(entry->pw_name);
+                       home_pwd_buf = xstrdup(entry->pw_dir);
+               }
+#endif
+
+#ifdef  BB_FEATURE_COMMAND_TAB_COMPLETION
+
+#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+               my_euid = geteuid();
+#endif
+               my_uid = getuid();
+               my_gid = getgid();
+#endif  /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+               handlers_sets |= SET_ATEXIT;
+               atexit(cmdedit_reset_term);     /* be sure to do this only once */
+       }
+}
+
+#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+
+static int is_execute(const struct stat *st)
+{
+       if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) ||
+               (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) ||
+               (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) ||
+               (st->st_mode & S_IXOTH)) return TRUE;
+       return FALSE;
+}
+
+#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+
+void bb_xasprintf(char **string_ptr, const char *format, ...)
+{
+       va_list p;
+       int r;
+       
+       va_start(p, format);
+       r = vasprintf(string_ptr, format, p);
+       va_end(p);
+
+       if (r < 0) {
+               perror_msg_and_die("bb_xasprintf");
+       }
+}
+
+static char **username_tab_completion(char *ud, int *num_matches)
+{
+       struct passwd *entry;
+       int userlen;
+       char *temp;
+
+
+       ud++;                           /* ~user/... to user/... */
+       userlen = strlen(ud);
+
+       if (num_matches == 0) {         /* "~/..." or "~user/..." */
+               char *sav_ud = ud - 1;
+               char *home = 0;
+
+               if (*ud == '/') {       /* "~/..."     */
+                       home = home_pwd_buf;
+               } else {
+                       /* "~user/..." */
+                       temp = strchr(ud, '/');
+                       *temp = 0;              /* ~user\0 */
+                       entry = getpwnam(ud);
+                       *temp = '/';            /* restore ~user/... */
+                       ud = temp;
+                       if (entry)
+                               home = entry->pw_dir;
+               }
+               if (home) {
+                       if ((userlen + strlen(home) + 1) < BUFSIZ) {
+                               char temp2[BUFSIZ];     /* argument size */
+
+                               /* /home/user/... */
+                               sprintf(temp2, "%s%s", home, ud);
+                               strcpy(sav_ud, temp2);
+                       }
+               }
+               return 0;       /* void, result save to argument :-) */
+       } else {
+               /* "~[^/]*" */
+               char **matches = (char **) NULL;
+               int nm = 0;
+
+               setpwent();
+
+               while ((entry = getpwent()) != NULL) {
+                       /* Null usernames should result in all users as possible completions. */
+                       if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
+
+                              bb_xasprintf(&temp, "~%s/", entry->pw_name);
+                               matches = xrealloc(matches, (nm + 1) * sizeof(char *));
+
+                               matches[nm++] = temp;
+                       }
+               }
+
+               endpwent();
+               (*num_matches) = nm;
+               return (matches);
+       }
+}
+#endif  /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */
+
+enum {
+       FIND_EXE_ONLY = 0,
+       FIND_DIR_ONLY = 1,
+       FIND_FILE_ONLY = 2,
+};
+
+static int path_parse(char ***p, int flags)
+{
+       int npth;
+       char *tmp;
+       char *pth;
+
+       /* if not setenv PATH variable, to search cur dir "." */
+       if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 ||
+               /* PATH=<empty> or PATH=:<empty> */
+               *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
+               return 1;
+       }
+
+       tmp = pth;
+       npth = 0;
+
+       for (;;) {
+               npth++;                 /* count words is + 1 count ':' */
+               tmp = strchr(tmp, ':');
+               if (tmp) {
+                       if (*++tmp == 0)
+                               break;  /* :<empty> */
+               } else
+                       break;
+       }
+
+       *p = xmalloc(npth * sizeof(char *));
+
+       tmp = pth;
+       (*p)[0] = xstrdup(tmp);
+       npth = 1;                       /* count words is + 1 count ':' */
+
+       for (;;) {
+               tmp = strchr(tmp, ':');
+               if (tmp) {
+                       (*p)[0][(tmp - pth)] = 0;       /* ':' -> '\0' */
+                       if (*++tmp == 0)
+                               break;                  /* :<empty> */
+               } else
+                       break;
+               (*p)[npth++] = &(*p)[0][(tmp - pth)];   /* p[next]=p[0][&'\0'+1] */
+       }
+
+       return npth;
+}
+
+static char *add_quote_for_spec_chars(char *found)
+{
+       int l = 0;
+       char *s = xmalloc((strlen(found) + 1) * 2);
+
+       while (*found) {
+               if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
+                       s[l++] = '\\';
+               s[l++] = *found++;
+       }
+       s[l] = 0;
+       return s;
+}
+
+static char **exe_n_cwd_tab_completion(char *command, int *num_matches,
+                                       int type)
+{
+
+       char **matches = 0;
+       DIR *dir;
+       struct dirent *next;
+       char dirbuf[BUFSIZ];
+       int nm = *num_matches;
+       struct stat st;
+       char *path1[1];
+       char **paths = path1;
+       int npaths;
+       int i;
+       char *found;
+       char *pfind = strrchr(command, '/');
+
+       path1[0] = ".";
+
+       if (pfind == NULL) {
+               /* no dir, if flags==EXE_ONLY - get paths, else "." */
+               npaths = path_parse(&paths, type);
+               pfind = command;
+       } else {
+               /* with dir */
+               /* save for change */
+               strcpy(dirbuf, command);
+               /* set dir only */
+               dirbuf[(pfind - command) + 1] = 0;
+#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               if (dirbuf[0] == '~')   /* ~/... or ~user/... */
+                       username_tab_completion(dirbuf, 0);
+#endif
+               /* "strip" dirname in command */
+               pfind++;
+
+               paths[0] = dirbuf;
+               npaths = 1;                             /* only 1 dir */
+       }
+
+       for (i = 0; i < npaths; i++) {
+
+               dir = opendir(paths[i]);
+               if (!dir)                       /* Don't print an error */
+                       continue;
+
+               while ((next = readdir(dir)) != NULL) {
+                       char *str_found = next->d_name;
+
+                       /* matched ? */
+                       if (strncmp(str_found, pfind, strlen(pfind)))
+                               continue;
+                       /* not see .name without .match */
+                       if (*str_found == '.' && *pfind == 0) {
+                               if (*paths[i] == '/' && paths[i][1] == 0
+                                       && str_found[1] == 0) str_found = "";   /* only "/" */
+                               else
+                                       continue;
+                       }
+                       found = concat_path_file(paths[i], str_found);
+                       /* hmm, remover in progress? */
+                       if (stat(found, &st) < 0)
+                               goto cont;
+                       /* find with dirs ? */
+                       if (paths[i] != dirbuf)
+                               strcpy(found, next->d_name);    /* only name */
+                       if (S_ISDIR(st.st_mode)) {
+                               /* name is directory      */
+                               str_found = found;
+                               found = concat_path_file(found, "");
+                               free(str_found);
+                               str_found = add_quote_for_spec_chars(found);
+                       } else {
+                               /* not put found file if search only dirs for cd */
+                               if (type == FIND_DIR_ONLY)
+                                       goto cont;
+                               str_found = add_quote_for_spec_chars(found);
+                               if (type == FIND_FILE_ONLY ||
+                                       (type == FIND_EXE_ONLY && is_execute(&st)))
+                                       strcat(str_found, " ");
+                       }
+                       /* Add it to the list */
+                       matches = xrealloc(matches, (nm + 1) * sizeof(char *));
+
+                       matches[nm++] = str_found;
+cont:
+                       free(found);
+               }
+               closedir(dir);
+       }
+       if (paths != path1) {
+               free(paths[0]);                 /* allocated memory only in first member */
+               free(paths);
+       }
+       *num_matches = nm;
+       return (matches);
+}
+
+static int match_compare(const void *a, const void *b)
+{
+       return strcmp(*(char **) a, *(char **) b);
+}
+
+
+
+#define QUOT    (UCHAR_MAX+1)
+
+#define collapse_pos(is, in) { \
+       memcpy(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
+       memcpy(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); }
+
+static int find_match(char *matchBuf, int *len_with_quotes)
+{
+       int i, j;
+       int command_mode;
+       int c, c2;
+       int int_buf[BUFSIZ + 1];
+       int pos_buf[BUFSIZ + 1];
+
+       /* set to integer dimension characters and own positions */
+       for (i = 0;; i++) {
+               int_buf[i] = (int) ((unsigned char) matchBuf[i]);
+               if (int_buf[i] == 0) {
+                       pos_buf[i] = -1;        /* indicator end line */
+                       break;
+               } else
+                       pos_buf[i] = i;
+       }
+
+       /* mask \+symbol and convert '\t' to ' ' */
+       for (i = j = 0; matchBuf[i]; i++, j++)
+               if (matchBuf[i] == '\\') {
+                       collapse_pos(j, j + 1);
+                       int_buf[j] |= QUOT;
+                       i++;
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+                       if (matchBuf[i] == '\t')        /* algorithm equivalent */
+                               int_buf[j] = ' ' | QUOT;
+#endif
+               }
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+               else if (matchBuf[i] == '\t')
+                       int_buf[j] = ' ';
+#endif
+
+       /* mask "symbols" or 'symbols' */
+       c2 = 0;
+       for (i = 0; int_buf[i]; i++) {
+               c = int_buf[i];
+               if (c == '\'' || c == '"') {
+                       if (c2 == 0)
+                               c2 = c;
+                       else {
+                               if (c == c2)
+                                       c2 = 0;
+                               else
+                                       int_buf[i] |= QUOT;
+                       }
+               } else if (c2 != 0 && c != '$')
+                       int_buf[i] |= QUOT;
+       }
+
+       /* skip commands with arguments if line have commands delimiters */
+       /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
+       for (i = 0; int_buf[i]; i++) {
+               c = int_buf[i];
+               c2 = int_buf[i + 1];
+               j = i ? int_buf[i - 1] : -1;
+               command_mode = 0;
+               if (c == ';' || c == '&' || c == '|') {
+                       command_mode = 1 + (c == c2);
+                       if (c == '&') {
+                               if (j == '>' || j == '<')
+                                       command_mode = 0;
+                       } else if (c == '|' && j == '>')
+                               command_mode = 0;
+               }
+               if (command_mode) {
+                       collapse_pos(0, i + command_mode);
+                       i = -1;                         /* hack incremet */
+               }
+       }
+       /* collapse `command...` */
+       for (i = 0; int_buf[i]; i++)
+               if (int_buf[i] == '`') {
+                       for (j = i + 1; int_buf[j]; j++)
+                               if (int_buf[j] == '`') {
+                                       collapse_pos(i, j + 1);
+                                       j = 0;
+                                       break;
+                               }
+                       if (j) {
+                               /* not found close ` - command mode, collapse all previous */
+                               collapse_pos(0, i + 1);
+                               break;
+                       } else
+                               i--;                    /* hack incremet */
+               }
+
+       /* collapse (command...(command...)...) or {command...{command...}...} */
+       c = 0;                                          /* "recursive" level */
+       c2 = 0;
+       for (i = 0; int_buf[i]; i++)
+               if (int_buf[i] == '(' || int_buf[i] == '{') {
+                       if (int_buf[i] == '(')
+                               c++;
+                       else
+                               c2++;
+                       collapse_pos(0, i + 1);
+                       i = -1;                         /* hack incremet */
+               }
+       for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
+               if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
+                       if (int_buf[i] == ')')
+                               c--;
+                       else
+                               c2--;
+                       collapse_pos(0, i + 1);
+                       i = -1;                         /* hack incremet */
+               }
+
+       /* skip first not quote space */
+       for (i = 0; int_buf[i]; i++)
+               if (int_buf[i] != ' ')
+                       break;
+       if (i)
+               collapse_pos(0, i);
+
+       /* set find mode for completion */
+       command_mode = FIND_EXE_ONLY;
+       for (i = 0; int_buf[i]; i++)
+               if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
+                       if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
+                               && matchBuf[pos_buf[0]]=='c'
+                               && matchBuf[pos_buf[1]]=='d' )
+                               command_mode = FIND_DIR_ONLY;
+                       else {
+                               command_mode = FIND_FILE_ONLY;
+                               break;
+                       }
+               }
+       /* "strlen" */
+       for (i = 0; int_buf[i]; i++);
+       /* find last word */
+       for (--i; i >= 0; i--) {
+               c = int_buf[i];
+               if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
+                       collapse_pos(0, i + 1);
+                       break;
+               }
+       }
+       /* skip first not quoted '\'' or '"' */
+       for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++);
+       /* collapse quote or unquote // or /~ */
+       while ((int_buf[i] & ~QUOT) == '/' &&
+                       ((int_buf[i + 1] & ~QUOT) == '/'
+                        || (int_buf[i + 1] & ~QUOT) == '~')) {
+               i++;
+       }
+
+       /* set only match and destroy quotes */
+       j = 0;
+       for (c = 0; pos_buf[i] >= 0; i++) {
+               matchBuf[c++] = matchBuf[pos_buf[i]];
+               j = pos_buf[i] + 1;
+       }
+       matchBuf[c] = 0;
+       /* old lenght matchBuf with quotes symbols */
+       *len_with_quotes = j ? j - pos_buf[0] : 0;
+
+       return command_mode;
+}
+
+/*
+   display by column original ideas from ls applet,
+   very optimize by my :)
+*/
+static void showfiles(char **matches, int nfiles)
+{
+       int ncols, row;
+       int column_width = 0;
+       int nrows = nfiles;
+
+       /* find the longest file name-  use that as the column width */
+       for (row = 0; row < nrows; row++) {
+               int l = strlen(matches[row]);
+
+               if (column_width < l)
+                       column_width = l;
+       }
+       column_width += 2;              /* min space for columns */
+       ncols = cmdedit_termw / column_width;
+
+       if (ncols > 1) {
+               nrows /= ncols;
+               if(nfiles % ncols)
+                       nrows++;        /* round up fractionals */
+               column_width = -column_width;   /* for printf("%-Ns", ...); */
+       } else {
+               ncols = 1;
+       }
+       for (row = 0; row < nrows; row++) {
+               int n = row;
+               int nc;
+
+               for(nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++)
+                       printf("%*s", column_width, matches[n]);
+               printf("%s\n", matches[n]);
+       }
+}
+
+
+static void input_tab(int *lastWasTab)
+{
+       /* Do TAB completion */
+       static int num_matches;
+       static char **matches;
+
+       if (lastWasTab == 0) {          /* free all memory */
+               if (matches) {
+                       while (num_matches > 0)
+                               free(matches[--num_matches]);
+                       free(matches);
+                       matches = (char **) NULL;
+               }
+               return;
+       }
+       if (! *lastWasTab) {
+
+               char *tmp;
+               int len_found;
+               char matchBuf[BUFSIZ];
+               int find_type;
+               int recalc_pos;
+
+               *lastWasTab = TRUE;             /* flop trigger */
+
+               /* Make a local copy of the string -- up
+                * to the position of the cursor */
+               tmp = strncpy(matchBuf, command_ps, cursor);
+               tmp[cursor] = 0;
+
+               find_type = find_match(matchBuf, &recalc_pos);
+
+               /* Free up any memory already allocated */
+               input_tab(0);
+
+#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               /* If the word starts with `~' and there is no slash in the word,
+                * then try completing this word as a username. */
+
+               if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
+                       matches = username_tab_completion(matchBuf, &num_matches);
+#endif
+               /* Try to match any executable in our path and everything
+                * in the current working directory that matches.  */
+               if (!matches)
+                       matches =
+                               exe_n_cwd_tab_completion(matchBuf,
+                                       &num_matches, find_type);
+               /* Remove duplicate found */
+               if(matches) {
+                       int i, j;
+                       /* bubble */
+                       for(i=0; i<(num_matches-1); i++)
+                               for(j=i+1; j<num_matches; j++)
+                                       if(matches[i]!=0 && matches[j]!=0 &&
+                                               strcmp(matches[i], matches[j])==0) {
+                                                       free(matches[j]);
+                                                       matches[j]=0;
+                                       }
+                       j=num_matches;
+                       num_matches = 0;
+                       for(i=0; i<j; i++)
+                               if(matches[i]) {
+                                       if(!strcmp(matches[i], "./"))
+                                               matches[i][1]=0;
+                                       else if(!strcmp(matches[i], "../"))
+                                               matches[i][2]=0;
+                                       matches[num_matches++]=matches[i];
+                               }
+               }
+               /* Did we find exactly one match? */
+               if (!matches || num_matches > 1) {
+                       char *tmp1;
+
+                       beep();
+                       if (!matches)
+                               return;         /* not found */
+                       /* sort */
+                       qsort(matches, num_matches, sizeof(char *), match_compare);
+
+                       /* find minimal match */
+                       tmp = xstrdup(matches[0]);
+                       for (tmp1 = tmp; *tmp1; tmp1++)
+                               for (len_found = 1; len_found < num_matches; len_found++)
+                                       if (matches[len_found][(tmp1 - tmp)] != *tmp1) {
+                                               *tmp1 = 0;
+                                               break;
+                                       }
+                       if (*tmp == 0) {        /* have unique */
+                               free(tmp);
+                               return;
+                       }
+               } else {                        /* one match */
+                       tmp = matches[0];
+                       /* for next completion current found */
+                       *lastWasTab = FALSE;
+               }
+
+               len_found = strlen(tmp);
+               /* have space to placed match? */
+               if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
+
+                       /* before word for match   */
+                       command_ps[cursor - recalc_pos] = 0;
+                       /* save   tail line        */
+                       strcpy(matchBuf, command_ps + cursor);
+                       /* add    match            */
+                       strcat(command_ps, tmp);
+                       /* add    tail             */
+                       strcat(command_ps, matchBuf);
+                       /* back to begin word for match    */
+                       input_backward(recalc_pos);
+                       /* new pos                         */
+                       recalc_pos = cursor + len_found;
+                       /* new len                         */
+                       len = strlen(command_ps);
+                       /* write out the matched command   */
+                       redraw(cmdedit_y, len - recalc_pos);
+               }
+               if (tmp != matches[0])
+                       free(tmp);
+       } else {
+               /* Ok -- the last char was a TAB.  Since they
+                * just hit TAB again, print a list of all the
+                * available choices... */
+               if (matches && num_matches > 0) {
+                       int sav_cursor = cursor;        /* change goto_new_line() */
+
+                       /* Go to the next line */
+                       goto_new_line();
+                       showfiles(matches, num_matches);
+                       redraw(0, len - sav_cursor);
+               }
+       }
+}
+#endif  /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+
+#if MAX_HISTORY >= 1
+static void get_previous_history(void)
+{
+       if(command_ps[0] != 0 || history[cur_history] == 0) {
+               free(history[cur_history]);
+               history[cur_history] = xstrdup(command_ps);
+       }
+       cur_history--;
+}
+
+static int get_next_history(void)
+{
+       int ch = cur_history;
+
+       if (ch < n_history) {
+               get_previous_history(); /* save the current history line */
+               return (cur_history = ch+1);
+       } else {
+               beep();
+               return 0;
+       }
+}
+
+#ifdef BB_FEATURE_COMMAND_SAVEHISTORY
+extern void load_history ( const char *fromfile )
+{
+       FILE *fp;
+       int hi;
+
+       /* cleanup old */
+
+       for(hi = n_history; hi > 0; ) {
+               hi--;
+               free ( history [hi] );
+       }
+
+       if (( fp = fopen ( fromfile, "r" ))) {
+
+               for ( hi = 0; hi < MAX_HISTORY; ) {
+                       char * hl = get_chomped_line_from_file(fp);
+                       int l;
+
+                       if(!hl)
+                               break;
+                       l = strlen(hl);
+                       if(l >= BUFSIZ)
+                               hl[BUFSIZ-1] = 0;
+                       if(l == 0 || hl[0] == ' ') {
+                               free(hl);
+                               continue;
+                       }
+                       history [hi++] = hl;
+               }
+               fclose ( fp );
+       }
+       cur_history = n_history = hi;
+}
+
+extern void save_history ( const char *tofile )
+{
+       FILE *fp = fopen ( tofile, "w" );
+
+       if ( fp ) {
+               int i;
+
+               for ( i = 0; i < n_history; i++ ) {
+                       fprintf(fp, "%s\n", history [i]);
+               }
+               fclose ( fp );
+       }
+}
+#endif
+
+#endif
+
+enum {
+       ESC = 27,
+       DEL = 127,
+};
+
+
+/*
+ * This function is used to grab a character buffer
+ * from the input file descriptor and allows you to
+ * a string with full command editing (sortof like
+ * a mini readline).
+ *
+ * The following standard commands are not implemented:
+ * ESC-b -- Move back one word
+ * ESC-f -- Move forward one word
+ * ESC-d -- Delete back one word
+ * ESC-h -- Delete forward one word
+ * CTL-t -- Transpose two characters
+ *
+ * Furthermore, the "vi" command editing keys are not implemented.
+ *
+ */
+
+
+int cmdedit_read_input(char *prompt, char command[BUFSIZ])
+{
+
+       int break_out = 0;
+       int lastWasTab = FALSE;
+       unsigned char c = 0;
+
+       /* prepare before init handlers */
+       cmdedit_y = 0;  /* quasireal y, not true work if line > xt*yt */
+       len = 0;
+       command_ps = command;
+
+       getTermSettings(0, (void *) &initial_settings);
+       memcpy(&new_settings, &initial_settings, sizeof(struct termios));
+       new_settings.c_lflag &= ~ICANON;        /* unbuffered input */
+       /* Turn off echoing and CTRL-C, so we can trap it */
+       new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
+       /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
+       new_settings.c_cc[VMIN] = 1;
+       new_settings.c_cc[VTIME] = 0;
+       /* Turn off CTRL-C, so we can trap it */
+#       ifndef _POSIX_VDISABLE
+#               define _POSIX_VDISABLE '\0'
+#       endif
+       new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
+       command[0] = 0;
+
+       setTermSettings(0, (void *) &new_settings);
+       handlers_sets |= SET_RESET_TERM;
+
+       /* Now initialize things */
+       cmdedit_init();
+       /* Print out the command prompt */
+       parse_prompt(prompt);
+
+       while (1) {
+
+               fflush(stdout);                 /* buffered out to fast */
+
+               if (safe_read(0, &c, 1) < 1)
+                       /* if we can't read input then exit */
+                       goto prepare_to_die;
+
+               switch (c) {
+               case '\n':
+               case '\r':
+                       /* Enter */
+                       goto_new_line();
+                       break_out = 1;
+                       break;
+               case 1:
+                       /* Control-a -- Beginning of line */
+                       input_backward(cursor);
+                       break;
+               case 2:
+                       /* Control-b -- Move back one character */
+                       input_backward(1);
+                       break;
+               case 3:
+                       /* Control-c -- stop gathering input */
+                       goto_new_line();
+                       command[0] = 0;
+                       len = 0;
+                       lastWasTab = FALSE;
+                       put_prompt();
+                       break;
+               case 4:
+                       /* Control-d -- Delete one character, or exit
+                        * if the len=0 and no chars to delete */
+                       if (len == 0) {
+prepare_to_die:
+#if !defined(BB_ASH)
+                               printf("exit");
+                               goto_new_line();
+                               /* cmdedit_reset_term() called in atexit */
+                               exit(EXIT_SUCCESS);
+#else
+                               break_out = -1; /* for control stoped jobs */
+                               break;
+#endif
+                       } else {
+                               input_delete();
+                       }
+                       break;
+               case 5:
+                       /* Control-e -- End of line */
+                       input_end();
+                       break;
+               case 6:
+                       /* Control-f -- Move forward one character */
+                       input_forward();
+                       break;
+               case '\b':
+               case DEL:
+                       /* Control-h and DEL */
+                       input_backspace();
+                       break;
+               case '\t':
+#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+                       input_tab(&lastWasTab);
+#endif
+                       break;
+               case 11:
+                       /* Control-k -- clear to end of line */
+                       *(command + cursor) = 0;
+                       len = cursor;
+                       printf("\033[J");
+                       break;
+               case 12:
+                       /* Control-l -- clear screen */
+                       printf("\033[H");
+                       redraw(0, len-cursor);
+                       break;
+#if MAX_HISTORY >= 1
+               case 14:
+                       /* Control-n -- Get next command in history */
+                       if (get_next_history())
+                               goto rewrite_line;
+                       break;
+               case 16:
+                       /* Control-p -- Get previous command from history */
+                       if (cur_history > 0) {
+                               get_previous_history();
+                               goto rewrite_line;
+                       } else {
+                               beep();
+                       }
+                       break;
+#endif
+               case 21:
+                       /* Control-U -- Clear line before cursor */
+                       if (cursor) {
+                               strcpy(command, command + cursor);
+                               redraw(cmdedit_y, len -= cursor);
+                       }
+                       break;
+               case 23:
+                       /* Control-W -- Remove the last word */
+                       while (cursor > 0 && isspace(command[cursor-1]))
+                               input_backspace();
+                       while (cursor > 0 &&!isspace(command[cursor-1]))
+                               input_backspace();
+                       break;
+               case ESC:{
+                       /* escape sequence follows */
+                       if (safe_read(0, &c, 1) < 1)
+                               goto prepare_to_die;
+                       /* different vt100 emulations */
+                       if (c == '[' || c == 'O') {
+                               if (safe_read(0, &c, 1) < 1)
+                                       goto prepare_to_die;
+                       }
+                       switch (c) {
+#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+                       case '\t':                      /* Alt-Tab */
+
+                               input_tab(&lastWasTab);
+                               break;
+#endif
+#if MAX_HISTORY >= 1
+                       case 'A':
+                               /* Up Arrow -- Get previous command from history */
+                               if (cur_history > 0) {
+                                       get_previous_history();
+                                       goto rewrite_line;
+                               } else {
+                                       beep();
+                               }
+                               break;
+                       case 'B':
+                               /* Down Arrow -- Get next command in history */
+                               if (!get_next_history())
+                               break;
+                               /* Rewrite the line with the selected history item */
+rewrite_line:
+                               /* change command */
+                               len = strlen(strcpy(command, history[cur_history]));
+                               /* redraw and go to end line */
+                               redraw(cmdedit_y, 0);
+                               break;
+#endif
+                       case 'C':
+                               /* Right Arrow -- Move forward one character */
+                               input_forward();
+                               break;
+                       case 'D':
+                               /* Left Arrow -- Move back one character */
+                               input_backward(1);
+                               break;
+                       case '3':
+                               /* Delete */
+                               input_delete();
+                               break;
+                       case '1':
+                       case 'H':
+                               /* Home (Ctrl-A) */
+                               input_backward(cursor);
+                               break;
+                       case '4':
+                       case 'F':
+                               /* End (Ctrl-E) */
+                               input_end();
+                               break;
+                       default:
+                               if (!(c >= '1' && c <= '9'))
+                                       c = 0;
+                               beep();
+                       }
+                       if (c >= '1' && c <= '9')
+                               do
+                                       if (safe_read(0, &c, 1) < 1)
+                                               goto prepare_to_die;
+                               while (c != '~');
+                       break;
+               }
+
+               default:        /* If it's regular input, do the normal thing */
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+                       /* Control-V -- Add non-printable symbol */
+                       if (c == 22) {
+                               if (safe_read(0, &c, 1) < 1)
+                                       goto prepare_to_die;
+                               if (c == 0) {
+                                       beep();
+                                       break;
+                               }
+                       } else
+#endif
+                       if (!Isprint(c))        /* Skip non-printable characters */
+                               break;
+
+                       if (len >= (BUFSIZ - 2))        /* Need to leave space for enter */
+                               break;
+
+                       len++;
+
+                       if (cursor == (len - 1)) {      /* Append if at the end of the line */
+                               *(command + cursor) = c;
+                               *(command + cursor + 1) = 0;
+                               cmdedit_set_out_char(0);
+                       } else {                        /* Insert otherwise */
+                               int sc = cursor;
+
+                               memmove(command + sc + 1, command + sc, len - sc);
+                               *(command + sc) = c;
+                               sc++;
+                               /* rewrite from cursor */
+                               input_end();
+                               /* to prev x pos + 1 */
+                               input_backward(cursor - sc);
+                       }
+
+                       break;
+               }
+               if (break_out)                  /* Enter is the command terminator, no more input. */
+                       break;
+
+               if (c != '\t')
+                       lastWasTab = FALSE;
+       }
+
+       setTermSettings(0, (void *) &initial_settings);
+       handlers_sets &= ~SET_RESET_TERM;
+
+#if MAX_HISTORY >= 1
+       /* Handle command history log */
+       /* cleanup may be saved current command line */
+       free(history[MAX_HISTORY]);
+       history[MAX_HISTORY] = 0;
+       if (len) {                                      /* no put empty line */
+               int i = n_history;
+                       /* After max history, remove the oldest command */
+               if (i >= MAX_HISTORY) {
+                       free(history[0]);
+                       for(i = 0; i < (MAX_HISTORY-1); i++)
+                               history[i] = history[i+1];
+               }
+               history[i++] = xstrdup(command);
+               cur_history = i;
+               n_history = i;
+#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+               num_ok_lines++;
+#endif
+       }
+#else  /* MAX_HISTORY < 1 */
+#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+       if (len) {              /* no put empty line */
+               num_ok_lines++;
+       }
+#endif
+#endif  /* MAX_HISTORY >= 1 */
+       if (break_out > 0) {
+               command[len++] = '\n';          /* set '\n' */
+               command[len] = 0;
+       }
+#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION)
+       input_tab(0);                           /* strong free */
+#endif
+#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+       free(cmdedit_prompt);
+#endif
+       cmdedit_reset_term();
+       return len;
+}
+
+
+
+#endif  /* BB_FEATURE_COMMAND_EDITING */
+
+
+#ifdef TEST
+
+const char *bb_applet_name = "debug stuff usage";
+
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#include <locale.h>
+#endif
+
+int main(int argc, char **argv)
+{
+       char buff[BUFSIZ];
+       char *prompt =
+#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+               "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
+\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
+\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
+#else
+               "% ";
+#endif
+
+#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+       setlocale(LC_ALL, "");
+#endif
+       while(1) {
+               int l;
+               l = cmdedit_read_input(prompt, buff);
+               if(l > 0 && buff[l-1] == '\n') {
+                       buff[l-1] = 0;
+                       printf("*** cmdedit_read_input() returned line =%s=\n", buff);
+               } else {
+                       break;
+               }
+       }
+       printf("*** cmdedit_read_input() detect ^D\n");
+       return 0;
+}
+
+#endif  /* TEST */
diff --git a/cmdedit.h b/cmdedit.h
new file mode 100644 (file)
index 0000000..991dafc
--- /dev/null
+++ b/cmdedit.h
@@ -0,0 +1,11 @@
+#ifndef CMDEDIT_H
+#define CMDEDIT_H
+
+int     cmdedit_read_input(char* promptStr, char* command);
+
+#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
+void    load_history ( const char *fromfile );
+void    save_history ( const char *tofile );
+#endif
+
+#endif /* CMDEDIT_H */
diff --git a/cmp.c b/cmp.c
new file mode 100644 (file)
index 0000000..57d83d8
--- /dev/null
+++ b/cmp.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cmp implementation for busybox
+ *
+ * Copyright (C) 1999,2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "busybox.h"
+
+int cmp_main(int argc, char **argv)
+{
+       FILE *fp1 = NULL, *fp2 = stdin;
+       char *filename1, *filename2 = "-";
+       int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE;
+
+       while ((c = getopt(argc, argv, "s")) != EOF) {
+               switch (c) {
+                       case 's':
+                               silent = TRUE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       filename1 = argv[optind];
+       switch (argc - optind) {
+               case 2:
+                       fp2 = xfopen(filename2 = argv[optind + 1], "r");
+               case 1:
+                       fp1 = xfopen(filename1, "r");
+                       break;
+               default:
+                       show_usage();
+       }
+
+       do {
+               c1 = fgetc(fp1);
+               c2 = fgetc(fp2);
+               if (c1 != c2) {
+                       if (silent)
+                               return EXIT_FAILURE;
+                       if (c1 == EOF)
+                               printf("EOF on %s\n", filename1);
+                       else if (c2 == EOF)
+                               printf("EOF on %s\n", filename2);
+                       else
+                               printf("%s %s differ: char %d, line %d\n", filename1, filename2,
+                                               char_pos, line_pos);
+                       return EXIT_FAILURE;
+               }
+               char_pos++;
+               if (c1 == '\n')
+                       line_pos++;
+       } while (c1 != EOF);
+
+       return EXIT_SUCCESS;
+}
diff --git a/cp.c b/cp.c
new file mode 100644 (file)
index 0000000..696b06e
--- /dev/null
+++ b/cp.c
@@ -0,0 +1,117 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cp implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+extern int cp_main(int argc, char **argv)
+{
+       int status = 0;
+       int opt;
+       int flags = 0;
+       int i;
+
+       while ((opt = getopt(argc, argv, "adfipRr")) != -1)
+               switch (opt) {
+               case 'a':
+                       flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR;
+                       /* fallthrough */
+               case 'd':
+                       flags |= FILEUTILS_PRESERVE_SYMLINKS;
+                       break;
+               case 'f':
+                       flags |= FILEUTILS_FORCE;
+                       break;
+               case 'i':
+                       flags |= FILEUTILS_INTERACTIVE;
+                       break;
+               case 'p':
+                       flags |= FILEUTILS_PRESERVE_STATUS;
+                       break;
+               case 'R':
+                       flags |= FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS;
+                       break;
+               case 'r':
+                       flags |= FILEUTILS_RECUR;
+                       break;
+               default:
+                       show_usage();
+               }
+       
+       if (optind + 2 > argc)
+               show_usage();
+
+       /* If there are only two arguments and...  */
+       if (optind + 2 == argc) {
+               struct stat source_stat;
+               struct stat dest_stat;
+               int source_exists = 1;
+               int dest_exists = 1;
+
+               if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+                               lstat(argv[optind], &source_stat) < 0) ||
+                               (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+                                stat(argv[optind], &source_stat))) {
+                       if (errno != ENOENT)
+                               perror_msg_and_die("unable to stat `%s'", argv[optind]);
+                       source_exists = 0;
+               }
+
+               if (stat(argv[optind + 1], &dest_stat) < 0) {
+                       if (errno != ENOENT)
+                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
+                       dest_exists = 0;
+               }
+               
+               /* ...if neither is a directory or...  */
+               if (((!source_exists || !S_ISDIR(source_stat.st_mode)) &&
+                               (!dest_exists || !S_ISDIR(dest_stat.st_mode))) ||
+                               /* ...recursing, the first is a directory, and the
+                                * second doesn't exist, then... */
+                               ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) &&
+                                !dest_exists)) {
+                       /* ...do a simple copy.  */
+                       if (copy_file(argv[optind], argv[optind + 1], flags) < 0)
+                               status = 1;
+                       return status;
+               }
+       }
+
+       for (i = optind; i < argc - 1; i++) {
+               char *dest = concat_path_file(argv[argc - 1],
+                               get_last_path_component(argv[i]));
+               if (copy_file(argv[i], dest, flags) < 0)
+                       status = 1;
+               free(dest);
+       }
+
+       return status;
+}
diff --git a/cpio.c b/cpio.c
new file mode 100644 (file)
index 0000000..7f68715
--- /dev/null
+++ b/cpio.c
@@ -0,0 +1,95 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Glenn McGrath 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Limitations:
+ *             Doesn't check CRC's
+ *             Only supports new ASCII and CRC formats
+ *
+ */
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int cpio_main(int argc, char **argv)
+{
+       FILE *src_stream = stdin;
+       char **extract_names = NULL;
+       int extract_function = 0;
+       int num_of_entries = 0;
+       int opt = 0;
+       mode_t oldmask = 0;
+
+       while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
+               switch (opt) {
+               case 'i': // extract
+                       extract_function |= extract_all_to_fs;
+                       break;
+               case 'd': // create _leading_ directories
+                       extract_function |= extract_create_leading_dirs;
+                       oldmask = umask(077); /* Make make_directory act like GNU cpio */
+                       break;
+               case 'm': // preserve modification time
+                       extract_function |= extract_preserve_date;
+                       break;
+               case 'v': // verbosly list files
+                       extract_function |= extract_verbose_list;
+                       break;
+               case 'u': // unconditional
+                       extract_function |= extract_unconditional;
+                       break;
+               case 't': // list files
+                       extract_function |= extract_list;
+                       break;
+               case 'F':
+                       src_stream = xfopen(optarg, "r");
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) {
+               extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/
+       }
+
+       if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) {
+               /* The meaning of v changes on extract */
+               extract_function ^= extract_verbose_list;
+               extract_function |= extract_list;
+       }
+
+       while (optind < argc) {
+               extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
+               extract_names[num_of_entries] = xstrdup(argv[optind]);
+               num_of_entries++;
+               extract_names[num_of_entries] = NULL;
+               optind++;
+       }
+
+       unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names);
+       if (oldmask) {
+               umask(oldmask); /* Restore umask if we changed it */
+       }
+       return EXIT_SUCCESS;
+}
+
diff --git a/cut.c b/cut.c
new file mode 100644 (file)
index 0000000..b60c41e
--- /dev/null
+++ b/cut.c
@@ -0,0 +1,356 @@
+/*
+ * cut.c - minimalist version of cut
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley
+ * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* getopt */
+#include <string.h>
+#include <limits.h>
+#include "busybox.h"
+
+
+/* globals from other files */
+extern int optind;
+extern char *optarg;
+
+
+/* option vars */
+static char part = 0; /* (b)yte, (c)har, (f)ields */
+static unsigned int supress_non_delimited_lines = 0;
+static char delim = '\t'; /* delimiter, default is tab */
+
+struct cut_list {
+       int startpos;
+       int endpos;
+};
+
+static const int BOL = 0;
+static const int EOL = INT_MAX;
+static const int NON_RANGE = -1;
+
+static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
+static unsigned int nlists = 0; /* number of elements in above list */
+
+
+static int cmpfunc(const void *a, const void *b)
+{
+       struct cut_list *la = (struct cut_list *)a;
+       struct cut_list *lb = (struct cut_list *)b;
+
+       if (la->startpos > lb->startpos)
+               return 1;
+       if (la->startpos < lb->startpos)
+               return -1;
+       return 0;
+}
+
+
+/*
+ * parse_lists() - parses a list and puts values into startpos and endpos.
+ * valid list formats: N, N-, N-M, -M 
+ * more than one list can be seperated by commas
+ */
+static void parse_lists(char *lists)
+{
+       char *ltok = NULL;
+       char *ntok = NULL;
+       char *junk;
+       int s = 0, e = 0;
+
+       /* take apart the lists, one by one (they are seperated with commas */
+       while ((ltok = strsep(&lists, ",")) != NULL) {
+
+               /* it's actually legal to pass an empty list */
+               if (strlen(ltok) == 0)
+                       continue;
+
+               /* get the start pos */
+               ntok = strsep(&ltok, "-");
+               if (ntok == NULL) {
+                       fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
+               } else if (strlen(ntok) == 0) {
+                       s = BOL;
+               } else {
+                       s = strtoul(ntok, &junk, 10);
+                       if(*junk != '\0' || s < 0)
+                               error_msg_and_die("invalid byte or field list");
+                       
+                       /* account for the fact that arrays are zero based, while the user
+                        * expects the first char on the line to be char # 1 */
+                       if (s != 0)
+                               s--;
+               }
+
+               /* get the end pos */
+               ntok = strsep(&ltok, "-");
+               if (ntok == NULL) {
+                       e = NON_RANGE;
+               } else if (strlen(ntok) == 0) {
+                       e = EOL;
+               } else {
+                       e = strtoul(ntok, &junk, 10);
+                       if(*junk != '\0' || e < 0)
+                               error_msg_and_die("invalid byte or field list");
+                       /* if the user specified and end position of 0, that means "til the
+                        * end of the line */
+                       if (e == 0)
+                               e = INT_MAX;
+                       e--; /* again, arrays are zero based, lines are 1 based */
+                       if (e == s)
+                               e = NON_RANGE;
+               }
+
+               /* if there's something left to tokenize, the user past an invalid list */
+               if (ltok)
+                       error_msg_and_die("invalid byte or field list");
+               
+               /* add the new list */
+               cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
+               cut_lists[nlists-1].startpos = s;
+               cut_lists[nlists-1].endpos = e;
+       }
+
+       /* make sure we got some cut positions out of all that */
+       if (nlists == 0)
+               error_msg_and_die("missing list of positions");
+
+       /* now that the lists are parsed, we need to sort them to make life easier
+        * on us when it comes time to print the chars / fields / lines */
+       qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
+
+}
+
+
+static void cut_line_by_chars(const char *line)
+{
+       int c, l;
+       /* set up a list so we can keep track of what's been printed */
+       char *printed = xcalloc(strlen(line), sizeof(char));
+
+       /* print the chars specified in each cut list */
+       for (c = 0; c < nlists; c++) {
+               l = cut_lists[c].startpos;
+               while (l < strlen(line)) {
+                       if (!printed[l]) {
+                               putchar(line[l]);
+                               printed[l] = 'X';
+                       }
+                       l++;
+                       if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
+                               break;
+               }
+       }
+       putchar('\n'); /* cuz we were handed a chomped line */
+       free(printed);
+}
+
+
+static void cut_line_by_fields(char *line)
+{
+       int c, f;
+       int ndelim = -1; /* zero-based / one-based problem */
+       int nfields_printed = 0;
+       char *field = NULL;
+       char d[2] = { delim, 0 };
+       char *printed;
+
+       /* test the easy case first: does this line contain any delimiters? */
+       if (strchr(line, delim) == NULL) {
+               if (!supress_non_delimited_lines)
+                       puts(line);
+               return;
+       }
+
+       /* set up a list so we can keep track of what's been printed */
+       printed = xcalloc(strlen(line), sizeof(char));
+
+       /* process each list on this line, for as long as we've got a line to process */
+       for (c = 0; c < nlists && line; c++) {
+               f = cut_lists[c].startpos;
+               do {
+
+                       /* find the field we're looking for */
+                       while (line && ndelim < f) {
+                               field = strsep(&line, d);
+                               ndelim++;
+                       }
+
+                       /* we found it, and it hasn't been printed yet */
+                       if (field && ndelim == f && !printed[ndelim]) {
+                               /* if this isn't our first time through, we need to print the
+                                * delimiter after the last field that was printed */
+                               if (nfields_printed > 0)
+                                       putchar(delim);
+                               fputs(field, stdout);
+                               printed[ndelim] = 'X';
+                               nfields_printed++;
+                       }
+
+                       f++;
+
+                       /* keep going as long as we have a line to work with, this is a
+                        * list, and we're not at the end of that list */
+               } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
+       }
+
+       /* if we printed anything at all, we need to finish it with a newline cuz
+        * we were handed a chomped line */
+       putchar('\n');
+
+       free(printed);
+}
+
+
+static void cut_file_by_lines(const char *line, unsigned int linenum)
+{
+       static int c = 0;
+       static int l = -1;
+       
+       /* I can't initialize this above cuz the "initializer isn't
+        * constant" *sigh* */
+       if (l == -1)
+               l = cut_lists[c].startpos;
+
+       /* get out if we have no more lists to process or if the lines are lower
+        * than what we're interested in */
+       if (c >= nlists || linenum < l)
+               return;
+
+       /* if the line we're looking for is lower than the one we were passed, it
+        * means we displayed it already, so move on */
+       while (l < linenum) {
+               l++;
+               /* move on to the next list if we're at the end of this one */
+               if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
+                       c++;
+                       /* get out if there's no more lists to process */
+                       if (c >= nlists)
+                               return;
+                       l = cut_lists[c].startpos;
+                       /* get out if the current line is lower than the one we just became
+                        * interested in */
+                       if (linenum < l)
+                               return;
+               }
+       }
+
+       /* If we made it here, it means we've found the line we're looking for, so print it */
+       puts(line);
+}
+
+
+/*
+ * snippy-snip
+ */
+static void cut_file(FILE *file)
+{
+       char *line = NULL;
+       unsigned int linenum = 0; /* keep these zero-based to be consistent */
+
+       /* go through every line in the file */
+       while ((line = get_line_from_file(file)) != NULL) {
+               chomp(line);
+
+               /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
+               if (part == 'c' || part == 'b')
+                       cut_line_by_chars(line);
+
+               /* cut based on fields */
+               else if (part == 'f') {
+                       if (delim == '\n')
+                               cut_file_by_lines(line, linenum);
+                       else
+                               cut_line_by_fields(line);
+               }
+
+               linenum++;
+               free(line);
+       }
+}
+
+
+extern int cut_main(int argc, char **argv)
+{
+       int opt;
+
+       while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) {
+               switch (opt) {
+                       case 'b':
+                       case 'c':
+                       case 'f':
+                               /* make sure they didn't ask for two types of lists */
+                               if (part != 0) {
+                                       error_msg_and_die("only one type of list may be specified");
+                               }
+                               part = (char)opt;
+                               parse_lists(optarg);
+                               break;
+                       case 'd':
+                               if (strlen(optarg) > 1) {
+                                       error_msg_and_die("the delimiter must be a single character");
+                               }
+                               delim = optarg[0];
+                               break;
+                       case 'n':
+                               /* no-op */
+                               break;
+                       case 's':
+                               supress_non_delimited_lines++;
+                               break;
+               }
+       }
+
+       if (part == 0) {
+               error_msg_and_die("you must specify a list of bytes, characters, or fields");
+       }
+
+       /*  non-field (char or byte) cutting has some special handling */
+       if (part != 'f') {
+               if (supress_non_delimited_lines) {
+                       error_msg_and_die("suppressing non-delimited lines makes sense"
+                                       " only when operating on fields");
+               }
+               if (delim != '\t' && part != 'f') {
+                       error_msg_and_die("a delimiter may be specified only when operating on fields");
+               }
+       }
+
+       /* argv[(optind)..(argc-1)] should be names of file to process. If no
+        * files were specified or '-' was specified, take input from stdin.
+        * Otherwise, we process all the files specified. */
+       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
+               cut_file(stdin);
+       }
+       else {
+               int i;
+               FILE *file;
+               for (i = optind; i < argc; i++) {
+                       file = wfopen(argv[i], "r");
+                       if(file) {
+                               cut_file(file);
+                               fclose(file);
+                       }
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/date.c b/date.c
new file mode 100644 (file)
index 0000000..41ceee2
--- /dev/null
+++ b/date.c
@@ -0,0 +1,247 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini date implementation for busybox
+ *
+ * by Matthew Grant <grantma@anathoth.gen.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include "busybox.h"
+
+
+/* This 'date' command supports only 2 time setting formats, 
+   all the GNU strftime stuff (its in libc, lets use it),
+   setting time using UTC and displaying int, as well as
+   an RFC 822 complient date output for shell scripting
+   mail commands */
+
+/* Input parsing code is always bulky - used heavy duty libc stuff as
+   much as possible, missed out a lot of bounds checking */
+
+/* Default input handling to save suprising some people */
+
+static struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
+{
+       int nr;
+
+       nr = sscanf(t_string, "%2d%2d%2d%2d%d",
+                               &(tm_time->tm_mon),
+                               &(tm_time->tm_mday),
+                               &(tm_time->tm_hour),
+                               &(tm_time->tm_min), &(tm_time->tm_year));
+
+       if (nr < 4 || nr > 5) {
+               error_msg_and_die(invalid_date, t_string); 
+       }
+
+       /* correct for century  - minor Y2K problem here? */
+       if (tm_time->tm_year >= 1900)
+               tm_time->tm_year -= 1900;
+       /* adjust date */
+       tm_time->tm_mon -= 1;
+
+       return (tm_time);
+
+}
+
+
+/* The new stuff for LRP */
+
+static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
+{
+       struct tm t;
+
+       /* Parse input and assign appropriately to tm_time */
+
+       if (t=*tm_time,sscanf(t_string, "%d:%d:%d",
+                          &t.tm_hour, &t.tm_min, &t.tm_sec) == 3) {
+                                       /* no adjustments needed */
+
+       } else if (t=*tm_time,sscanf(t_string, "%d:%d",
+                                         &t.tm_hour, &t.tm_min) == 2) {
+                                       /* no adjustments needed */
+
+
+       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d:%d",
+                                         &t.tm_mon,
+                                         &t.tm_mday,
+                                         &t.tm_hour,
+                                         &t.tm_min, &t.tm_sec) == 5) {
+
+               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
+
+       } else if (t=*tm_time,sscanf(t_string, "%d.%d-%d:%d",
+                                         &t.tm_mon,
+                                         &t.tm_mday,
+                                         &t.tm_hour, &t.tm_min) == 4) {
+
+               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
+
+       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d:%d",
+                                         &t.tm_year,
+                                         &t.tm_mon,
+                                         &t.tm_mday,
+                                         &t.tm_hour,
+                                         &t.tm_min, &t.tm_sec) == 6) {
+
+               t.tm_year -= 1900;      /* Adjust years */
+               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
+
+       } else if (t=*tm_time,sscanf(t_string, "%d.%d.%d-%d:%d",
+                                         &t.tm_year,
+                                         &t.tm_mon,
+                                         &t.tm_mday,
+                                         &t.tm_hour, &t.tm_min) == 5) {
+               t.tm_year -= 1900;      /* Adjust years */
+               t.tm_mon -= 1;  /* Adjust dates from 1-12 to 0-11 */
+
+       } else {
+               error_msg_and_die(invalid_date, t_string); 
+       }
+       *tm_time = t;
+       return (tm_time);
+}
+
+
+int date_main(int argc, char **argv)
+{
+       char *date_str = NULL;
+       char *date_fmt = NULL;
+       char *t_buff;
+       int c;
+       int set_time = 0;
+       int rfc822 = 0;
+       int utc = 0;
+       int use_arg = 0;
+       time_t tm;
+       struct tm tm_time;
+
+       /* Interpret command line args */
+       while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) {
+               switch (c) {
+                       case 'R':
+                               rfc822 = 1;
+                               break;
+                       case 's':
+                               set_time = 1;
+                               if ((date_str != NULL) || ((date_str = optarg) == NULL)) {
+                                       show_usage();
+                               }
+                               break;
+                       case 'u':
+                               utc = 1;
+                               if (putenv("TZ=UTC0") != 0)
+                                       error_msg_and_die(memory_exhausted);
+                               break;
+                       case 'd':
+                               use_arg = 1;
+                               if ((date_str != NULL) || ((date_str = optarg) == NULL))
+                                       show_usage();
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+'))
+               date_fmt = &argv[optind][1];   /* Skip over the '+' */
+       else if (date_str == NULL) {
+               set_time = 1;
+               date_str = argv[optind];
+       } 
+#if 0
+       else {
+               error_msg("date_str='%s'  date_fmt='%s'\n", date_str, date_fmt);
+               show_usage();
+       }
+#endif
+
+       /* Now we have parsed all the information except the date format
+          which depends on whether the clock is being set or read */
+
+       time(&tm);
+       memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
+       /* Zero out fields - take her back to midnight! */
+       if (date_str != NULL) {
+               tm_time.tm_sec = 0;
+               tm_time.tm_min = 0;
+               tm_time.tm_hour = 0;
+       }
+
+       /* Process any date input to UNIX time since 1 Jan 1970 */
+       if (date_str != NULL) {
+
+               if (strchr(date_str, ':') != NULL) {
+                       date_conv_ftime(&tm_time, date_str);
+               } else {
+                       date_conv_time(&tm_time, date_str);
+               }
+
+               /* Correct any day of week and day of year etc. fields */
+               tm = mktime(&tm_time);
+               if (tm < 0)
+                       error_msg_and_die(invalid_date, date_str); 
+               if ( utc ) {
+                       if (putenv("TZ=UTC0") != 0)
+                               error_msg_and_die(memory_exhausted);
+               }
+
+               /* if setting time, set it */
+               if (set_time) {
+                       if (stime(&tm) < 0) {
+                               perror_msg("cannot set date");
+                       }
+               }
+       }
+
+       /* Display output */
+
+       /* Deal with format string */
+       if (date_fmt == NULL) {
+               date_fmt = (rfc822
+                                       ? (utc
+                                          ? "%a, %e %b %Y %H:%M:%S GMT"
+                                          : "%a, %e %b %Y %H:%M:%S %z")
+                                       : "%a %b %e %H:%M:%S %Z %Y");
+
+       } else if (*date_fmt == '\0') {
+               /* Imitate what GNU 'date' does with NO format string! */
+               printf("\n");
+               return EXIT_SUCCESS;
+       }
+
+       /* Handle special conversions */
+
+       if (strncmp(date_fmt, "%f", 2) == 0) {
+               date_fmt = "%Y.%m.%d-%H:%M:%S";
+       }
+
+       /* Print OUTPUT (after ALL that!) */
+       t_buff = xmalloc(201);
+       strftime(t_buff, 200, date_fmt, &tm_time);
+       puts(t_buff);
+
+       return EXIT_SUCCESS;
+}
diff --git a/dc.c b/dc.c
new file mode 100644 (file)
index 0000000..8d7a92a
--- /dev/null
+++ b/dc.c
@@ -0,0 +1,182 @@
+/* vi: set sw=4 ts=4: */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+#include "busybox.h"
+
+/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
+
+static double stack[100];
+static unsigned int pointer;
+
+static void push(double a)
+{
+       if (pointer >= (sizeof(stack) / sizeof(*stack)))
+               error_msg_and_die("stack overflow");
+       stack[pointer++] = a;
+}
+
+static double pop()
+{
+       if (pointer == 0)
+               error_msg_and_die("stack underflow");
+       return stack[--pointer];
+}
+
+static void add()
+{
+       push(pop() + pop());
+}
+
+static void sub()
+{
+       double subtrahend = pop();
+
+       push(pop() - subtrahend);
+}
+
+static void mul()
+{
+       push(pop() * pop());
+}
+
+static void divide()
+{
+       double divisor = pop();
+
+       push(pop() / divisor);
+}
+
+static void and()
+{
+       push((unsigned int) pop() & (unsigned int) pop());
+}
+
+static void or()
+{
+       push((unsigned int) pop() | (unsigned int) pop());
+}
+
+static void eor()
+{
+       push((unsigned int) pop() ^ (unsigned int) pop());
+}
+
+static void not()
+{
+       push(~(unsigned int) pop());
+}
+
+static void print()
+{
+       printf("%g\n", pop());
+}
+
+struct op {
+       const char *name;
+       void (*function) ();
+};
+
+static const struct op operators[] = {
+       {"+",   add},
+       {"add", add},
+       {"-",   sub},
+       {"sub", sub},
+       {"*",   mul},
+       {"mul", mul},
+       {"/",   divide},
+       {"div", divide},
+       {"and", and},
+       {"or",  or},
+       {"not", not},
+       {"eor", eor},
+       {0,     0}
+};
+
+static void stack_machine(const char *argument)
+{
+       char *endPointer = 0;
+       double d;
+       const struct op *o = operators;
+
+       if (argument == 0) {
+               print();
+               return;
+       }
+
+       d = strtod(argument, &endPointer);
+
+       if (endPointer != argument) {
+               push(d);
+               return;
+       }
+
+       while (o->name != 0) {
+               if (strcmp(o->name, argument) == 0) {
+                       (*(o->function)) ();
+                       return;
+               }
+               o++;
+       }
+       error_msg_and_die("%s: syntax error.", argument);
+}
+
+/* return pointer to next token in buffer and set *buffer to one char
+ * past the end of the above mentioned token 
+ */
+static char *get_token(char **buffer)
+{
+       char *start   = NULL;
+       char *current = *buffer;
+
+       while (isspace(*current)) { current++; }
+       if (*current != 0) {
+               start = current;
+               while (!isspace(*current) && current != 0) { current++; }
+               *buffer = current;
+       }
+       return start;
+}
+
+/* In Perl one might say, scalar m|\s*(\S+)\s*|g */
+static int number_of_tokens(char *buffer)
+{
+       int   i = 0;
+       char *b = buffer;
+       while (get_token(&b)) { i++; }
+       return i;
+}
+
+int dc_main(int argc, char **argv)
+{
+       /* take stuff from stdin if no args are given */
+       if (argc <= 1) {
+               int i, len;
+               char *line   = NULL;
+               char *cursor = NULL;
+               char *token  = NULL;
+               while ((line = get_line_from_file(stdin))) {
+                       cursor = line;
+                       len = number_of_tokens(line);
+                       for (i = 0; i < len; i++) {
+                               token = get_token(&cursor);
+                               *cursor++ = 0;
+                               stack_machine(token);
+                       }
+                       free(line);
+               }
+       } else {
+               if (*argv[1]=='-')
+                       show_usage();
+               while (argc >= 2) {
+                       stack_machine(argv[1]);
+                       argv++;
+                       argc--;
+               }
+       }
+       stack_machine(0);
+       return EXIT_SUCCESS;
+}
diff --git a/dd.c b/dd.c
new file mode 100644 (file)
index 0000000..ecacf64
--- /dev/null
+++ b/dd.c
@@ -0,0 +1,171 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dd implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include "busybox.h"
+
+
+static const struct suffix_mult dd_suffixes[] = {
+       { "c", 1 },
+       { "w", 2 },
+       { "b", 512 },
+       { "kD", 1000 },
+       { "k", 1024 },
+       { "MD", 1000000 },
+       { "M", 1048576 },
+       { "GD", 1000000000 },
+       { "G", 1073741824 },
+       { NULL, 0 }
+};
+
+int dd_main(int argc, char **argv)
+{
+       int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE, noerror = FALSE;
+       size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0;
+       size_t bs = 512, count = -1;
+       ssize_t n;
+       off_t seek = 0, skip = 0;
+       char *infile = NULL, *outfile = NULL, *buf;
+
+       for (i = 1; i < argc; i++) {
+               if (strncmp("bs=", argv[i], 3) == 0)
+                       bs = parse_number(argv[i]+3, dd_suffixes);
+               else if (strncmp("count=", argv[i], 6) == 0)
+                       count = parse_number(argv[i]+6, dd_suffixes);
+               else if (strncmp("seek=", argv[i], 5) == 0)
+                       seek = parse_number(argv[i]+5, dd_suffixes);
+               else if (strncmp("skip=", argv[i], 5) == 0)
+                       skip = parse_number(argv[i]+5, dd_suffixes);
+               else if (strncmp("if=", argv[i], 3) == 0)
+                       infile = argv[i]+3;
+               else if (strncmp("of=", argv[i], 3) == 0)
+                       outfile = argv[i]+3;
+               else if (strncmp("conv=", argv[i], 5) == 0) {
+                       buf = argv[i]+5;
+                       while (1) {
+                               if (strncmp("notrunc", buf, 7) == 0) {
+                                       trunc = FALSE;
+                                       buf += 7;
+                               } else if (strncmp("sync", buf, 4) == 0) {
+                                       sync_flag = TRUE;
+                                       buf += 4;
+                               } else if (strncmp("noerror", buf, 7) == 0) {
+                                       noerror = TRUE;
+                                       buf += 7;
+                               } else {
+                                       error_msg_and_die("invalid conversion `%s'", argv[i]+5);
+                               }
+                               if (buf[0] == '\0')
+                                       break;
+                               if (buf[0] == ',')
+                                       buf++;
+                       }
+               } else
+                       show_usage();
+       }
+
+       buf = xmalloc(bs);
+
+       if (infile != NULL) {
+               if ((ifd = open(infile, O_RDONLY)) < 0)
+                       perror_msg_and_die("%s", infile);
+       } else {
+               ifd = STDIN_FILENO;
+               infile = "standard input";
+       }
+
+       if (outfile != NULL) {
+               oflag = O_WRONLY | O_CREAT;
+
+               if (!seek && trunc)
+                       oflag |= O_TRUNC;
+
+               if ((ofd = open(outfile, oflag, 0666)) < 0)
+                       perror_msg_and_die("%s", outfile);
+
+               if (seek && trunc) {
+                       if (ftruncate(ofd, seek * bs) < 0) {
+                               struct stat st;
+                               if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) ||
+                                               S_ISDIR (st.st_mode))
+                                       perror_msg_and_die("%s", outfile);
+                       }
+               }
+       } else {
+               ofd = STDOUT_FILENO;
+               outfile = "standard output";
+       }
+
+       if (skip) {
+               if (lseek(ifd, skip * bs, SEEK_CUR) < 0)
+                       perror_msg_and_die("%s", infile);
+       }
+
+       if (seek) {
+               if (lseek(ofd, seek * bs, SEEK_CUR) < 0)
+                       perror_msg_and_die("%s", outfile);
+       }
+
+       while (in_full + in_part != count) {
+               if (noerror) {
+                       /* Pre-zero the buffer when doing the noerror thing */
+                       memset(buf, '\0', bs);
+               }
+               n = safe_read(ifd, buf, bs);
+               if (n < 0) {
+                       if (noerror) {
+                               n = bs;
+                               perror_msg("%s", infile);
+                       } else {
+                               perror_msg_and_die("%s", infile);
+                       }
+               }
+               if (n == 0)
+                       break;
+               if (n == bs)
+                       in_full++;
+               else
+                       in_part++;
+               if (sync_flag) {
+                       memset(buf + n, '\0', bs - n);
+                       n = bs;
+               }
+               n = full_write(ofd, buf, n);
+               if (n < 0)
+                       perror_msg_and_die("%s", outfile);
+               if (n == bs)
+                       out_full++;
+               else
+                       out_part++;
+       }
+
+       fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part);
+       fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part);
+
+       return EXIT_SUCCESS;
+}
diff --git a/deallocvt.c b/deallocvt.c
new file mode 100644 (file)
index 0000000..b7dcc9e
--- /dev/null
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
+ * Renamed deallocvt.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+/* From <linux/vt.h> */
+static const int VT_DISALLOCATE = 0x5608;  /* free memory associated to vt */
+
+int deallocvt_main(int argc, char *argv[])
+{
+       int fd, num, i;
+
+       //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-')))
+       if (argc > 2)
+               show_usage();
+
+       fd = get_console_fd();
+
+       if (argc == 1) {
+               /* deallocate all unused consoles */
+               if (ioctl(fd, VT_DISALLOCATE, 0))
+                       perror_msg_and_die("VT_DISALLOCATE");
+       } else {
+               for (i = 1; i < argc; i++) {
+                       num = atoi(argv[i]);
+                       if (num == 0)
+                               error_msg("0: illegal VT number");
+                       else if (num == 1)
+                               error_msg("VT 1 cannot be deallocated");
+                       else if (ioctl(fd, VT_DISALLOCATE, num))
+                               perror_msg_and_die("VT_DISALLOCATE");
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/debian/Config.h-deb b/debian/Config.h-deb
new file mode 100644 (file)
index 0000000..7b41574
--- /dev/null
@@ -0,0 +1,493 @@
+/* vi: set sw=4 ts=4: */
+// This file defines the feature set to be compiled into busybox.
+// When you turn things off here, they won't be compiled in at all.
+//
+//// This file is parsed by sed.  You MUST use single line comments.
+//   i.e.,  //#define BB_BLAH
+//
+//
+// BusyBox Applications
+//#define BB_ADJTIMEX
+#define BB_AR
+//#define BB_ASH
+//#define BB_BASENAME
+#define BB_CAT
+#define BB_CHGRP
+#define BB_CHMOD
+#define BB_CHOWN
+#define BB_CHROOT
+//#define BB_CHVT
+#define BB_CLEAR
+//#define BB_CMP
+#define BB_CP
+//#define BB_CPIO
+#define BB_CUT
+//#define BB_DATE
+//#define BB_DC
+//#define BB_DD
+//#define BB_DEALLOCVT
+#define BB_DF
+#define BB_DIRNAME
+#define BB_DMESG
+//#define BB_DOS2UNIX
+//#define BB_DPKG
+//#define BB_DPKG_DEB
+//#define BB_DUTMP
+//#define BB_DU
+//#define BB_DUMPKMAP
+#define BB_ECHO
+//#define BB_ENV
+#define BB_EXPR
+//#define BB_FBSET
+//#define BB_FDFLUSH
+#define BB_FIND
+#define BB_FREE
+//#define BB_FREERAMDISK
+//#define BB_FSCK_MINIX
+//#define BB_GETOPT
+#define BB_GREP
+#define BB_GUNZIP
+#define BB_GZIP
+#define BB_HALT
+#define BB_HEAD
+//#define BB_HOSTID
+#define BB_HOSTNAME
+//#define BB_HUSH
+#define BB_ID
+#define BB_IFCONFIG
+#define BB_INIT
+//#define BB_INSMOD
+#define BB_KILL
+#define BB_KILLALL
+#define BB_KLOGD
+//#define BB_LASH
+//#define BB_LENGTH
+#define BB_LN
+//#define BB_LOADACM
+//#define BB_LOADFONT
+#define BB_LOADKMAP
+#define BB_LOGGER
+//#define BB_LOGNAME
+#define BB_LOSETUP
+#define BB_LS
+//#define BB_LSMOD
+//#define BB_MAKEDEVS
+#define BB_MD5SUM
+#define BB_MKDIR
+//#define BB_MKFIFO
+//#define BB_MKFS_MINIX
+#define BB_MKNOD
+#define BB_MKSWAP
+//#define BB_MKTEMP
+//#define BB_MODPROBE
+#define BB_MORE
+#define BB_MOUNT
+//#define BB_MSH
+//#define BB_MT
+#define BB_MV
+//#define BB_NC
+//#define BB_NSLOOKUP
+//#define BB_PIDOF
+#define BB_PING
+//#define BB_PIVOT_ROOT
+#define BB_POWEROFF
+//#define BB_PRINTF
+#define BB_PS
+#define BB_PWD
+//#define BB_RDATE
+//#define BB_READLINK
+#define BB_REBOOT
+//#define BB_RENICE
+#define BB_RESET
+#define BB_RM
+#define BB_RMDIR
+//#define BB_RMMOD
+#define BB_ROUTE
+//#define BB_RPM2CPIO
+#define BB_SED
+//#define BB_SETKEYCODES
+#define BB_SLEEP
+#define BB_SORT
+//#define BB_STTY
+#define BB_SWAPONOFF
+#define BB_SYNC
+#define BB_SYSLOGD
+#define BB_TAIL
+#define BB_TAR
+//#define BB_TEE
+#define BB_TEST
+//#define BB_TELNET
+//#define BB_TFTP
+//#define BB_TIME
+//#define BB_TOP
+#define BB_TOUCH
+#define BB_TR
+//#define BB_TRACEROUTE
+#define BB_TRUE_FALSE
+#define BB_TTY
+//#define BB_UNIX2DOS
+//#define BB_UUENCODE
+//#define BB_UUDECODE
+#define BB_UMOUNT
+#define BB_UNIQ
+#define BB_UNAME
+//#define BB_UPDATE
+#define BB_UPTIME
+//#define BB_USLEEP
+//#define BB_VI
+//#define BB_WATCHDOG
+#define BB_WC
+#define BB_WGET
+#define BB_WHICH
+#define BB_WHOAMI
+//#define BB_XARGS
+//#define BB_YES
+// End of Applications List
+//
+//
+//
+// ---------------------------------------------------------
+// This is where feature definitions go.  Generally speaking,
+// turning this stuff off makes things a bit smaller (and less 
+// pretty/useful).
+//
+//
+// If you enabled one or more of the shells, you may select which one
+// should be run when sh is invoked:
+//#define BB_FEATURE_SH_IS_ASH
+//#define BB_FEATURE_SH_IS_HUSH
+//#define BB_FEATURE_SH_IS_LASH
+//#define BB_FEATURE_SH_IS_MSH
+//
+// BusyBox will, by default, malloc space for its buffers.  This costs code
+// size for the call to xmalloc.  You can use the following feature to have
+// them put on the stack.  For some very small machines with limited stack
+// space, this can be deadly.  For most folks, this works just fine...
+//#define BB_FEATURE_BUFFERS_GO_ON_STACK
+// The third alternative for buffer allocation is to use BSS.  This works
+// beautifully for computers with a real MMU (and OS support), but wastes
+// runtime RAM for uCLinux.  This behavior was the only one available for
+// BusyBox versions 0.48 and earlier.
+//#define BB_FEATURE_BUFFERS_GO_IN_BSS
+//
+// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
+// thereby eliminating the need for the /proc filesystem and thereby saving
+// lots and lots memory for more important things.  NOTE:  If you enable this
+// feature, you _must_ have patched the kernel to include the devps patch that
+// is included in the busybox/kernel-patches directory.  You will also need to
+// create some device special files in /dev on your embedded system:
+//        mknod /dev/mtab c 10 22
+//        mknod /dev/ps c 10 21
+// I emailed Linus and this patch will not be going into the stock kernel.
+//#define BB_FEATURE_USE_DEVPS_PATCH
+//
+// show verbose usage messages
+//#define BB_FEATURE_VERBOSE_USAGE
+//
+// Use termios to manipulate the screen ('more' is prettier with this on)
+#define BB_FEATURE_USE_TERMIOS
+//
+// calculate terminal & column widths (for more, ls, and telnet)
+#define BB_FEATURE_AUTOWIDTH
+//
+// show username/groupnames for ls
+#define BB_FEATURE_LS_USERNAME
+//
+// show file timestamps in ls
+#define BB_FEATURE_LS_TIMESTAMPS
+//
+// enable ls -p and -F
+#define BB_FEATURE_LS_FILETYPES
+//
+// sort the file names
+#define BB_FEATURE_LS_SORTFILES
+//
+// enable ls -R
+#define BB_FEATURE_LS_RECURSIVE
+//
+// enable ls -L
+#define BB_FEATURE_LS_FOLLOWLINKS
+//
+// Use color to identify different file types
+#define BB_FEATURE_LS_COLOR
+//
+// Disable for a smaller (but less functional) ping
+#define BB_FEATURE_FANCY_PING
+//
+// Make init use a simplified /etc/inittab file (recommended).
+#define BB_FEATURE_USE_INITTAB
+//
+//Enable init being called as /linuxrc
+#define BB_FEATURE_LINUXRC
+//
+//Have init enable core dumping for child processes (for debugging only) 
+//#define BB_FEATURE_INIT_COREDUMPS
+//
+//Make sure nothing is printed to the console on boot
+//#define BB_FEATURE_EXTRA_QUIET
+//
+// enable syslogd -R remotehost
+//#define BB_FEATURE_REMOTE_LOG
+//
+// enable syslogd -C
+//#define BB_FEATURE_IPC_SYSLOG
+//
+//Disable for a simple tail implementation (2.34k vs 3k for the full one).
+//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
+#define BB_FEATURE_FANCY_TAIL
+//
+// Enable support for loop devices in mount
+#define BB_FEATURE_MOUNT_LOOP
+//
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+//#define BB_FEATURE_MTAB_SUPPORT
+//
+// Enable support for mounting remote NFS volumes. 
+// You may need to mount with "-o nolock" if you are
+// not running a local portmapper daemon...
+//
+// If you are using uClibc, be sure that you've already compiled
+// uClibc with INCLUDE_RPC=true (contained in the Config file)
+#define BB_FEATURE_NFSMOUNT
+//
+// Enable support forced filesystem unmounting 
+// (i.e., in case of an unreachable NFS system).
+#define BB_FEATURE_MOUNT_FORCE
+//
+// Enable support for creation of tar files.
+#define BB_FEATURE_TAR_CREATE
+//
+// Enable support for "--exclude" and "-X" for excluding files
+//#define BB_FEATURE_TAR_EXCLUDE
+//
+// Enable support for tar -z option (currently only works for inflating)
+#define BB_FEATURE_TAR_GZIP 
+//
+// Enable reverse sort
+//#define BB_FEATURE_SORT_REVERSE
+//
+// Enable uniqe sort
+//#define BB_FEATURE_SORT_UNIQUE
+//
+// Enable command line editing in the shell.  
+// Only relevant if a shell is enabled. On by default.
+//#define BB_FEATURE_COMMAND_EDITING
+//
+// Enable tab completion in the shell.  This is now working quite nicely.
+// This feature adds a bit over 4k. Only relevant if a shell is enabled.
+//#define BB_FEATURE_COMMAND_TAB_COMPLETION
+//
+// Attempts to match usernames in a ~-prefixed path
+//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
+//
+//Allow the shell to invoke all the compiled in BusyBox applets as if they
+//were shell builtins.  Nice for staticly linking an emergency rescue shell,
+//among other things. Off by default.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_STANDALONE_SHELL
+//
+//When this is enabled, busybox shell applets can be called using full path
+//names.  This causes applets (i.e., most busybox commands) to override
+//real commands on the filesystem.  For example, if you run run /bin/cat, it
+//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
+//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
+//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
+// Only relevant if a shell is enabled. Off by default.
+//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+//
+// Uncomment this option for a fancy shell prompt that includes the
+// current username and hostname.  On systems that don't have usernames
+// or hostnames, this can look hideous.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_FANCY_PROMPT
+//
+// Uncomment this option to disable job control.  Job control lets you 
+// run jobs in the background (which completely useless for is all you 
+// are doing is running scripts).  Disabing this is bad for interactive
+// use, since when you hit ^C in an application, it will also kill the 
+// shell.  This adds about 2.5k on an x86 system.
+//#define BB_FEATURE_ASH_JOB_CONTROL
+//
+//Turn on extra fbset options
+//#define BB_FEATURE_FBSET_FANCY
+//
+//Turn on fbset readmode support
+//#define BB_FEATURE_FBSET_READMODE
+//
+// Support insmod/lsmod/rmmod for post 2.1 kernels
+//#define BB_FEATURE_NEW_MODULE_INTERFACE
+//
+// Support insmod/lsmod/rmmod for pre 2.1 kernels
+//#define BB_FEATURE_OLD_MODULE_INTERFACE
+//
+// Support module version checking
+//#define BB_FEATURE_INSMOD_VERSION_CHECKING
+//
+// Support for uClinux memory usage optimization, which will load the image
+// directly into the kernel memory.  This divides memory requrements by three.
+// If you are not running uClinux (i.e., your CPU has an MMU) leave this
+// disabled...
+//#define BB_FEATURE_INSMOD_LOADINKMEM
+//
+// Support for Minix filesystem, version 2
+//#define BB_FEATURE_MINIX2
+//
+// Enable ifconfig status reporting output -- this feature adds 7k.
+#define BB_FEATURE_IFCONFIG_STATUS
+//
+// Enable ifconfig slip-specific options "keepalive" and "outfill"
+//#define BB_FEATURE_IFCONFIG_SLIP
+//
+// Enable ifconfig options "mem_start", "io_addr", and "irq".
+#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+//
+// Enable ifconfig option "hw".  Currently works for only with "ether".
+#define BB_FEATURE_IFCONFIG_HW
+//
+// Allows "broadcast +" to set broadcast automatically based on hostaddr
+// and netmask, at a cost of about 100 bytes of code (i386).
+//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
+//
+// Enable busybox --install [-s]
+// to create links (or symlinks) for all the commands that are 
+// compiled into the binary.  (needs /proc filesystem)
+#define BB_FEATURE_INSTALLER
+//
+// Enable a nifty progress meter in wget (adds just under 2k)
+#define BB_FEATURE_WGET_STATUSBAR
+//
+// Enable HTTP authentication in wget
+#define BB_FEATURE_WGET_AUTHENTICATION
+//
+// Clean up all memory before exiting -- usually not needed
+// as the OS can clean up...  Don't enable this unless you
+// have a really good reason for cleaning things up manually.
+//#define BB_FEATURE_CLEAN_UP
+//
+// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
+#define BB_FEATURE_HUMAN_READABLE
+//
+// Support for the find -type option.
+#define BB_FEATURE_FIND_TYPE
+//
+// Support for the find -perm option.
+#define BB_FEATURE_FIND_PERM
+//
+// Support for the find -mtime option.
+#define BB_FEATURE_FIND_MTIME
+//
+//// Support for the find -newer option.
+#define BB_FEATURE_FIND_NEWER
+//
+// Support for the -A -B and -C context flags in grep
+//#define BB_FEATURE_GREP_CONTEXT
+//
+// Support for the EGREP applet (alias to the grep applet)
+//#define BB_FEATURE_GREP_EGREP_ALIAS
+//
+// Tell tftp what commands that should be supported.
+#define BB_FEATURE_TFTP_PUT
+#define BB_FEATURE_TFTP_GET
+//
+// features for vi
+//#define BB_FEATURE_VI_COLON          // ":" colon commands, no "ex" mode
+//#define BB_FEATURE_VI_YANKMARK               // Yank/Put commands and Mark cmds
+//#define BB_FEATURE_VI_SEARCH         // search and replace cmds
+//#define BB_FEATURE_VI_USE_SIGNALS    // catch signals
+//#define BB_FEATURE_VI_DOT_CMD                // remember previous cmd and "." cmd
+//#define BB_FEATURE_VI_READONLY               // vi -R and "view" mode
+//#define BB_FEATURE_VI_SETOPTS                // set-able options,  ai ic showmatch
+//#define BB_FEATURE_VI_SET            // :set
+//#define BB_FEATURE_VI_WIN_RESIZE     // handle window resize
+//
+// Enable a if you system have setuped locale
+//#define BB_LOCALE_SUPPORT
+//
+// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
+#define BB_FEATURE_TELNET_TTYPE
+//
+// Support for devfs.
+//#define BB_FEATURE_DEVFS
+//
+// End of Features List
+//
+//
+//
+//
+//
+//
+//---------------------------------------------------
+// Nothing beyond this point should ever be touched by 
+// mere mortals so leave this stuff alone.
+//
+#include <features.h>
+#if defined(__uClinux__)
+       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
+       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
+       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
+       #undef BB_UPDATE                /* Uses daemon() */
+#endif
+#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
+       #if defined BB_FEATURE_COMMAND_EDITING
+               #define BB_CMDEDIT
+       #else
+               #undef BB_FEATURE_COMMAND_EDITING
+               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
+               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               #undef BB_FEATURE_SH_FANCY_PROMPT
+       #endif
+#else
+       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       #undef BB_FEATURE_SH_STANDALONE_SHELL
+       #undef BB_FEATURE_SH_FANCY_PROMPT
+#endif
+//
+#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
+       #define BB_TEST
+#endif
+//
+#ifdef BB_KILLALL
+       #ifndef BB_KILL
+               #define BB_KILL
+       #endif
+#endif
+//
+#ifndef BB_INIT
+       #undef BB_FEATURE_LINUXRC
+#endif
+//
+#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
+       #define BB_NFSMOUNT
+#endif
+//
+#if defined BB_FEATURE_AUTOWIDTH
+       #ifndef BB_FEATURE_USE_TERMIOS
+               #define BB_FEATURE_USE_TERMIOS
+       #endif
+#endif
+//
+#if defined BB_INSMOD || defined BB_LSMOD
+       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
+               #define BB_FEATURE_NEW_MODULE_INTERFACE
+       #endif
+#endif
+//
+#ifdef BB_UNIX2DOS
+       #define BB_DOS2UNIX
+#endif 
+//
+#ifdef BB_SYSLOGD
+       #if defined BB_FEATURE_IPC_SYSLOG
+               #define BB_LOGREAD
+       #endif
+#endif
+//
+#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
+# define shell_main ash_main
+#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
+# define shell_main hush_main
+#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
+# define shell_main lash_main
+#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
+# define shell_main msh_main
+#endif
diff --git a/debian/Config.h-static b/debian/Config.h-static
new file mode 100644 (file)
index 0000000..879642c
--- /dev/null
@@ -0,0 +1,493 @@
+/* vi: set sw=4 ts=4: */
+// This file defines the feature set to be compiled into busybox.
+// When you turn things off here, they won't be compiled in at all.
+//
+//// This file is parsed by sed.  You MUST use single line comments.
+//   i.e.,  //#define BB_BLAH
+//
+//
+// BusyBox Applications
+//#define BB_ADJTIMEX
+#define BB_AR
+#define BB_ASH
+#define BB_BASENAME
+#define BB_CAT
+#define BB_CHGRP
+#define BB_CHMOD
+#define BB_CHOWN
+#define BB_CHROOT
+#define BB_CHVT
+#define BB_CLEAR
+#define BB_CMP
+#define BB_CP
+#define BB_CPIO
+#define BB_CUT
+#define BB_DATE
+#define BB_DC
+#define BB_DD
+#define BB_DEALLOCVT
+#define BB_DF
+#define BB_DIRNAME
+#define BB_DMESG
+#define BB_DOS2UNIX
+#define BB_DPKG
+#define BB_DPKG_DEB
+#define BB_DUTMP
+#define BB_DU
+#define BB_DUMPKMAP
+#define BB_ECHO
+#define BB_ENV
+#define BB_EXPR
+#define BB_FBSET
+#define BB_FDFLUSH
+#define BB_FIND
+#define BB_FREE
+#define BB_FREERAMDISK
+#define BB_FSCK_MINIX
+#define BB_GETOPT
+#define BB_GREP
+#define BB_GUNZIP
+#define BB_GZIP
+#define BB_HALT
+#define BB_HEAD
+#define BB_HOSTID
+#define BB_HOSTNAME
+//#define BB_HUSH
+#define BB_ID
+#define BB_IFCONFIG
+#define BB_INIT
+//#define BB_INSMOD
+#define BB_KILL
+#define BB_KILLALL
+#define BB_KLOGD
+//#define BB_LASH
+#define BB_LENGTH
+#define BB_LN
+#define BB_LOADACM
+#define BB_LOADFONT
+#define BB_LOADKMAP
+#define BB_LOGGER
+#define BB_LOGNAME
+#define BB_LOSETUP
+#define BB_LS
+#define BB_LSMOD
+#define BB_MAKEDEVS
+#define BB_MD5SUM
+#define BB_MKDIR
+#define BB_MKFIFO
+#define BB_MKFS_MINIX
+#define BB_MKNOD
+#define BB_MKSWAP
+#define BB_MKTEMP
+#define BB_MODPROBE
+#define BB_MORE
+#define BB_MOUNT
+//#define BB_MSH
+#define BB_MT
+#define BB_MV
+#define BB_NC
+#define BB_NSLOOKUP
+#define BB_PIDOF
+#define BB_PING
+#define BB_PIVOT_ROOT
+#define BB_POWEROFF
+#define BB_PRINTF
+#define BB_PS
+#define BB_PWD
+#define BB_RDATE
+#define BB_READLINK
+#define BB_REBOOT
+#define BB_RENICE
+#define BB_RESET
+#define BB_RM
+#define BB_RMDIR
+#define BB_RMMOD
+#define BB_ROUTE
+#define BB_RPM2CPIO
+#define BB_SED
+#define BB_SETKEYCODES
+#define BB_SLEEP
+#define BB_SORT
+#define BB_STTY
+#define BB_SWAPONOFF
+#define BB_SYNC
+#define BB_SYSLOGD
+#define BB_TAIL
+#define BB_TAR
+#define BB_TEE
+#define BB_TEST
+#define BB_TELNET
+#define BB_TFTP
+#define BB_TIME
+#define BB_TOP
+#define BB_TOUCH
+#define BB_TR
+#define BB_TRACEROUTE
+#define BB_TRUE_FALSE
+#define BB_TTY
+#define BB_UNIX2DOS
+#define BB_UUENCODE
+#define BB_UUDECODE
+#define BB_UMOUNT
+#define BB_UNIQ
+#define BB_UNAME
+#define BB_UPDATE
+#define BB_UPTIME
+#define BB_USLEEP
+#define BB_VI
+#define BB_WATCHDOG
+#define BB_WC
+#define BB_WGET
+#define BB_WHICH
+#define BB_WHOAMI
+#define BB_XARGS
+#define BB_YES
+// End of Applications List
+//
+//
+//
+// ---------------------------------------------------------
+// This is where feature definitions go.  Generally speaking,
+// turning this stuff off makes things a bit smaller (and less 
+// pretty/useful).
+//
+//
+// If you enabled one or more of the shells, you may select which one
+// should be run when sh is invoked:
+#define BB_FEATURE_SH_IS_ASH
+//#define BB_FEATURE_SH_IS_HUSH
+//#define BB_FEATURE_SH_IS_LASH
+//#define BB_FEATURE_SH_IS_MSH
+//
+// BusyBox will, by default, malloc space for its buffers.  This costs code
+// size for the call to xmalloc.  You can use the following feature to have
+// them put on the stack.  For some very small machines with limited stack
+// space, this can be deadly.  For most folks, this works just fine...
+//#define BB_FEATURE_BUFFERS_GO_ON_STACK
+// The third alternative for buffer allocation is to use BSS.  This works
+// beautifully for computers with a real MMU (and OS support), but wastes
+// runtime RAM for uCLinux.  This behavior was the only one available for
+// BusyBox versions 0.48 and earlier.
+//#define BB_FEATURE_BUFFERS_GO_IN_BSS
+//
+// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
+// thereby eliminating the need for the /proc filesystem and thereby saving
+// lots and lots memory for more important things.  NOTE:  If you enable this
+// feature, you _must_ have patched the kernel to include the devps patch that
+// is included in the busybox/kernel-patches directory.  You will also need to
+// create some device special files in /dev on your embedded system:
+//        mknod /dev/mtab c 10 22
+//        mknod /dev/ps c 10 21
+// I emailed Linus and this patch will not be going into the stock kernel.
+//#define BB_FEATURE_USE_DEVPS_PATCH
+//
+// show verbose usage messages
+#define BB_FEATURE_VERBOSE_USAGE
+//
+// Use termios to manipulate the screen ('more' is prettier with this on)
+#define BB_FEATURE_USE_TERMIOS
+//
+// calculate terminal & column widths (for more, ls, and telnet)
+#define BB_FEATURE_AUTOWIDTH
+//
+// show username/groupnames for ls
+#define BB_FEATURE_LS_USERNAME
+//
+// show file timestamps in ls
+#define BB_FEATURE_LS_TIMESTAMPS
+//
+// enable ls -p and -F
+#define BB_FEATURE_LS_FILETYPES
+//
+// sort the file names
+#define BB_FEATURE_LS_SORTFILES
+//
+// enable ls -R
+#define BB_FEATURE_LS_RECURSIVE
+//
+// enable ls -L
+#define BB_FEATURE_LS_FOLLOWLINKS
+//
+// Use color to identify different file types
+#define BB_FEATURE_LS_COLOR
+//
+// Disable for a smaller (but less functional) ping
+#define BB_FEATURE_FANCY_PING
+//
+// Make init use a simplified /etc/inittab file (recommended).
+#define BB_FEATURE_USE_INITTAB
+//
+//Enable init being called as /linuxrc
+#define BB_FEATURE_LINUXRC
+//
+//Have init enable core dumping for child processes (for debugging only) 
+//#define BB_FEATURE_INIT_COREDUMPS
+//
+//Make sure nothing is printed to the console on boot
+//#define BB_FEATURE_EXTRA_QUIET
+//
+// enable syslogd -R remotehost
+#define BB_FEATURE_REMOTE_LOG
+//
+// enable syslogd -C
+//#define BB_FEATURE_IPC_SYSLOG
+//
+//Disable for a simple tail implementation (2.34k vs 3k for the full one).
+//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
+#define BB_FEATURE_FANCY_TAIL
+//
+// Enable support for loop devices in mount
+#define BB_FEATURE_MOUNT_LOOP
+//
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+//#define BB_FEATURE_MTAB_SUPPORT
+//
+// Enable support for mounting remote NFS volumes. 
+// You may need to mount with "-o nolock" if you are
+// not running a local portmapper daemon...
+//
+// If you are using uClibc, be sure that you've already compiled
+// uClibc with INCLUDE_RPC=true (contained in the Config file)
+#define BB_FEATURE_NFSMOUNT
+//
+// Enable support forced filesystem unmounting 
+// (i.e., in case of an unreachable NFS system).
+#define BB_FEATURE_MOUNT_FORCE
+//
+// Enable support for creation of tar files.
+#define BB_FEATURE_TAR_CREATE
+//
+// Enable support for "--exclude" and "-X" for excluding files
+#define BB_FEATURE_TAR_EXCLUDE
+//
+// Enable support for tar -z option (currently only works for inflating)
+#define BB_FEATURE_TAR_GZIP 
+//
+// Enable reverse sort
+#define BB_FEATURE_SORT_REVERSE
+//
+// Enable uniqe sort
+#define BB_FEATURE_SORT_UNIQUE
+//
+// Enable command line editing in the shell.  
+// Only relevant if a shell is enabled. On by default.
+#define BB_FEATURE_COMMAND_EDITING
+//
+// Enable tab completion in the shell.  This is now working quite nicely.
+// This feature adds a bit over 4k. Only relevant if a shell is enabled.
+#define BB_FEATURE_COMMAND_TAB_COMPLETION
+//
+// Attempts to match usernames in a ~-prefixed path
+#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
+//
+//Allow the shell to invoke all the compiled in BusyBox applets as if they
+//were shell builtins.  Nice for staticly linking an emergency rescue shell,
+//among other things. Off by default.
+// Only relevant if a shell is enabled.
+#define BB_FEATURE_SH_STANDALONE_SHELL
+//
+//When this is enabled, busybox shell applets can be called using full path
+//names.  This causes applets (i.e., most busybox commands) to override
+//real commands on the filesystem.  For example, if you run run /bin/cat, it
+//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
+//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
+//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
+// Only relevant if a shell is enabled. Off by default.
+#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+//
+// Uncomment this option for a fancy shell prompt that includes the
+// current username and hostname.  On systems that don't have usernames
+// or hostnames, this can look hideous.
+// Only relevant if a shell is enabled.
+#define BB_FEATURE_SH_FANCY_PROMPT
+//
+// Uncomment this option to disable job control.  Job control lets you 
+// run jobs in the background (which completely useless for is all you 
+// are doing is running scripts).  Disabing this is bad for interactive
+// use, since when you hit ^C in an application, it will also kill the 
+// shell.  This adds about 2.5k on an x86 system.
+#define BB_FEATURE_ASH_JOB_CONTROL
+//
+//Turn on extra fbset options
+//#define BB_FEATURE_FBSET_FANCY
+//
+//Turn on fbset readmode support
+#define BB_FEATURE_FBSET_READMODE
+//
+// Support insmod/lsmod/rmmod for post 2.1 kernels
+#define BB_FEATURE_NEW_MODULE_INTERFACE
+//
+// Support insmod/lsmod/rmmod for pre 2.1 kernels
+//#define BB_FEATURE_OLD_MODULE_INTERFACE
+//
+// Support module version checking
+//#define BB_FEATURE_INSMOD_VERSION_CHECKING
+//
+// Support for uClinux memory usage optimization, which will load the image
+// directly into the kernel memory.  This divides memory requrements by three.
+// If you are not running uClinux (i.e., your CPU has an MMU) leave this
+// disabled...
+//#define BB_FEATURE_INSMOD_LOADINKMEM
+//
+// Support for Minix filesystem, version 2
+#define BB_FEATURE_MINIX2
+//
+// Enable ifconfig status reporting output -- this feature adds 7k.
+#define BB_FEATURE_IFCONFIG_STATUS
+//
+// Enable ifconfig slip-specific options "keepalive" and "outfill"
+#define BB_FEATURE_IFCONFIG_SLIP
+//
+// Enable ifconfig options "mem_start", "io_addr", and "irq".
+#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+//
+// Enable ifconfig option "hw".  Currently works for only with "ether".
+#define BB_FEATURE_IFCONFIG_HW
+//
+// Allows "broadcast +" to set broadcast automatically based on hostaddr
+// and netmask, at a cost of about 100 bytes of code (i386).
+#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
+//
+// Enable busybox --install [-s]
+// to create links (or symlinks) for all the commands that are 
+// compiled into the binary.  (needs /proc filesystem)
+//#define BB_FEATURE_INSTALLER
+//
+// Enable a nifty progress meter in wget (adds just under 2k)
+#define BB_FEATURE_WGET_STATUSBAR
+//
+// Enable HTTP authentication in wget
+#define BB_FEATURE_WGET_AUTHENTICATION
+//
+// Clean up all memory before exiting -- usually not needed
+// as the OS can clean up...  Don't enable this unless you
+// have a really good reason for cleaning things up manually.
+//#define BB_FEATURE_CLEAN_UP
+//
+// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
+#define BB_FEATURE_HUMAN_READABLE
+//
+// Support for the find -type option.
+#define BB_FEATURE_FIND_TYPE
+//
+// Support for the find -perm option.
+#define BB_FEATURE_FIND_PERM
+//
+// Support for the find -mtime option.
+#define BB_FEATURE_FIND_MTIME
+//
+//// Support for the find -newer option.
+#define BB_FEATURE_FIND_NEWER
+//
+// Support for the -A -B and -C context flags in grep
+#define BB_FEATURE_GREP_CONTEXT
+//
+// Support for the EGREP applet (alias to the grep applet)
+#define BB_FEATURE_GREP_EGREP_ALIAS
+//
+// Tell tftp what commands that should be supported.
+#define BB_FEATURE_TFTP_PUT
+#define BB_FEATURE_TFTP_GET
+//
+// features for vi
+#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
+#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
+#define BB_FEATURE_VI_SEARCH           // search and replace cmds
+#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
+#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
+#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
+#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
+#define BB_FEATURE_VI_SET              // :set
+#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
+//
+// Enable a if you system have setuped locale
+//#define BB_LOCALE_SUPPORT
+//
+// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
+#define BB_FEATURE_TELNET_TTYPE
+//
+// Support for devfs.
+//#define BB_FEATURE_DEVFS
+//
+// End of Features List
+//
+//
+//
+//
+//
+//
+//---------------------------------------------------
+// Nothing beyond this point should ever be touched by 
+// mere mortals so leave this stuff alone.
+//
+#include <features.h>
+#if defined(__uClinux__)
+       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
+       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
+       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
+       #undef BB_UPDATE                /* Uses daemon() */
+#endif
+#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
+       #if defined BB_FEATURE_COMMAND_EDITING
+               #define BB_CMDEDIT
+       #else
+               #undef BB_FEATURE_COMMAND_EDITING
+               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
+               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               #undef BB_FEATURE_SH_FANCY_PROMPT
+       #endif
+#else
+       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       #undef BB_FEATURE_SH_STANDALONE_SHELL
+       #undef BB_FEATURE_SH_FANCY_PROMPT
+#endif
+//
+#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
+       #define BB_TEST
+#endif
+//
+#ifdef BB_KILLALL
+       #ifndef BB_KILL
+               #define BB_KILL
+       #endif
+#endif
+//
+#ifndef BB_INIT
+       #undef BB_FEATURE_LINUXRC
+#endif
+//
+#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
+       #define BB_NFSMOUNT
+#endif
+//
+#if defined BB_FEATURE_AUTOWIDTH
+       #ifndef BB_FEATURE_USE_TERMIOS
+               #define BB_FEATURE_USE_TERMIOS
+       #endif
+#endif
+//
+#if defined BB_INSMOD || defined BB_LSMOD
+       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
+               #define BB_FEATURE_NEW_MODULE_INTERFACE
+       #endif
+#endif
+//
+#ifdef BB_UNIX2DOS
+       #define BB_DOS2UNIX
+#endif 
+//
+#ifdef BB_SYSLOGD
+       #if defined BB_FEATURE_IPC_SYSLOG
+               #define BB_LOGREAD
+       #endif
+#endif
+//
+#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
+# define shell_main ash_main
+#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
+# define shell_main hush_main
+#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
+# define shell_main lash_main
+#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
+# define shell_main msh_main
+#endif
diff --git a/debian/Config.h-udeb b/debian/Config.h-udeb
new file mode 100644 (file)
index 0000000..82ec784
--- /dev/null
@@ -0,0 +1,493 @@
+/* vi: set sw=4 ts=4: */
+// This file defines the feature set to be compiled into busybox.
+// When you turn things off here, they won't be compiled in at all.
+//
+//// This file is parsed by sed.  You MUST use single line comments.
+//   i.e.,  //#define BB_BLAH
+//
+//
+// BusyBox Applications
+//#define BB_ADJTIMEX
+#define BB_AR
+//#define BB_ASH
+#define BB_BASENAME
+#define BB_CAT
+//#define BB_CHGRP
+#define BB_CHMOD
+#define BB_CHOWN
+#define BB_CHROOT
+#define BB_CHVT
+//#define BB_CLEAR
+//#define BB_CMP
+#define BB_CP
+//#define BB_CPIO
+#define BB_CUT
+//#define BB_DATE
+//#define BB_DC
+//#define BB_DD
+//#define BB_DEALLOCVT
+#define BB_DF
+#define BB_DIRNAME
+#define BB_DMESG
+//#define BB_DOS2UNIX
+//#define BB_DPKG
+//#define BB_DPKG_DEB
+//#define BB_DUTMP
+//#define BB_DU
+//#define BB_DUMPKMAP
+#define BB_ECHO
+#define BB_ENV
+#define BB_EXPR
+//#define BB_FBSET
+//#define BB_FDFLUSH
+#define BB_FIND
+#define BB_FREE
+#define BB_FREERAMDISK
+//#define BB_FSCK_MINIX
+//#define BB_GETOPT
+#define BB_GREP
+#define BB_GUNZIP
+//#define BB_GZIP
+//#define BB_HALT
+#define BB_HEAD
+//#define BB_HOSTID
+//#define BB_HOSTNAME
+//#define BB_HUSH
+#define BB_ID
+#define BB_IFCONFIG
+#define BB_INIT
+//#define BB_INSMOD
+#define BB_KILL
+//#define BB_KILLALL
+#define BB_KLOGD
+//#define BB_LASH
+//#define BB_LENGTH
+#define BB_LN
+//#define BB_LOADACM
+//#define BB_LOADFONT
+//#define BB_LOADKMAP
+//#define BB_LOGGER
+//#define BB_LOGNAME
+//#define BB_LOSETUP
+#define BB_LS
+#define BB_LSMOD
+//#define BB_MAKEDEVS
+#define BB_MD5SUM
+#define BB_MKDIR
+//#define BB_MKFIFO
+//#define BB_MKFS_MINIX
+#define BB_MKNOD
+//#define BB_MKSWAP
+//#define BB_MKTEMP
+//#define BB_MODPROBE
+//#define BB_MORE
+#define BB_MOUNT
+//#define BB_MSH
+//#define BB_MT
+#define BB_MV
+//#define BB_NC
+//#define BB_NSLOOKUP
+#define BB_PIDOF
+#define BB_PING
+#define BB_PIVOT_ROOT
+//#define BB_POWEROFF
+//#define BB_PRINTF
+#define BB_PS
+#define BB_PWD
+//#define BB_RDATE
+//#define BB_READLINK
+#define BB_REBOOT
+//#define BB_RENICE
+//#define BB_RESET
+#define BB_RM
+#define BB_RMDIR
+//#define BB_RMMOD
+#define BB_ROUTE
+//#define BB_RPM2CPIO
+#define BB_SED
+//#define BB_SETKEYCODES
+//#define BB_SLEEP
+#define BB_SORT
+//#define BB_STTY
+//#define BB_SWAPONOFF
+#define BB_SYNC
+#define BB_SYSLOGD
+#define BB_TAIL
+#define BB_TAR
+//#define BB_TEE
+//#define BB_TEST
+#define BB_TELNET
+//#define BB_TFTP
+//#define BB_TIME
+//#define BB_TOP
+#define BB_TOUCH
+#define BB_TR
+//#define BB_TRACEROUTE
+#define BB_TRUE_FALSE
+//#define BB_TTY
+//#define BB_UNIX2DOS
+//#define BB_UUENCODE
+//#define BB_UUDECODE
+#define BB_UMOUNT
+//#define BB_UNIQ
+#define BB_UNAME
+//#define BB_UPDATE
+//#define BB_UPTIME
+//#define BB_USLEEP
+//#define BB_VI
+//#define BB_WATCHDOG
+#define BB_WC
+#define BB_WGET
+//#define BB_WHICH
+//#define BB_WHOAMI
+//#define BB_XARGS
+//#define BB_YES
+// End of Applications List
+//
+//
+//
+// ---------------------------------------------------------
+// This is where feature definitions go.  Generally speaking,
+// turning this stuff off makes things a bit smaller (and less 
+// pretty/useful).
+//
+//
+// If you enabled one or more of the shells, you may select which one
+// should be run when sh is invoked:
+//#define BB_FEATURE_SH_IS_ASH
+//#define BB_FEATURE_SH_IS_HUSH
+//#define BB_FEATURE_SH_IS_LASH
+#define BB_FEATURE_SH_IS_MSH
+//
+// BusyBox will, by default, malloc space for its buffers.  This costs code
+// size for the call to xmalloc.  You can use the following feature to have
+// them put on the stack.  For some very small machines with limited stack
+// space, this can be deadly.  For most folks, this works just fine...
+//#define BB_FEATURE_BUFFERS_GO_ON_STACK
+// The third alternative for buffer allocation is to use BSS.  This works
+// beautifully for computers with a real MMU (and OS support), but wastes
+// runtime RAM for uCLinux.  This behavior was the only one available for
+// BusyBox versions 0.48 and earlier.
+//#define BB_FEATURE_BUFFERS_GO_IN_BSS
+//
+// Turn this on to use Erik's very cool devps, and devmtab kernel drivers,
+// thereby eliminating the need for the /proc filesystem and thereby saving
+// lots and lots memory for more important things.  NOTE:  If you enable this
+// feature, you _must_ have patched the kernel to include the devps patch that
+// is included in the busybox/kernel-patches directory.  You will also need to
+// create some device special files in /dev on your embedded system:
+//        mknod /dev/mtab c 10 22
+//        mknod /dev/ps c 10 21
+// I emailed Linus and this patch will not be going into the stock kernel.
+//#define BB_FEATURE_USE_DEVPS_PATCH
+//
+// show verbose usage messages
+//#define BB_FEATURE_VERBOSE_USAGE
+//
+// Use termios to manipulate the screen ('more' is prettier with this on)
+#define BB_FEATURE_USE_TERMIOS
+//
+// calculate terminal & column widths (for more, ls, and telnet)
+#define BB_FEATURE_AUTOWIDTH
+//
+// show username/groupnames for ls
+#define BB_FEATURE_LS_USERNAME
+//
+// show file timestamps in ls
+#define BB_FEATURE_LS_TIMESTAMPS
+//
+// enable ls -p and -F
+//#define BB_FEATURE_LS_FILETYPES
+//
+// sort the file names
+#define BB_FEATURE_LS_SORTFILES
+//
+// enable ls -R
+//#define BB_FEATURE_LS_RECURSIVE
+//
+// enable ls -L
+#define BB_FEATURE_LS_FOLLOWLINKS
+//
+// Use color to identify different file types
+#define BB_FEATURE_LS_COLOR
+//
+// Disable for a smaller (but less functional) ping
+#define BB_FEATURE_FANCY_PING
+//
+// Make init use a simplified /etc/inittab file (recommended).
+#define BB_FEATURE_USE_INITTAB
+//
+//Enable init being called as /linuxrc
+#define BB_FEATURE_LINUXRC
+//
+//Have init enable core dumping for child processes (for debugging only) 
+//#define BB_FEATURE_INIT_COREDUMPS
+//
+//Make sure nothing is printed to the console on boot
+//#define BB_FEATURE_EXTRA_QUIET
+//
+// enable syslogd -R remotehost
+//#define BB_FEATURE_REMOTE_LOG
+//
+// enable syslogd -C
+//#define BB_FEATURE_IPC_SYSLOG
+//
+//Disable for a simple tail implementation (2.34k vs 3k for the full one).
+//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. 
+//#define BB_FEATURE_FANCY_TAIL
+//
+// Enable support for loop devices in mount
+#define BB_FEATURE_MOUNT_LOOP
+//
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+//#define BB_FEATURE_MTAB_SUPPORT
+//
+// Enable support for mounting remote NFS volumes. 
+// You may need to mount with "-o nolock" if you are
+// not running a local portmapper daemon...
+//
+// If you are using uClibc, be sure that you've already compiled
+// uClibc with INCLUDE_RPC=true (contained in the Config file)
+#define BB_FEATURE_NFSMOUNT
+//
+// Enable support forced filesystem unmounting 
+// (i.e., in case of an unreachable NFS system).
+#define BB_FEATURE_MOUNT_FORCE
+//
+// Enable support for creation of tar files.
+//#define BB_FEATURE_TAR_CREATE
+//
+// Enable support for "--exclude" and "-X" for excluding files
+//#define BB_FEATURE_TAR_EXCLUDE
+//
+// Enable support for tar -z option (currently only works for inflating)
+#define BB_FEATURE_TAR_GZIP 
+//
+// Enable reverse sort
+//#define BB_FEATURE_SORT_REVERSE
+//
+// Enable uniqe sort
+//#define BB_FEATURE_SORT_UNIQUE
+//
+// Enable command line editing in the shell.  
+// Only relevant if a shell is enabled. On by default.
+#define BB_FEATURE_COMMAND_EDITING
+//
+// Enable tab completion in the shell.  This is now working quite nicely.
+// This feature adds a bit over 4k. Only relevant if a shell is enabled.
+#define BB_FEATURE_COMMAND_TAB_COMPLETION
+//
+// Attempts to match usernames in a ~-prefixed path
+//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
+//
+//Allow the shell to invoke all the compiled in BusyBox applets as if they
+//were shell builtins.  Nice for staticly linking an emergency rescue shell,
+//among other things. Off by default.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_STANDALONE_SHELL
+//
+//When this is enabled, busybox shell applets can be called using full path
+//names.  This causes applets (i.e., most busybox commands) to override
+//real commands on the filesystem.  For example, if you run run /bin/cat, it
+//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_
+//busybox.  Some systems want this, others do not.  Choose wisely.  :-) This
+//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled.
+// Only relevant if a shell is enabled. Off by default.
+//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+//
+// Uncomment this option for a fancy shell prompt that includes the
+// current username and hostname.  On systems that don't have usernames
+// or hostnames, this can look hideous.
+// Only relevant if a shell is enabled.
+//#define BB_FEATURE_SH_FANCY_PROMPT
+//
+// Uncomment this option to disable job control.  Job control lets you 
+// run jobs in the background (which completely useless for is all you 
+// are doing is running scripts).  Disabing this is bad for interactive
+// use, since when you hit ^C in an application, it will also kill the 
+// shell.  This adds about 2.5k on an x86 system.
+#define BB_FEATURE_ASH_JOB_CONTROL
+//
+//Turn on extra fbset options
+//#define BB_FEATURE_FBSET_FANCY
+//
+//Turn on fbset readmode support
+//#define BB_FEATURE_FBSET_READMODE
+//
+// Support insmod/lsmod/rmmod for post 2.1 kernels
+//#define BB_FEATURE_NEW_MODULE_INTERFACE
+//
+// Support insmod/lsmod/rmmod for pre 2.1 kernels
+//#define BB_FEATURE_OLD_MODULE_INTERFACE
+//
+// Support module version checking
+//#define BB_FEATURE_INSMOD_VERSION_CHECKING
+//
+// Support for uClinux memory usage optimization, which will load the image
+// directly into the kernel memory.  This divides memory requrements by three.
+// If you are not running uClinux (i.e., your CPU has an MMU) leave this
+// disabled...
+//#define BB_FEATURE_INSMOD_LOADINKMEM
+//
+// Support for Minix filesystem, version 2
+//#define BB_FEATURE_MINIX2
+//
+// Enable ifconfig status reporting output -- this feature adds 7k.
+#define BB_FEATURE_IFCONFIG_STATUS
+//
+// Enable ifconfig slip-specific options "keepalive" and "outfill"
+//#define BB_FEATURE_IFCONFIG_SLIP
+//
+// Enable ifconfig options "mem_start", "io_addr", and "irq".
+#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+//
+// Enable ifconfig option "hw".  Currently works for only with "ether".
+#define BB_FEATURE_IFCONFIG_HW
+//
+// Allows "broadcast +" to set broadcast automatically based on hostaddr
+// and netmask, at a cost of about 100 bytes of code (i386).
+//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS
+//
+// Enable busybox --install [-s]
+// to create links (or symlinks) for all the commands that are 
+// compiled into the binary.  (needs /proc filesystem)
+//#define BB_FEATURE_INSTALLER
+//
+// Enable a nifty progress meter in wget (adds just under 2k)
+#define BB_FEATURE_WGET_STATUSBAR
+//
+// Enable HTTP authentication in wget
+//#define BB_FEATURE_WGET_AUTHENTICATION
+//
+// Clean up all memory before exiting -- usually not needed
+// as the OS can clean up...  Don't enable this unless you
+// have a really good reason for cleaning things up manually.
+//#define BB_FEATURE_CLEAN_UP
+//
+// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G)
+#define BB_FEATURE_HUMAN_READABLE
+//
+// Support for the find -type option.
+#define BB_FEATURE_FIND_TYPE
+//
+// Support for the find -perm option.
+#define BB_FEATURE_FIND_PERM
+//
+// Support for the find -mtime option.
+#define BB_FEATURE_FIND_MTIME
+//
+//// Support for the find -newer option.
+#define BB_FEATURE_FIND_NEWER
+//
+// Support for the -A -B and -C context flags in grep
+//#define BB_FEATURE_GREP_CONTEXT
+//
+// Support for the EGREP applet (alias to the grep applet)
+//#define BB_FEATURE_GREP_EGREP_ALIAS
+//
+// Tell tftp what commands that should be supported.
+#define BB_FEATURE_TFTP_PUT
+#define BB_FEATURE_TFTP_GET
+//
+// features for vi
+#define BB_FEATURE_VI_COLON            // ":" colon commands, no "ex" mode
+#define BB_FEATURE_VI_YANKMARK         // Yank/Put commands and Mark cmds
+#define BB_FEATURE_VI_SEARCH           // search and replace cmds
+#define BB_FEATURE_VI_USE_SIGNALS      // catch signals
+#define BB_FEATURE_VI_DOT_CMD          // remember previous cmd and "." cmd
+#define BB_FEATURE_VI_READONLY         // vi -R and "view" mode
+#define BB_FEATURE_VI_SETOPTS          // set-able options,  ai ic showmatch
+#define BB_FEATURE_VI_SET              // :set
+#define BB_FEATURE_VI_WIN_RESIZE       // handle window resize
+//
+// Enable a if you system have setuped locale
+//#define BB_LOCALE_SUPPORT
+//
+// Support for TELNET to pass TERM type to remote host.  Adds 384 bytes.
+#define BB_FEATURE_TELNET_TTYPE
+//
+// Support for devfs.
+//#define BB_FEATURE_DEVFS
+//
+// End of Features List
+//
+//
+//
+//
+//
+//
+//---------------------------------------------------
+// Nothing beyond this point should ever be touched by 
+// mere mortals so leave this stuff alone.
+//
+#include <features.h>
+#if defined(__uClinux__)
+       #undef BB_RPM2CPIO              /* Uses gz_open(), which uses fork() */
+       #undef BB_DPKG_DEB              /* Uses gz_open(), which uses fork() */
+       #undef BB_FEATURE_TAR_GZIP      /* Uses fork() */
+       #undef BB_UPDATE                /* Uses daemon() */
+#endif
+#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH
+       #if defined BB_FEATURE_COMMAND_EDITING
+               #define BB_CMDEDIT
+       #else
+               #undef BB_FEATURE_COMMAND_EDITING
+               #undef BB_FEATURE_COMMAND_TAB_COMPLETION
+               #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+               #undef BB_FEATURE_SH_FANCY_PROMPT
+       #endif
+#else
+       #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       #undef BB_FEATURE_SH_STANDALONE_SHELL
+       #undef BB_FEATURE_SH_FANCY_PROMPT
+#endif
+//
+#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST
+       #define BB_TEST
+#endif
+//
+#ifdef BB_KILLALL
+       #ifndef BB_KILL
+               #define BB_KILL
+       #endif
+#endif
+//
+#ifndef BB_INIT
+       #undef BB_FEATURE_LINUXRC
+#endif
+//
+#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT
+       #define BB_NFSMOUNT
+#endif
+//
+#if defined BB_FEATURE_AUTOWIDTH
+       #ifndef BB_FEATURE_USE_TERMIOS
+               #define BB_FEATURE_USE_TERMIOS
+       #endif
+#endif
+//
+#if defined BB_INSMOD || defined BB_LSMOD
+       #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE
+               #define BB_FEATURE_NEW_MODULE_INTERFACE
+       #endif
+#endif
+//
+#ifdef BB_UNIX2DOS
+       #define BB_DOS2UNIX
+#endif 
+//
+#ifdef BB_SYSLOGD
+       #if defined BB_FEATURE_IPC_SYSLOG
+               #define BB_LOGREAD
+       #endif
+#endif
+//
+#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH
+# define shell_main ash_main
+#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH
+# define shell_main hush_main
+#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH
+# define shell_main lash_main
+#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH
+# define shell_main msh_main
+#endif
diff --git a/debian/README.debian b/debian/README.debian
new file mode 100644 (file)
index 0000000..a43fde4
--- /dev/null
@@ -0,0 +1,10 @@
+BusyBox for Debian
+----------------------
+
+BusyBox is being developed and maintained by Erik Andersen
+<andersee@debian.org>.
+
+If you have a problem with BusyBox, send email to the Debian bug tracking
+system that lives at <submit@bugs.busybox.net> 
+
+Erik Andersen <andersee@debian.org>, Sun, 18 Jun 2000 21:52:00 -0600
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..236766e
--- /dev/null
@@ -0,0 +1,318 @@
+busybox (1:0.60.5-2) unstable; urgency=low
+  
+  * It turns out that for the .udeb, we don't want to disable 
+    BB_FEATURE_LINUXRC, we just want to kill the /linuxrc link.
+    Thanks to Matt Kraai for tracking this one down.  (closes: #161611)
+
+ -- Erik Andersen <andersee@debian.org>  Thu, 31 Oct 2002 02:25:01 -0700
+
+busybox (1:0.60.5-1) unstable; urgency=low
+  
+  * New version released.  See Changelog for non-Debian specific details.
+  * zcat no longer tries to delete source files (closes: #164968)
+  * Eliminate /linuxrc from the .udeb (closes: #163890)
+  * Fix description of the --install option (closes: #164178)
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 26 Oct 2002 06:23:51 -0600
+
+busybox (1:0.60.4-1.1) unstable; urgency=low
+
+  * NMU
+  * Fix cp -a so it handles symlinks properly (closes: #163501)
+
+ -- Tollef Fog Heen <tfheen@debian.org>  Sun,  6 Oct 2002 16:08:45 +0200
+
+busybox (1:0.60.4-1) unstable; urgency=low
+  
+  * New version released.  See Changelog for non-Debian specific details.
+  * enable uname for the debian-installer (closes: #158706)
+  * enable losetup for the boot floppies (closes: #138060)
+  * init behaves itself better consoles go missing (closes: #129626)
+  * In 'free', buffers change as buffered data increases (closes: #148396)
+  * Functions for debootstrap added to the .udeb (closes: #124388)
+  * This bug is not reproducable (closes: #127522)
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 18 Sep 2002 14:13:05 -0600
+
+busybox (1:0.60.3-1) unstable; urgency=low
+  
+  * New version released.  See Changelog for non-Debian specific details.
+  * makedevs no longer segfaults (closes: #123921)
+  * wget no longer crashes (closes: #138943)
+  * wget now checks the safe_fwrite return code (closes: #143179)
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 27 Apr 2002 01:33:34 -0600
+
+busybox (1:0.60.2-3) testing unstable; urgency=low
+  
+  * Fix wc stdin handling (closes: #123387).
+  * Fix wget to do just one DNS lookup (closes: #124068)
+
+ -- Erik Andersen <andersee@debian.org>  Sun, 16 Dec 2001 22:51:03 -0700
+
+busybox (1:0.60.2-2) unstable; urgency=low
+  
+  * Several small bugfixes (closes: #120353, #120369, #122638, 
+  * Reworked wc.c to fix the severe efficiency problems and make it 
+    smaller.  This one is mainly for the boot-floppies (closes: #120441)
+  * Enable hostname (closes: #120511)
+
+ -- Erik Andersen <andersee@debian.org>  Thu,  6 Dec 2001 00:06:33 -0700
+
+busybox (1:0.60.2-1) unstable; urgency=low
+  
+  * New version released.  See Changelog for non-Debian specific details.
+  * dpkg.c now uses an int for getopt (closes: #118975)
+  * s390 console reboot msg is now appropriate (closes: #118859)
+  * the manpage is no longer empty (closes: #117013)
+  * no more .o files in the source tarball (closes: #112046)
+  * the .udeb contents are exactly as Joey wants them (closes: #105352)
+  * busybox ash is the default shell for the -static package,
+    so it can cope with /etc/profile just fine (closes: #95745)
+
+ -- Erik Andersen <andersee@debian.org>  Tue, 20 Nov 2001 03:41:29 -0700
+
+busybox (1:0.60.1-8) unstable; urgency=low
+  
+  * Adjusted some apps for the debian installer's .udeb package.
+    Enabled ifconfig, route.  
+    Disabled chgrp, clear, date, dd, du, gzip, halt, head, killall,
+    loadkmap, logger, mkswap, more, poweroff, reset, sleep, sort, 
+    swapon, swapoff, touch, tty, uniq, uname, uptime, vi, wc, which,
+    whoami, xargs, and yes.
+
+ -- Erik Andersen <andersee@debian.org>  Thu, 18 Oct 2001 22:59:06 -0600
+
+busybox (1:0.60.1-7) unstable; urgency=low
+  
+  * Re-enable wget's status bar for today's dbootstrap change. (closes: #115717)
+  * Enable initrd support (even if they are a bad idea). (closes: #114727)
+
+ -- Erik Andersen <andersee@debian.org>  Mon, 15 Oct 2001 20:45:57 -0600
+
+busybox (1:0.60.1-6) unstable; urgency=low
+  
+  * Re-enable wc, gzip, tty, and expr. (closes: #114906)
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 10 Oct 2001 02:47:50 -0600
+
+busybox (1:0.60.1-5) unstable; urgency=low
+  
+  * Time to make this official.  This enables several applets, such
+    as ifconfig and route, and disables several others.
+  * Revert ash to the version in the busybox stable branch.  For the 
+    -3 non-release, I tried the one from busybox unstable (which lived 
+    up to its name).  (closes: #112503)
+  * Enable id, disable ash (closes: #114260, #113698)
+  * Backport several bugfixes from unstable
+
+ -- Erik Andersen <andersee@debian.org>  Fri,  5 Oct 2001 23:03:15 -0600
+
+busybox (1:0.60.1-4) unstable; urgency=low
+  
+  * Doh!  With busybox ash, we need test and echo enabled...
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 26 Sep 2001 00:05:04 -0600
+
+busybox (1:0.60.1-3) unstable; urgency=low
+
+  * This upload is to test whether disabling several applets, and
+    enabling several others will help.  Enabled is ifconfig, route,
+    and ash.  Disabled is basename, date, echo, env, expr, gzip, 
+    lsmod, and wc.
+
+ -- Erik Andersen <andersee@debian.org>  Tue, 25 Sep 2001 17:45:16 -0600
+
+busybox (1:0.60.1-2) unstable; urgency=low
+
+  * Disabled several applets to make busybox be a bit thinner, since the 
+    powerpc boot floppies are _very_ tight on space (closes: #112503)
+  * Teach 'mount' about usbdevfs (closes: #111055) 
+  * Busybox supports full online help, but due to space constraints on
+    the boot floppies, it will not be enabled.  People can read the 
+    busybox documentation if they need full details. (closes: #111350) 
+
+ -- Erik Andersen <andersee@debian.org>  Sun, 23 Sep 2001 23:32:15 -0600
+
+busybox (1:0.60.1-1) unstable; urgency=low
+
+  * New stable version released.  See changelog for details.
+  * Enabled 'ar' for the udeb
+
+ -- Erik Andersen <andersee@debian.org>  Thu, 23 Aug 2001 15:44:14 -0600
+
+busybox (1:0.60.0-1) unstable; urgency=low
+
+  * New stable version released.  See changelog for details.
+
+ -- Erik Andersen <andersee@debian.org>  Thu,  2 Aug 2001 12:12:37 -0600
+
+busybox (1:0.52-1.1) unstable; urgency=high
+
+  * Non-maintainer upload
+  * Fixed wget -P handling (closes: #106223).
+
+ -- Matt Kraai <kraai@debian.org>  Wed, 25 Jul 2001 11:01:38 -0600
+
+busybox (1:0.52-1) unstable; urgency=high
+
+  * New version released.  See changelog for details.
+
+ -- Erik Andersen <andersee@debian.org>  Sat,  7 Jul 2001 01:23:45 -0600
+
+busybox (1:0.51-10) unstable; urgency=high
+
+  * Fix a compile problem with gcc 3.0 on hppa (closes: #102045)
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 23 Jun 2001 23:55:57 -0600
+
+busybox (1:0.51-9) unstable; urgency=high
+
+  * tar was creating leading directories with 0777 permissions as
+    as reult of faulty umask handling.  This fixes it, repairing
+    a grave security problem in the woody the boot floppies.
+    (closes: #101169)
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 20 Jun 2001 16:17:38 -0600
+
+busybox (1:0.51-8) unstable; urgency=high
+
+  * Fix cp from /proc, where size=0 (closes: #100369)
+  * Add some padding to struct sysinfo for m68k.
+  * Apparently some bugs failed to be closed when master choked
+    (closes: #99627, #99637, #98571)
+  * Disable the busybox shell for the .deb, since it is not needed
+    for the boot floppies.
+
+ -- Erik Andersen <andersee@debian.org>  Mon, 11 Jun 2001 13:26:07 -0600
+
+busybox (1:0.51-7) unstable; urgency=high
+
+  * Fix tar permission setting for existing directories (closes: #99627)
+  * Do not remove the .cvsignore files on 'make release' (closes: #99637)
+
+ -- Erik Andersen <andersee@debian.org>  Mon,  4 Jun 2001 10:55:19 -0600
+
+busybox (1:0.51-6) testing unstable; urgency=high
+
+  * Update the version in testing so DHCP in the woody boot-floppies will work.
+  * Enable expr for the boot-floppies (closes: #98433)
+  * It builds on arm just fine now (closes: #97510)
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 23 May 2001 14:50:13 -0600
+
+busybox (1:0.51-5) unstable; urgency=low
+
+  * Backport a sed fix from 0.52pre
+  * Backport chroot fix from 0.52pre
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 16 May 2001 23:50:33 -0600
+
+busybox (1:0.51-4) unstable; urgency=low
+
+  * Backport from 0.52pre an endianness bugfix for md5sum
+  * Backport some updates to grep and sed
+  * Fix 'wget -O -' so it sets the quiet flag
+
+ -- Erik Andersen <andersee@debian.org>  Mon, 14 May 2001 14:17:36 -0600
+
+busybox (1:0.51-3) unstable; urgency=low
+
+  * This is the "I am an idiot" release.
+  * Make cp and mv work again (closes: #97290) 
+  * Fix the version number.
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 12 May 2001 17:35:58 -0600
+
+busybox (0.51-2) unstable; urgency=low
+
+  * Backport several release critical fixes into the 0.51 codebase
+    so the boot-floppies will work again.
+  * Fix a link ordering problem. (closes: #93362)
+  * Fixed gunzip (closes: #94331)
+  * Fixed cp permission setting (closes: #94580)
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 12 May 2001 11:22:35 -0600
+
+busybox (0.51-1) unstable; urgency=low
+
+  * Fixes several critical bugs (see the busybox changelog
+    for complete details)
+  * Force USE_SYSTEM_PWD_GRP=false, so busybox bypasses
+    the glibc NSS libraries. (closes: #93362)
+  * Fixed a bug in sed's address range handling (closes: #91758) 
+  * Removed irrelevant cruft from the bottem of debian/changelog
+
+ -- Erik Andersen <andersee@debian.org>  Tue, 10 Apr 2001 14:07:29 -0600
+
+busybox (0.50-2) unstable; urgency=low
+  
+  * Enabled freeramdisk and pivot_root in the udeb (closes: #91336)
+  * Disabled lash (the busybox shell) in the udeb (closes: #91337)
+  * fixed a bug in syslog, a problem with rebooting when booted as
+    an initrd, and a few other minor problems.
+
+ -- Erik Andersen <andersee@debian.org>  Sun, 25 Mar 2001 20:59:44 -0700
+
+
+busybox (0.50-2) unstable; urgency=low
+  
+  * Enabled freeramdisk and pivot_root in the udeb (closes: #91336)
+  * Disabled lash (the busybox shell) in the udeb (closes: #91337)
+  * fixed a bug in syslog, a problem with rebooting when booted as
+    an initrd, and a few other minor problems.
+
+ -- Erik Andersen <andersee@debian.org>  Sun, 25 Mar 2001 20:59:44 -0700
+
+busybox (0.50-1) unstable; urgency=low
+
+  * Tons on improvements all around -- See changelog for details.
+  * Fix malformed Build-Depends (closes: #86930)
+  * grep has worked for some time now (closes: #81084)
+  * init compiles with DEBUG_INIT enabled (closes: #85794)
+  * md5sum no longer displays filename when reading stdin (closes: #81283)
+  * lsmod, rmmod, and insmod are no longer enabled (closes: #85642)
+  * busybox and buxybox-static now conflict/replace each other (closes: #80421)
+
+ -- Erik Andersen <andersee@debian.org>  Thu, 15 Mar 2001 14:45:00 -0700
+
+busybox (0.49-1) unstable; urgency=low
+
+  * Lots more source updates and bug fixes.  See changelog for details.
+
+ -- Erik Andersen <andersee@debian.org>  Sat, 27 Jan 2001 01:45:53 -0700
+
+busybox (0.48-1) unstable; urgency=low
+
+  * Lots more source updates and bug fixes.  See changelog for details.
+  * Now includes .udeb support for the debian-installer.  The .udeb 
+    probably needs some more work, but this should be a good start.
+
+ -- Erik Andersen <andersee@debian.org>  Wed, 13 Dec 2000 08:36:07 -0700
+
+busybox (0.47-1) unstable; urgency=low
+
+  * New version released.  See changelog for details.
+
+ -- Erik Andersen <andersee@debian.org>  Mon, 25 Sep 2000 23:00:56 -0600
+
+busybox (0.46-1) unstable; urgency=low
+
+  * New version released.  See changelog for details.
+
+ -- Erik Andersen <andersee@debian.org>  Tue, 11 Jul 2000 12:15:44 -0600
+
+busybox (0.45-1) unstable; urgency=low
+
+  * First attempt at packaging BusyBox as a .deb.  This has been in 
+    in the Debian boot-floppies CVS tree forever.  Hopefully, having it as a
+    standalone app will make life easier for me, the debian-installer team, and
+    everyone else as well...
+  * I have created a busybox-static that can be used as a rescue shell when you 
+    hose your system.  Just invoke "busybox sh" to fir up the shell.  This has
+    every app provided by busybox staically linked in.  There have been several
+    times in the past that I would have loved to have this sitting on my system
+    (i.e. when libc gets screwed up.)
+
+ -- Erik Andersen <andersee@debian.org>  Tue, 27 Jun 2000 12:26:41 -0600
+
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..92551e7
--- /dev/null
@@ -0,0 +1,67 @@
+Source: busybox
+Priority: optional
+Maintainer: Erik Andersen <andersee@debian.org>
+Build-Depends: debhelper (>= 2.1.18), dpkg-dev (>= 1.7.0)
+Standards-Version: 3.2.1.0
+
+Package: busybox
+Architecture: any
+Depends: ${shlibs:Depends}
+Conflicts: busybox-static
+Replaces: busybox-static 
+Section: utils
+Description: Tiny utilities for small and embedded systems. 
+ BusyBox combines tiny versions of many common UNIX utilities into a single
+ small executable. It provides minimalist replacements for the most common
+ utilities you would usually find on your desktop system (i.e., ls, cp, mv,
+ mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
+ their full-featured GNU cousins; however, the options that are included
+ provide the expected functionality and behave very much like their GNU
+ counterparts.
+ .
+ This package installs the BusyBox binary but does not install symlinks
+ for any of the supported utilities.  You can use /bin/busybox --install
+ to install BusyBox to the root directory (you do not want to do this
+ to your your Debian system, except in dire emergencies!).
+
+Package: busybox-static
+Architecture: any
+Depends: ${shlibs:Depends}
+Conflicts: busybox
+Replaces: busybox
+Section: shells
+Priority: extra
+Description: Standalone rescue shell with tons of builtin utilities. 
+ BusyBox combines tiny versions of many common UNIX utilities into a single
+ small executable. It provides minimalist replacements for the most common
+ utilities you would usually find on your desktop system (i.e., ls, cp, mv,
+ mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
+ their full-featured GNU cousins; however, the options that are included
+ provide the expected functionality and behave very much like their GNU
+ counterparts.
+ .
+ BusyBox-static provides you with a statically linked simple stand alone shell
+ that provides all the utilities available in BusyBox.  This package is
+ intended to be used as a rescue shell, in the event that you screw up your
+ system.  Invoke "busybox sh" and you have a standalone shell ready to save
+ your system from certain destruction.  Invoke "busybox", and it will list the
+ available builtin commands.
+
+Package: busybox-udeb
+Architecture: any
+Depends: ${shlibs:Depends}
+Section: debian-installer
+Priority: standard
+Description: Tiny utilities for the debian-installer
+ BusyBox combines tiny versions of many common UNIX utilities into a single
+ small executable. It provides minimalist replacements for the most common
+ utilities you would usually find on your desktop system (i.e., ls, cp, mv,
+ mount, tar, etc.).  The utilities in BusyBox generally have fewer options than
+ their full-featured GNU cousins; however, the options that are included
+ provide the expected functionality and behave very much like their GNU
+ counterparts.
+ .
+ busybox-udeb is used by the debian-installer, so unless you are working
+ on the debian-installer, this package is not for you.  Installing this 
+ on your Debian system is a very, very bad idea.  You have been warned.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..68a96e6
--- /dev/null
@@ -0,0 +1,7 @@
+This package was debianized by Erik Andersen <andersee@debian.org> on
+Sun, 18 Jun 2000 23:31:02 -0600
+
+It was downloaded from ftp://ftp.lineo.com/pub/busybox
+HomePage is at: http://busybox.lineo.com/
+
+Copyright: GPL
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..dd0ffa4
--- /dev/null
@@ -0,0 +1,194 @@
+#!/usr/bin/make -f
+
+# This is a bit unusual, in that I have to completely recompile everything
+# for each package I build (obviously static and dynamic builds require
+# things to be recompiled...)
+
+# This is the debhelper compatability version to use.
+#export DH_COMPAT=1
+
+bbbd=debian/busybox_builddir
+bb=debian/tmp
+bbsbd=debian/busybox_static_builddir
+bbs=debian/busybox-static
+bbubd=debian/busybox_udeb_builddir
+bbu=debian/busybox-udeb
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f debian/build-stamp-busybox debian/build-stamp-busybox-static debian/build-stamp-busybox-udeb
+       -$(MAKE) clean
+       -rm -rf $(bb) $(bbbd) $(bbs) $(bbsbd) $(bbubd) $(bbu)
+       dh_clean
+
+build: debian/build-stamp-busybox
+debian/build-stamp-busybox:
+       dh_testdir
+       mkdir -p $(bbbd)
+       cp Makefile $(bbbd)
+       cp debian/Config.h-deb $(bbbd)/Config.h
+       -(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" applet_source_list)
+       (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
+       touch debian/build-stamp-busybox
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+       # Do not run 'make install', since we do not want all the symlinks. 
+       # This just installes the busybox binary...
+       #(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bb)" install)
+       mkdir -p $(bb)/bin/
+       cp $(bbbd)/busybox $(bb)/bin/busybox
+       mkdir -p $(bb)/usr/share/doc/busybox
+       cp $(bbbd)/docs/BusyBox.html $(bb)/usr/share/doc/busybox/
+       mkdir -p $(bb)/usr/share/man/man1
+       cp $(bbbd)/docs/BusyBox.1 $(bb)/usr/share/man/man1/busybox.1
+
+# Now for the statically linked stuff
+build-static: debian/build-stamp-busybox-static
+debian/build-stamp-busybox-static:
+       dh_testdir
+       mkdir -p $(bbsbd)
+       cp Makefile $(bbsbd)
+       cp debian/Config.h-static $(bbsbd)/Config.h
+       (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
+       touch debian/build-stamp-busybox-static
+
+install-static: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+       # Do not run 'make install', since we do not want all the symlinks. 
+       # This just installes the busybox binary...
+       #(cd $(bbsbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbs)" install)
+       mkdir -p $(bbs)/bin/
+       cp $(bbsbd)/busybox $(bbs)/bin/busybox
+       mkdir -p $(bbs)/usr/share/doc/busybox-static
+       cp $(bbsbd)/docs/BusyBox.html $(bbs)/usr/share/doc/busybox-static/
+       mkdir -p $(bbs)/usr/share/man/man1/
+       cp $(bbsbd)/docs/BusyBox.1 $(bbs)/usr/share/man/man1/busybox.1
+
+half_clean:
+       dh_testdir
+       dh_testroot
+       rm -rf $(bbs) debian/build-stamp-busybox-static
+       -$(MAKE) clean
+
+do_static: half_clean build-static install-static
+
+
+
+# Now for the .udeb stuff
+PACKAGE=busybox-udeb
+VERSION=$(shell dpkg-parsechangelog | grep ^Version: | cut -d ' ' -f 2 | sed -e s/[0-9]://g)
+ARCH=$(shell dpkg --print-architecture)
+FILENAME=$(PACKAGE)_$(VERSION)_$(ARCH).udeb
+
+build-udeb: debian/build-stamp-busybox-udeb
+debian/build-stamp-busybox-udeb:
+       dh_testdir
+       mkdir -p $(bbubd)
+       cp Makefile $(bbubd)
+       cp debian/Config.h-udeb $(bbubd)/Config.h
+       (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../")
+       touch debian/build-stamp-busybox-udeb
+
+install-udeb: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+       (cd $(bbubd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbu)" install)
+       rm -f $(bbu)/linuxrc
+       mkdir -p $(bbu)/usr/share/man/man1/
+       cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1
+
+three_quarter_clean:
+       dh_testdir
+       dh_testroot
+       rm -rf $(bbu) debian/build-stamp-busybox-udeb
+       -$(MAKE) clean
+
+do_udeb: three_quarter_clean build-udeb install-udeb
+
+
+
+# Build architecture-independent files here.
+binary-indep:
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: busybox busybox-static busybox-udeb
+
+busybox: install
+       @echo "--- Building: $@"
+       dh_testdir
+       dh_testroot
+       dh_installdirs
+       dh_installdocs       -p$@  $(bbbd)/docs/BusyBox.txt \
+               $(bbbd)/docs/BusyBox.html docs/style-guide.txt \
+               AUTHORS README TODO
+       rm -rf `find $(bb) -name CVS`
+       rm -f `find $(bb) -name .cvsignore`
+       dh_installchangelogs -p$@ Changelog
+       dh_undocumented      -p$@
+       dh_strip             -p$@
+       dh_compress          -p$@
+       dh_fixperms          -p$@
+       dh_installdeb        -p$@
+       dh_shlibdeps         -p$@
+       dh_gencontrol        -p$@
+       dh_md5sums           -p$@
+       dh_builddeb          -p$@
+
+
+busybox-static: do_static
+       @echo "--- Building: $@"
+       dh_testdir
+       dh_testroot
+       dh_installdirs
+       dh_installdocs       -p$@  $(bbsbd)/docs/BusyBox.txt \
+               $(bbsbd)/docs/BusyBox.html docs/style-guide.txt \
+               AUTHORS README TODO
+       rm -rf `find $(bbs) -name CVS`
+       rm -f `find $(bbs) -name .cvsignore`
+       dh_installchangelogs -p$@ Changelog
+       dh_undocumented      -p$@
+       dh_strip             -p$@
+       dh_compress          -p$@
+       dh_fixperms          -p$@
+       dh_installdeb        -p$@
+       dh_shlibdeps         -p$@
+       dh_gencontrol        -p$@
+       dh_md5sums           -p$@
+       dh_builddeb          -p$@
+
+
+# Note that this builds a .udeb, which is not policy compliant or anything.
+#
+busybox-udeb: do_udeb
+       @echo "--- Building: $@"
+       dh_testdir
+       dh_testroot
+       dh_installdirs
+       dh_strip             -p$@
+       dh_compress          -p$@
+       dh_fixperms          -p$@
+       dh_installdeb        -p$@
+       dh_shlibdeps         -p$@
+       #Make _very_ sure there are no docs lurking about.
+       rm -rf $(bbu)/usr/share/man
+       #dh_gencontrol        -p$@
+       # Don't write your stupid guesses to debian/files.
+       dh_gencontrol        -p$@ -- -fdebian/files~
+       # Register file manually.
+       dpkg-distaddfile $(FILENAME) debian-installer standard
+       dh_md5sums           -p$@
+       dh_builddeb          -p$@ --filename=$(FILENAME)
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/df.c b/df.c
new file mode 100644 (file)
index 0000000..535ab58
--- /dev/null
+++ b/df.c
@@ -0,0 +1,158 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini df implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * based on original code by (I think) Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mntent.h>
+#include <sys/vfs.h>
+#include <getopt.h>
+#include "busybox.h"
+
+extern const char mtab_file[]; /* Defined in utility.c */
+#ifdef BB_FEATURE_HUMAN_READABLE
+static unsigned long df_disp_hr = KILOBYTE; 
+#endif
+
+static int do_df(char *device, const char *mount_point)
+{
+       struct statfs s;
+       long blocks_used;
+       long blocks_percent_used;
+
+       if (statfs(mount_point, &s) != 0) {
+               perror_msg("%s", mount_point);
+               return FALSE;
+       }
+
+       if (s.f_blocks > 0) {
+               blocks_used = s.f_blocks - s.f_bfree;
+               if(blocks_used == 0)
+                       blocks_percent_used = 0;
+               else {
+                       blocks_percent_used = (long)
+                         (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5);
+               }
+               if (strcmp(device, "/dev/root") == 0) {
+                       /* Adjusts device to be the real root device,
+                        * or leaves device alone if it can't find it */
+                       device = find_real_root_device_name(device);
+                       if(device==NULL)
+                               return FALSE;
+               }
+#ifdef BB_FEATURE_HUMAN_READABLE
+               printf("%-20s %9s ", device,
+                               make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
+
+               printf("%9s ",
+                               make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr));
+
+               printf("%9s %3ld%% %s\n",
+                               make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
+                               blocks_percent_used, mount_point);
+#else
+               printf("%-20s %9ld %9ld %9ld %3ld%% %s\n",
+                               device,
+                               (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)),
+                               (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)),
+                               (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)),
+                               blocks_percent_used, mount_point);
+#endif
+       }
+
+       return TRUE;
+}
+
+extern int df_main(int argc, char **argv)
+{
+       int status = EXIT_SUCCESS;
+       int opt = 0;
+       int i = 0;
+       char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */
+
+       while ((opt = getopt(argc, argv, "k"
+#ifdef BB_FEATURE_HUMAN_READABLE
+       "hm"
+#endif
+)) > 0)
+       {
+               switch (opt) {
+#ifdef BB_FEATURE_HUMAN_READABLE
+                       case 'h':
+                               df_disp_hr = 0;
+                               strcpy(disp_units_hdr, "     Size");
+                               break;
+                       case 'm':
+                               df_disp_hr = MEGABYTE;
+                               strcpy(disp_units_hdr, "1M-blocks");
+                               break;
+#endif
+                       case 'k':
+                               /* default display is kilobytes */
+                               break;
+                       default:
+                                         show_usage();
+               }
+       }
+
+       printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr,
+              "Used", "Available", "Use%", "Mounted on");
+
+       if(optind < argc) {
+               struct mntent *mount_entry;
+               for(i = optind; i < argc; i++)
+               {
+                       if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) {
+                               error_msg("%s: can't find mount point.", argv[i]);
+                               status = EXIT_FAILURE;
+                       } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
+                               status = EXIT_FAILURE;
+               }
+       } else {
+               FILE *mount_table;
+               struct mntent *mount_entry;
+
+               mount_table = setmntent(mtab_file, "r");
+               if (mount_table == 0) {
+                       perror_msg("%s", mtab_file);
+                       return EXIT_FAILURE;
+               }
+
+               while ((mount_entry = getmntent(mount_table))) {
+                       if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir))
+                               status = EXIT_FAILURE;
+               }
+               endmntent(mount_table);
+       }
+
+       return status;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/dirname.c b/dirname.c
new file mode 100644 (file)
index 0000000..3872337
--- /dev/null
+++ b/dirname.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dirname implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "busybox.h"
+
+extern int dirname_main(int argc, char **argv)
+{
+       if ((argc < 2) || (**(argv + 1) == '-'))
+               show_usage();
+       argv++;
+
+       puts (dirname (argv[0]));
+
+       return EXIT_SUCCESS;
+}
diff --git a/dmesg.c b/dmesg.c
new file mode 100644 (file)
index 0000000..73de6d1
--- /dev/null
+++ b/dmesg.c
@@ -0,0 +1,95 @@
+/* vi: set sw=4 ts=4: */
+/* dmesg.c -- Print out the contents of the kernel ring buffer
+ * Created: Sat Oct  9 16:19:47 1993
+ * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
+ * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
+ * This program comes with ABSOLUTELY NO WARRANTY.
+ * Modifications by Rick Sladkey (jrs@world.std.com)
+ * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
+ * by Peeter Joot.  This was also suggested by John Hudson.
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ * from util-linux -- adapted for busybox by 
+ * Erik Andersen <andersee@debian.org>. I ripped out Native Language 
+ * Support, replaced getopt, added some gotos for redundant stuff.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#if __GNU_LIBRARY__ < 5
+# ifdef __alpha__
+#   define klogctl syslog
+# endif
+#else
+# include <sys/klog.h>
+#endif
+
+#include "busybox.h"
+
+int dmesg_main(int argc, char **argv)
+{
+       char *buf;
+       int c;
+       int bufsize = 8196;
+       int i;
+       int n;
+       int level = 0;
+       int lastc;
+       int cmd = 3;
+
+       while ((c = getopt(argc, argv, "cn:s:")) != EOF) {
+               switch (c) {
+               case 'c':
+                       cmd = 4;
+                       break;
+               case 'n':
+                       cmd = 8;
+                       if (optarg == NULL)
+                               show_usage();
+                       level = atoi(optarg);
+                       break;
+               case 's':
+                       if (optarg == NULL)
+                               show_usage();
+                       bufsize = atoi(optarg);
+                       break;
+               default:
+                       show_usage();
+               }
+       }                       
+
+       if (optind < argc) {
+               show_usage();
+       }
+
+       if (cmd == 8) {
+               if (klogctl(cmd, NULL, level) < 0)
+                       perror_msg_and_die("klogctl");
+               return EXIT_SUCCESS;
+       }
+
+       if (bufsize < 4096)
+               bufsize = 4096;
+       buf = (char *) xmalloc(bufsize);
+       if ((n = klogctl(cmd, buf, bufsize)) < 0)
+               perror_msg_and_die("klogctl");
+
+       lastc = '\n';
+       for (i = 0; i < n; i++) {
+               if (lastc == '\n' && buf[i] == '<') {
+                       i++;
+                       while (buf[i] >= '0' && buf[i] <= '9')
+                               i++;
+                       if (buf[i] == '>')
+                               i++;
+               }
+               lastc = buf[i];
+               putchar(lastc);
+       }
+       if (lastc != '\n')
+               putchar('\n');
+       return EXIT_SUCCESS;
+}
diff --git a/docs/.cvsignore b/docs/.cvsignore
new file mode 100644 (file)
index 0000000..ec9e94b
--- /dev/null
@@ -0,0 +1,8 @@
+BusyBox.txt
+BusyBox.1
+BusyBox.html
+busybox.txt
+busybox.ps
+busybox.pdf
+busybox
+busybox.pod
diff --git a/docs/autodocifier.pl b/docs/autodocifier.pl
new file mode 100755 (executable)
index 0000000..e6e2b0c
--- /dev/null
@@ -0,0 +1,287 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Long;
+
+# collect lines continued with a '\' into an array 
+sub continuation {
+       my $fh = shift;
+       my @line;
+
+       while (<$fh>) {
+               my $s = $_;
+               $s =~ s/\\\s*$//;
+               #$s =~ s/#.*$//;
+               push @line, $s;
+               last unless (/\\\s*$/);
+       }
+       return @line;
+}
+
+# regex && eval away unwanted strings from documentation
+sub beautify {
+       my $text = shift;
+       $text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg;
+       $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
+       $text =~ s/"\s*"//sg;
+       my @line = split("\n", $text);
+       $text = join('',
+               map { 
+                       s/^\s*"//;
+                       s/"\s*$//;
+                       s/%/%%/g;
+                       s/\$/\\\$/g;
+                       eval qq[ sprintf(qq{$_}) ]
+               } @line
+       );
+       return $text;
+}
+
+# generate POD for an applet
+sub pod_for_usage {
+       my $name  = shift;
+       my $usage = shift;
+
+       # make options bold
+       my $trivial = $usage->{trivial};
+       $trivial =~ s/(?<!\w)(-\w+)/B<$1>/sxg;
+       my @f0 = 
+               map { $_ !~ /^\s/ && s/(?<!\w)(-\w+)/B<$1>/g; $_ }
+               split("\n", $usage->{full});
+
+       # add "\n" prior to certain lines to make indented
+       # lines look right
+       my @f1;
+       my $len = @f0;
+       for (my $i = 0; $i < $len; $i++) {
+               push @f1, $f0[$i];
+               if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) {
+                       next if ($f0[$i] =~ /^$/);
+                       push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s);
+               }
+       }
+       my $full = join("\n", @f1);
+
+       # prepare notes if they exist
+       my $notes = (defined $usage->{notes})
+               ? "$usage->{notes}\n\n"
+               : "";
+
+       # prepare examples if they exist
+       my $example = (defined $usage->{example})
+               ?  
+                       "Example:\n\n" .
+                       join ("\n", 
+                       map  { "\t$_" } 
+                       split("\n", $usage->{example})) . "\n\n"
+               : "";
+
+       return
+               "=item B<$name>".
+               "\n\n"  .
+               "$name $trivial".
+               "\n\n"  .
+               $full   .
+               "\n\n"  .
+               $notes  .
+               $example.
+               "-------------------------------".
+               "\n\n"
+       ;
+}
+
+# FIXME | generate SGML for an applet
+sub sgml_for_usage {
+       my $name  = shift;
+       my $usage = shift;
+       return
+               "<fixme>\n".
+               "  $name\n".
+               "</fixme>\n"
+       ;
+}
+
+# the keys are applet names, and 
+# the values will contain hashrefs of the form:
+#
+# {
+#     trivial => "...",
+#     full    => "...",
+#     notes   => "...",
+#     example => "...",
+# }
+my %docs;
+
+
+# get command-line options
+
+my %opt;
+
+GetOptions(
+       \%opt,
+       "help|h",
+       "sgml|s",
+       "pod|p",
+       "verbose|v",
+);
+
+if (defined $opt{help}) {
+       print
+               "$0 [OPTION]... [FILE]...\n",
+               "\t--help\n",
+               "\t--sgml\n",
+               "\t--pod\n",
+               "\t--verbose\n",
+       ;
+       exit 1;
+}
+
+
+# collect documenation into %docs
+
+foreach (@ARGV) {
+       open(USAGE, $_) || die("$0: $_: $!");
+       my $fh = *USAGE;
+       my ($applet, $type, @line);
+       while (<$fh>) {
+               if (/^#define (\w+)_(\w+)_usage/) {
+                       $applet = $1;
+                       $type   = $2;
+                       @line   = continuation($fh);
+                       my $doc = $docs{$applet} ||= { };
+                       my $text      = join("\n", @line);
+                       $doc->{$type} = beautify($text);
+               }
+       }
+}
+
+
+# generate structured documentation
+
+my $generator = \&pod_for_usage;
+if (defined $opt{sgml}) {
+       $generator = \&sgml_for_usage;
+}
+
+foreach my $applet (sort keys %docs) {
+       print $generator->($applet, $docs{$applet});
+}
+
+exit 0;
+
+__END__
+
+=head1 NAME
+
+autodocifier.pl - generate docs for busybox based on usage.h
+
+=head1 SYNOPSIS
+
+autodocifier.pl [OPTION]... [FILE]...
+
+Example:
+
+    ( cat docs/busybox_header.pod; \
+      docs/autodocifier.pl usage.h; \
+      cat docs/busybox_footer.pod ) > docs/busybox.pod
+
+=head1 DESCRIPTION
+
+The purpose of this script is to automagically generate documentation
+for busybox using its usage.h as the original source for content.
+Currently, the same content has to be duplicated in 3 places in
+slightly different formats -- F<usage.h>, F<docs/busybox.pod>, and
+F<docs/busybox.sgml>.  This is tedious, so Perl has come to the rescue.
+
+This script was based on a script by Erik Andersen <andersee@debian.org>
+which was in turn based on a script by Mark Whitley <markw@codepoet.org>
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+This displays the help message.
+
+=item B<--pod>
+
+Generate POD (this is the default)
+
+=item B<--sgml>
+
+Generate SGML
+
+=item B<--verbose>
+
+Be verbose (not implemented)
+
+=back
+
+=head1 FORMAT
+
+The following is an example of some data this script might parse.
+
+    #define length_trivial_usage \
+            "STRING"
+    #define length_full_usage \
+            "Prints out the length of the specified STRING."
+    #define length_example_usage \
+            "$ length Hello\n" \
+            "5\n"
+
+Each entry is a cpp macro that defines a string.  The macros are
+named systematically in the form:
+
+    $name_$type_usage
+
+$name is the name of the applet.  $type can be "trivial", "full", "notes",
+or "example".  Every documentation macro must end with "_usage".
+
+The definition of the types is as follows:
+
+=over 4
+
+=item B<trivial>
+
+This should be a brief, one-line description of parameters that
+the command expects.  This will be displayed when B<-h> is issued to
+a command.  I<REQUIRED>
+
+=item B<full>
+
+This should contain descriptions of each option.  This will also
+be displayed along with the trivial help if BB_FEATURE_TRIVIAL_HELP
+is disabled.  I<REQUIRED>
+
+=item B<notes>
+
+This is documentation that is intended to go in the POD or SGML, but
+not be printed when a B<-h> is given to a command.  To see an example
+of notes being used, see init_notes_usage.  I<OPTIONAL>
+
+=item B<example>
+
+This should be an example of how the command is acutally used.
+This will not be printed when a B<-h> is given to a command -- it
+is inteded only for the POD or SGML documentation.  I<OPTIONAL>
+
+=back
+
+=head1 FILES
+
+F<usage.h>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2001 John BEPPU.  All rights reserved.  This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.
+
+=head1 AUTHOR
+
+John BEPPU <beppu@codepoet.org>
+
+=cut
+
+# $Id: autodocifier.pl,v 1.22 2001/11/19 23:57:54 andersen Exp $
diff --git a/docs/busybox.sgml b/docs/busybox.sgml
new file mode 100644 (file)
index 0000000..3dbd850
--- /dev/null
@@ -0,0 +1,3974 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [ ]>
+<book id="BusyBoxDocumentation">
+ <bookinfo>
+  <title>BusyBox - The Swiss Army Knife of Embedded Linux</title>
+  
+  <legalnotice>
+   <para>
+     This documentation is free software; you can redistribute
+     it and/or modify it under the terms of the GNU General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later
+     version.
+   </para>
+      
+   <para>
+     This program is distributed in the hope that it will be
+     useful, but WITHOUT ANY WARRANTY; without even the implied
+     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+     See the GNU General Public License for more details.
+   </para>
+      
+   <para>
+     You should have received a copy of the GNU General Public
+     License along with this program; if not, write to the Free
+     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+  <chapter id="Introduction">
+     <title>Introduction</title>
+
+       <para>
+       BusyBox combines tiny versions of many common UNIX utilities into a single
+       small executable. It provides minimalist replacements for most of the
+       utilities you usually find in fileutils, shellutils, findutils, textutils,
+       grep, gzip, tar, etc. BusyBox provides a fairly complete POSIX environment
+       for any small or embedded system. The utilities in BusyBox generally have
+       fewer options than their full-featured GNU cousins; however, the options
+       that are included provide the expected functionality and behave very much
+       like their GNU counterparts. 
+       </para>
+
+       <para>
+       BusyBox has been written with size-optimization and limited resources in
+       mind. It is also extremely modular so you can easily include or exclude
+       commands (or features) at compile time. This makes it easy to customize
+       your embedded systems. To create a working system, just add a kernel, a
+       shell (such as ash), and an editor (such as elvis-tiny or ae).
+       </para>
+  </chapter>
+
+  <chapter id="Syntax">
+     <title>How to use BusyBox</title>
+       <sect1 id="How-to-use-BusyBox">
+           <title>Syntax</title>
+
+           <para>
+           <screen>
+            BusyBox &lt;function&gt; [arguments...]  # or
+           </screen>
+           </para>
+
+           <para>
+           <screen>
+            &lt;function&gt; [arguments...]          # if symlinked
+           </screen>
+           </para>
+       </sect1>
+
+       <sect1 id="Invoking-BusyBox">
+           <title>Invoking BusyBox</title>
+
+           <para>
+           When you create a link to BusyBox for the function you wish to use, when
+           BusyBox is called using that link it will behave as if the command itself
+           has been invoked.
+           </para>
+
+           <para>
+           For example, entering
+           </para>
+
+           <para>
+           <screen>
+                   ln -s ./BusyBox ls
+                   ./ls
+           </screen>
+           </para>
+
+           <para>
+           will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled
+           into BusyBox). 
+           </para>
+
+           <para>
+           You can also invoke BusyBox by issuing the command as an argument on the
+           command line. For example, entering
+           </para>
+
+           <para>
+           <screen>
+                   ./BusyBox ls
+           </screen>
+           </para>
+
+           <para>
+           will also cause BusyBox to behave as 'ls'. 
+           </para>
+
+       </sect1>
+
+       <sect1 id="Common-options">
+           <title>Common options</title>
+
+           <para>
+           Most BusyBox commands support the <emphasis>--help</emphasis> option to provide 
+           a terse runtime description of their behavior. 
+           </para>
+       </sect1>
+  </chapter>
+
+  <chapter id="Commands">
+     <title>BusyBox Commands</title>
+       <sect1 id="Available-BusyBox-Commands">
+           <title>Available BusyBox Commands</title>
+               <para>
+               Currently defined functions include:
+               </para>
+
+               <para>
+               ar, basename, cat, chgrp, chmod, chown, chroot, chvt, clear,
+               cp, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dpkg-deb,
+               du, dumpkmap, dutmp, echo, false, fbset, fdflush, find, free,
+               freeramdisk, fsck.minix, grep, gunzip, gzip, halt, head,
+               hostid, hostname, id, init, insmod, kill, killall, length, ln,
+               loadacm, loadfont, loadkmap, logger, logname, ls, lsmod,
+               makedevs, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp,
+               more, mount, mt, mv, nc, nslookup, ping, poweroff, printf, ps,
+               pwd, reboot, renice, reset, rm, rmdir, rmmod, sed, setkeycodes, sh, sleep,
+               sort, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet,
+               test, touch, tr, true, tty, umount, uname, uniq, update,
+               uptime, usleep, uudecode, uuencode, wc, which, whoami, yes,
+               zcat, [
+               </para>
+       </sect1>
+
+       <sect1 id="ar">
+           <title>ar</title>
+
+               <para>
+               Usage: ar [OPTION] archive [FILENAME]...
+               </para>
+
+               <para>
+               Extract or list files from an ar archive.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       o       Preserve original dates
+                       p       Extract to stdout
+                       t       List
+                       x       Extract
+                       v       Verbosely list files processed
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="basename">
+           <title>basename</title>
+               <para>
+               Usage: basename FILE [SUFFIX]
+               </para>
+
+               <para>
+               Strip directory path and suffixes from FILE. If specified, also removes
+               any trailing SUFFIX.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ basename /usr/local/bin/foo
+                       foo
+                       $ basename /usr/local/bin/
+                       bin
+                       $ basename /foo/bar.txt .txt
+                       bar
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="cat">
+           <title>cat</title>
+
+               <para>
+               Usage: cat [FILE]...
+               </para>
+
+               <para>
+               Concatenate <literal>FILE(s)</literal> and prints them to the standard
+               output.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ cat /proc/uptime
+                       110716.72 17.67
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="chgrp">
+           <title>chgrp</title>
+
+               <para>
+               Usage: chgrp [OPTION]... GROUP FILE...
+               </para>
+
+               <para>
+               Change the group membership of each FILE to GROUP.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -R      Change files and directories recursively
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -l /tmp/foo
+                       -r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo
+                       $ chgrp root /tmp/foo
+                       $ ls -l /tmp/foo
+                       -r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="chmod">
+           <title>chmod</title>
+
+               <para>
+               Usage: chmod [<emphasis>-R</emphasis>] MODE[,MODE]... FILE...
+               </para>
+
+               <para>
+               Change file access permissions for the specified
+               <literal>FILE(s)</literal> (or directories). Each MODE is defined by
+               combining the letters for WHO has access to the file, an OPERATOR for
+               selecting how the permissions should be changed, and a PERMISSION for
+               <literal>FILE(s)</literal> (or directories).
+               </para>
+
+               <para>
+               WHO may be chosen from
+               </para>
+
+               <para>
+               <screen>
+                       u       User who owns the file
+                       g       Users in the file's Group
+                       o       Other users not in the file's group
+                       a       All users
+               </screen>
+               </para>
+
+               <para>
+               OPERATOR may be chosen from
+               </para>
+
+               <para>
+               <screen>
+                       +       Add a permission
+                       -       Remove a permission
+                       =       Assign a permission
+               </screen>
+               </para>
+
+               <para>
+               PERMISSION may be chosen from
+               </para>
+
+               <para>
+               <screen>
+                       r       Read
+                       w       Write
+                       x       Execute (or access for directories)
+                       s       Set user (or group) ID bit
+                       t       Sticky bit (for directories prevents removing files by non-owners)
+               </screen>
+               </para>
+
+               <para>
+               Alternately, permissions can be set numerically where the first three
+               numbers are calculated by adding the octal values, such as
+               </para>
+
+               <para>
+               <screen>
+                       4       Read
+                       2       Write
+                       1       Execute
+               </screen>
+               </para>
+
+               <para>
+               An optional fourth digit can also be used to specify
+               </para>
+
+               <para>
+               <screen>
+                       4       Set user ID
+                       2       Set group ID
+                       1       Sticky bit
+               </screen>
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -R      Change files and directories recursively.
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -l /tmp/foo
+                       -rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo
+                       $ chmod u+x /tmp/foo
+                       $ ls -l /tmp/foo
+                       -rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*
+                       $ chmod 444 /tmp/foo
+                       $ ls -l /tmp/foo
+                       -r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+       
+       <sect1 id="chown">
+           <title>chown</title>
+               <para>
+               Usage: chown [OPTION]... OWNER[&lt;.|:&gt;[GROUP] FILE...
+               </para>
+
+               <para>
+               Change the owner and/or group of each FILE to OWNER and/or GROUP.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -R      Change files and directories recursively
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -l /tmp/foo
+                       -r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo
+                       $ chown root /tmp/foo
+                       $ ls -l /tmp/foo
+                       -r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo
+                       $ chown root.root /tmp/foo
+                       ls -l /tmp/foo
+                       -r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="chroot">
+           <title>chroot</title>
+               <para>
+               Usage: chroot NEWROOT [COMMAND...]
+               </para>
+
+               <para>
+               Run COMMAND with root directory set to NEWROOT.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -l /bin/ls
+                       lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -&gt; /BusyBox
+                       $ mount /dev/hdc1 /mnt -t minix
+                       $ chroot /mnt
+                       $ ls -l /bin/ls
+                       -rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="chvt">
+           <title>chvt</title>
+               <para>
+               Usage: chvt N
+               </para>
+
+               <para>
+               Change the foreground virtual terminal to /dev/ttyN
+               </para>
+       </sect1>
+
+       <sect1 id="clear">
+           <title>clear</title>
+
+               <para>
+               Usage: clear
+               </para>
+
+               <para>
+               Clear the screen.
+               </para>
+       </sect1>
+
+       <sect1 id="cp">
+           <title>cp</title>
+
+               <para>
+               Usage: cp [OPTION]... SOURCE DEST
+               </para>
+
+               <para>
+               <screen>
+                  or: cp [OPTION]... SOURCE... DIRECTORY
+               </screen>
+               </para>
+
+               <para>
+               Copy SOURCE to DEST, or multiple <literal>SOURCE(s)</literal> to
+               DIRECTORY.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Same as -dpR
+                       -d      Preserve links
+                       -p      Preserve file attributes if possible
+                       -R      Copy directories recursively
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="cut">
+           <title>cut</title>
+
+               <para>
+               Usage: cut [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               Print selected fields from each input FILE to standard output.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                               -b LIST Output only bytes from LIST
+                               -c LIST Output only characters from LIST
+                               -d CHAR Use CHAR instead of tab as the field delimiter
+                               -s      Output only the lines containing delimiter
+                               -f N    Print only these fields
+                               -n      Ignored
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo "Hello world" | cut -f 1 -d ' '
+                       Hello
+                       $ echo "Hello world" | cut -f 2 -d ' '
+                       world
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="date">
+           <title>date</title>
+
+               <para>
+               Usage: date [OPTION]... [+FORMAT]
+               </para>
+
+               <para>
+               <screen>
+                 or:  date [OPTION] [MMDDhhmm[[CC]YY][.ss]]
+               </screen>
+               </para>
+
+               <para>
+               Display the current time in the given FORMAT, or set the system date.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -R      Output RFC-822 compliant date string
+                       -s      Set time described by STRING
+                       -u      Print or set Coordinated Universal Time
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ date
+                       Wed Apr 12 18:52:41 MDT 2000
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dc">
+           <title>dc</title>
+
+               <para>
+               Usage: dc [EXPRESSION]
+               </para>
+
+               <para>
+               This is a Tiny RPN calculator that understands the
+               following operations: +, -, /, *, and, or, not, eor. If
+               no arguments are given, dc will process input from
+               stdin.
+               </para>
+
+               <para>
+               The behaviour of BusyBox/dc deviates (just a little ;-)
+               from GNU/dc, but this will be remedied in the future.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dc 2 2 +
+                       4
+                       $ dc 8 8 \* 2 2 + /
+                       16
+                       $ dc 0 1 and
+                       0
+                       $ dc 0 1 or
+                       1
+                       $ echo 72 9 div 8 mul | dc
+                       64
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dd">
+           <title>dd</title>
+
+               <para>
+               Usage: dd [OPTION]...
+               </para>
+
+               <para>
+               Copy a file, converting and formatting according to
+               options.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       if=FILE Read from FILE instead of stdin
+                       of=FILE Write to FILE instead of stdout
+                       bs=N    Read and write N bytes at a time
+                       count=N Copy only N input blocks
+                       skip=N  Skip N input blocks
+                       seek=N  Skip N output blocks
+               </screen>
+               </para>
+
+               <para>
+               Numbers may be suffixed by w (x2), k (x1024), b (x512),
+               or M (x1024^2).
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dd if=/dev/zero of=/dev/ram1 bs=1M count=4
+                       4+0 records in
+                       4+0 records out
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="deallocvt">
+           <title>deallocvt</title>
+
+               <para>
+               Usage: deallocvt N
+               </para>
+
+               <para>
+               Deallocate unused virtual terminal /dev/ttyN.
+               </para>
+       </sect1>
+
+       <sect1 id="df">
+           <title>df</title>
+
+               <para>
+               Usage: df [FILE]...
+               </para>
+
+               <para>
+               Print the filesystem space used and space available.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ df
+                       Filesystem           1k-blocks      Used Available Use% Mounted on
+                       /dev/sda3              8690864   8553540    137324  98% /
+                       /dev/sda1                64216     36364     27852  57% /boot
+                       $ df /dev/sda3
+                       Filesystem           1k-blocks      Used Available Use% Mounted on
+                       /dev/sda3              8690864   8553540    137324  98% /
+               </screen>
+               </para>
+       </sect1>
+       
+       <sect1 id="dirname">
+           <title>dirname</title>
+
+               <para>
+               Usage: dirname NAME
+               </para>
+
+               <para>
+               Strip non-directory suffix from NAME.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dirname /tmp/foo
+                       /tmp
+                       $ dirname /tmp/foo/
+                       /tmp
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dmesg">
+           <title>dmesg</title>
+
+               <para>
+               Usage: dmesg [OPTION]...
+               </para>
+
+               <para>
+               Print or control the kernel ring buffer.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c              Clear the ring buffer after printing
+                       -n LEVEL        Set the console logging level to LEVEL
+                       -s BUFSIZE      Query ring buffer using a buffer of BUFSIZE
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dos2unix">
+           <title>dos2unix</title>
+
+               <para>
+               Usage: dos2unix < dosfile > unixfile
+               </para>
+
+               <para>
+               Converts a text file from dos format to unix format.
+               </para>
+
+       </sect1>
+
+       <sect1 id="dpkg-deb">
+           <title>dpkg-deb</title>
+
+               <para>
+               Usage: dpkg-deb [OPTION] archive [directory] 
+               </para>
+
+               <para>
+               Debian package archive (.deb) manipulation tool 
+               </para>
+
+               <para>
+               Options:
+               </para>
+               
+               <para>
+               <screen>
+                       -c      List the contents of the filesystem tree archive portion of the package 
+                       -e      Extracts the control information files from a package archive into the specified directory.
+                               If  no  directory  is specified then a subdirectory DEBIAN in the current directory is used.
+                       -x      Silently extracts the filesystem tree from a package archive into the specified directory.
+                       -X      Extracts the filesystem tree from a package archive into the specified directory, listing the files as it goes. 
+                       If required the specified directory (but not its parents) will be created.
+               </screen>
+               <para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       dpkg-deb -e ./busybox_0.48-1_i386.deb
+                       dpkg-deb -x ./busybox_0.48-1_i386.deb ./unpack_dir
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="du">
+           <title>du</title>
+
+               <para>
+               Usage: du [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               Summarize the disk space used for each FILE or current
+               directory.  Disk space printed in units of 1k (i.e.,
+               1024 bytes).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -l      Count sizes many times if hard linked
+                       -s      Display only a total for each argument
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ du
+                       16      ./CVS
+                       12      ./kernel-patches/CVS
+                       80      ./kernel-patches
+                       12      ./tests/CVS
+                       36      ./tests
+                       12      ./scripts/CVS
+                       16      ./scripts
+                       12      ./docs/CVS
+                       104     ./docs
+                       2417    .
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dumpkmap">
+           <title>dumpkmap</title>
+
+               <para>
+               Usage: dumpkmap
+               </para>
+
+               <para>
+               Prints out a binary keyboard translation table to standard output.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dumpkmap &lt; keymap
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="dutmp">
+           <title>dutmp</title>
+
+               <para>
+               Usage: dutmp [FILE]
+               </para>
+
+               <para>
+               Dump utmp file format (pipe delimited) from FILE or
+               stdin to stdout.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dutmp /var/run/utmp
+                       8|7||si|||0|0|0|955637625|760097|0
+                       2|0|~|~~|reboot||0|0|0|955637625|782235|0
+                       1|20020|~|~~|runlevel||0|0|0|955637625|800089|0
+                       8|125||l4|||0|0|0|955637629|998367|0
+                       6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0
+                       6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0
+                       7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="echo">
+           <title>echo</title>
+
+               <para>
+               Usage: echo [OPTION]... [ARG]...
+               </para>
+
+               <para>
+               Print ARGs to stdout.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -n      Suppress trailing newline
+                       -e      Enable interpretation of escaped characters
+                       -E      Disable interpretation of escaped characters
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo "Erik is cool"
+                       Erik is cool
+                       $ echo -e "Erik\nis\ncool"
+                       Erik
+                       is
+                       cool
+                       $ echo "Erik\nis\ncool"
+                       Erik\nis\ncool
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="expr">
+           <title>expr</title>
+
+               <para>
+               Usage: expr EXPRESSION
+               </para>
+
+               <para>
+               Prints the value of EXPRESSION to standard output.
+               </para>
+
+               <para>
+               EXPRESSION may be:
+               </para>
+
+               <para>
+               <screen>
+                       ARG1 |  ARG2    ARG1 if it is neither null nor 0, otherwise ARG2
+                       ARG1 &  ARG2    ARG1 if neither argument is null or 0, otherwise 0
+                       ARG1 &lt  ARG2    ARG1 is less than ARG2
+                       ARG1 &lt= ARG2    ARG1 is less than or equal to ARG2
+                       ARG1 =  ARG2    ARG1 is equal to ARG2
+                       ARG1 != ARG2    ARG1 is unequal to ARG2
+                       ARG1 &gt= ARG2    ARG1 is greater than or equal to ARG2
+                       ARG1 &gt  ARG2    ARG1 is greater than ARG2
+                       ARG1 +  ARG2    arithmetic sum of ARG1 and ARG2
+                       ARG1 -  ARG2    arithmetic difference of ARG1 and ARG2
+                       ARG1 *  ARG2    arithmetic product of ARG1 and ARG2
+                       ARG1 /  ARG2    arithmetic quotient of ARG1 divided by ARG2
+                       ARG1 %  ARG2    arithmetic remainder of ARG1 divided by ARG2
+                       STRING : REGEXP             anchored pattern match of REGEXP in STRING
+                       match STRING REGEXP         same as STRING : REGEXP
+                       substr STRING POS LENGTH    substring of STRING, POS counted from 1
+                       index STRING CHARS          index in STRING where any CHARS is found, or 0
+                       length STRING               length of STRING
+                       quote TOKEN                 interpret TOKEN as a string, even if it is a
+                                                       keyword like `match' or an operator like `/'
+                       ( EXPRESSION )              value of EXPRESSION
+               </screen>
+               </para>
+
+               <para>
+               Beware that many operators need to be escaped or quoted for shells.
+               Comparisons are arithmetic if both ARGs are numbers, else
+               lexicographical.  Pattern matches return the string matched between
+               \( and \) or null; if \( and \) are not used, they return the number
+               of characters matched or 0.
+               </para>
+
+       </sect1>
+
+
+       <sect1 id="false">
+           <title>false</title>
+
+               <para>
+               Usage: false
+               </para>
+
+               <para>
+               Return an exit code of FALSE (1).
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ false
+                       $ echo $?
+                       1
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="fbset">
+           <title>fbset</title>
+
+               <para>
+               Usage: fbset [OPTION]... [MODE]
+               </para>
+
+               <para>
+               Show and modify frame buffer device settings.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -h                                              Display option summary
+                       -fb DEVICE                                      Operate on DEVICE
+                       -db FILE                                        Use FILE for mode database
+                       -g XRES YRES VXRES VYRES DEPTH                  Set all geometry parameters
+                       -t PIXCLOCK LEFT RIGHT UPPER LOWER HSLEN VSLEN  Set all timing parameters
+                       -xres RES                                       Set visible horizontal resolution
+                       -yres RES                                       Set visible vertical resolution
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ fbset
+                       mode "1024x768-76"
+                                       # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz
+                                       geometry 1024 768 1024 768 16
+                                       timings 12714 128 32 16 4 128 4
+                                       accel false
+                                       rgba 5/11,6/5,5/0,0/0
+                       endmode
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="fdflush">
+           <title>fdflush</title>
+
+               <para>
+               Usage: fdflush DEVICE
+               </para>
+
+               <para>
+               Force floppy disk drive to detect disk change on DEVICE.
+               </para>
+       </sect1>
+
+       <sect1 id="find">
+           <title>find</title>
+
+               <para>
+               Usage: find [PATH]... [EXPRESSION]
+               </para>
+
+               <para>
+               Search for files in a directory hierarchy. The default
+               PATH is the current directory; default EXPRESSION is
+               '-print'.
+               </para>
+
+               <para>
+               EXPRESSION may consist of:
+               </para>
+
+               <para>
+               <screen>
+                       -follow         Dereference symbolic links
+                       -name PATTERN   File name (leading directories removed) matches PATTERN
+                       -type X         Filetype matches X (where X is one of: f,d,l,b,c,...)
+                       -perm PERMS     Permissions match any of (+NNN); all of (-NNN); or exactly (NNN)
+                       -mtime TIME     Modified time is greater than (+N); less than (-N); or exactly (N) days
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ find / -name /etc/passwd
+                       /etc/passwd
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="free">
+           <title>free</title>
+
+               <para>
+               Usage: free
+               </para>
+
+               <para>
+               Displays the amount of free and used system memory.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ free
+                       total         used         free       shared      buffers
+                         Mem:       257628       248724         8904        59644        93124
+                        Swap:       128516         8404       120112
+                       Total:       386144       257128       129016
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="freeramdisk">
+           <title>freeramdisk</title>
+
+               <para>
+               Usage: freeramdisk DEVICE
+               </para>
+
+               <para>
+               Free all memory used by the ramdisk DEVICE.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ freeramdisk /dev/ram2
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="fsck.minix">
+           <title>fsck.minix</title>
+
+               <para>
+               Usage: fsck.minix [OPTION]... DEVICE
+               </para>
+
+               <para>
+               Perform a consistency check on the MINIX filesystem on
+               DEVICE.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -l      List all filenames
+                       -r      Perform interactive repairs
+                       -a      Perform automatic repairs
+                       -v      Verbose
+                       -s      Output super-block information
+                       -m      Activate MINIX-like "mode not cleared" warnings
+                       -f      Force file system check.
+               </screen>
+               </para>
+       </sect1>
+       
+       <sect1 id="getopt">
+           <title>getopt</title>
+
+               <para>
+               Usage: getopt [OPTIONS]...
+               </para>
+
+               <para>
+               Parse command options
+               </para>
+
+               <para>
+               <screen>
+                  -a, --alternative            Allow long options starting with single -\n"
+                  -l, --longoptions=longopts   Long options to be recognized\n"
+                  -n, --name=progname          The name under which errors are reported\n"
+                  -o, --options=optstring      Short options to be recognized\n"
+                  -q, --quiet                  Disable error reporting by getopt(3)\n"
+                  -Q, --quiet-output           No normal output\n"
+                  -s, --shell=shell            Set shell quoting conventions\n"
+                  -T, --test                   Test for getopt(1) version\n"
+                  -u, --unqote                 Do not quote the output\n"
+               </screen>
+               </para>
+
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ cat getopt.test
+                       #!/bin/sh
+                       GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
+                               -n 'example.busybox' -- "$@"`
+                       if [ $? != 0 ] ; then  exit 1 ; fi
+                       eval set -- "$GETOPT"
+                       while true ; do
+                         case $1 in
+                           -a|--a-long) echo "Option a" ; shift ;;
+                           -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
+                           -c|--c-long)
+                             case "$2" in
+                               "") echo "Option c, no argument"; shift 2 ;;
+                               *)  echo "Option c, argument \`$2'" ; shift 2 ;;
+                             esac ;;
+                           --) shift ; break ;;
+                           *) echo "Internal error!" ; exit 1 ;;
+                         esac
+                       done
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="grep">
+           <title>grep</title>
+
+               <para>
+               Usage: grep [OPTIONS]... PATTERN [FILE]...
+               </para>
+
+               <para>
+               Search for PATTERN in each FILE or stdin.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -h      Suppress the prefixing filename on output
+                       -i      Ignore case distinctions
+                       -n      Print line number with output lines
+                       -q      Be quiet. Returns 0 if result was found, 1 otherwise
+                       -v      Select non-matching lines
+               </screen>
+               </para>
+
+               <para>
+               This version of grep matches full regular expressions.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ grep root /etc/passwd
+                       root:x:0:0:root:/root:/bin/bash
+                       $ grep ^[rR]oo. /etc/passwd
+                       root:x:0:0:root:/root:/bin/bash
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="gunzip">
+           <title>gunzip</title>
+
+               <para>
+               Usage: gunzip [OPTION]... FILE
+               </para>
+
+               <para>
+               Uncompress FILE (or stdin if FILE is '-').
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Write output to standard output
+                       -t      Test compressed file integrity
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -la /tmp/BusyBox*
+                       -rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz
+                       $ gunzip /tmp/BusyBox-0.43.tar.gz
+                       $ ls -la /tmp/BusyBox*
+                       -rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="gzip">
+           <title>gzip</title>
+
+               <para>
+               Usage: gzip [OPTION]... FILE
+               </para>
+
+               <para>
+               Compress FILE (or stdin if FILE is '-') with maximum
+               compression to FILE.gz (or stdout if FILE is '-').
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Write output to standard output
+                       -d      decompress
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -la /tmp/BusyBox*
+                       -rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar
+                       $ gzip /tmp/BusyBox-0.43.tar
+                       $ ls -la /tmp/BusyBox*
+                       -rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/BusyBox-0.43.tar.gz
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="halt">
+           <title>halt</title>
+
+               <para>
+               Usage: halt
+               </para>
+
+               <para>
+               Halt the system.
+               </para>
+       </sect1>
+
+       <sect1 id="head">
+           <title>head</title>
+
+               <para>
+               Usage: head [OPTION] FILE...
+               </para>
+
+               <para>
+               Print first 10 lines of each FILE to standard output.
+               With more than one FILE, precede each with a header
+               giving the file name. With no FILE, or when FILE is -,
+               read standard input.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -n NUM  Print first NUM lines instead of first 10
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ head -n 2 /etc/passwd
+                       root:x:0:0:root:/root:/bin/bash
+                       daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="hostid">
+           <title>hostid</title>
+
+               <para>
+               Usage: hostid
+               </para>
+
+               <para>
+               Prints out a unique 32-bit identifier for the current
+               machine. The 32-bit identifier is intended to be unique
+               among all UNIX systems in existence. 
+               </para>
+       </sect1>
+
+       <sect1 id="hostname">
+           <title>hostname</title>
+
+               <para>
+               Usage: hostname [OPTION]... [HOSTNAME|-F FILE]
+               </para>
+
+               <para>
+               Get or set the hostname or DNS domain name. If a
+               hostname is given (or a file with the -F parameter), the
+               host name will be set.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -s              Short
+                       -i              Addresses for the hostname
+                       -d              DNS domain name
+                       -F, --file FILE Use the contents of FILE to specify the hostname
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ hostname
+                       slag
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="id">
+           <title>id</title>
+
+               <para>
+               Usage: id [OPTION]... [USERNAME]
+               </para>
+
+               <para>
+               Print information for USERNAME or the current user.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -g      Print only the group ID
+                       -u      Print only the user ID
+                       -n      print a name instead of a number (with for -ug)
+                       -r      Print the real user ID instead of the effective ID (with -ug)
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ id
+                       uid=1000(andersen) gid=1000(andersen)
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="init">
+           <title>init</title>
+
+               <para>
+               Usage: init
+               </para>
+
+               <para>
+               Init is the parent of all processes.
+               </para>
+
+               <para>
+               This version of init is designed to be run only by the
+               kernel.
+               </para>
+
+               <para>
+               BusyBox init doesn't support multiple runlevels. The
+               runlevels field of the /etc/inittab file is completely
+               ignored by BusyBox init. If you want runlevels, use
+               sysvinit.
+               </para>
+
+               <para>
+               BusyBox init works just fine without an inittab. If no
+               inittab is found, it has the following default behavior:
+               </para>
+
+               <para>
+               <screen>
+                       ::sysinit:/etc/init.d/rcS
+                       ::askfirst:/bin/sh
+               </screen>
+               </para>
+
+               <para>
+               If it detects that /dev/console is _not_ a serial
+               console, it will also run:
+               </para>
+
+               <para>
+               <screen>
+                       tty2::askfirst:/bin/sh
+               </screen>
+               </para>
+
+               <para>
+               If you choose to use an /etc/inittab file, the inittab
+               entry format is as follows:
+               </para>
+
+               <para>
+               <screen>
+                       &lt;id&gt;:&lt;runlevels&gt;:&lt;action&gt;:&lt;process&gt;
+               </screen>
+               </para>
+
+               <sect2>
+                   <title>id</title>
+                       <para>
+
+                       WARNING: This field has a non-traditional meaning for BusyBox init!
+                       The id field is used by BusyBox init to specify the controlling tty
+                       for the specified process to run on.  The contents of this field
+                       are appended to "/dev/" and used as-is.  There is no need for this
+                       field to be unique, although if it isn't you may have strange
+                       results.  If this field is left blank, the controlling tty is set
+                       to the console.  Also note that if BusyBox detects that a serial
+                       console is in use, then only entries whose controlling tty is
+                       either the serial console or /dev/null will be run.  BusyBox init
+                       does nothing with utmp.  We don't need no stinkin' utmp.
+
+                       </para>
+               </sect2>
+
+               <sect2>
+                   <title>runlevels</title>
+
+                       <para>
+                       The runlevels field is completely ignored.
+                       </para>
+               </sect2>
+
+               <sect2>
+                   <title>action</title>
+
+
+                       <para>
+                       Valid actions include: sysinit, respawn, askfirst, wait, 
+                       once, and ctrlaltdel.
+                       </para>
+
+
+                       <para>
+                       The available actions can be classified into two groups: actions
+                       that are run only once, and actions that are re-run when the specified
+                       process exits.
+                       </para>
+
+                       <para>
+                       Run only-once actions:
+                       </para>
+
+                       <para>
+                       'sysinit' is the first item run on boot.  init waits until all
+                       sysinit actions are completed before continuing.  Following the
+                       completion of all sysinit actions, all 'wait' actions are run.
+                       'wait' actions, like  'sysinit' actions, cause init to wait until
+                       the specified task completes.  'once' actions are asyncronous,
+                       therefore, init does not wait for them to complete.  'ctrlaltdel'
+                       actions are run immediately before init causes the system to reboot
+                       (unmounting filesystems with a 'ctrlaltdel' action is a very good
+                        idea).
+                       </para>
+
+                       <para>
+                       Run repeatedly actions:
+                       </para>
+
+                       <para>
+                       'respawn' actions are run after the 'once' actions.  When a process
+                       started with a 'respawn' action exits, init automatically restarts
+                       it.  Unlike sysvinit, BusyBox init does not stop processes from
+                       respawning out of control.  The 'askfirst' actions acts just like
+                       respawn, except that before running the specified process it
+                       displays the line "Please press Enter to activate this console."
+                       and then waits for the user to press enter before starting the
+                       specified process.  
+                       </para>
+
+                       <para>
+                       Unrecognized actions (like initdefault) will cause init to emit an
+                       error message, and then go along with its business.  All actions are
+                       run in the reverse order from how they appear in /etc/inittab.
+                       </para>
+
+               </sect2>
+
+               <sect2>
+                   <title>process</title>
+
+                       <para>
+                       Specifies the process to be executed and its
+                       command line.
+                       </para>
+               </sect2>
+
+               <sect2>
+                   <title>Example /etc/inittab file</title>
+
+                   <para>
+                   <screen>
+                           # This is run first except when booting in single-user mode.
+                           #
+                           ::sysinit:/etc/init.d/rcS
+
+                           # /bin/sh invocations on selected ttys
+                           #
+                           # Start an "askfirst" shell on the console (whatever that may be)
+                           ::askfirst:-/bin/sh
+                           # Start an "askfirst" shell on /dev/tty2-4
+                           tty2::askfirst:-/bin/sh
+                           tty2::askfirst:-/bin/sh
+                           tty2::askfirst:-/bin/sh
+
+                           # /sbin/getty invocations for selected ttys
+                           #
+                           tty4::respawn:/sbin/getty 38400 tty5
+                           tty5::respawn:/sbin/getty 38400 tty6
+
+                           # Example of how to put a getty on a serial line (for a terminal)
+                           #
+                           #::respawn:/sbin/getty -L ttyS0 9600 vt100
+                           #::respawn:/sbin/getty -L ttyS1 9600 vt100
+                           #
+                           # Example how to put a getty on a modem line.
+                           #::respawn:/sbin/getty 57600 ttyS2
+
+                           # Stuff to do before rebooting
+                           ::ctrlaltdel:/bin/umount -a -r
+                           ::ctrlaltdel:/sbin/swapoff
+                   </screen>
+                   </para>
+               </sect2>
+       </sect1>
+
+       <sect1 id="insmod">
+           <title>insmod</title>
+
+               <para>
+               Usage: insmod [OPTION]... MODULE [symbol=value]...
+               </para>
+
+               <para>
+               Load MODULE into the kernel.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -f      Force module to load into the wrong kernel version.
+                       -k      Make module autoclean-able.
+                       -v      Verbose output
+                       -x      Do not export externs
+                       -L      Prevent simultaneous loads of the same module
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="kill">
+           <title>kill</title>
+
+               <para>
+               Usage: kill [OPTION] PID...
+               </para>
+
+               <para>
+               Send a signal (default is SIGTERM) to the specified
+               PID(s).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -l      List all signal names and numbers
+                       -SIG    Send signal SIG
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ps | grep apache
+                       252 root     root     S [apache]
+                       263 www-data www-data S [apache]
+                       264 www-data www-data S [apache]
+                       265 www-data www-data S [apache]
+                       266 www-data www-data S [apache]
+                       267 www-data www-data S [apache]
+                       $ kill 252
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="killall">
+           <title>killall</title>
+
+               <para>
+               Usage: killall [OPTION] NAME...
+               </para>
+
+               <para>
+               Send a signal (default is SIGTERM) to the specified
+               NAME(s).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -l      List all signal names and numbers
+                       -SIG    Send signal SIG
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ killall apache
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="length">
+           <title>length</title>
+
+               <para>
+               Usage: length STRING
+               </para>
+
+               <para>
+               Print the length of STRING.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ length "Hello"
+                       5
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="ln">
+           <title>ln</title>
+
+               <para>
+               Usage: ln [OPTION]... TARGET FILE|DIRECTORY
+               </para>
+
+               <para>
+               Create a link named FILE or DIRECTORY to the specified
+               TARGET.  You may use '--' to indicate that all following
+               arguments are non-options.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -s      Make symbolic link instead of hard link
+                       -f      Remove existing destination file
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ln -s BusyBox /tmp/ls
+                       $ ls -l /tmp/ls
+                       lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -&gt; BusyBox*
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="loadacm">
+           <title>loadacm</title>
+
+               <para>
+               Usage: loadacm
+               </para>
+
+               <para>
+               Load an acm from stdin.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ loadacm &lt; /etc/i18n/acmname
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="loadfont">
+           <title>loadfont</title>
+
+               <para>
+               Usage: loadfont
+               </para>
+
+               <para>
+               Load a console font from stdin.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ loadfont &lt; /etc/i18n/fontname
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="loadkmap">
+           <title>loadkmap</title>
+
+               <para>
+               Usage: loadkmap
+               </para>
+
+               <para>
+               Load a binary keyboard translation table from stdin.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ loadkmap &lt; /etc/i18n/lang-keymap
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="logger">
+           <title>logger</title>
+
+               <para>
+               Usage: logger [OPTION]... [MESSAGE]
+               </para>
+
+               <para>
+               Write MESSAGE to the system log.  If MESSAGE is omitted, log
+               stdin.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -s      Log to stderr as well as the system log
+                       -t      Log using the specified tag (defaults to user name)
+                       -p      Enter the message with the specified priority
+                               This may be numerical or a ``facility.level'' pair
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ logger "hello"
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="logname">
+           <title>logname</title>
+
+               <para>
+               Usage: logname
+               </para>
+
+               <para>
+               Print the name of the current user.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ logname
+                       root
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="ls">
+           <title>ls</title>
+
+               <para>
+               Usage: ls [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Do not hide entries starting with .
+                       -c      With  -l:  show ctime (the time of last
+                               modification of file status information)
+                       -d      List directory entries instead of contents
+                       -e      List both full date and full time
+                       -l      Use a long listing format
+                       -n      List numeric UIDs and GIDs instead of names
+                       -p      Append indicator (one of /=@|) to entries
+                       -u      With -l: show access time (the time of last
+                               access of the file)
+                       -x      List entries by lines instead of by columns
+                       -A      Do not list implied . and ..
+                       -C      List entries by columns
+                       -F      Append indicator (one of */=@|) to entries
+                       -L      list entries pointed to by symbolic links
+                       -R      List subdirectories recursively
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="lsmod">
+           <title>lsmod</title>
+
+               <para>
+               Usage: lsmod
+               </para>
+
+               <para>
+               List currently loaded kernel modules.
+               </para>
+       </sect1>
+
+       <sect1 id="makedevs">
+           <title>makedevs</title>
+
+               <para>
+               Usage: makedevsf NAME TYPE MAJOR MINOR FIRST LAST [s]
+               </para>
+
+               <para>
+               Create a range of block or character special files.
+               </para>
+
+               <para>
+               TYPE may be:
+               </para>
+
+               <para>
+               <screen>
+                       b       Make a block (buffered) device
+                       c or u  Make a character (un-buffered) device
+                       p       Make a named pipe. MAJOR and MINOR are ignored for named pipes
+               </screen>
+               </para>
+
+               <para>
+               FIRST specifies the number appended to NAME to create
+               the first device.  LAST specifies the number of the last
+               item that should be created. If 's' is the last
+               argument, the base device is created as well.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ makedevs /dev/ttyS c 4 66 2 63
+                       [creates ttyS2-ttyS63]
+                       $ makedevs /dev/hda b 3 0 0 8 s
+                       [creates hda,hda1-hda8]
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="md5sum">
+           <title>md5sum</title>
+
+               <para>
+               Usage: md5sum [OPTION]... FILE...
+               </para>
+
+               <para>
+               Print or check MD5 checksums.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -b      Read files in binary mode
+                       -c      Check MD5 sums against given list
+                       -t      Read files in text mode (default)
+                       -g      Read a string
+               </screen>
+               </para>
+
+               <para>
+               The following two options are useful only when verifying
+               checksums:
+               </para>
+
+               <para>
+               <screen>
+                       -s      Don't output anything, status code shows success
+                       -w      Warn about improperly formated MD5 checksum lines
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ md5sum busybox
+                       6fd11e98b98a58f64ff3398d7b324003  busybox
+                       $ md5sum -c
+                       6fd11e98b98a58f64ff3398d7b324003  busybox
+                       6fd11e98b98a58f64ff3398d7b324002  busybox
+                       md5sum: MD5 check failed for 'busybox'
+                       ^D
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mkdir">
+           <title>mkdir</title>
+
+               <para>
+               Usage: mkdir [OPTION]... DIRECTORY...
+               </para>
+
+               <para>
+               Create the DIRECTORY(s), if they do not already exist.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -m      Set permission mode (as in chmod), not rwxrwxrwx - umask
+                       -p      No error if directory exists, make parent directories as needed
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ mkdir /tmp/foo
+                       $ mkdir /tmp/foo
+                       /tmp/foo: File exists
+                       $ mkdir /tmp/foo/bar/baz
+                       /tmp/foo/bar/baz: No such file or directory
+                       $ mkdir -p /tmp/foo/bar/baz
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mkfifo">
+           <title>mkfifo</title>
+
+               <para>
+               Usage: mkfifo [OPTION] NAME
+               </para>
+
+               <para>
+               Create a named pipe (identical to 'mknod NAME p').
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -m MODE Create the pipe using the specified mode (default a=rw)
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mkfs.minix">
+           <title>mkfs.minix</title>
+
+               <para>
+               Usage: mkfs.minix [OPTION]... NAME [BLOCKS]
+               </para>
+
+               <para>
+               Make a MINIX filesystem.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c              Check the device for bad blocks
+                       -n [14|30]      Specify the maximum length of filenames
+                       -i              Specify the number of inodes for the filesystem
+                       -l FILENAME     Read the bad blocks list from FILENAME
+                       -v              Make a Minix version 2 filesystem
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mknod">
+           <title>mknod</title>
+
+               <para>
+               Usage: mknod [OPTION]... NAME TYPE MAJOR MINOR
+               </para>
+
+               <para>
+               Create a special file (block, character, or pipe).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -m      Create the special file using the specified mode (default a=rw)
+               </screen>
+               </para>
+
+               <para>
+               TYPE may be:
+               </para>
+
+               <para>
+               <screen>
+                       b       Make a block (buffered) device
+                       c or u  Make a character (un-buffered) device
+                       p       Make a named pipe. MAJOR and MINOR are ignored for named pipes
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ mknod /dev/fd0 b 2 0 
+                       $ mknod -m 644 /tmp/pipe p
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mkswap">
+           <title>mkswap</title>
+
+               <para>
+               Usage: mkswap [OPTION]... DEVICE [BLOCKS]
+               </para>
+
+               <para>
+               Prepare a disk partition to be used as a swap partition.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Check for read-ability.
+                       -v0     Make version 0 swap [max 128 Megs].
+                       -v1     Make version 1 swap [big!] (default for kernels &gt; 2.1.117).
+                       BLOCKS  Number of block to use (default is entire partition).
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mktemp">
+           <title>mktemp</title>
+
+               <para>
+               Usage: mktemp TEMPLATE
+               </para>
+
+               <para>
+               Creates a temporary file with its name based on
+               TEMPLATE.  TEMPLATE is any name with six `Xs' (i.e.,
+               /tmp/temp.XXXXXX).
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ mktemp /tmp/temp.XXXXXX
+                       /tmp/temp.mWiLjM
+                       $ ls -la /tmp/temp.mWiLjM
+                       -rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="more">
+           <title>more</title>
+
+               <para>
+               Usage: more [FILE]...
+               </para>
+
+               <para>
+               Page through text one screenful at a time.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ dmesg | more
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mount">
+           <title>mount</title>
+
+               <para>
+               Usage: mount [OPTION]...
+               </para>
+
+               <para>
+               <screen>
+                  or: mount [OPTION]... DEVICE DIRECTORY
+               </screen>
+               </para>
+
+               <para>
+               Mount filesystems.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Mount all filesystems in /etc/fstab
+                       -o      One of the many filesystem options listed below
+                       -r      Mount the filesystem read-only
+                       -t TYPE Specify the filesystem type
+                       -w      Mount the filesystem read-write
+               </screen>
+               </para>
+
+               <para>
+               Options for use with the -o flag:
+               </para>
+
+               <para>
+               <screen>
+                       async/sync      Writes are asynchronous / synchronous
+                       atime/noatime   Enable / disable updates to inode access times
+                       dev/nodev       Allow / disallow use of special device files
+                       exec/noexec     Allow / disallow use of executable files
+                       loop            Mount a file via loop device
+                       suid/nosuid     Allow / disallow set-user-id-root programs
+                       remount         Remount a currently mounted filesystem
+                       ro/rw           Mount filesystem read-only / read-write
+               </screen>
+               </para>
+
+               <para>
+               There are even more flags that are filesystem specific.
+               You'll have to see the written documentation for those.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ mount
+                       /dev/hda3 on / type minix (rw)
+                       proc on /proc type proc (rw)
+                       devpts on /dev/pts type devpts (rw)
+                       $ mount /dev/fd0 /mnt -t msdos -o ro
+                       $ mount /tmp/diskimage /opt -t ext2 -o loop
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mt">
+           <title>mt</title>
+
+               <para>
+               Usage: mt [OPTION] OPCODE VALUE
+               </para>
+
+               <para>
+               Control magnetic tape drive operation.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -f DEVICE       Control DEVICE
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="mv">
+           <title>mv</title>
+
+               <para>
+               Usage: mv SOURCE DEST
+               </para>
+
+               <para>
+               <screen>
+                  or: mv SOURCE... DIRECTORY
+               </screen>
+               </para>
+
+               <para>
+               Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ mv /tmp/foo /bin/bar
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="nc">
+           <title>nc</title>
+
+               <para>
+               Usage: nc HOST PORT
+               </para>
+
+               <para>
+                  or: nc -p PORT -l
+               </para>
+
+
+               <para>
+               Open a pipe to HOST:PORT or listen for a connection on PORT.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ nc foobar.somedomain.com 25
+                       220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600
+                       help
+                       214-Commands supported:
+                       214-    HELO EHLO MAIL RCPT DATA AUTH
+                       214     NOOP QUIT RSET HELP
+                       quit
+                       221 foobar closing connection
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="nslookup">
+           <title>nslookup</title>
+
+               <para>
+               Usage: nslookup [HOST]
+               </para>
+
+               <para>
+               Query the nameserver for the IP address of the given
+               HOST.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ nslookup localhost
+                       Server:     default
+                       Address:    default
+
+                       Name:       debian
+                       Address:    127.0.0.1
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="ping">
+           <title>ping</title>
+
+               <para>
+               Usage: ping [OPTION]... HOST
+               </para>
+
+               <para>
+               Send ICMP ECHO_REQUEST packets to HOST.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c COUNT        Send only COUNT pings
+                       -s SIZE         Send SIZE data bytes in packets (default=56)
+                       -q              Quiet mode, only displays output at start and when finished
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ping localhost
+                       PING slag (127.0.0.1): 56 data bytes
+                       64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms
+
+                       --- debian ping statistics ---
+                       1 packets transmitted, 1 packets received, 0% packet loss
+                       round-trip min/avg/max = 20.1/20.1/20.1 ms
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="poweroff">
+           <title>poweroff</title>
+
+               <para>
+               Usage: poweroff
+               </para>
+
+               <para>
+               Shut down the system, and request that the kernel turn
+               off power upon halting.
+               </para>
+       </sect1>
+
+       <sect1 id="printf">
+           <title>printf</title>
+
+               <para>
+               Usage: printf FORMAT [ARGUMENT]...
+               </para>
+
+               <para>
+               Format and print the given data in a manner similar to
+               the C printf command.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ printf "Val=%d\n" 5
+                       Val=5
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="ps">
+           <title>ps</title>
+
+               <para>
+               Usage: ps
+               </para>
+
+               <para>
+               Report process status.  This version of ps accepts no
+               options.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ps
+                         PID  Uid      Gid State Command
+                           1 root     root     S init
+                           2 root     root     S [kflushd]
+                           3 root     root     S [kupdate]
+                           4 root     root     S [kpiod]
+                           5 root     root     S [kswapd]
+                         742 andersen andersen S [bash]
+                         743 andersen andersen S -bash
+                         745 root     root     S [getty]
+                        2990 andersen andersen R ps
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="pwd">
+           <title>pwd</title>
+
+               <para>
+               Usage: pwd
+               </para>
+
+               <para>
+               Print the full filename of the current working
+               directory.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ pwd
+                       /root
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="rdate">
+           <title>rdate</title>
+
+               <para>
+               Usage: rdate [OPTION] HOST
+               </para>
+
+               <para>
+               Get and possibly set the system date and time from a remote HOST.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -s      Set the system date and time (default).
+                       -p      Print the date and time.
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="reboot">
+           <title>reboot</title>
+
+               <para>
+               Usage: reboot
+               </para>
+
+               <para>
+               Reboot the system.
+               </para>
+       </sect1>
+
+       <sect1 id="renice">
+           <title>renice</title>
+
+               <para>
+               Usage: renice priority pid [pid ...]
+               </para>
+
+               <para>
+               Changes priority of running processes. Allowed priorities range
+               from 20 (the process runs only when nothing else is running) to 0
+               (default priority) to -20 (almost nothing else ever gets to run).
+               </para>
+       </sect1>
+
+       <sect1 id="reset">
+           <title>reset</title>
+
+               <para>
+               Usage: reset
+               </para>
+
+               <para>
+               Resets the screen.
+               </para>
+       </sect1>
+
+       <sect1 id="rm">
+           <title>rm</title>
+
+               <para>
+               Usage: rm [OPTION]... FILE...
+               </para>
+
+               <para>
+               Remove (unlink) the FILE(s).  You may use '--' to
+               indicate that all following arguments are non-options.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -i              Always prompt before removing each destinations
+                       -f              Remove existing destinations, never prompt
+                       -r or -R        Remove the contents of directories recursively
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ rm -rf /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="rmdir">
+           <title>rmdir</title>
+
+               <para>
+               Usage: rmdir DIRECTORY...
+               </para>
+
+               <para>
+               Remove DIRECTORY(s) if they are empty.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ rmdir /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="rmmod">
+           <title>rmmod</title>
+
+               <para>
+               Usage: rmmod [OPTION]... [MODULE]...
+               </para>
+
+               <para>
+               Unload MODULE(s) from the kernel.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Try to remove all unused kernel modules
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ rmmod tulip
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="sed">
+           <title>sed</title>
+
+               <para>
+               Usage: sed [OPTION]... SCRIPT [FILE]...
+               </para>
+
+               <para>
+               Allowed sed scripts come in the following form:
+               </para>
+
+               <para>
+               <screen>
+               ADDR [!] COMMAND
+               </screen>
+               </para>
+
+               <para>
+               ADDR can be:
+               </para>
+
+               <para>
+               <screen>
+                       NUMBER    Match specified line number
+                       $         Match last line
+                       /REGEXP/  Match specified regexp
+               </screen>
+               </para>
+
+               <para>
+               ! inverts the meaning of the match
+               </para>
+
+               <para>
+               COMMAND can be:
+               </para>
+
+               <para>
+               <screen>
+                       s/regexp/replacement/[igp]
+                               which attempt to match regexp against the pattern space
+                               and if successful replaces the matched portion with replacement.
+                       aTEXT
+                               which appends TEXT after the pattern space
+               </screen>
+               </para>
+
+               <para>
+               This version of sed matches full regular expressions.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -e      Add the script to the commands to be executed
+                       -n      Suppress automatic printing of pattern space
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'
+                       bar
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="setkeycodes">
+           <title>setkeycodes</title>
+
+               <para>
+               Usage: setkeycodes SCANCODE KEYCODE ...
+               </para>
+
+               <para>
+               Set entries into the kernel's scancode-to-keycode map,
+               allowing unusual keyboards to generate usable keycodes.
+               </para>
+
+               <para>
+               SCANCODE may be either xx or e0xx (hexadecimal), and
+               KEYCODE is given in decimal.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ setkeycodes e030 127
+               </screen>
+               </para>
+       </sect1>
+
+
+       <sect1 id="sh">
+           <title>sh</title>
+
+               <para>
+               Usage: sh
+               </para>
+
+               <para>
+               lash -- the BusyBox LAme SHell (command interpreter)
+               </para>
+
+               <para>
+               This command does not yet have proper documentation.  
+               </para>
+
+               <para>
+               Use lash just as you would use any other shell. It
+               properly handles pipes, redirects, job control, can be
+               used as the shell for scripts (#!/bin/sh), and has a
+               sufficient set of builtins to do what is needed. It does
+               not (yet) support Bourne Shell syntax. If you need
+               things like ``if-then-else'', ``while'', and such, use
+               ash or bash. If you just need a very simple and
+               extremely small shell, this will do the job.
+               </para>
+       </sect1>
+
+       <sect1 id="sleep">
+           <title>sleep</title>
+
+               <para>
+               Usage: sleep N
+               </para>
+
+               <para>
+               Pause for N seconds.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ sleep 2
+                       [2 second delay results]
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="sort">
+           <title>sort</title>
+
+               <para>
+               Usage: sort [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               Sort lines of text in FILE(s).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -n      Compare numerically
+                       -r      Reverse after sorting
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo -e "e\nf\nb\nd\nc\na" | sort
+                       a
+                       b
+                       c
+                       d
+                       e
+                       f
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="swapoff">
+           <title>swapoff</title>
+
+               <para>
+               Usage: swapoff [OPTION] [DEVICE]
+               </para>
+
+               <para>
+               Stop swapping virtual memory pages on DEVICE.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Stop swapping on all swap devices
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="swapon">
+           <title>swapon</title>
+
+               <para>
+               Usage: swapon [OPTION] [DEVICE]
+               </para>
+
+               <para>
+               Start swapping virtual memory pages on the given device.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Start swapping on all swap devices
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="sync">
+           <title>sync</title>
+
+               <para>
+               Usage: sync
+               </para>
+
+               <para>
+               Write all buffered filesystem blocks to disk.
+               </para>
+       </sect1>
+
+       <sect1 id="syslogd">
+           <title>syslogd</title>
+
+               <para>
+               Usage: syslogd [OPTION]...
+               </para>
+
+               <para>
+               Linux system and kernel (provides klogd) logging
+               utility. Note that this version of syslogd/klogd ignores
+               /etc/syslog.conf.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -m NUM  Interval between MARK lines (default=20min, 0=off)
+                       -n      Run as a foreground process
+                       -K      Do not start up the klogd process
+                       -O FILE Use an alternate log file (default=/var/log/messages)
+                       -R HOST[:PORT] Log remotely to IP or hostname on PORT (default PORT=514/UDP)
+                       -L      Log locally as well as network logging (default is network only)
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+               $ syslogd -R masterlog:514
+               $ syslogd -R 192.168.1.1:601
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="tail">
+           <title>tail</title>
+
+               <para>
+               Usage: tail [OPTION] [FILE]...
+               </para>
+
+               <para>
+               Print last 10 lines of each FILE to standard output.
+               With more than one FILE, precede each with a header
+               giving the file name. With no FILE, or when FILE is -,
+               read stdin.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -n NUM  Print last NUM lines instead of last 10
+                       -f      Output data as the file grows.  This version
+                               of 'tail -f' supports only one file at a time.
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ tail -n 1 /etc/resolv.conf
+                       nameserver 10.0.0.1
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="tar">
+           <title>tar</title>
+
+               <para>
+               Usage: tar [MODE] [OPTION] [FILE]...
+               </para>
+
+               <para>
+               
+               </para>
+
+               <para>
+               MODE may be chosen from
+               </para>
+
+               <para>
+               <screen>
+                       c       Create
+                       x       Extract
+                       t       List
+               </screen>
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       f FILE                  Use FILE for tarfile (or stdin if '-')
+                       O                               Extract to stdout
+                       exclude FILE    File to exclude
+                       v                               List files processed
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ zcat /tmp/tarball.tar.gz | tar -xf -
+                       $ tar -cf /tmp/tarball.tar /usr/local
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="tee">
+           <title>tee</title>
+
+               <para>
+               Usage: tee [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               Copy stdin to FILE(s), and also to stdout.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Append to the given FILEs, do not overwrite
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo "Hello" | tee /tmp/foo
+                       Hello
+                       $ cat /tmp/foo
+                       Hello
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="telnet">
+           <title>telnet</title>
+
+               <para>
+               Usage: telnet HOST [PORT]
+               </para>
+
+               <para>
+               Establish interactive communication with another
+               computer over a network using the TELNET protocol.
+               </para>
+       </sect1>
+
+       <sect1 id="test">
+           <title>test, [</title>
+
+               <para>
+               Usage: test EXPRESSION
+               </para>
+
+               <para>
+                  or: [ EXPRESSION ]
+               </para>
+
+               <para>
+               Check file types and compare values returning an exit
+               code determined by the value of EXPRESSION.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ test 1 -eq 2
+                       $ echo $?
+                       1
+                       $ test 1 -eq 1
+                       $ echo $?
+                       0
+                       $ [ -d /etc ]
+                       $ echo $?
+                       0
+                       $ [ -d /junk ]
+                       $ echo $?
+                       1
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="touch">
+           <title>touch</title>
+
+               <para>
+               Usage: touch [OPTION]... FILE...
+               </para>
+
+               <para>
+               Update the last-modified date on (or create) FILE(s).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Do not create files
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls -l /tmp/foo
+                       /bin/ls: /tmp/foo: No such file or directory
+                       $ touch /tmp/foo
+                       $ ls -l /tmp/foo
+                       -rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="tr">
+           <title>tr</title>
+
+               <para>
+               Usage: tr [OPTION]... STRING1 [STRING2]
+               </para>
+
+               <para>
+               Translate, squeeze, and/or delete characters from stdin,
+               writing to stdout.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Take complement of STRING1
+                       -d      Delete input characters coded STRING1
+                       -s      Squeeze multiple output characters of STRING2 into one character
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo "gdkkn vnqkc" | tr [a-y] [b-z]
+                       hello world
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="true">
+           <title>true</title>
+
+               <para>
+               Usage: true
+               </para>
+
+               <para>
+               Return an exit code of TRUE (1).
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ true
+                       $ echo $?
+                       0
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="tty">
+           <title>tty</title>
+
+               <para>
+               Usage: tty
+               </para>
+
+               <para>
+               Print the file name of the terminal connected to stdin.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -s      Print nothing, only return an exit status
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ tty
+                       /dev/tty2
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="umount">
+           <title>umount</title>
+
+               <para>
+               Usage: umount [OPTION]... DEVICE|DIRECTORY
+               </para>
+
+               <para>
+               
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Unmount all file systems
+                       -r      Try to remount devices as read-only if mount is busy
+                       -f      Force filesystem umount (i.e., unreachable NFS server)
+                       -l      Do not free loop device (if a loop device has been used)
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ umount /dev/hdc1 
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="uname">
+           <title>uname</title>
+
+               <para>
+               Usage: uname [OPTION]...
+               </para>
+
+               <para>
+               Print certain system information. With no OPTION, same
+               as -s.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -a      Print all information
+                       -m      Print the machine (hardware) type
+                       -n      Print the machine's network node hostname
+                       -r      Print the operating system release
+                       -s      Print the operating system name
+                       -p      Print the host processor type
+                       -v      Print the operating system version
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ uname -a
+                       Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="uniq">
+           <title>uniq</title>
+
+               <para>
+               Usage: uniq [INPUT [OUTPUT]]
+               </para>
+
+               <para>
+               Discard all but one of successive identical lines from
+               INPUT (or stdin), writing to OUTPUT (or stdout).
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+               -c              prefix lines by the number of occurrences
+               -d              only print duplicate lines
+               -u              only print unique lines
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ echo -e "a\na\nb\nc\nc\na" | sort | uniq
+                       a
+                       b
+                       c
+               </screen>
+               </para>
+       </sect1>
+       
+       <sect1 id="unix2dos">
+           <title>unix2dos</title>
+
+               <para>
+               Usage: unix2dos < unixfile > dosfile
+               </para>
+
+               <para>
+               Converts a text file from unix format to dos format.
+               </para>
+
+       </sect1>
+
+       <sect1 id="unrpm">
+           <title>unrpm</title>
+
+               <para>
+               Usage: unrpm < package.rpm | gzip -d | cpio -idmuv
+               </para>
+
+               <para>
+               Extracts an rpm archive.
+               </para>
+
+       </sect1>
+
+       <sect1 id="update">
+           <title>update</title>
+
+               <para>
+               Usage: update [OPTION]...
+               </para>
+
+               <para>
+               Periodically flush filesystem buffers.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -S      Force use of sync(2) instead of flushing
+                       -s SECS Call sync this often (default 30)
+                       -f SECS Flush some buffers this often (default 5)
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="uptime">
+           <title>uptime</title>
+
+               <para>
+               Usage: uptime
+               </para>
+
+               <para>
+               Display how long the system has been running since boot.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ uptime
+                         1:55pm  up  2:30, load average: 0.09, 0.04, 0.00
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="usleep">
+           <title>usleep</title>
+
+               <para>
+               Usage: usleep N
+               </para>
+
+               <para>
+               Pause for N microseconds.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ usleep 1000000
+                       [pauses for 1 second]
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="uudecode">
+           <title>uudecode</title>
+
+               <para>
+               Usage: uudecode [OPTION] [FILE]
+               </para>
+
+               <para>
+               Uudecode a uuencoded file.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -o FILE Direct output to FILE
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ uudecode -o busybox busybox.uu
+                       $ ls -l busybox
+                       -rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="uuencode">
+           <title>uuencode</title>
+
+               <para>
+               Usage: uuencode [OPTION] [INFILE] OUTFILE
+               </para>
+
+               <para>
+               Uuencode a file.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -m      Use base64 encoding as of RFC1521
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ uuencode busybox busybox
+                       begin 755 busybox
+                       M?T5,1@$!`0````````````(``P`!````L+@$"#0```!0N@,``````#0`(``&amp;
+                       .....
+                       $ uudecode busybox busybox &gt; busybox.uu
+                       $
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="watchdog">
+           <title>watchdog</title>
+
+               <para>
+               Usage: watchdog device
+               </para>
+
+               <para>
+               Periodically writes to watchdog device B<device>.
+               </para>
+       </sect1>
+
+       <sect1 id="wc">
+           <title>wc</title>
+
+               <para>
+               Usage: wc [OPTION]... [FILE]...
+               </para>
+
+               <para>
+               Print line, word, and byte counts for each FILE, and a
+               total line if more than one FILE is specified. With no
+               FILE, read stdin.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -c      Print the byte counts
+                       -l      Print the newline counts
+                       -L      Print the length of the longest line
+                       -w      Print the word counts
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ wc /etc/passwd
+                            31      46    1365 /etc/passwd
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="which">
+           <title>which</title>
+
+               <para>
+               Usage: which [COMMAND]...
+               </para>
+
+               <para>
+               Locate COMMAND(s).
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ which login
+                       /bin/login
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="whoami">
+           <title>whoami</title>
+
+               <para>
+               Usage: whoami
+               </para>
+
+               <para>
+               Print the user name associated with the current
+               effective user id.
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ whoami
+                       andersen
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="xargs">
+           <title>xargs</title>
+
+               <para>
+               Usage: xargs [OPTIONS] [COMMAND] [ARGS...]
+               </para>
+
+               <para>
+               Executes COMMAND on every item given by standard input.
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -t      Print the command just before it is run
+               </screen>
+               </para>
+
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+                       $ ls | xargs gzip
+                       $ find . -name '*.c' -print | xargs rm
+               </screen>
+               </para>
+       </sect1>
+
+       <sect1 id="yes">
+           <title>yes</title>
+
+               <para>
+               Usage: yes [STRING]...
+               </para>
+
+               <para>
+               Repeatedly output a line with all specified STRING(s),
+               or `y'.
+               </para>
+       </sect1>
+
+       <sect1 id="zcat">
+           <title>zcat</title>
+
+               <para>
+               Usage: zcat [OPTION]... FILE
+               </para>
+
+               <para>
+               Uncompress FILE (or stdin if FILE is '-') to stdout.  
+               </para>
+
+               <para>
+               Options:
+               </para>
+
+               <para>
+               <screen>
+                       -t      Test compressed file integrity
+               </screen>
+               </para>
+
+               <para>
+               Example:
+               </para>
+
+               <para>
+               <screen>
+               </screen>
+               </para>
+       </sect1>
+  </chapter>
+
+  <chapter id="LIBC-NSS">
+    <title>LIBC NSS</title>
+
+       <para>
+       GNU Libc uses the Name Service Switch (NSS) to configure the
+       behavior of the C library for the local environment, and to
+       configure how it reads system data, such as passwords and group
+       information. BusyBox has made it Policy that it will never use
+       NSS, and will never use libc calls that make use of NSS. This
+       allows you to run an embedded system without the need for
+       installing an /etc/nsswitch.conf file and without /lib/libnss_*
+       libraries installed.
+       </para>
+
+       <para>
+       If you are using a system that is using a remote LDAP server for
+       authentication via GNU libc NSS, and you want to use BusyBox,
+       then you will need to adjust the BusyBox source. Chances are
+       though, that if you have enough space to install of that stuff
+       on your system, then you probably want the full GNU utilities.
+       </para>
+  </chapter>
+
+  <chapter id="SEE-ALSO">
+    <title>SEE ALSO</title>
+
+       <para>
+       <literal>textutils(1),</literal>
+       <literal>shellutils(1),</literal>
+       etc...
+       </para>
+  </chapter>
+
+  <chapter id="MAINTAINER">
+    <title>MAINTAINER</title>
+
+       <para>
+       Erik Andersen &lt;andersee@debian.org&gt; &lt;andersen@codepoet.org&gt;
+       </para>
+  </chapter>
+
+  <chapter id="AUTHORS">
+    <title>AUTHORS</title>
+
+       <para>
+       The following people have made significant contributions to 
+       BusyBox -- whether they know it or not.
+       </para>
+
+       <para>
+       Erik Andersen &lt;andersee@debian.org&gt;
+       </para>
+
+       <para>
+       Edward Betts &lt;edward@debian.org&gt;
+       </para>
+
+       <para>
+       John Beppu &lt;beppu@codepoet.org&gt;
+       </para>
+
+       <para>
+       Brian Candler &lt;B.Candler@pobox.com&gt;
+       </para>
+
+       <para>
+       Randolph Chung &lt;tausq@debian.org&gt;
+       </para>
+
+       <para>
+       Dave Cinege &lt;dcinege@psychosis.com&gt;       
+       </para>
+
+       <para>
+       Karl M. Hegbloom &lt;karlheg@debian.org&gt;
+       </para>
+
+       <para>
+       Daniel Jacobowitz &lt;dan@debian.org&gt;
+       </para>
+
+       <para>
+       Matt Kraai &lt;kraai@alumni.carnegiemellon.edu&gt;
+       </para>
+
+       <para>
+       John Lombardo &lt;john@deltanet.com&gt; 
+       </para>
+
+       <para>
+       Glenn McGrath &lt;bug1@netconnect.com.au&gt;
+       </para>
+
+       <para>
+       Bruce Perens &lt;bruce@perens.com&gt;
+       </para>
+
+       <para>
+       Chip Rosenthal &lt;chip@unicom.com&gt;, &lt;crosenth@covad.com&gt;
+       </para>
+
+       <para>
+       Pavel Roskin &lt;proski@gnu.org&gt;
+       </para>
+
+       <para>
+       Gyepi Sam &lt;gyepi@praxis-sw.com&gt;
+       </para>
+
+       <para>
+       Linus Torvalds &lt;torvalds@transmeta.com&gt;
+       </para>
+
+        <para>
+        Mark Whitley &lt;markw@codepoet.org&gt;
+        </para>
+
+       <para>
+       Charles P. Wright &lt;cpwright@villagenet.com&gt;
+       </para>
+
+       <para>
+       Enrique Zanardi &lt;ezanardi@ull.es&gt;
+       </para>
+
+
+  </chapter>
+</book>    <!-- End of the book -->
diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod
new file mode 100644 (file)
index 0000000..6ba8716
--- /dev/null
@@ -0,0 +1,169 @@
+=back
+
+=head1 LIBC NSS
+
+GNU Libc uses the Name Service Switch (NSS) to configure the behavior of the C
+library for the local environment, and to configure how it reads system data,
+such as passwords and group information.  BusyBox has made it Policy that it
+will never use NSS, and will never use and libc calls that make use of NSS.
+This allows you to run an embedded system without the need for installing an
+/etc/nsswitch.conf file and without and /lib/libnss_* libraries installed.
+
+If you are using a system that is using a remote LDAP server for authentication
+via GNU libc NSS, and you want to use BusyBox, then you will need to adjust the
+BusyBox source.  Chances are though, that if you have enough space to install
+of that stuff on your system, then you probably want the full GNU utilities.
+
+=head1 SEE ALSO
+
+textutils(1), shellutils(1), etc...
+
+=head1 MAINTAINER
+
+Erik Andersen <andersee@debian.org> <andersen@codepoet.org>
+
+=head1 AUTHORS
+
+The following people have contributed code to BusyBox whether
+they know it or not.
+
+
+=for html <br>
+
+Erik Andersen <andersee@debian.org> <andersen@codepoet.org>
+
+    Tons of new stuff, major rewrite of most of the
+    core apps, tons of new apps as noted in header files.
+
+=for html <br>
+
+John Beppu <beppu@codepoet.org>
+
+    du, head, nslookup, sort, tee, uniq (so Kraai could rewrite them ;-),
+    documentation
+
+=for html <br>
+
+Edward Betts <edward@debian.org>
+
+    expr, hostid, logname, tty, wc, whoami, yes
+=for html <br>
+
+Brian Candler <B.Candler@pobox.com>
+
+    tiny-ls(ls)
+
+=for html <br>
+
+Randolph Chung <tausq@debian.org>
+
+    fbset, ping, hostname, and mkfifo
+
+=for html <br>
+
+Dave Cinege <dcinege@psychosis.com>    
+
+    more(v2), makedevs, dutmp, modularization, auto links file, 
+    various fixes, Linux Router Project maintenance
+
+=for html <br>
+
+Larry Doolittle <ldoolitt@recycle.lbl.gov>
+
+    various fixes, shell rewrite
+
+=for html <br>
+
+Karl M. Hegbloom <karlheg@debian.org>
+
+    cp_mv.c, the test suite, various fixes to utility.c, &c.
+
+=for html <br>
+
+Sterling Huxley <sterling@europa.com>
+
+    vi (!!!)
+
+=for html <br>
+
+Daniel Jacobowitz <dan@debian.org>
+
+    mktemp.c
+
+=for html <br>
+
+Matt Kraai <kraai@alumni.carnegiemellon.edu>
+
+    documentation, bugfixes
+
+=for html <br>
+
+John Lombardo <john@deltanet.com>      
+
+    dirname, tr
+
+=for html <br>
+
+Glenn McGrath <bug1@netconnect.com.au>
+
+    ar.c
+
+=for html <br>
+
+Vladimir Oleynik <dzo@simtreas.ru>
+
+    cmdedit, stty-port, locale, various fixes 
+    and irreconcilable critic of everything not perfect.
+
+=for html <br>
+
+Bruce Perens <bruce@pixar.com>
+
+    Original author of BusyBox. His code is still in many apps.
+
+=for html <br>
+
+Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com>
+
+    wget - Contributed by permission of Covad Communications
+
+=for html <br>
+
+Pavel Roskin <proski@gnu.org>
+
+    Lots of bugs fixes and patches.
+
+=for html <br>
+
+Gyepi Sam <gyepi@praxis-sw.com>
+
+    Remote logging feature for syslogd
+
+=for html <br>
+
+Linus Torvalds <torvalds@transmeta.com>
+
+    mkswap, fsck.minix, mkfs.minix
+
+=for html <br>
+
+Mark Whitley <markw@codepoet.org>
+
+    sed remix, bug fixes, style-guide, etc.
+
+=for html <br>
+
+Charles P. Wright <cpwright@villagenet.com>
+
+    gzip, mini-netcat(nc)
+
+=for html <br>
+
+Enrique Zanardi <ezanardi@ull.es>
+
+    tarcat (since removed), loadkmap, various fixes, Debian maintenance
+
+=cut
+
+# $Id: busybox_footer.pod,v 1.5 2001/11/19 23:57:54 andersen Exp $
diff --git a/docs/busybox_header.pod b/docs/busybox_header.pod
new file mode 100644 (file)
index 0000000..764d6e3
--- /dev/null
@@ -0,0 +1,74 @@
+# vi: set sw=4 ts=4:
+
+=head1 NAME
+
+BusyBox - The Swiss Army Knife of Embedded Linux
+
+=head1 SYNTAX
+
+ BusyBox <function> [arguments...]  # or
+
+ <function> [arguments...]         # if symlinked
+
+=head1 DESCRIPTION
+
+BusyBox combines tiny versions of many common UNIX utilities into a single
+small executable. It provides minimalist replacements for most of the utilities
+you usually find in fileutils, shellutils, findutils, textutils, grep, gzip,
+tar, etc.  BusyBox provides a fairly complete POSIX environment for any small
+or embedded system.  The utilities in BusyBox generally have fewer options than
+their full-featured GNU cousins; however, the options that are included provide
+the expected functionality and behave very much like their GNU counterparts. 
+
+BusyBox has been written with size-optimization and limited resources in mind.
+It is also extremely modular so you can easily include or exclude commands (or
+features) at compile time.  This makes it easy to customize your embedded
+systems.  To create a working system, just add a kernel, a shell (such as ash),
+and an editor (such as elvis-tiny or ae).
+
+=head1 USAGE
+
+When you create a link to BusyBox for the function you wish to use, when BusyBox
+is called using that link it will behave as if the command itself has been invoked.
+
+For example, entering
+
+       ln -s ./BusyBox ls
+       ./ls
+
+will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled
+into BusyBox). 
+
+You can also invoke BusyBox by issuing the command as an argument on the
+command line.  For example, entering
+
+       ./BusyBox ls
+
+will also cause BusyBox to behave as 'ls'. 
+
+=head1 COMMON OPTIONS
+
+Most BusyBox commands support the B<-h> option to provide a
+terse runtime description of their behavior. 
+
+=head1 COMMANDS
+
+Currently defined functions include:
+
+adjtimex, ar, basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear,
+cmp, cp, cpio, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dos2unix, dpkg,
+dpkg-deb, du, dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find, free,
+freeramdisk, fsck.minix, getopt, grep, gunzip, gzip, halt, head, hostid,
+hostname, id, ifconfig, init, insmod, kill, killall, klogd, length, ln,
+loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs, md5sum,
+mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc,
+nslookup, ping, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, reboot,
+renice, reset, rm, rmdir, rmmod, route, rpm2cpio, sed, setkeycodes,
+sh, sleep, sort, stty, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet,
+test, tftp, touch, tr, true, tty, umount, uname, uniq, unix2dos, update, uptime,
+usleep, uudecode, uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat,
+[
+
+=over 4
+
+
diff --git a/docs/contributing.txt b/docs/contributing.txt
new file mode 100644 (file)
index 0000000..7103d3e
--- /dev/null
@@ -0,0 +1,476 @@
+Contributing To Busybox
+=======================
+
+This document describes what you need to do to contribute to Busybox, where
+you can help, guidelines on testing, and how to submit a well-formed patch
+that is more likely to be accepted.
+
+The Busybox home page is at: http://busybox.lineo.com
+
+
+
+Pre-Contribution Checklist
+--------------------------
+
+So you want to contribute to Busybox, eh? Great, wonderful, glad you want to
+help. However, before you dive in, headlong and hotfoot, there are some things
+you need to do:
+
+
+Checkout the Latest Code from CVS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a necessary first step. Please do not try to work with the last
+released version, as there is a good chance that somebody has already fixed
+the bug you found. Somebody might have even added the feature you had in mind.
+Don't make your work obsolete before you start!
+
+For information on how to check out Busybox from CVS, please look at the
+following links:
+
+       http://oss.lineo.com/cvs_anon.html
+       http://oss.lineo.com/cvs_howto.html
+
+
+Read the Mailing List
+~~~~~~~~~~~~~~~~~~~~~
+
+No one is required to read the entire archives of the mailing list, but you
+should at least read up on what people have been talking about lately. If
+you've recently discovered a problem, chances are somebody else has too. If
+you're the first to discover a problem, post a message and let the rest of us
+know.
+
+Archives can be found here:
+
+       http://oss.lineo.com/lists/busybox/
+
+If you have a serious interest in Busybox, i.e., you are using it day-to-day or
+as part of an embedded project, it would be a good idea to join the mailing
+list.
+
+A web-based sign-up form can be found here:
+
+       http://oss.lineo.com/mailman/listinfo/busybox
+
+
+Coordinate with the Applet Maintainer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some (not all) of the applets in Busybox are "owned" by a maintainer who has
+put significant effort into it and is probably more familiar with it than
+others. To find the maintainer of an applet, look at the top of the .c file
+for a name following the word 'Copyright' or 'Written by' or 'Maintainer'.
+
+Before plunging ahead, it's a good idea to send a message to the mailing list
+that says: "Hey, I was thinking about adding the 'transmogrify' feature to the
+'foo' applet.  Would this be useful? Is anyone else working on it?" You might
+want to CC the maintainer (if any) with your question.
+
+
+
+Areas Where You Can Help
+------------------------
+
+Busybox can always use improvement! If you're looking for ways to help, there
+there are a variety of areas where you could help.
+
+
+What Busybox Doesn't Need
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before listing the areas where you _can_ help, it's worthwhile to mention the
+areas where you shouldn't bother. While Busybox strives to be the "Swiss Army
+Knife" of embedded Linux, there are some applets that will not be accepted:
+
+ - Any filesystem manipulation tools: Busybox is filesystem independent and
+   we do not want to start adding mkfs/fsck tools for every (or any)
+   filesystem under the sun. (fsck_minix.c and mkfs_minix.c are living on
+   borrowed time.) There are far too many of these tools out there.  Use
+   the upstream version. Not everything has to be part of Busybox.
+
+ - Any partitioning tools: Partitioning a device is typically done once and
+   only once, and tools which do this generally do not need to reside on the
+   target device (esp a flash device). If you need a partitioning tool, grab
+   one (such as fdisk, sfdisk, or cfdisk from util-linux) and use that, but
+   don't try to merge it into busybox. These are nasty and complex and we
+   don't want to maintain them.
+
+ - Any disk, device, or media-specific tools: Use the -utils or -tools package
+   that was designed for your device; don't try to shoehorn them into Busybox.
+
+ - Any architecture specific tools: Busybox is (or should be) architecture
+   independent. Do not send us tools that cannot be used across multiple
+   platforms / arches.
+
+ - Any daemons that are not essential to basic system operation. To date, only
+   syslogd and klogd meet this requirement. We do not need a web server, an
+   ftp daemon, a dhcp server, a mail transport agent or a dns resolver. If you
+   need one of those, you are welcome to ask the folks on the mailing list for
+   recommendations, but please don't bloat up Busybox with any of these.
+
+
+Bug Reporting
+~~~~~~~~~~~~~
+
+If you find a bug in Busybox, you can send a bug report to our bug tracking
+system (homepage: http://bugs.lineo.com). Instructions on how to send a bug
+report to the tracking system can be found at:
+
+       http://bugs.lineo.com/Reporting.html
+       
+The README file that comes with Busybox also describes how to submit a bug.
+
+A well-written bug report should include a transcript of a shell session that
+demonstrates the bad behavior and enables anyone else to duplicate the bug on
+their own machine. The following is such an example:
+
+       When I execute Busybox 'date' it produces unexpected results.
+
+       This is using GNU date:
+       $ date
+       Wed Mar 21 14:19:41 MST 2001
+
+       This is using Busybox date:
+       $ date
+       codswaddle
+
+
+Bug Triage
+~~~~~~~~~~
+
+Validating and confirming bugs is nearly as important as reporting them in the
+first place. It is valuable to know if a bug can be duplicated on a different
+machine, on a different filesystem, on a different architecture, with a
+different C library, and so forth.
+
+To see a listing of all the bugs currently filed against Busybox, look here:
+
+       http://bugs.lineo.com/db/pa/lbusybox.html
+
+If you have comments to add to a bug (can / can't duplicate, think a bug
+should be closed / reopened), please send it to [bugnumber]@bugs.lineo.com.
+The message you send will automatically be forwarded to the mailing list for
+all to see.
+
+
+Write Documentation
+~~~~~~~~~~~~~~~~~~~
+
+Chances are, documentation in Busybox is either missing or needs improvement.
+Either way, help is welcome.
+
+Work is being done to automatically generate documentation from sources,
+especially from the usage.h file. If you want to correct the documentation,
+please make changes to the pre-generation parts, rather than the generated
+documentation. [More to come on this later...]
+
+It is preferred that modifications to documentation be submitted in patch
+format (more on this below), but we're a little more lenient when it comes to
+docs. You could, for example, just say "after the listing of the mount
+options, the following example would be helpful..."
+
+
+Consult Existing Sources
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For a quick listing of "needs work" spots in the sources, cd into the Busybox
+directory and run the following:
+
+       for i in TODO FIXME XXX; do grep $i *.[ch]; done
+
+This will show all of the trouble spots or 'questionable' code. Pick a spot,
+any spot, these are all invitations for you to contribute.
+
+
+Consult The Bug-Tracking System
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Head to: http://bugs.lineo.com/db/pa/lBusybox.html and look at the bugs on
+there. Pick one you think you can fix, and fix it. If it's a wishlist item and
+someone's requesting a new feature, take a stab at adding it. Everything
+previously said about "reading the mailing list" and "coordinating with the
+applet maintainer" still applies.
+
+
+Add a New Applet
+~~~~~~~~~~~~~~~~
+
+If you want to add a new applet to Busybox, we'd love to see it. However,
+before you write any code, please ask beforehand on the mailing list something
+like "Do you think applet 'foo' would be useful in Busybox?" or "Would you
+guys accept applet 'foo' into Busybox if I were to write it?" If the answer is
+"no" by the folks on the mailing list, then you've saved yourself some time.
+Conversely, you could get some positive responses from folks who might be
+interested in helping you implement it, or can recommend the best approach.
+Perhaps most importantly, this is your way of calling "dibs" on something and
+avoiding duplication of effort.
+
+Also, before you write a line of code, please read the 'new-applet-HOWTO.txt'
+file in the docs/ directory.
+
+
+Janitorial Work
+~~~~~~~~~~~~~~~
+
+These are dirty jobs, but somebody's gotta do 'em.
+
+ - Converting applets to use getopt() for option processing. Type 'grep -L
+   getopt *.c' to get a listing of the applets that currently don't use
+   getopt. If a .c file processes no options, it should have a line that
+   reads: /* no options, no getopt */ somewhere in the file.
+
+ - Replace any "naked" calls to malloc, calloc, realloc, str[n]dup, fopen with
+   the x* equivalents found in utility.c.
+
+ - Security audits:
+   http://www.securityfocus.com/frames/?content=/forums/secprog/secure-programming.html
+
+ - Synthetic code removal: http://www.perl.com/pub/2000/06/commify.html - This
+   is very Perl-specific, but the advice given in here applies equally well to
+   C.
+
+ - C library funciton use audits: Verifying that functions are being used
+   properly (called with the right args), replacing unsafe library functions
+   with safer versions, making sure return codes are being checked, etc.
+
+ - Where appropriate, replace preprocessor defined macros and values with
+   compile-time equivalents.
+
+ - Style guide compliance. See: docs/style-guide.txt
+
+ - Add testcases to tests/testcases.
+
+ - Makefile improvements:
+   http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html
+   (I think the recursive problems are pretty much taken care of at this point, non?)
+
+ - "Ten Commandments" compliance: (this is a "maybe", certainly not as
+   important as any of the previous items.)
+    http://web.onetelnet.ch/~twolf/tw/c/ten_commandments.html
+
+Other useful links:
+
+ - the comp.lang.c FAQ: http://web.onetelnet.ch/~twolf/tw/c/index.html#Sources
+
+
+
+Submitting Patches To Busybox
+-----------------------------
+
+Here are some guidelines on how to submit a patch to Busybox.
+
+
+Making A Patch
+~~~~~~~~~~~~~~
+
+If you've got anonymous CVS access set up, making a patch is simple. Just make
+sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'.
+You can send the resulting .patch file to the mailing list with a description
+of what it does. (But not before you test it! See the next section for some
+guidelines.) It is preferred that patches be sent as attachments, but it is
+not required.
+
+Also, feel free to help test other people's patches and reply to them with
+comments. You can apply a patch by saving it into your busybox/ directory and
+typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test
+if it works as advertised, and post your findings to the mailing list.
+
+NOTE: Please do not include extraneous or irrelevant changes in your patches.
+Please do not try to "bundle" two patches together into one. Make single,
+discreet changes on a per-patch basis. Sometimes you need to make a patch that
+touches code in many places, but these kind of patches are rare and should be
+coordinated with a maintainer.
+
+
+Testing Guidelines
+~~~~~~~~~~~~~~~~~~
+
+It's considered good form to test your new feature before you submit a patch
+to the mailing list, and especially before you commit a change to CVS. Here
+are some guidelines on how to test your changes.
+
+ - Always test Busybox applets against GNU counterparts and make sure the
+   behavior / output is identical between the two.
+
+ - Try several different permutations and combinations of the features you're
+   adding (i.e., different combinations of command-line switches) and make sure
+   they all work; make sure one feature does not interfere with another.
+
+ - Make sure you test compiling against the source both with the feature
+   turned on and turned off in Config.h and make sure Busybox compiles cleanly
+   both ways.
+
+ - Run the multibuild.pl script in the tests directory and make sure
+   everything checks out OK. (Do this from within the busybox/ directory by
+   typing: 'tests/multibuild.pl'.)
+
+
+Making Sure Your Patch Doesn't Get Lost
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you don't want your patch to be lost or forgotten, send it to the bug
+tracking system (http://bugs.lineo.com). You do this by emailing your patch in
+a message to submit@bugs.lineo.com with a subject line something like this:
+
+       [PATCH] - Adds "transmogrify" feature to "foo"
+
+In the body, you should have a pseudo-header that looks like the following:
+
+    Package: busybox
+    Version: v0.50pre (or whatever the current version is)
+    Severity: wishlist
+
+The remainder of the body should read along these lines:
+
+       This patch adds the "transmogrify" feature to the "foo" applet. I have
+       tested this on [arch] system(s) and it works. I have tested it against the
+       GNU counterparts and the outputs are identical. I have run the scripts in
+       the 'tests' directory and nothing breaks.
+
+Detailed instructions on how to submit a bug to the tracking system are at:
+
+       http://bugs.lineo.com/Reporting.html
+
+If you have a patch that will fix and close a reported bug, please send a
+message to [bugnumber]@bugs.lineo.com with your patch attached. It will catch
+people's attention if you have a subject line like the following:
+
+       [PATCH INCLUDED] - Fix attached, please apply and close this bug
+
+
+
+Improving Your Chances of Patch Acceptance
+------------------------------------------
+
+Even after you send a brilliant patch to the mailing list, sometimes it can go
+unnoticed, un-replied-to, and sometimes (sigh) even lost. This is an
+unfortunate fact of life, but there are steps you can take to help your patch
+get noticed and convince a maintainer that it should be added:
+
+
+Be Succinct
+~~~~~~~~~~~
+
+A patch that includes small, isolated, obvious changes is more likely to be
+accepted than a patch that touches code in lots of different places or makes
+sweeping, dubious changes.
+
+
+Back It Up
+~~~~~~~~~~
+
+Hard facts on why your patch is better than the existing code will go a long
+way toward convincing maintainers that your patch should be included.
+Specifically, patches are more likely to be accepted if they are provably more
+correct, smaller, faster, simpler, or more maintainable than the existing
+code.
+
+Conversely, any patch that is supported with nothing more than "I think this
+would be cool" or "this patch is good because I say it is and I've got a Phd
+in Computer Science" will likely be ignored.
+
+
+Follow The Style Guide
+~~~~~~~~~~~~~~~~~~~~~~
+
+It's considered good form to abide by the established coding style used in a
+project; Busybox is no exception. We have gone so far as to delineate the
+"elements of Busybox style" in the file docs/style-guide.txt. Please follow
+them.
+
+
+Work With Someone Else
+~~~~~~~~~~~~~~~~~~~~~~
+
+Working on a patch in isolation is less effective than working with someone
+else for a variety of reasons. If another Busybox user is interested in what
+you're doing, then it's two (or more) voices instead of one that can petition
+for inclusion of the patch. You'll also have more people that can test your
+changes, or even offer suggestions on better approaches you could take.
+
+Getting other folks interested follows as a natural course if you've received
+responses from queries to applet maintainer or positive responses from folks
+on the mailing list.
+
+We've made strident efforts to put a useful "collaboration" infrastructure in
+place in the form of mailing lists, the bug tracking system, and CVS. Please
+use these resources.
+
+
+Send Patches to the Bug Tracking System
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This was mentioned above in the "Making Sure Your Patch Doesn't Get Lost"
+section, but it is worth mentioning again. A patch sent to the mailing list
+might be unnoticed and forgotten. A patch sent to the bug tracking system will
+be stored and closely connected to the bug it fixes.
+
+
+Be Polite
+~~~~~~~~~
+
+The old saying "You'll catch more flies with honey than you will with vinegar"
+applies when submitting patches to the mailing list for approval. The way you
+present your patch is sometimes just as important as the actual patch itself
+(if not more so). Being rude to the maintainers is not an effective way to
+convince them that your patch should be included; it will likely have the
+opposite effect.
+
+
+
+Committing Changes to CVS
+-------------------------
+
+If you submit several patches that demonstrate that you are a skilled and wise
+coder, you may be invited to become a committer, thus enabling you to commit
+changes directly to CVS. This is nice because you don't have to wait for
+someone else to commit your change for you, you can just do it yourself.
+
+But note that this is a priviledge that comes with some responsibilities. You
+should test your changes before you commit them. You should also talk to an
+applet maintainer before you make any kind of sweeping changes to somebody
+else's code. Big changes should still go to the mailing list first. Remember,
+being wise, polite, and discreet is more important than being clever.
+
+
+When To Commit
+~~~~~~~~~~~~~~
+
+Generally, you should feel free to commit a change if:
+
+ - Your changes are small and don't touch many files
+ - You are fixing a bug
+ - Somebody has told you that it's okay
+ - It's obviously the Right Thing
+
+The more of the above are true, the better it is to just commit a change
+directly to CVS.
+
+
+When Not To Commit
+~~~~~~~~~~~~~~~~~~
+
+Even if you have commit rights, you should probably still post a patch to the
+mailing list if:
+
+ - Your changes are broad and touch many different files
+ - You are adding a feature
+ - Your changes are speculative or experimental (i.e., trying a new algorithm)
+ - You are not the maintainer and your changes make the maintainer cringe
+
+The more of the above are true, the better it is to post a patch to the
+mailing list instead of committing.
+
+
+
+Final Words
+-----------
+
+If all of this seems complicated, don't panic, it's really not that tough. If
+you're having difficulty following some of the steps outlined in this
+document don't worry, the folks on the Busybox mailing list are a fairly
+good-natured bunch and will work with you to help get your patches into shape
+or help you make contributions.
+
+
diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt
new file mode 100644 (file)
index 0000000..f79504f
--- /dev/null
@@ -0,0 +1,138 @@
+How to Add a New Applet to BusyBox
+==================================
+
+This document details the steps you must take to add a new applet to BusyBox.
+
+Credits:
+Matt Kraai - initial writeup
+Mark Whitley - the remix
+
+
+Initial Write
+-------------
+
+First, write your applet.  Be sure to include copyright information at the
+top, such as who you stole the code from and so forth. Also include the
+mini-GPL boilerplate. Be sure to name the main function <applet>_main instead
+of main.  And be sure to put it in <applet>.c.  For a new applet mu, here is
+the code that would go in mu.c:
+
+----begin example code------
+
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mu implementation for busybox
+ *
+ *
+ * Copyright (C) [YEAR] by [YOUR NAME] <YOUR EMAIL>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+
+int mu_main(int argc, char **argv)
+{
+       int fd;
+       char mu;
+
+       if ((fd = open("/dev/random", O_RDONLY)) < 0)
+               perror_msg_and_die("/dev/random");
+
+       if ((n = safe_read(fd, &mu, 1)) < 1)
+               perror_msg_and_die("/dev/random");
+
+       return mu;
+}
+
+----end example code------
+
+
+Coding Style
+------------
+
+Before you submit your applet for inclusion in BusyBox, (or better yet, before
+you _write_ your applet) please read through the style guide in the docs
+directory and make your program compliant.
+
+
+Some Words on libbb
+-------------------
+
+As you are writing your applet, please be aware of the body of pre-existing
+useful functions in libbb. Use these instead of reinventing the wheel.
+
+Additionally, if you have any useful, general-purpose functions in your
+program that could be useful in another program, consider putting them in
+libbb.
+
+
+Usage String(s)
+---------------
+
+Next, add usage information for you applet to usage.h. This should look like
+the following:
+
+       #define mu_trivial_usage \
+               "-[abcde] FILES"
+       #define mu_full_usage \
+               "Returns an indeterminate value.\n\n" \
+               "Options:\n" \
+               "\t-a\t\tfirst function\n" \
+               "\t-b\t\tsecond function\n" \
+
+If your program supports flags, the flags should be mentioned on the first
+line (-[abcde]) and a detailed description of each flag should go in the
+mu_full_usage section, one flag per line. (Numerous examples of this
+currently exist in usage.h.)
+
+
+Header Files
+------------
+
+Next, add an entry to applets.h.  Be *sure* to keep the list in alphabetical
+order, or else it will break the binary-search lookup algorithm in busybox.c
+and the Gods of BusyBox smite you. Yea, verily:
+
+       /* all programs above here are alphabetically "less than" 'mu' */
+       #ifdef BB_MU
+               APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage)
+       #endif
+       /* all programs below here are alphabetically "greater than" 'mu' */
+
+
+Finally, add a define for your applet to Config.h:
+
+       #define BB_MU
+
+
+Documentation
+-------------
+
+If you're feeling especially nice, you should also document your applet in the
+docs directory (but nobody ever does that).
+
+
+The Grand Announcement
+----------------------
+
+Then create a diff -urN of the files you added (<applet>.c, usage.c,
+applets.h, Config.h) and send it to the mailing list:
+busybox@oss.lineo.com. Sending patches as attachments is preferred, but
+not required.
+
+
diff --git a/docs/style-guide.txt b/docs/style-guide.txt
new file mode 100644 (file)
index 0000000..c71f1e6
--- /dev/null
@@ -0,0 +1,680 @@
+Busybox Style Guide
+===================
+
+This document describes the coding style conventions used in Busybox. If you
+add a new file to Busybox or are editing an existing file, please format your
+code according to this style. If you are the maintainer of a file that does
+not follow these guidelines, please -- at your own convenience -- modify the
+file(s) you maintain to bring them into conformance with this style guide.
+Please note that this is a low priority task.
+
+To help you format the whitespace of your programs, an ".indent.pro" file is
+included in the main Busybox source directory that contains option flags to
+format code as per this style guide. This way you can run GNU indent on your
+files by typing 'indent myfile.c myfile.h' and it will magically apply all the
+right formatting rules to your file. Please _do_not_ run this on all the files
+in the directory, just your own.
+
+
+
+Declaration Order
+-----------------
+
+Here is the order in which code should be laid out in a file:
+
+ - commented program name and one-line description
+ - commented author name and email address(es)
+ - commented GPL boilerplate
+ - commented longer description / notes for the program (if needed)
+ - #includes of .h files with angle brackets (<>) around them
+ - #includes of .h files with quotes ("") around them
+ - #defines (if any, note the section below titled "Avoid the Preprocessor")
+ - const and global variables
+ - function declarations (if necessary)
+ - function implementations
+
+
+
+Whitespace and Formatting
+-------------------------
+
+This is everybody's favorite flame topic so let's get it out of the way right
+up front.
+
+
+Tabs vs. Spaces in Line Indentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The preference in Busybox is to indent lines with tabs. Do not indent lines
+with spaces and do not indents lines using a mixture of tabs and spaces. (The
+indentation style in the Apache and Postfix source does this sort of thing:
+\s\s\s\sif (expr) {\n\tstmt; --ick.) The only exception to this rule is
+multi-line comments that use an asterisk at the beginning of each line, i.e.:
+
+       /t/*
+       /t * This is a block comment.
+       /t * Note that it has multiple lines
+       /t * and that the beginning of each line has a tab plus a space
+       /t * except for the opening '/*' line where the slash
+       /t * is used instead of a space.
+       /t */
+
+Furthermore, The preference is that tabs be set to display at four spaces
+wide, but the beauty of using only tabs (and not spaces) at the beginning of
+lines is that you can set your editor to display tabs at *whatever* number of
+spaces is desired and the code will still look fine.
+
+
+Operator Spacing
+~~~~~~~~~~~~~~~~
+
+Put spaces between terms and operators. Example:
+
+       Don't do this:
+
+               for(i=0;i<num_items;i++){
+
+       Do this instead:
+
+               for (i = 0; i < num_items; i++) {
+
+       While it extends the line a bit longer, the spaced version is more
+       readable. An allowable exception to this rule is the situation where
+       excluding the spacing makes it more obvious that we are dealing with a
+       single term (even if it is a compound term) such as:
+
+               if (str[idx] == '/' && str[idx-1] != '\\')
+
+       or
+
+               if ((argc-1) - (optind+1) > 0)
+
+
+Bracket Spacing
+~~~~~~~~~~~~~~~
+
+If an opening bracket starts a function, it should be on the
+next line with no spacing before it. However, if a bracket follows an opening
+control block, it should be on the same line with a single space (not a tab)
+between it and the opening control block statement. Examples:
+
+       Don't do this:
+
+               while (!done)
+               {
+
+               do
+               {
+
+       Don't do this either:
+
+               while (!done){
+
+               do{
+
+       And for heaven's sake, don't do this:
+
+               while (!done)
+                 {
+
+               do
+                 {
+
+       Do this instead:
+
+               while (!done) {
+
+               do {
+
+
+Spacing around Parentheses
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Put a space between C keywords and left parens, but not between function names
+and the left paren that starts it's parameter list (whether it is being
+declared or called). Examples:
+
+       Don't do this:
+
+               while(foo) {
+               for(i = 0; i < n; i++) {
+
+       Do this instead:
+
+               while (foo) {
+               for (i = 0; i < n; i++) {
+
+       But do functions like this:
+
+               static int my_func(int foo, char bar)
+               ...
+               baz = my_func(1, 2);
+
+Also, don't put a space between the left paren and the first term, nor between
+the last arg and the right paren.
+
+       Don't do this:
+
+               if ( x < 1 )
+               strcmp( thisstr, thatstr )
+
+       Do this instead:
+
+               if (x < 1)
+               strcmp(thisstr, thatstr)
+
+
+Cuddled Elses
+~~~~~~~~~~~~~
+
+Also, please "cuddle" your else statements by putting the else keyword on the
+same line after the right bracket that closes an 'if' statement.
+
+       Don't do this:
+
+       if (foo) {
+               stmt;
+       }
+       else {
+               stmt;
+       }
+
+       Do this instead:
+
+       if (foo) {
+               stmt;
+       } else {
+               stmt;
+       }
+
+The exception to this rule is if you want to include a comment before the else
+block. Example:
+
+       if (foo) {
+               stmts...
+       }
+       /* otherwise, we're just kidding ourselves, so re-frob the input */
+       else {
+               other_stmts...
+       }
+
+
+
+Variable and Function Names
+---------------------------
+
+Use the K&R style with names in all lower-case and underscores occasionally
+used to separate words (e.g., "variable_name" and "numchars" are both
+acceptable). Using underscores makes variable and function names more readable
+because it looks like whitespace; using lower-case is easy on the eyes.
+
+       Frowned upon:
+
+               hitList
+               TotalChars
+               szFileName
+               pf_Nfol_TriState
+
+       Preferred:
+
+               hit_list
+               total_chars
+               file_name
+               sensible_name
+
+Exceptions:
+
+ - Enums, macros, and constant variables are occasionally written in all
+   upper-case with words optionally seperatedy by underscores (i.e. FIFOTYPE,
+   ISBLKDEV()).
+
+ - Nobody is going to get mad at you for using 'pvar' as the name of a
+   variable that is a pointer to 'var'.
+
+
+Converting to K&R
+~~~~~~~~~~~~~~~~~
+
+The Busybox codebase is very much a mixture of code gathered from a variety of
+sources. This explains why the current codebase contains such a hodge-podge of
+different naming styles (Java, Pascal, K&R, just-plain-weird, etc.). The K&R
+guideline explained above should therefore be used on new files that are added
+to the repository. Furthermore, the maintainer of an existing file that uses
+alternate naming conventions should, at his own convenience, convert those
+names over to K&R style. Converting variable names is a very low priority
+task.
+
+If you want to do a search-and-replace of a single variable name in different
+files, you can do the following in the busybox directory:
+
+       $ perl -pi -e 's/\bOldVar\b/new_var/g' *.[ch]
+
+If you want to convert all the non-K&R vars in your file all at once, follow
+these steps:
+
+ - In the busybox directory type 'scripts/mk2knr.pl files-to-convert'. This
+   does not do the actual conversion, rather, it generates a script called
+   'convertme.pl' that shows what will be converted, giving you a chance to
+   review the changes beforehand.
+
+ - Review the 'convertme.pl' script that gets generated in the busybox
+   directory and remove / edit any of the substitutions in there. Please
+   especially check for false positives (strings that should not be
+   converted).
+
+ - Type './convertme.pl same-files-as-before' to perform the actual
+   conversion.
+
+ - Compile and see if everything still works.
+Please be aware of changes that have cascading effects into other files. For
+example, if you're changing the name of something in, say utility.c, you
+should probably run 'scripts/mk2knr.pl utility.c' at first, but when you run
+the 'convertme.pl' script you should run it on _all_ files like so:
+'./convertme.pl *.[ch]'.
+
+
+
+Avoid The Preprocessor
+----------------------
+
+At best, the preprocessor is a necessary evil, helping us account for platform
+and architecture differences. Using the preprocessor unnecessarily is just
+plain evil.
+
+
+The Folly of #define
+~~~~~~~~~~~~~~~~~~~~
+
+Use 'const <type> var' for declaring constants.
+
+       Don't do this:
+
+               #define var 80
+
+       Do this instead, when the variable is in a header file and will be used in
+       several source files: 
+
+               const int var = 80; 
+
+       Or do this when the variable is used only in a single source file:
+
+               static const int var = 80; 
+
+Declaring variables as '[static] const' gives variables an actual type and
+makes the compiler do type checking for you; the preprocessor does _no_ type
+checking whatsoever, making it much more error prone. Declaring variables with
+'[static] const' also makes debugging programs much easier since the value of
+the variable can be easily queried and displayed.
+
+
+The Folly of Macros
+~~~~~~~~~~~~~~~~~~~
+
+Use 'static inline' instead of a macro.
+
+       Don't do this:
+
+               #define mini_func(param1, param2) (param1 << param2)
+
+       Do this instead:
+
+               static inline int mini_func(int param1, param2)
+               {
+                       return (param1 << param2);
+               }
+
+Static inline functions are greatly preferred over macros. They provide type
+safety, have no length limitations, no formatting limitations, have an actual
+return value, and under gcc they are as cheap as macros. Besides, really long
+macros with backslashes at the end of each line are ugly as sin.
+
+
+The Folly of #ifdef
+~~~~~~~~~~~~~~~~~~~
+
+Code cluttered with ifdefs is difficult to read and maintain. Don't do it.
+Instead, put your ifdefs at the top of your .c file (or in a header), and
+conditionally define 'static inline' functions, (or *maybe* macros), which are
+used in the code.  
+
+       Don't do this:
+
+               ret = my_func(bar, baz);
+               if (!ret)
+                       return -1;
+               #ifdef BB_FEATURE_FUNKY
+                       maybe_do_funky_stuff(bar, baz);
+               #endif
+
+       Do this instead:
+
+       (in .h header file)
+
+               #ifdef BB_FEATURE_FUNKY
+               static inline void maybe_do_funky_stuff (int bar, int baz)
+               {
+                       /* lotsa code in here */
+               }
+               #else
+               static inline void maybe_do_funky_stuff (int bar, int baz) {}
+               #endif
+
+       (in the .c source file)
+
+               ret = my_func(bar, baz);
+               if (!ret)
+                       return -1;
+               maybe_do_funky_stuff(bar, baz);
+
+The great thing about this approach is that the compiler will optimize away
+the "no-op" case (the empty function) when the feature is turned off.
+
+Note also the use of the word 'maybe' in the function name to indicate
+conditional execution.
+
+
+
+Notes on Strings
+----------------
+
+Strings in C can get a little thorny. Here's some guidelines for dealing with
+strings in Busybox. (There is surely more that could be added to this
+section.)
+
+
+String Files
+~~~~~~~~~~~~
+
+Put all help/usage messages in usage.c. Put other strings in messages.c.
+Putting these strings into their own file is a calculated decision designed to
+confine spelling errors to a single place and aid internationalization
+efforts, if needed. (Side Note: we might want to use a single file - maybe
+called 'strings.c' - instead of two, food for thought).
+
+
+Testing String Equivalence
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There's a right way and a wrong way to test for sting equivalence with
+strcmp():
+
+       The wrong way:
+
+               if (!strcmp(string, "foo")) {
+                       ...
+
+       The right way:
+
+               if (strcmp(string, "foo") == 0){
+                       ...
+
+The use of the "equals" (==) operator in the latter example makes it much more
+obvious that you are testing for equivalence. The former example with the
+"not" (!) operator makes it look like you are testing for an error. In a more
+perfect world, we would have a streq() function in the string library, but
+that ain't the world we're living in.
+
+
+Avoid Dangerous String Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unfortunately, the way C handles strings makes them prone to overruns when
+certain library functions are (mis)used. The following table  offers a summary
+of some of the more notorious troublemakers:
+
+function     overflows         preferred
+----------------------------------------
+strcpy       dest string       strncpy
+strcat       dest string       strncat
+gets         string it gets    fgets
+getwd        buf string        getcwd
+[v]sprintf   str buffer        [v]snprintf
+realpath     path buffer       use with pathconf
+[vf]scanf    its arguments     just avoid it
+
+
+The above is by no means a complete list. Be careful out there.
+
+
+
+Avoid Big Static Buffers
+------------------------
+
+First, some background to put this discussion in context: Static buffers look
+like this in code:
+
+       /* in a .c file outside any functions */
+       static char *buffer[BUFSIZ]; /* happily used by any function in this file,
+                                       but ick! big! */
+
+The problem with these is that any time any busybox app is run, you pay a
+memory penalty for this buffer, even if the applet that uses said buffer is
+not run. This can be fixed, thusly:
+
+       static char *buffer;
+       ...
+       other_func()
+       {
+               strcpy(buffer, lotsa_chars); /* happily uses global *buffer */
+       ...
+       foo_main()
+       {
+               buffer = xmalloc(sizeof(char)*BUFSIZ);
+       ...
+
+However, this approach trades bss segment for text segment. Rather than
+mallocing the buffers (and thus growing the text size), buffers can be
+declared on the stack in the *_main() function and made available globally by
+assigning them to a global pointer thusly:
+
+       static char *pbuffer;
+       ...
+       other_func()
+       {
+               strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */
+       ...
+       foo_main()
+       {
+               char *buffer[BUFSIZ]; /* declared locally, on stack */
+               pbuffer = buffer;     /* but available globally */
+       ...
+
+This last approach has some advantages (low code size, space not used until
+it's needed), but can be a problem in some low resource machines that have
+very limited stack space (e.g., uCLinux).
+
+A macro is declared in busybox.h that implements compile-time selection
+between xmalloc() and stack creation, so you can code the line in question as
+
+               RESERVE_BB_BUFFER(buffer, BUFSIZ);
+
+and the right thing will happen, based on your configuration.
+
+
+
+Miscellaneous Coding Guidelines
+-------------------------------
+
+The following are important items that don't fit into any of the above
+sections.
+
+
+Model Busybox Applets After GNU Counterparts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When in doubt about the proper behavior of a Busybox program (output,
+formatting, options, etc.), model it after the equivalent GNU program.
+Doesn't matter how that program behaves on some other flavor of *NIX; doesn't
+matter what the POSIX standard says or doesn't say, just model Busybox
+programs after their GNU counterparts and it will make life easier on (nearly)
+everyone.
+
+The only time we deviate from emulating the GNU behavior is when:
+
+       - We are deliberately not supporting a feature (such as a command line
+         switch)
+       - Emulating the GNU behavior is prohibitively expensive (lots more code
+         would be required, lots more memory would be used, etc.)
+       - The difference is minor or cosmetic
+
+A note on the 'cosmetic' case: Output differences might be considered
+cosmetic, but if the output is significant enough to break other scripts that
+use the output, it should really be fixed.
+
+
+Scope
+~~~~~
+
+If a const variable is used only in a single source file, put it in the source
+file and not in a header file. Likewise, if a const variable is used in only
+one function, do not make it global to the file. Instead, declare it inside
+the function body. Bottom line: Make a conscious effort to limit declarations
+to the smallest scope possible.
+
+Inside applet files, all functions should be declared static so as to keep the
+global name space clean. The only exception to this rule is the "applet_main"
+function which must be declared extern.
+
+If you write a function that performs a task that could be useful outside the
+immediate file, turn it into a general-purpose function with no ties to any
+applet and put it in the utility.c file instead.
+
+
+Brackets Are Your Friends
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Please use brackets on all if and else statements, even if it is only one
+line. Example:
+
+       Don't do this:
+
+               if (foo)
+                       stmt1;
+               stmt2
+               stmt3;
+
+       Do this instead:
+
+               if (foo) {
+                       stmt1;
+               }
+               stmt2
+               stmt3;
+
+The "bracketless" approach is error prone because someday you might add a line
+like this:
+
+               if (foo)
+                       stmt1;
+                       new_line();
+               stmt2
+               stmt3;
+
+And the resulting behavior of your program would totally bewilder you. (Don't
+laugh, it happens to us all.) Remember folks, this is C, not Python.
+
+
+Function Declarations
+~~~~~~~~~~~~~~~~~~~~~
+
+Do not use old-style function declarations that declare variable types between
+the parameter list and opening bracket. Example:
+
+       Don't do this:
+
+               int foo(parm1, parm2)
+                       char parm1;
+                       float parm2;
+               {
+                       ....
+
+       Do this instead:
+
+               int foo(char parm1, float parm2)
+               {
+                       ....
+
+The only time you would ever need to use the old declaration syntax is to
+support ancient, antediluvian compilers. To our good fortune, we have access
+to more modern compilers and the old declaration syntax is neither necessary
+nor desired.
+
+
+Emphasizing Logical Blocks
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Organization and readability are improved by putting extra newlines around
+blocks of code that perform a single task. These are typically blocks that
+begin with a C keyword, but not always.
+
+Furthermore, you should put a single comment (not necessarily one line, just
+one comment) before the block, rather than commenting each and every line.
+There is an optimal ammount of commenting that a program can have; you can
+comment too much as well as too little.
+
+A picture is really worth a thousand words here, the following example
+illustrates how to emphasize logical blocks:
+
+       while (line = get_line_from_file(fp)) {
+
+               /* eat the newline, if any */
+               chomp(line);
+
+               /* ignore blank lines */
+               if (strlen(file_to_act_on) == 0) {
+                       continue;
+               }
+
+               /* if the search string is in this line, print it,
+                * unless we were told to be quiet */
+               if (strstr(line, search) && !be_quiet) {
+                       puts(line);
+               }
+
+               /* clean up */
+               free(line);
+       }
+
+
+Processing Options with getopt
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If your applet needs to process  command-line switches, please use getopt() to
+do so. Numerous examples can be seen in many of the existing applets, but
+basically it boils down to two things: at the top of the .c file, have this
+line in the midst of your #includes:
+
+       #include <getopt.h>
+
+And a code block similar to the following near the top of your applet_main()
+routine:
+
+    while ((opt = getopt(argc, argv, "abc")) > 0) { 
+            switch (opt) {
+            case 'a':
+                do_a_opt = 1;
+                break;
+            case 'b':
+                do_b_opt = 1;
+                break;
+            case 'c':
+                do_c_opt = 1;
+                break;
+            default:
+                show_usage();    /* in utility.c */
+            }
+    }
+
+If your applet takes no options (such as 'init'), there should be a line
+somewhere in the file reads:
+
+       /* no options, no getopt */
+
+That way, when people go grepping to see which applets need to be converted to
+use getopt, they won't get false positives.
+
+Additional Note: Do not use the getopt_long library function and do not try to
+hand-roll your own long option parsing. Busybox applets should only support
+short options. Explanations and examples of the short options should be
+documented in usage.h.
diff --git a/dos2unix.c b/dos2unix.c
new file mode 100644 (file)
index 0000000..f4ce2b8
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * dos2unix for BusyBox
+ *
+ * dos2unix '\n' convertor 0.5.0
+ *   based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
+ * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
+ * All rights reserved.
+ *
+ * dos2unix filters reading input from stdin and writing output to stdout.
+ * Without arguments it reverts the format (e.i. if source is in UNIX format,
+ * output is in DOS format and vice versa).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * See the COPYING file for license information.
+ */
+
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#if (__GNU_LIBRARY__ > 5)
+#include <stdint.h>
+#endif
+#include <fcntl.h>
+#include <sys/time.h>
+#include "busybox.h"
+
+
+/* We are making a lame pseudo-random string generator here.  in
+ * convert(), each pass through the while loop will add more and more
+ * stuff into value, which is _supposed_ to wrap.  We don't care about
+ * it being accurate.  We care about it being messy, since we then mod
+ * it by the sizeof(letters) and then use that as an index into letters
+ * to pick a random letter to add to out temporary file. */
+typedef unsigned long int bb_uint64_t;
+
+static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+// if fn is NULL then input is stdin and output is stdout
+static int convert(char *fn, int ConvType) 
+{
+       int c, fd;
+       struct timeval tv;
+       char tempFn[BUFSIZ];
+       static bb_uint64_t value=0;
+       FILE *in = stdin, *out = stdout;
+
+       if (fn != NULL) {
+               if ((in = wfopen(fn, "rw")) == NULL) {
+                       return -1;
+               }
+               safe_strncpy(tempFn, fn, sizeof(tempFn));
+               c = strlen(tempFn);
+               tempFn[c] = '.';
+               while(1) {
+                   if (c >=BUFSIZ)
+                       error_msg_and_die("unique name not found");
+                   /* Get some semi random stuff to try and make a
+                    * random filename based (and in the same dir as)
+                    * the input file... */
+                   gettimeofday (&tv, NULL);
+                   value += ((bb_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
+                   tempFn[++c] = letters[value % 62];
+                   tempFn[c+1] = '\0';
+                   value /= 62;
+
+                   if ((fd = open(tempFn, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 ) {
+                       continue;
+                   }
+                   out = fdopen(fd, "w+");
+                   if (!out) {
+                       close(fd);
+                       remove(tempFn);
+                       continue;
+                   }
+                   break;
+               }
+       }
+
+       while ((c = fgetc(in)) != EOF) {
+               if (c == '\r') {
+                       if ((ConvType == CT_UNIX2DOS) && (fn != NULL)) {
+                               // file is alredy in DOS format so it is not necessery to touch it
+                               remove(tempFn);
+                               if (fclose(in) < 0 || fclose(out) < 0) {
+                                       perror_msg(NULL);
+                                       return -2;
+                               }
+                               return 0;
+                       }
+                       if (!ConvType)
+                               ConvType = CT_DOS2UNIX;
+                       break;
+               }
+               if (c == '\n') {
+                       if ((ConvType == CT_DOS2UNIX) && (fn != NULL)) {
+                               // file is alredy in UNIX format so it is not necessery to touch it
+                               remove(tempFn);
+                               if ((fclose(in) < 0) || (fclose(out) < 0)) {
+                                       perror_msg(NULL);
+                                       return -2;
+                               }
+                               return 0;
+                       }
+                       if (!ConvType) {
+                               ConvType = CT_UNIX2DOS;
+                       }
+                       if (ConvType == CT_UNIX2DOS) {
+                               fputc('\r', out);
+                       }
+                       fputc('\n', out);
+                       break;
+               }
+               fputc(c, out);
+       }
+       if (c != EOF)
+               while ((c = fgetc(in)) != EOF) {
+                       if (c == '\r')
+                               continue;
+                       if (c == '\n') {
+                               if (ConvType == CT_UNIX2DOS)
+                                       fputc('\r', out);
+                               fputc('\n', out);
+                               continue;
+                       }
+               fputc(c, out);
+       }
+
+       if (fn != NULL) {
+           if (fclose(in) < 0 || fclose(out) < 0) {
+               perror_msg(NULL);
+               remove(tempFn);
+               return -2;
+           }
+
+           /* Assume they are both on the same filesystem (which
+            * should be true since we put them into the same directory
+            * so we _should_ be ok, but you never know... */
+           if (rename(tempFn, fn) < 0) {
+               perror_msg("unable to rename '%s' as '%s'", tempFn, fn);
+               return -1;
+           }
+       }
+
+       return 0;
+}
+
+int dos2unix_main(int argc, char *argv[]) 
+{
+       int ConvType = CT_AUTO;
+       int o;
+
+       //See if we are supposed to be doing dos2unix or unix2dos 
+       if (argv[0][0]=='d') {
+           ConvType = CT_DOS2UNIX;
+       }
+       if (argv[0][0]=='u') {
+           ConvType = CT_UNIX2DOS;
+       }
+
+       // process parameters
+       while ((o = getopt(argc, argv, "du")) != EOF) {
+               switch (o) {
+               case 'd':
+                       ConvType = CT_UNIX2DOS;
+                       break;
+               case 'u':
+                       ConvType = CT_DOS2UNIX;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       if (optind < argc) {
+               while(optind < argc)
+                       if ((o = convert(argv[optind++], ConvType)) < 0)
+                               break;
+       }
+       else
+               o = convert(NULL, ConvType);
+
+       return o;
+}
+
diff --git a/dpkg.c b/dpkg.c
new file mode 100644 (file)
index 0000000..4ea4dba
--- /dev/null
+++ b/dpkg.c
@@ -0,0 +1,1445 @@
+/*
+ *  Mini dpkg implementation for busybox.
+ *  This is not meant as a replacemnt for dpkg
+ *
+ *  Copyright (C) 2001 by Glenn McGrath
+ *             
+ *  Started life as a busybox implementation of udpkg
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Known difference between busybox dpkg and the official dpkg that i dont
+ * consider important, its worth keeping a note of differences anyway, just to
+ * make it easier to maintain.
+ *  - The first value for the Confflile: field isnt placed on a new line.
+ *  - The <package>.control file is extracted and kept in the info dir.
+ *  - When installing a package the Status: field is placed at the end of the
+ *      section, rather than just after the Package: field.
+ *  - Packages with previously unknown status are inserted at the begining of
+ *      the status file
+ *
+ * Bugs that need to be fixed
+ *  - (unknown, please let me know when you find any)
+ *
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+/* NOTE: If you vary HASH_PRIME sizes be aware,
+ * 1) Tweaking these will have a big effect on how much memory this program uses.
+ * 2) For computational efficiency these hash tables should be at least 20%
+ *    larger than the maximum number of elements stored in it.
+ * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking
+ *    for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt
+ * 4) If you go bigger than 15 bits you may get into trouble (untested) as its
+ *    sometimes cast to an unsigned int, if you go to 16 bit you will overlap
+ *    int's and chaos is assured, 16381 is the max prime for 14 bit field
+ */
+
+/* NAME_HASH_PRIME, Stores package names and versions, 
+ * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
+ * as there a lot of duplicate version numbers */
+#define NAME_HASH_PRIME 16381
+char *name_hashtable[NAME_HASH_PRIME + 1];
+
+/* PACKAGE_HASH_PRIME, Maximum number of unique packages,
+ * It must not be smaller than STATUS_HASH_PRIME,
+ * Currently only packages from status_hashtable are stored in here, but in
+ * future this may be used to store packages not only from a status file,
+ * but an available_hashtable, and even multiple packages files.
+ * Package can be stored more than once if they have different versions.
+ * e.g. The same package may have different versions in the status file
+ *      and available file */
+#define PACKAGE_HASH_PRIME 10007
+typedef struct edge_s {
+       unsigned int operator:3;
+       unsigned int type:4;
+       unsigned int name:14;
+       unsigned int version:14;
+} edge_t;
+
+typedef struct common_node_s {
+       unsigned int name:14;
+       unsigned int version:14;
+       unsigned int num_of_edges:14;
+       edge_t **edge;
+} common_node_t;
+common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
+
+/* Currently it doesnt store packages that have state-status of not-installed
+ * So it only really has to be the size of the maximum number of packages
+ * likely to be installed at any one time, so there is a bit of leaway here */
+#define STATUS_HASH_PRIME 8191
+typedef struct status_node_s {
+       unsigned int package:14;        /* has to fit PACKAGE_HASH_PRIME */
+       unsigned int status:14;         /* has to fit STATUS_HASH_PRIME */
+} status_node_t;
+status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
+
+/* Even numbers are for 'extras', like ored dependecies or null */
+enum edge_type_e {
+       EDGE_NULL = 0,
+       EDGE_PRE_DEPENDS = 1,
+       EDGE_OR_PRE_DEPENDS = 2,
+       EDGE_DEPENDS = 3,
+       EDGE_OR_DEPENDS = 4,
+       EDGE_REPLACES = 5,
+       EDGE_PROVIDES = 7,
+       EDGE_CONFLICTS = 9,
+       EDGE_SUGGESTS = 11,
+       EDGE_RECOMMENDS = 13,
+       EDGE_ENHANCES = 15
+};
+enum operator_e {
+       VER_NULL = 0,
+       VER_EQUAL = 1,
+       VER_LESS = 2,
+       VER_LESS_EQUAL = 3,
+       VER_MORE = 4,
+       VER_MORE_EQUAL = 5,
+       VER_ANY = 6
+};
+
+enum dpkg_opt_e {
+       dpkg_opt_purge = 1,
+       dpkg_opt_remove = 2,
+       dpkg_opt_unpack = 4,
+       dpkg_opt_configure = 8,
+       dpkg_opt_install = 16,
+       dpkg_opt_package_name = 32,
+       dpkg_opt_filename = 64,
+       dpkg_opt_list_installed = 128,
+       dpkg_opt_force_ignore_depends = 256
+};
+
+typedef struct deb_file_s {
+       char *control_file;
+       char *filename;
+       unsigned int package:14;
+} deb_file_t;
+
+
+void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
+{
+       unsigned long int hash_num = key[0];
+       int len = strlen(key);
+       int i;
+
+       /* Maybe i should have uses a "proper" hashing algorithm here instead
+        * of making one up myself, seems to be working ok though. */
+       for(i = 1; i < len; i++) {
+               /* shifts the ascii based value and adds it to previous value
+                * shift amount is mod 24 because long int is 32 bit and data
+                * to be shifted is 8, dont want to shift data to where it has
+                * no effect*/
+               hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); 
+       }
+       *start = (unsigned int) hash_num % hash_prime;
+       *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1));
+}
+
+/* this adds the key to the hash table */
+int search_name_hashtable(const char *key)
+{
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+//     char *temp;
+
+       make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
+       while(name_hashtable[probe_address] != NULL) {
+               if (strcmp(name_hashtable[probe_address], key) == 0) {
+                       return(probe_address);
+               } else {
+                       probe_address -= probe_decrement;
+                       if ((int)probe_address < 0) {
+                               probe_address += NAME_HASH_PRIME;
+                       }
+               }
+       }
+       name_hashtable[probe_address] = xstrdup(key);
+       return(probe_address);
+}
+
+/* this DOESNT add the key to the hashtable
+ * TODO make it consistent with search_name_hashtable
+ */
+unsigned int search_status_hashtable(const char *key)
+{
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+
+       make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
+       while(status_hashtable[probe_address] != NULL) {
+               if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) {
+                       break;
+               } else {
+                       probe_address -= probe_decrement;
+                       if ((int)probe_address < 0) {
+                               probe_address += STATUS_HASH_PRIME;
+                       }
+               }
+       }
+       return(probe_address);
+}
+
+/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
+int version_compare_part(const char *version1, const char *version2)
+{
+       int upstream_len1 = 0;
+       int upstream_len2 = 0;
+       char *name1_char;
+       char *name2_char;
+       int len1 = 0;
+       int len2 = 0;
+       int tmp_int;
+       int ver_num1;
+       int ver_num2;
+       int ret;
+
+       if (version1 == NULL) {
+               version1 = xstrdup("");
+       }
+       if (version2 != NULL) {
+               version2 = xstrdup("");
+       }
+       upstream_len1 = strlen(version1);
+       upstream_len2 = strlen(version2);
+
+       while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
+               /* Compare non-digit section */
+               tmp_int = strcspn(&version1[len1], "0123456789");
+               name1_char = xstrndup(&version1[len1], tmp_int);
+               len1 += tmp_int;
+               tmp_int = strcspn(&version2[len2], "0123456789");
+               name2_char = xstrndup(&version2[len2], tmp_int);
+               len2 += tmp_int;
+               tmp_int = strcmp(name1_char, name2_char);
+               free(name1_char);
+               free(name2_char);
+               if (tmp_int != 0) {
+                       ret = tmp_int;
+                       goto cleanup_version_compare_part;
+               }
+
+               /* Compare digits */
+               tmp_int = strspn(&version1[len1], "0123456789");
+               name1_char = xstrndup(&version1[len1], tmp_int);
+               len1 += tmp_int;
+               tmp_int = strspn(&version2[len2], "0123456789");
+               name2_char = xstrndup(&version2[len2], tmp_int);
+               len2 += tmp_int;
+               ver_num1 = atoi(name1_char);
+               ver_num2 = atoi(name2_char);
+               free(name1_char);
+               free(name2_char);
+               if (ver_num1 < ver_num2) {
+                       ret = -1;
+                       goto cleanup_version_compare_part;
+               }
+               else if (ver_num1 > ver_num2) {
+                       ret = 1;
+                       goto cleanup_version_compare_part;
+               }
+       }
+       ret = 0;
+cleanup_version_compare_part:
+       return(ret);
+}
+
+/* if ver1 < ver2 return -1,
+ * if ver1 = ver2 return 0,
+ * if ver1 > ver2 return 1,
+ */
+int version_compare(const unsigned int ver1, const unsigned int ver2)
+{
+       char *ch_ver1 = name_hashtable[ver1];
+       char *ch_ver2 = name_hashtable[ver2];
+
+       char epoch1, epoch2;
+       char *deb_ver1, *deb_ver2;
+       char *ver1_ptr, *ver2_ptr;
+       char *upstream_ver1;
+       char *upstream_ver2;
+       int result;
+
+       /* Compare epoch */
+       if (ch_ver1[1] == ':') {
+               epoch1 = ch_ver1[0];
+               ver1_ptr = strchr(ch_ver1, ':') + 1;
+       } else {
+               epoch1 = '0';
+               ver1_ptr = ch_ver1;
+       }
+       if (ch_ver2[1] == ':') {
+               epoch2 = ch_ver2[0];
+               ver2_ptr = strchr(ch_ver2, ':') + 1;
+       } else {
+               epoch2 = '0';
+               ver2_ptr = ch_ver2;
+       }
+       if (epoch1 < epoch2) {
+               return(-1);
+       }
+       else if (epoch1 > epoch2) {
+               return(1);
+       }
+
+       /* Compare upstream version */
+       upstream_ver1 = xstrdup(ver1_ptr);
+       upstream_ver2 = xstrdup(ver2_ptr);
+
+       /* Chop off debian version, and store for later use */
+       deb_ver1 = strrchr(upstream_ver1, '-');
+       deb_ver2 = strrchr(upstream_ver2, '-');
+       if (deb_ver1) {
+               deb_ver1[0] = '\0';
+               deb_ver1++;
+       }
+       if (deb_ver2) {
+               deb_ver2[0] = '\0';
+               deb_ver2++;
+       }
+       result = version_compare_part(upstream_ver1, upstream_ver2);
+
+       free(upstream_ver1);
+       free(upstream_ver2);
+
+       if (result != 0) {
+               return(result);
+       }
+
+       /* Compare debian versions */
+       return(version_compare_part(deb_ver1, deb_ver2));
+}
+
+int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
+{
+       const int version_result = version_compare(version1, version2);
+       switch(operator) {
+               case (VER_ANY):
+                       return(TRUE);
+               case (VER_EQUAL):
+                       if (version_result == 0) {
+                               return(TRUE);
+                       }
+                       break;
+               case (VER_LESS):
+                       if (version_result < 0) {
+                               return(TRUE);
+                       }
+                       break;
+               case (VER_LESS_EQUAL):
+                       if (version_result <= 0) {
+                               return(TRUE);
+                       }
+                       break;
+               case (VER_MORE):
+                       if (version_result > 0) {
+                               return(TRUE);
+                       }
+                       break;
+               case (VER_MORE_EQUAL):
+                       if (version_result >= 0) {
+                               return(TRUE);
+                       }
+                       break;
+       }
+       return(FALSE);
+}
+
+
+int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
+{
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+
+       make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
+       while(package_hashtable[probe_address] != NULL) {
+               if (package_hashtable[probe_address]->name == name) {
+                       if (operator == VER_ANY) {
+                               return(probe_address);
+                       }
+                       if (test_version(package_hashtable[probe_address]->version, version, operator)) {
+                               return(probe_address);
+                       }
+               }
+               probe_address -= probe_decrement;
+               if ((int)probe_address < 0) {
+                       probe_address += PACKAGE_HASH_PRIME;
+               }
+       }
+       return(probe_address);
+}
+
+/*
+ * Create one new node and one new edge for every dependency.
+ */
+void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
+{
+       char *line = xstrdup(whole_line);
+       char *line2;
+       char *line_ptr1 = NULL;
+       char *line_ptr2 = NULL;
+       char *field;
+       char *field2;
+       char *version;
+       edge_t *edge;
+       int offset_ch;
+       int type;
+
+       field = strtok_r(line, ",", &line_ptr1);
+       do {
+               line2 = xstrdup(field);
+               field2 = strtok_r(line2, "|", &line_ptr2);
+               if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) {
+                       type = EDGE_OR_DEPENDS;
+               }
+               else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) {
+                       type = EDGE_OR_PRE_DEPENDS;
+               } else {
+                       type = edge_type;
+               }
+
+               do {
+                       edge = (edge_t *) xmalloc(sizeof(edge_t));
+                       edge->type = type;
+
+                       /* Skip any extra leading spaces */
+                       field2 += strspn(field2, " ");
+
+                       /* Get dependency version info */
+                       version = strchr(field2, '(');
+                       if (version == NULL) {
+                               edge->operator = VER_ANY;
+                               /* Get the versions hash number, adding it if the number isnt already in there */
+                               edge->version = search_name_hashtable("ANY");
+                       } else {
+                               /* Skip leading ' ' or '(' */
+                               version += strspn(field2, " ");
+                               version += strspn(version, "(");
+                               /* Calculate length of any operator charactors */
+                               offset_ch = strspn(version, "<=>");
+                               /* Determine operator */
+                               if (offset_ch > 0) {
+                                       if (strncmp(version, "=", offset_ch) == 0) {
+                                               edge->operator = VER_EQUAL;
+                                       }
+                                       else if (strncmp(version, "<<", offset_ch) == 0) {
+                                               edge->operator = VER_LESS;
+                                       }
+                                       else if (strncmp(version, "<=", offset_ch) == 0) {
+                                               edge->operator = VER_LESS_EQUAL;
+                                       }
+                                       else if (strncmp(version, ">>", offset_ch) == 0) {
+                                               edge->operator = VER_MORE;
+                                       }
+                                       else if (strncmp(version, ">=", offset_ch) == 0) {
+                                               edge->operator = VER_MORE_EQUAL;
+                                       } else {
+                                               error_msg_and_die("Illegal operator\n");
+                                       }
+                               }
+                               /* skip to start of version numbers */
+                               version += offset_ch;
+                               version += strspn(version, " ");
+
+                               /* Truncate version at trailing ' ' or ')' */
+                               version[strcspn(version, " )")] = '\0';
+                               /* Get the versions hash number, adding it if the number isnt already in there */
+                               edge->version = search_name_hashtable(version);
+                       }
+
+                       /* Get the dependency name */
+                       field2[strcspn(field2, " (")] = '\0';
+                       edge->name = search_name_hashtable(field2);
+       
+                       /* link the new edge to the current node */
+                       parent_node->num_of_edges++;
+                       parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1));
+                       parent_node->edge[parent_node->num_of_edges - 1] = edge;
+               } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL);
+               free(line2);
+       } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL);
+       free(line);
+
+       return;
+}
+
+void free_package(common_node_t *node)
+{
+       int i;
+       if (node != NULL) {
+               for (i = 0; i < node->num_of_edges; i++) {
+                       if (node->edge[i] != NULL) {
+                               free(node->edge[i]);
+                       }
+               }
+               if (node->edge != NULL) {
+                       free(node->edge);
+               }
+               if (node != NULL) {
+                       free(node);
+               }
+       }
+}
+
+unsigned int fill_package_struct(char *control_buffer)
+{
+       common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t));
+
+       char **field_name = xmalloc(sizeof(char *));
+       char **field_value = xmalloc(sizeof(char *));
+       int field_start = 0;
+       int num = -1;
+       int buffer_length = strlen(control_buffer);
+
+       new_node->version = search_name_hashtable("unknown");
+       while (field_start < buffer_length) {
+               field_start += read_package_field(&control_buffer[field_start], field_name, field_value);
+
+               if (*field_name == NULL) {
+                       goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !!
+               }
+
+               if (strcmp(*field_name, "Package") == 0) {
+                       new_node->name = search_name_hashtable(*field_value);
+               }
+               else if (strcmp(*field_name, "Version") == 0) {
+                       new_node->version = search_name_hashtable(*field_value);
+               }
+               else if (strcmp(*field_name, "Pre-Depends") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS);
+               }
+               else if (strcmp(*field_name, "Depends") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_DEPENDS);
+               }
+               else if (strcmp(*field_name, "Replaces") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_REPLACES);
+               }
+               else if (strcmp(*field_name, "Provides") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_PROVIDES);
+               }
+               else if (strcmp(*field_name, "Conflicts") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS);
+               }
+               else if (strcmp(*field_name, "Suggests") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS);
+               }
+               else if (strcmp(*field_name, "Recommends") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS);
+               }
+               else if (strcmp(*field_name, "Enhances") == 0) {
+                       add_split_dependencies(new_node, *field_value, EDGE_ENHANCES);
+               }
+fill_package_struct_cleanup:
+               if (*field_name) {
+                       free(*field_name);
+               }
+               if (*field_value) {
+                       free(*field_value);
+               }
+       }
+       free(field_name);
+       free(field_value);
+
+       if (new_node->version == search_name_hashtable("unknown")) {
+               free_package(new_node);
+               return(-1);
+       }
+       num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL);
+       if (package_hashtable[num] == NULL) {
+               package_hashtable[num] = new_node;
+       } else {
+               free_package(new_node);
+       }
+       return(num);
+}
+
+/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
+unsigned int get_status(const unsigned int status_node, const int num)
+{
+       char *status_string = name_hashtable[status_hashtable[status_node]->status];
+       char *state_sub_string;
+       unsigned int state_sub_num;
+       int len;
+       int i;
+
+       /* set tmp_string to point to the start of the word number */
+       for (i = 1; i < num; i++) {
+               /* skip past a word */
+               status_string += strcspn(status_string, " ");
+               /* skip past the seperating spaces */
+               status_string += strspn(status_string, " ");
+       }
+       len = strcspn(status_string, " \n\0");
+       state_sub_string = xstrndup(status_string, len);
+       state_sub_num = search_name_hashtable(state_sub_string);
+       free(state_sub_string);
+       return(state_sub_num);
+}
+
+void set_status(const unsigned int status_node_num, const char *new_value, const int position)
+{
+       const unsigned int new_value_len = strlen(new_value);
+       const unsigned int new_value_num = search_name_hashtable(new_value);
+       unsigned int want = get_status(status_node_num, 1);
+       unsigned int flag = get_status(status_node_num, 2);
+       unsigned int status = get_status(status_node_num, 3);
+       int want_len = strlen(name_hashtable[want]);
+       int flag_len = strlen(name_hashtable[flag]);
+       int status_len = strlen(name_hashtable[status]);
+       char *new_status;
+
+       switch (position) {
+               case (1):
+                       want = new_value_num;
+                       want_len = new_value_len;
+                       break;
+               case (2):
+                       flag = new_value_num;
+                       flag_len = new_value_len;
+                       break;
+               case (3):
+                       status = new_value_num;
+                       status_len = new_value_len;
+                       break;
+               default:
+                       error_msg_and_die("DEBUG ONLY: this shouldnt happen");
+       }
+
+       new_status = (char *) xmalloc(want_len + flag_len + status_len + 3);
+       sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]);
+       status_hashtable[status_node_num]->status = search_name_hashtable(new_status);
+       free(new_status);
+       return;
+}
+
+void index_status_file(const char *filename)
+{
+       FILE *status_file;
+       char *control_buffer;
+       char *status_line;
+       status_node_t *status_node = NULL;
+       unsigned int status_num;
+
+       status_file = xfopen(filename, "r");
+       while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) {
+               const unsigned int package_num = fill_package_struct(control_buffer);
+               if (package_num != -1) {
+                       status_node = xmalloc(sizeof(status_node_t));
+                       /* fill_package_struct doesnt handle the status field */
+                       status_line = strstr(control_buffer, "Status:");
+                       if (status_line != NULL) {
+                               status_line += 7;
+                               status_line += strspn(status_line, " \n\t");
+                               status_line = xstrndup(status_line, strcspn(status_line, "\n\0"));
+                               status_node->status = search_name_hashtable(status_line);
+                               free(status_line);
+                       }
+                       status_node->package = package_num;
+                       status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]);
+                       status_hashtable[status_num] = status_node;
+               }
+               free(control_buffer);
+       }
+       fclose(status_file);
+       return;
+}
+
+
+char *get_depends_field(common_node_t *package, const int depends_type)
+{
+       char *depends = NULL;
+       char *old_sep = (char *)xcalloc(1, 3);
+       char *new_sep = (char *)xcalloc(1, 3);
+       int line_size = 0;
+       int depends_size;
+
+       int i;
+
+       for (i = 0; i < package->num_of_edges; i++) {
+               if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) ||
+                       (package->edge[i]->type == EDGE_OR_DEPENDS)) {
+               }
+
+               if ((package->edge[i]->type == depends_type) ||
+                       (package->edge[i]->type == depends_type + 1)) {
+                       /* Check if its the first time through */
+
+                       depends_size = 8 + strlen(name_hashtable[package->edge[i]->name])
+                               + strlen(name_hashtable[package->edge[i]->version]);
+                       line_size += depends_size;
+                       depends = (char *) xrealloc(depends, line_size + 1);
+
+                       /* Check to see if this dependency is the type we are looking for
+                        * +1 to check for 'extra' types, e.g. ored dependecies */
+                       strcpy(old_sep, new_sep);
+                       if (package->edge[i]->type == depends_type) {
+                               strcpy(new_sep, ", ");
+                       }
+                       else if (package->edge[i]->type == depends_type + 1) {
+                               strcpy(new_sep, "| ");
+                       }
+
+                       if (depends_size == line_size) {
+                               strcpy(depends, "");
+                       } else {
+                               if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) {
+                                       strcat(depends, " | ");
+                               } else {
+                                       strcat(depends, ", ");
+                               }
+                       }
+
+                       strcat(depends, name_hashtable[package->edge[i]->name]);
+                       if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) {
+                               if (package->edge[i]->operator == VER_EQUAL) {
+                                       strcat(depends, " (= ");
+                               }
+                               else if (package->edge[i]->operator == VER_LESS) {
+                                       strcat(depends, " (<< ");
+                               }
+                               else if (package->edge[i]->operator == VER_LESS_EQUAL) {
+                                       strcat(depends, " (<= ");
+                               }
+                               else if (package->edge[i]->operator == VER_MORE) {
+                                       strcat(depends, " (>> ");
+                               }
+                               else if (package->edge[i]->operator == VER_MORE_EQUAL) {
+                                       strcat(depends, " (>= ");
+                               } else {
+                                       strcat(depends, " (");
+                               }
+                               strcat(depends, name_hashtable[package->edge[i]->version]);
+                               strcat(depends, ")");
+                       }
+               }
+       }
+       return(depends);
+}
+
+void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
+{
+       char *name;
+       char *value;
+       int start = 0;
+       while (1) {
+               start += read_package_field(&control_buffer[start], &name, &value);
+               if (name == NULL) {
+                       break;
+               }
+               if (strcmp(name, "Status") != 0) {
+                       fprintf(new_status_file, "%s: %s\n", name, value);
+               }
+       }
+       return;
+}
+
+/* This could do with a cleanup */
+void write_status_file(deb_file_t **deb_file)
+{
+       FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
+       FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
+       char *package_name;
+       char *status_from_file;
+       char *control_buffer = NULL;
+       char *tmp_string;
+       int status_num;
+       int field_start = 0;
+       int write_flag;
+       int i = 0;
+
+       /* Update previously known packages */
+       while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) {
+               tmp_string = strstr(control_buffer, "Package:") + 8;
+               tmp_string += strspn(tmp_string, " \n\t");
+               package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0"));
+               write_flag = FALSE;
+               tmp_string = strstr(control_buffer, "Status:");
+               if (tmp_string != NULL) {
+                       /* Seperate the status value from the control buffer */
+                       tmp_string += 7;
+                       tmp_string += strspn(tmp_string, " \n\t");
+                       status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n"));
+               } else {
+                       status_from_file = NULL;
+               }
+
+               /* Find this package in the status hashtable */
+               status_num = search_status_hashtable(package_name);
+               if (status_hashtable[status_num] != NULL) {
+                       const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status];
+                       if (strcmp(status_from_file, status_from_hashtable) != 0) {
+                               /* New status isnt exactly the same as old status */
+                               const int state_status = get_status(status_num, 3);
+                               if ((strcmp("installed", name_hashtable[state_status]) == 0) ||
+                                       (strcmp("unpacked", name_hashtable[state_status]) == 0)) {
+                                       /* We need to add the control file from the package */
+                                       i = 0;
+                                       while(deb_file[i] != NULL) {
+                                               if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) {
+                                                       /* Write a status file entry with a modified status */
+                                                       /* remove trailing \n's */
+                                                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+                                                       set_status(status_num, "ok", 2);
+                                                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
+                                                       write_flag = TRUE;
+                                                       break;
+                                               }
+                                               i++;
+                                       }
+                                       /* This is temperary, debugging only */
+                                       if (deb_file[i] == NULL) {
+                                               error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name);
+                                       }
+                               }
+                               else if (strcmp("not-installed", name_hashtable[state_status]) == 0) {
+                                       /* Only write the Package, Status, Priority and Section lines */
+                                       fprintf(new_status_file, "Package: %s\n", package_name);
+                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+
+                                       while (1) {
+                                               char *field_name;
+                                               char *field_value;
+                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+                                               if (field_name == NULL) {
+                                                       break;
+                                               }
+                                               if ((strcmp(field_name, "Priority") == 0) ||
+                                                       (strcmp(field_name, "Section") == 0)) {
+                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+                                               }
+                                       }
+                                       write_flag = TRUE;
+                                       fputs("\n", new_status_file);
+                               }
+                               else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
+                                       /* only change the status line */
+                                       while (1) {
+                                               char *field_name;
+                                               char *field_value;
+                                               field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value);
+                                               if (field_name == NULL) {
+                                                       break;
+                                               }
+                                               /* Setup start point for next field */
+                                               if (strcmp(field_name, "Status") == 0) {
+                                                       fprintf(new_status_file, "Status: %s\n", status_from_hashtable);
+                                               } else {
+                                                       fprintf(new_status_file, "%s: %s\n", field_name, field_value);
+                                               }
+                                       }
+                                       write_flag = TRUE;
+                                       fputs("\n", new_status_file);
+                               }
+                       }
+               }
+               /* If the package from the status file wasnt handle above, do it now*/
+               if (write_flag == FALSE) {
+                       fprintf(new_status_file, "%s\n\n", control_buffer);
+               }
+
+               if (status_from_file != NULL) {
+                       free(status_from_file);
+               }
+               free(package_name);
+               free(control_buffer);
+       }
+
+       /* Write any new packages */
+       for(i = 0; deb_file[i] != NULL; i++) {
+               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]);
+               if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) {
+                       write_buffer_no_status(new_status_file, deb_file[i]->control_file);
+                       set_status(status_num, "ok", 2);
+                       fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]);
+               }
+       }
+       fclose(old_status_file);
+       fclose(new_status_file);
+
+
+       /* Create a seperate backfile to dpkg */
+       if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
+               struct stat stat_buf;   
+               if (stat("/var/lib/dpkg/status", &stat_buf) == 0) {
+                       error_msg_and_die("Couldnt create backup status file");
+               }
+               /* Its ok if renaming the status file fails becasue status 
+                * file doesnt exist, maybe we are starting from scratch */
+               error_msg("No status file found, creating new one");
+       }
+
+       if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) {
+               error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file");
+       }
+}
+
+int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
+{
+       int *conflicts = NULL;
+       int conflicts_num = 0;
+       int state_status;
+       int state_flag;
+       int state_want;
+       unsigned int status_package_num;
+       int i = deb_start;
+       int j, k;
+
+       /* Check for conflicts
+        * TODO: TEST if conflicts with other packages to be installed
+        *
+        * Add install packages and the packages they provide
+        * to the list of files to check conflicts for
+        */
+
+       /* Create array of package numbers to check against
+        * installed package for conflicts*/
+       while (deb_file[i] != NULL) {
+               const unsigned int package_num = deb_file[i]->package;
+               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
+               conflicts[conflicts_num] = package_num;
+               conflicts_num++;
+               /* add provides to conflicts list */
+               for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
+                       if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
+                               const int conflicts_package_num = search_package_hashtable(
+                                       package_hashtable[package_num]->edge[j]->name,
+                                       package_hashtable[package_num]->edge[j]->version,
+                                       package_hashtable[package_num]->edge[j]->operator);
+                               if (package_hashtable[conflicts_package_num] == NULL) {
+                                       /* create a new package */
+                                       common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t));
+                                       new_node->name = package_hashtable[package_num]->edge[j]->name;
+                                       new_node->version = package_hashtable[package_num]->edge[j]->version;
+                                       new_node->num_of_edges = 0;
+                                       new_node->edge = NULL;
+                                       package_hashtable[conflicts_package_num] = new_node;
+                               }
+                               conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
+                               conflicts[conflicts_num] = conflicts_package_num;
+                               conflicts_num++;
+                       }
+               }
+               i++;
+       }
+
+       /* Check conflicts */
+       for (i = 0; i < conflicts_num; i++) {
+               /* Check for conflicts */
+               for (j = 0; j < STATUS_HASH_PRIME; j++) {
+                       if (status_hashtable[j] == NULL) {
+                               continue;
+                       }
+                       state_flag = get_status(j, 2);
+                       state_status = get_status(j, 3);
+                       if ((state_status != search_name_hashtable("installed"))
+                               && (state_flag != search_name_hashtable("want-install"))) {
+                               continue;
+                       }
+                       status_package_num = status_hashtable[j]->package;
+                       for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) {
+                               const edge_t *package_edge = package_hashtable[status_package_num]->edge[k];
+                               if (package_edge->type != EDGE_CONFLICTS) {
+                                       continue;
+                               }
+                               if (package_edge->name != package_hashtable[conflicts[i]]->name) {
+                                       continue;
+                               }
+                               /* There is a conflict against the package name
+                                * check if version conflict as well */
+                               if (test_version(package_hashtable[deb_file[i]->package]->version,
+                                               package_edge->version, package_edge->operator)) {
+                                       error_msg_and_die("Package %s conflict with %s",
+                                               name_hashtable[package_hashtable[deb_file[i]->package]->name],
+                                               name_hashtable[package_hashtable[status_package_num]->name]);
+                               }
+                       }
+               }
+       }
+
+       /* Check dependendcies */
+       i = 0;
+       while (deb_file[i] != NULL) {
+               const common_node_t *package_node = package_hashtable[deb_file[i]->package];
+               int status_num = 0;
+
+               for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) {
+                       const edge_t *package_edge = package_node->edge[j];
+                       const unsigned int package_num = search_package_hashtable(package_edge->name,
+                               package_edge->version, package_edge->operator);
+
+                       status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]);
+                       state_status = get_status(status_num, 3);
+                       state_want = get_status(status_num, 1);
+                       switch (package_edge->type) {
+                               case(EDGE_PRE_DEPENDS):
+                               case(EDGE_OR_PRE_DEPENDS):
+                                       /* It must be already installed */
+                                       /* NOTE: This is untested, nothing apropriate in my status file */
+                                       if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) {
+                                               error_msg_and_die("Package %s pre-depends on %s, but it is not installed",
+                                                       name_hashtable[package_node->name],
+                                                       name_hashtable[package_edge->name]);
+                                       }
+                                       break;
+                               case(EDGE_DEPENDS):
+                               case(EDGE_OR_DEPENDS):
+                                       /* It must be already installed, or to be installed */
+                                       if ((package_hashtable[package_num] == NULL) ||
+                                               ((state_status != search_name_hashtable("installed")) &&
+                                               (state_want != search_name_hashtable("want_install")))) {
+                                               error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed",
+                                                       name_hashtable[package_node->name],
+                                                       name_hashtable[package_edge->name]);
+                                       }
+                                       break;
+                       }
+               }
+               i++;
+       }
+       free(conflicts);
+       return(TRUE);
+}
+
+char **create_list(const char *filename)
+{
+       FILE *list_stream;
+       char **file_list = xmalloc(sizeof(char *));
+       char *line = NULL;
+       char *last_char;
+       int length = 0;
+       int count = 0;
+
+       /* dont use [xw]fopen here, handle error ourself */
+       list_stream = fopen(filename, "r");
+       if (list_stream == NULL) {
+               *file_list = NULL;
+               return(file_list);
+       }
+       while (getline(&line, &length, list_stream) != -1) {
+               file_list = xrealloc(file_list, sizeof(char *) * (length + 1));
+               last_char = last_char_is(line, '\n');
+               if (last_char) {
+                       *last_char = '\0';
+               }
+               file_list[count] = xstrdup(line);
+               free(line);
+               count++;
+               length = 0;
+       }
+       fclose(list_stream);
+
+       if (count == 0) {
+               return(NULL);
+       } else {
+               file_list[count] = NULL;
+               return(file_list);
+       }
+}
+
+/* maybe i should try and hook this into remove_file.c somehow */
+int remove_file_array(char **remove_names, char **exclude_names)
+{
+       struct stat path_stat;
+       int match_flag;
+       int remove_flag = FALSE;
+       int i,j;
+
+       if (remove_names == NULL) {
+               return(FALSE);
+       }
+       for (i = 0; remove_names[i] != NULL; i++) {
+               match_flag = FALSE;
+               if (exclude_names != NULL) {
+                       for (j = 0; exclude_names[j] != 0; j++) {
+                               if (strcmp(remove_names[i], exclude_names[j]) == 0) {
+                                       match_flag = TRUE;
+                                       break;
+                               }
+                       }
+               }
+               if (!match_flag) {
+                       if (lstat(remove_names[i], &path_stat) < 0) {
+                               continue;
+                       }
+                       if (S_ISDIR(path_stat.st_mode)) {
+                               if (rmdir(remove_names[i]) != -1) {
+                                       remove_flag = TRUE;
+                               }
+                       } else {
+                               if (unlink(remove_names[i]) != -1) {
+                                       remove_flag = TRUE;
+                               }
+                       }
+               }
+       }
+       return(remove_flag);
+}
+
+int run_package_script(const char *package_name, const char *script_type)
+{
+       struct stat path_stat;
+       char *script_path;
+
+       script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21);
+       sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type);
+
+       /* If the file doesnt exist is isnt a fatal */
+       if (lstat(script_path, &path_stat) < 0) {
+               free(script_path);
+               return(EXIT_SUCCESS);
+       } else {
+               free(script_path);
+               return(system(script_path));
+       }
+}
+
+void all_control_list(char **remove_files, const char *package_name)
+{
+       const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm",
+               "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL };
+       int i;
+
+       /* Create a list of all /var/lib/dpkg/info/<package> files */
+       for(i = 0; i < 10; i++) {
+               remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21);
+               sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]);
+       }
+       remove_files[10] = NULL;
+}
+
+void remove_package(const unsigned int package_num)
+{
+       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+       const unsigned int status_num = search_status_hashtable(package_name);
+       const int package_name_length = strlen(package_name);
+       char **remove_files;
+       char **exclude_files;
+       char list_name[package_name_length + 25];
+       char conffile_name[package_name_length + 30];
+       int return_value;
+
+       printf("Removing %s ...\n", package_name);
+
+       /* run prerm script */
+       return_value = run_package_script(package_name, "prerm");
+       if (return_value == -1) {
+               error_msg_and_die("script failed, prerm failure");
+       }
+
+       /* Create a list of files to remove, and a seperate list of those to keep */
+       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
+       remove_files = create_list(list_name);
+
+       sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name);
+       exclude_files = create_list(conffile_name);
+
+       /* Some directories cant be removed straight away, so do multiple passes */
+       while (remove_file_array(remove_files, exclude_files) == TRUE);
+
+       /* Create a list of all /var/lib/dpkg/info/<package> files */
+       remove_files = xmalloc(11);
+       all_control_list(remove_files, package_name);
+
+       /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep  */
+       exclude_files = xmalloc(sizeof(char*) * 3);
+       exclude_files[0] = xstrdup(conffile_name);
+       exclude_files[1] = xmalloc(package_name_length + 27);
+       sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name);
+       exclude_files[2] = NULL;
+
+       remove_file_array(remove_files, exclude_files);
+
+       /* rename <package>.conffile to <package>.list */
+       rename(conffile_name, list_name);
+
+       /* Change package status */
+       set_status(status_num, "deinstall", 1);
+       set_status(status_num, "config-files", 3);
+}
+
+void purge_package(const unsigned int package_num)
+{
+       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+       const unsigned int status_num = search_status_hashtable(package_name);
+       char **remove_files;
+       char **exclude_files;
+       char list_name[strlen(package_name) + 25];
+
+       /* run prerm script */
+       if (run_package_script(package_name, "prerm") == -1) {
+               error_msg_and_die("script failed, prerm failure");
+       }
+
+       /* Create a list of files to remove */
+       sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
+       remove_files = create_list(list_name);
+
+       exclude_files = xmalloc(1);
+       exclude_files[0] = NULL;
+
+       /* Some directories cant be removed straight away, so do multiple passes */
+       while (remove_file_array(remove_files, exclude_files) == TRUE);
+
+       /* Create a list of all /var/lib/dpkg/info/<package> files */
+       remove_files = xmalloc(11);
+       all_control_list(remove_files, package_name);
+       remove_file_array(remove_files, exclude_files);
+
+       /* run postrm script */
+       if (run_package_script(package_name, "postrm") == -1) {
+               error_msg_and_die("postrm fialure.. set status to what?");
+       }
+
+       /* Change package status */
+       set_status(status_num, "purge", 1);
+       set_status(status_num, "not-installed", 3);
+}
+
+void unpack_package(deb_file_t *deb_file)
+{
+       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+       const unsigned int status_num = search_status_hashtable(package_name);
+       const unsigned int status_package_num = status_hashtable[status_num]->status;
+
+       FILE *out_stream;
+       char *info_prefix;
+
+       /* If existing version, remove it first */
+       if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
+               /* Package is already installed, remove old version first */
+               printf("Preparing to replace %s %s (using %s) ...\n", package_name,
+                       name_hashtable[package_hashtable[status_package_num]->version],
+                       deb_file->filename);
+               remove_package(status_package_num);
+       } else {
+               printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename);
+       }
+
+       /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
+       info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1);
+       sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name);
+       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL);
+
+       /* Extract data.tar.gz to the root directory */
+       deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL);
+
+       /* Create the list file */
+       strcat(info_prefix, "list");
+       out_stream = xfopen(info_prefix, "w");                  
+       deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL);
+       fclose(out_stream);
+
+       /* change status */
+       set_status(status_num, "install", 1);
+       set_status(status_num, "unpacked", 3);
+
+       free(info_prefix);
+}
+
+void configure_package(deb_file_t *deb_file)
+{
+       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+       const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
+       const int status_num = search_status_hashtable(package_name);
+       int return_value;
+
+       printf("Setting up %s (%s)\n", package_name, package_version);
+
+       /* Run the preinst prior to extracting */
+       return_value = run_package_script(package_name, "postinst");
+       if (return_value == -1) {
+               /* TODO: handle failure gracefully */
+               error_msg_and_die("postrm failure.. set status to what?");
+       }
+       /* Change status to reflect success */
+       set_status(status_num, "install", 1);
+       set_status(status_num, "installed", 3);
+}
+
+extern int dpkg_main(int argc, char **argv)
+{
+       deb_file_t **deb_file = NULL;
+       status_node_t *status_node;
+       int opt = 0;
+       int package_num;
+       int dpkg_opt = 0;
+       int deb_count = 0;
+       int state_status;
+       int status_num;
+       int i;
+
+       while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) {
+               switch (opt) {
+                       case 'C': // equivalent to --configure in official dpkg
+                               dpkg_opt |= dpkg_opt_configure;
+                               dpkg_opt |= dpkg_opt_package_name;
+                               break;
+                       case 'F': // equivalent to --force in official dpkg
+                               if (strcmp(optarg, "depends") == 0) {
+                                       dpkg_opt |= dpkg_opt_force_ignore_depends;
+                               }                               
+                       case 'i':
+                               dpkg_opt |= dpkg_opt_install;
+                               dpkg_opt |= dpkg_opt_filename;
+                               break;
+                       case 'l':
+                               dpkg_opt |= dpkg_opt_list_installed;
+                       case 'P':
+                               dpkg_opt |= dpkg_opt_purge;
+                               dpkg_opt |= dpkg_opt_package_name;
+                               break;
+                       case 'r':
+                               dpkg_opt |= dpkg_opt_remove;
+                               dpkg_opt |= dpkg_opt_package_name;
+                               break;
+                       case 'u':       /* Equivalent to --unpack in official dpkg */
+                               dpkg_opt |= dpkg_opt_unpack;
+                               dpkg_opt |= dpkg_opt_filename;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if ((argc == optind) || (dpkg_opt == 0)) {
+               show_usage();
+       } 
+
+       puts("(Reading database ... xxxxx files and directories installed.)");
+       index_status_file("/var/lib/dpkg/status");
+
+       /* Read arguments and store relevant info in structs */
+       deb_file = xmalloc(sizeof(deb_file_t));
+       while (optind < argc) {
+               deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t));
+               if (dpkg_opt & dpkg_opt_filename) {
+                       deb_file[deb_count]->filename = xstrdup(argv[optind]);
+                       deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control");
+                       if (deb_file[deb_count]->control_file == NULL) {
+                               error_msg_and_die("Couldnt extract control file");
+                       }
+                       package_num = fill_package_struct(deb_file[deb_count]->control_file);
+
+                       if (package_num == -1) {
+                               error_msg("Invalid control file in %s", argv[optind]);
+                               continue;
+                       }
+                       deb_file[deb_count]->package = (unsigned int) package_num;
+                       /* Add the package to the status hashtable */
+                       if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) {
+                               status_node = (status_node_t *) xmalloc(sizeof(status_node_t));
+                               status_node->package = deb_file[deb_count]->package;
+                               /* use reinstreq isnt changed to "ok" until the package control info
+                                * is written to the status file*/
+                               status_node->status = search_name_hashtable("install reinstreq not-installed");
+
+                               status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
+                               status_hashtable[status_num] = status_node;
+                       }
+               }
+               else if (dpkg_opt & dpkg_opt_package_name) {
+                       deb_file[deb_count]->filename = NULL;
+                       deb_file[deb_count]->control_file = NULL;
+                       deb_file[deb_count]->package = search_package_hashtable(
+                               search_name_hashtable(argv[optind]),
+                               search_name_hashtable("ANY"), VER_ANY);
+                       if (package_hashtable[deb_file[deb_count]->package] == NULL) {
+                               error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]);
+                       }
+                       state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3);
+
+                       /* check package status is "installed" */
+                       if (dpkg_opt & dpkg_opt_remove) {
+                               if ((strcmp(name_hashtable[state_status], "not-installed") == 0) ||
+                                       (strcmp(name_hashtable[state_status], "config-files") == 0)) {
+                                       error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
+                               }
+                       }
+                       else if (dpkg_opt & dpkg_opt_purge) {
+                               /* if package status is "conf-files" then its ok */
+                               if (strcmp(name_hashtable[state_status], "not-installed") == 0) {
+                                       error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]);
+                               }
+                       }
+               }
+               deb_count++;
+               optind++;
+       }
+       deb_file[deb_count] = NULL;
+
+       /* Check that the deb file arguments are installable */
+       /* TODO: check dependencies before removing */
+       if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) {
+               if (!check_deps(deb_file, 0, deb_count)) {
+                       error_msg_and_die("Dependency check failed");
+               }
+       }
+
+       for (i = 0; i < deb_count; i++) {
+               /* Remove or purge packages */
+               if (dpkg_opt & dpkg_opt_remove) {
+                       remove_package(deb_file[i]->package);
+               }
+               else if (dpkg_opt & dpkg_opt_purge) {
+                       purge_package(deb_file[i]->package);
+               }
+               else if (dpkg_opt & dpkg_opt_unpack) {
+                       unpack_package(deb_file[i]);
+               }
+               else if (dpkg_opt & dpkg_opt_install) {
+                       unpack_package(deb_file[i]);
+                       configure_package(deb_file[i]);
+               }
+               else if (dpkg_opt & dpkg_opt_configure) {
+                       configure_package(deb_file[i]);
+               }
+       }
+
+       write_status_file(deb_file);
+
+       for (i = 0; i < deb_count; i++) {
+               free(deb_file[i]->control_file);
+               free(deb_file[i]->filename);
+               free(deb_file[i]);
+       }
+       free(deb_file);
+
+       for (i = 0; i < NAME_HASH_PRIME; i++) {
+               if (name_hashtable[i] != NULL) {
+                       free(name_hashtable[i]);
+               }
+       }
+
+       for (i = 0; i < PACKAGE_HASH_PRIME; i++) {
+               free_package(package_hashtable[i]);
+       }
+
+       for (i = 0; i < STATUS_HASH_PRIME; i++) {
+               if (status_hashtable[i] != NULL) {
+                       free(status_hashtable[i]);
+               }
+       }
+
+       return(EXIT_FAILURE);
+}
+
diff --git a/dpkg_deb.c b/dpkg_deb.c
new file mode 100644 (file)
index 0000000..a933c69
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include "busybox.h"
+
+extern int dpkg_deb_main(int argc, char **argv)
+{
+       char *prefix = NULL;
+       char *filename = NULL;
+       char *output_buffer = NULL;
+       int opt = 0;
+       int arg_type = 0;
+       int deb_extract_funct = extract_create_leading_dirs | extract_unconditional;    
+       
+       const int arg_type_prefix = 1;
+       const int arg_type_field = 2;
+       const int arg_type_filename = 4;
+//     const int arg_type_un_ar_gz = 8;
+
+       while ((opt = getopt(argc, argv, "ceftXxI")) != -1) {
+               switch (opt) {
+                       case 'c':
+                               deb_extract_funct |= extract_data_tar_gz;
+                               deb_extract_funct |= extract_verbose_list;
+                               break;
+                       case 'e':
+                               arg_type = arg_type_prefix;
+                               deb_extract_funct |= extract_control_tar_gz;
+                               deb_extract_funct |= extract_all_to_fs;
+                               break;
+                       case 'f':
+                               arg_type = arg_type_field;
+                               deb_extract_funct |= extract_control_tar_gz;
+                               deb_extract_funct |= extract_one_to_buffer;
+                               filename = xstrdup("./control");
+                               break;
+                       case 't': /* --fsys-tarfile, i just made up this short name */
+                               /* Integrate the functionality needed with some code from ar.c */
+                               error_msg_and_die("Option disabled");
+//                             arg_type = arg_type_un_ar_gz;
+                               break;
+                       case 'X':
+                               arg_type = arg_type_prefix;
+                               deb_extract_funct |= extract_data_tar_gz;
+                               deb_extract_funct |= extract_all_to_fs;
+                               deb_extract_funct |= extract_list;
+                       case 'x':
+                               arg_type = arg_type_prefix;
+                               deb_extract_funct |= extract_data_tar_gz;
+                               deb_extract_funct |= extract_all_to_fs;
+                               break;
+                       case 'I':
+                               arg_type = arg_type_filename;
+                               deb_extract_funct |= extract_control_tar_gz;
+                               deb_extract_funct |= extract_one_to_buffer;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (optind == argc)  {
+               show_usage();
+       }
+
+       /* Workout where to extract the files */
+       if (arg_type == arg_type_prefix) {
+               /* argument is a dir name */
+               if ((optind + 1) == argc ) {
+                       prefix = xstrdup("./DEBIAN/");
+               } else {
+                       prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2);
+                       strcpy(prefix, argv[optind + 1]);
+                       /* Make sure the directory has a trailing '/' */
+                       if (last_char_is(prefix, '/') == NULL) {
+                               strcat(prefix, "/");
+                       }
+               }
+               mkdir(prefix, 0777);
+       }
+
+       if (arg_type == arg_type_filename) {
+               if ((optind + 1) != argc) {
+                       filename = xstrdup(argv[optind + 1]);
+               } else {
+                       error_msg_and_die("-I currently requires a filename to be specified");
+               }
+       }
+
+       output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename);
+
+       if ((arg_type == arg_type_filename) && (output_buffer != NULL)) {
+               puts(output_buffer);
+       }
+       else if (arg_type == arg_type_field) {
+               char *field = NULL;
+               char *name;
+               char *value;
+               int field_start = 0;
+
+               while (1) {
+                       field_start += read_package_field(&output_buffer[field_start], &name, &value);
+                       if (name == NULL) {
+                               break;
+                       }
+                       if (strcmp(name, argv[optind + 1]) == 0) {
+                               puts(value);
+                       }
+                       free(field);
+               }
+       }
+
+       return(EXIT_SUCCESS);
+}
diff --git a/du.c b/du.c
new file mode 100644 (file)
index 0000000..d2b85b4
--- /dev/null
+++ b/du.c
@@ -0,0 +1,194 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini du implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ * Copyright (C) 2002  Edward Betts <edward@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include "busybox.h"
+
+
+#ifdef BB_FEATURE_HUMAN_READABLE
+static unsigned long disp_hr = KILOBYTE;
+#endif
+
+typedef void (Display) (long, char *);
+
+static int du_depth = 0;
+static int count_hardlinks = 0;
+static int one_file_system = 0;
+static dev_t dir_dev = 0;
+
+static Display *print;
+
+static void print_normal(long size, char *filename)
+{
+#ifdef BB_FEATURE_HUMAN_READABLE
+       printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
+#else
+       printf("%ld\t%s\n", size, filename);
+#endif
+}
+
+static void print_summary(long size, char *filename)
+{
+       if (du_depth == 1) {
+               print_normal(size, filename);
+       }
+}
+
+/* tiny recursive du */
+static long du(char *filename)
+{
+       struct stat statbuf;
+       long sum;
+
+       if ((lstat(filename, &statbuf)) != 0) {
+               perror_msg("%s", filename);
+               return 0;
+       }
+       if (du_depth == 0)
+               dir_dev = statbuf.st_dev;
+       else if (one_file_system && dir_dev != statbuf.st_dev)
+               return 0;
+
+       du_depth++;
+       sum = (statbuf.st_blocks >> 1);
+
+       /* Don't add in stuff pointed to by symbolic links */
+       if (S_ISLNK(statbuf.st_mode)) {
+               sum = 0L;
+               if (du_depth == 1) {
+               }
+       }
+       if (S_ISDIR(statbuf.st_mode)) {
+               DIR *dir;
+               struct dirent *entry;
+               char *newfile;
+
+               dir = opendir(filename);
+               if (!dir) {
+                       du_depth--;
+                       return 0;
+               }
+
+               newfile = last_char_is(filename, '/');
+               if (newfile)
+                       *newfile = '\0';
+
+               while ((entry = readdir(dir))) {
+                       char *name = entry->d_name;
+
+                       if ((strcmp(name, "..") == 0)
+                               || (strcmp(name, ".") == 0)) {
+                               continue;
+                       }
+                       newfile = concat_path_file(filename, name);
+                       sum += du(newfile);
+                       free(newfile);
+               }
+               closedir(dir);
+               print(sum, filename);
+       }
+       else if (statbuf.st_nlink > 1 && !count_hardlinks) {
+               /* Add files with hard links only once */
+               if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
+                       sum = 0L;
+                       if (du_depth == 1)
+                               print(sum, filename);
+               }
+               else {
+                       add_to_ino_dev_hashtable(&statbuf, NULL);
+               }
+       }
+       du_depth--;
+       return sum;
+}
+
+int du_main(int argc, char **argv)
+{
+       int status = EXIT_SUCCESS;
+       int i;
+       int c;
+
+       /* default behaviour */
+       print = print_normal;
+
+       /* parse argv[] */
+       while ((c = getopt(argc, argv, "slx"
+#ifdef BB_FEATURE_HUMAN_READABLE
+"hm"
+#endif
+"k")) != EOF) {
+                       switch (c) {
+                       case 's':
+                                       print = print_summary;
+                                       break;
+                       case 'l':
+                                       count_hardlinks = 1;
+                                       break;
+                       case 'x':
+                                       one_file_system = 1;
+                                       break;
+#ifdef BB_FEATURE_HUMAN_READABLE
+                       case 'h': disp_hr = 0;        break;
+                       case 'm': disp_hr = MEGABYTE; break;
+#endif
+                       case 'k': break;
+                       default:
+                                       show_usage();
+                       }
+       }
+
+       /* go through remaining args (if any) */
+       if (optind >= argc) {
+               if (du(".") == 0)
+                       status = EXIT_FAILURE;
+       } else {
+               long sum;
+
+               for (i=optind; i < argc; i++) {
+                       sum = du(argv[i]);
+                       if(is_directory(argv[i], FALSE, NULL)==FALSE) {
+                               print_normal(sum, argv[i]);
+                       }
+                       reset_ino_dev_hashtable();
+               }
+       }
+
+       return status;
+}
+
+/* $Id: du.c,v 1.53 2002/09/18 19:21:06 andersen Exp $ */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/dumpkmap.c b/dumpkmap.c
new file mode 100644 (file)
index 0000000..22652a5
--- /dev/null
@@ -0,0 +1,95 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dumpkmap implementation for busybox
+ *
+ * Copyright (C) Arne Bernin <arne@matrix.loopback.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+/* From <linux/kd.h> */
+struct kbentry {
+       unsigned char kb_table;
+       unsigned char kb_index;
+       unsigned short kb_value;
+};
+static const int KDGKBENT = 0x4B46;  /* gets one entry in translation table */
+
+/* From <linux/keyboard.h> */
+static const int NR_KEYS = 128;
+static const int MAX_NR_KEYMAPS = 256;
+
+int dumpkmap_main(int argc, char **argv)
+{
+       struct kbentry ke;
+       int i, j, fd;
+       char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap";
+
+       if (argc>=2 && *argv[1]=='-') {
+               show_usage();
+       }
+
+       fd = open(CURRENT_VC, O_RDWR);
+       if (fd < 0) {
+               perror_msg("Error opening " CURRENT_VC);
+               return EXIT_FAILURE;
+       }
+
+       write(1, magic, 7);
+
+       for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0;
+       flags[0]=1; 
+       flags[1]=1;
+       flags[2]=1;
+       flags[4]=1;
+       flags[5]=1;
+       flags[6]=1;
+       flags[8]=1;
+       flags[9]=1;
+       flags[10]=1;
+       flags[12]=1;
+       
+       /* dump flags */
+       for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); 
+
+       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
+               if (flags[i] == 1) {
+                       for (j = 0; j < NR_KEYS; j++) {
+                               ke.kb_index = j;
+                               ke.kb_table = i;
+                               if (ioctl(fd, KDGKBENT, &ke) < 0) {
+                               
+                                       error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value);
+                                       }
+                               else {
+                                       write(1,(void*)&ke.kb_value,2); 
+                                       }       
+                               
+                       }
+               }
+       }
+       close(fd);
+       return EXIT_SUCCESS;
+}
diff --git a/dutmp.c b/dutmp.c
new file mode 100644 (file)
index 0000000..9b9124a
--- /dev/null
+++ b/dutmp.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+ * 
+ * dutmp
+ * Takes utmp formated file on stdin and dumps it's contents 
+ * out in colon delimited fields. Easy to 'cut' for shell based 
+ * versions of 'who', 'last', etc. IP Addr is output in hex, 
+ * little endian on x86.
+ * 
+ * Modified to support all sorts of libcs by 
+ * Erik Andersen <andersen@codepoet.org>
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <utmp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include "busybox.h"
+
+extern int dutmp_main(int argc, char **argv)
+{
+
+       int file;
+       struct utmp ut;
+
+       if (argc<2) {
+               file = fileno(stdin);
+       } else if (*argv[1] == '-' ) {
+               show_usage();
+       } else  {
+               file = open(argv[1], O_RDONLY);
+               if (file < 0) {
+                       perror_msg_and_die(io_error, argv[1]);
+               }
+       }
+
+/* Kludge around the fact that the binary format for utmp has changed. */
+#if __GNU_LIBRARY__ < 5
+       /* Linux libc5 */
+       while (read(file, (void*)&ut, sizeof(struct utmp))) {
+               printf("%d|%d|%s|%s|%s|%s|%s|%lx\n",
+                               ut.ut_type, ut.ut_pid, ut.ut_line,
+                               ut.ut_id, ut.ut_user, ut.ut_host,
+                               ctime(&(ut.ut_time)), 
+                               (long)ut.ut_addr);
+       }
+#else
+       /* Glibc, uClibc, etc. */
+       while (read(file, (void*)&ut, sizeof(struct utmp))) {
+               printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n",
+               ut.ut_type, ut.ut_pid, ut.ut_line,
+               ut.ut_id, ut.ut_user,   ut.ut_host,
+               ut.ut_exit.e_termination, ut.ut_exit.e_exit,
+               ut.ut_session,
+               ut.ut_tv.tv_sec, ut.ut_tv.tv_usec,
+               ut.ut_addr);
+       }
+#endif
+       return EXIT_SUCCESS;
+}
diff --git a/echo.c b/echo.c
new file mode 100644 (file)
index 0000000..31c0315
--- /dev/null
+++ b/echo.c
@@ -0,0 +1,152 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * echo implementation for busybox
+ *
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int 
+echo_main(int argc, char** argv)
+{
+       int nflag = 0;
+       int eflag = 0;
+
+       /* Skip argv[0]. */
+       argc--;
+       argv++;
+
+       while (argc > 0 && *argv[0] == '-')
+       {
+               register char *temp;
+               register int ix;
+
+               /*
+                * If it appears that we are handling options, then make sure
+                * that all of the options specified are actually valid.
+                * Otherwise, the string should just be echoed.
+                */
+               temp = argv[0] + 1;
+
+               for (ix = 0; temp[ix]; ix++)
+               {
+                       if (strrchr("neE", temp[ix]) == 0)
+                               goto just_echo;
+               }
+
+               if (!*temp)
+                       goto just_echo;
+
+               /*
+                * All of the options in temp are valid options to echo.
+                * Handle them.
+                */
+               while (*temp)
+               {
+                       if (*temp == 'n')
+                               nflag = 1;
+                       else if (*temp == 'e')
+                               eflag = 1;
+                       else if (*temp == 'E')
+                               eflag = 0;
+                       else
+                               goto just_echo;
+
+                       temp++;
+               }
+               argc--;
+               argv++;
+       }
+
+just_echo:
+       while (argc > 0) {
+               const char *arg = argv[0];
+               register int c;
+
+               while ((c = *arg++)) {
+
+                       /* Check for escape sequence. */
+                       if (c == '\\' && eflag && *arg) {
+                               if (*arg == 'c') {
+                                       /* '\c' means cancel newline. */
+                                       nflag = 1;
+                                       arg++;
+                                       continue;
+                               } else {
+                                       c = process_escape_sequence(&arg);
+                               }
+                       }
+
+                       putchar(c);
+               }
+               argc--;
+               argv++;
+               if (argc > 0)
+                       putchar(' ');
+       }
+       if (!nflag)
+               putchar('\n');
+       fflush(stdout);
+
+       return EXIT_SUCCESS;
+}
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ *     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.
+ *
+ *     @(#)echo.c      8.1 (Berkeley) 5/31/93
+ */
diff --git a/env.c b/env.c
new file mode 100644 (file)
index 0000000..40a6001
--- /dev/null
+++ b/env.c
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * env implementation for busybox
+ *
+ * Copyright (c) 1988, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original copyright notice is retained at the end of this file.
+ *
+ * Modified for BusyBox by Erik Andersen <andersee@debian.org>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int env_main(int argc, char** argv)
+{
+       char **ep, *p;
+       char *cleanenv[1];
+       int ignore_environment = 0;
+       int ch;
+
+       while ((ch = getopt(argc, argv, "+iu:")) != -1) {
+               switch(ch) {
+               case 'i':
+                       ignore_environment = 1;
+                       break;
+               case 'u':
+                       unsetenv(optarg);
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+       if (optind != argc && !strcmp(argv[optind], "-")) {
+               ignore_environment = 1;
+               argv++;
+       }
+       if (ignore_environment) {
+               environ = cleanenv;
+               cleanenv[0] = NULL;
+       }
+       for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
+               if (putenv(*argv) < 0)
+                       perror_msg_and_die("%s", *argv);
+       if (*argv) {
+               execvp(*argv, argv);
+               perror_msg_and_die("%s", *argv);
+       }
+       for (ep = environ; *ep; ep++)
+               puts(*ep);
+       return 0;
+}
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ */
+
+
diff --git a/expr.c b/expr.c
new file mode 100644 (file)
index 0000000..d6cc82e
--- /dev/null
+++ b/expr.c
@@ -0,0 +1,535 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini expr implementation for busybox
+ *
+ * based on GNU expr Mike Parker.
+ * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
+ *
+ * Busybox modifications 
+ * Copyright (c) 2000  Edward Betts <edward@debian.org>.
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2 of the license, or
+ * (at your option) any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose. see the gnu
+ * general public license for more details.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program; if not, write to the free software
+ * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
+ *
+ */
+
+/* This program evaluates expressions.  Each token (operator, operand,
+ * parenthesis) of the expression must be a seperate argument.  The
+ * parser used is a reasonably general one, though any incarnation of
+ * it is language-specific.  It is especially nice for expressions.
+ *
+ * No parse tree is needed; a new node is evaluated immediately.
+ * One function can handle multiple operators all of equal precedence,
+ * provided they all associate ((x op x) op x). */
+
+/* no getopt needed */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+
+/* The kinds of value we can have.  */
+enum valtype {
+       integer,
+       string
+};
+typedef enum valtype TYPE;
+
+/* A value is.... */
+struct valinfo {
+       TYPE type;                      /* Which kind. */
+       union {                         /* The value itself. */
+               int i;
+               char *s;
+       } u;
+};
+typedef struct valinfo VALUE;
+
+/* The arguments given to the program, minus the program name.  */
+static char **args;
+
+static VALUE *docolon (VALUE *sv, VALUE *pv);
+static VALUE *eval (void);
+static VALUE *int_value (int i);
+static VALUE *str_value (char *s);
+static int nextarg (char *str);
+static int null (VALUE *v);
+static int toarith (VALUE *v);
+static void freev (VALUE *v);
+static void tostring (VALUE *v);
+
+int expr_main (int argc, char **argv)
+{
+       VALUE *v;
+
+       if (argc == 1) {
+               error_msg_and_die("too few arguments");
+       }
+
+       args = argv + 1;
+
+       v = eval ();
+       if (*args)
+               error_msg_and_die ("syntax error");
+
+       if (v->type == integer)
+               printf ("%d\n", v->u.i);
+       else
+               puts (v->u.s);
+
+       exit (null (v));
+}
+
+/* Return a VALUE for I.  */
+
+static VALUE *int_value (int i)
+{
+       VALUE *v;
+
+       v = xmalloc (sizeof(VALUE));
+       v->type = integer;
+       v->u.i = i;
+       return v;
+}
+
+/* Return a VALUE for S.  */
+
+static VALUE *str_value (char *s)
+{
+       VALUE *v;
+
+       v = xmalloc (sizeof(VALUE));
+       v->type = string;
+       v->u.s = strdup (s);
+       return v;
+}
+
+/* Free VALUE V, including structure components.  */
+
+static void freev (VALUE *v)
+{
+       if (v->type == string)
+               free (v->u.s);
+       free (v);
+}
+
+/* Return nonzero if V is a null-string or zero-number.  */
+
+static int null (VALUE *v)
+{
+       switch (v->type) {
+               case integer:
+                       return v->u.i == 0;
+               case string:
+                       return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
+               default:
+                       abort ();
+       }
+}
+
+/* Coerce V to a string value (can't fail).  */
+
+static void tostring (VALUE *v)
+{
+       char *temp;
+
+       if (v->type == integer) {
+               temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
+               sprintf (temp, "%d", v->u.i);
+               v->u.s = temp;
+               v->type = string;
+       }
+}
+
+/* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
+
+static int toarith (VALUE *v)
+{
+       int i;
+
+       switch (v->type) {
+               case integer:
+                       return 1;
+               case string:
+                       i = 0;
+                       /* Don't interpret the empty string as an integer.  */
+                       if (v->u.s == 0)
+                               return 0;
+                       i = atoi(v->u.s);
+                       free (v->u.s);
+                       v->u.i = i;
+                       v->type = integer;
+                       return 1;
+               default:
+                       abort ();
+       }
+}
+
+/* Return nonzero if the next token matches STR exactly.
+   STR must not be NULL.  */
+
+static int
+nextarg (char *str)
+{
+       if (*args == NULL)
+               return 0;
+       return strcmp (*args, str) == 0;
+}
+
+/* The comparison operator handling functions.  */
+
+#define cmpf(name, rel)                                        \
+static int name (l, r) VALUE *l; VALUE *r;             \
+{                                                      \
+       if (l->type == string || r->type == string) {           \
+               tostring (l);                           \
+               tostring (r);                           \
+               return strcmp (l->u.s, r->u.s) rel 0;   \
+       }                                               \
+       else                                            \
+               return l->u.i rel r->u.i;               \
+}
+ cmpf (less_than, <)
+ cmpf (less_equal, <=)
+ cmpf (equal, ==)
+ cmpf (not_equal, !=)
+ cmpf (greater_equal, >=)
+ cmpf (greater_than, >)
+
+#undef cmpf
+
+/* The arithmetic operator handling functions.  */
+
+#define arithf(name, op)                       \
+static                                         \
+int name (l, r) VALUE *l; VALUE *r;            \
+{                                              \
+  if (!toarith (l) || !toarith (r))            \
+    error_msg_and_die ("non-numeric argument");        \
+  return l->u.i op r->u.i;                     \
+}
+
+#define arithdivf(name, op)                    \
+static int name (l, r) VALUE *l; VALUE *r;             \
+{                                              \
+  if (!toarith (l) || !toarith (r))            \
+    error_msg_and_die ( "non-numeric argument");       \
+  if (r->u.i == 0)                             \
+    error_msg_and_die ( "division by zero");           \
+  return l->u.i op r->u.i;                     \
+}
+
+ arithf (plus, +)
+ arithf (minus, -)
+ arithf (multiply, *)
+ arithdivf (divide, /)
+ arithdivf (mod, %)
+
+#undef arithf
+#undef arithdivf
+
+/* Do the : operator.
+   SV is the VALUE for the lhs (the string),
+   PV is the VALUE for the rhs (the pattern).  */
+
+static VALUE *docolon (VALUE *sv, VALUE *pv)
+{
+       VALUE *v;
+       const char *errmsg;
+       struct re_pattern_buffer re_buffer;
+       struct re_registers re_regs;
+       int len;
+
+       tostring (sv);
+       tostring (pv);
+
+       if (pv->u.s[0] == '^') {
+               fprintf (stderr, "\
+warning: unportable BRE: `%s': using `^' as the first character\n\
+of a basic regular expression is not portable; it is being ignored",
+               pv->u.s);
+       }
+
+       len = strlen (pv->u.s);
+       memset (&re_buffer, 0, sizeof (re_buffer));
+       memset (&re_regs, 0, sizeof (re_regs));
+       re_buffer.allocated = 2 * len;
+       re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
+       re_buffer.translate = 0;
+       re_syntax_options = RE_SYNTAX_POSIX_BASIC;
+       errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
+       if (errmsg) {
+               error_msg_and_die("%s", errmsg);
+       }
+
+       len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
+       if (len >= 0) {
+               /* Were \(...\) used? */
+               if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
+                       sv->u.s[re_regs.end[1]] = '\0';
+                       v = str_value (sv->u.s + re_regs.start[1]);
+               }
+               else
+                       v = int_value (len);
+       }
+       else {
+               /* Match failed -- return the right kind of null.  */
+               if (re_buffer.re_nsub > 0)
+                       v = str_value ("");
+               else
+                       v = int_value (0);
+       }
+       free (re_buffer.buffer);
+       return v;
+}
+
+/* Handle bare operands and ( expr ) syntax.  */
+
+static VALUE *eval7 (void)
+{
+       VALUE *v;
+
+       if (!*args)
+               error_msg_and_die ( "syntax error");
+
+       if (nextarg ("(")) {
+               args++;
+               v = eval ();
+               if (!nextarg (")"))
+                       error_msg_and_die ( "syntax error");
+                       args++;
+                       return v;
+               }
+
+       if (nextarg (")"))
+               error_msg_and_die ( "syntax error");
+
+       return str_value (*args++);
+}
+
+/* Handle match, substr, index, length, and quote keywords.  */
+
+static VALUE *eval6 (void)
+{
+       VALUE *l, *r, *v, *i1, *i2;
+
+       if (nextarg ("quote")) {
+               args++;
+               if (!*args)
+                       error_msg_and_die ( "syntax error");
+               return str_value (*args++);
+       }
+       else if (nextarg ("length")) {
+               args++;
+               r = eval6 ();
+               tostring (r);
+               v = int_value (strlen (r->u.s));
+               freev (r);
+               return v;
+       }
+       else if (nextarg ("match")) {
+               args++;
+               l = eval6 ();
+               r = eval6 ();
+               v = docolon (l, r);
+               freev (l);
+               freev (r);
+               return v;
+       }
+       else if (nextarg ("index")) {
+               args++;
+               l = eval6 ();
+               r = eval6 ();
+               tostring (l);
+               tostring (r);
+               v = int_value (strcspn (l->u.s, r->u.s) + 1);
+               if (v->u.i == (int) strlen (l->u.s) + 1)
+                       v->u.i = 0;
+               freev (l);
+               freev (r);
+               return v;
+       }
+       else if (nextarg ("substr")) {
+               args++;
+               l = eval6 ();
+               i1 = eval6 ();
+               i2 = eval6 ();
+               tostring (l);
+               if (!toarith (i1) || !toarith (i2)
+                       || i1->u.i > (int) strlen (l->u.s)
+                       || i1->u.i <= 0 || i2->u.i <= 0)
+               v = str_value ("");
+               else {
+                       v = xmalloc (sizeof(VALUE));
+                       v->type = string;
+                       v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
+                               l->u.s + i1->u.i - 1, i2->u.i);
+                               v->u.s[i2->u.i] = 0;
+               }
+               freev (l);
+               freev (i1);
+               freev (i2);
+               return v;
+       }
+       else
+               return eval7 ();
+}
+
+/* Handle : operator (pattern matching).
+   Calls docolon to do the real work.  */
+
+static VALUE *eval5 (void)
+{
+       VALUE *l, *r, *v;
+
+       l = eval6 ();
+       while (nextarg (":")) {
+               args++;
+               r = eval6 ();
+               v = docolon (l, r);
+               freev (l);
+               freev (r);
+               l = v;
+       }
+       return l;
+}
+
+/* Handle *, /, % operators.  */
+
+static VALUE *eval4 (void)
+{
+       VALUE *l, *r;
+       int (*fxn) (), val;
+
+       l = eval5 ();
+       while (1) {
+               if (nextarg ("*"))
+                       fxn = multiply;
+               else if (nextarg ("/"))
+                       fxn = divide;
+               else if (nextarg ("%"))
+                       fxn = mod;
+               else
+                       return l;
+               args++;
+               r = eval5 ();
+               val = (*fxn) (l, r);
+               freev (l);
+               freev (r);
+               l = int_value (val);
+       }
+}
+
+/* Handle +, - operators.  */
+
+static VALUE *eval3 (void)
+{
+       VALUE *l, *r;
+       int (*fxn) (), val;
+
+       l = eval4 ();
+       while (1) {
+               if (nextarg ("+"))
+                       fxn = plus;
+               else if (nextarg ("-"))
+                       fxn = minus;
+               else
+                       return l;
+               args++;
+               r = eval4 ();
+               val = (*fxn) (l, r);
+               freev (l);
+               freev (r);
+               l = int_value (val);
+       }
+}
+
+/* Handle comparisons.  */
+
+static VALUE *eval2 (void)
+{
+       VALUE *l, *r;
+       int (*fxn) (), val;
+
+       l = eval3 ();
+       while (1) {
+               if (nextarg ("<"))
+                       fxn = less_than;
+               else if (nextarg ("<="))
+                       fxn = less_equal;
+               else if (nextarg ("=") || nextarg ("=="))
+                       fxn = equal;
+               else if (nextarg ("!="))
+                       fxn = not_equal;
+               else if (nextarg (">="))
+                       fxn = greater_equal;
+               else if (nextarg (">"))
+                       fxn = greater_than;
+               else
+                       return l;
+               args++;
+               r = eval3 ();
+               toarith (l);
+               toarith (r);
+               val = (*fxn) (l, r);
+               freev (l);
+               freev (r);
+               l = int_value (val);
+       }
+}
+
+/* Handle &.  */
+
+static VALUE *eval1 (void)
+{
+       VALUE *l, *r;
+
+       l = eval2 ();
+       while (nextarg ("&")) {
+               args++;
+               r = eval2 ();
+               if (null (l) || null (r)) {
+                       freev (l);
+                       freev (r);
+                       l = int_value (0);
+               }
+               else
+                       freev (r);
+       }
+       return l;
+}
+
+/* Handle |.  */
+
+static VALUE *eval (void)
+{
+       VALUE *l, *r;
+
+       l = eval1 ();
+       while (nextarg ("|")) {
+               args++;
+               r = eval1 ();
+               if (null (l)) {
+                       freev (l);
+                       l = r;
+               }
+               else
+                       freev (r);
+       }
+       return l;
+}
diff --git a/fbset.c b/fbset.c
new file mode 100644 (file)
index 0000000..8daee66
--- /dev/null
+++ b/fbset.c
@@ -0,0 +1,427 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini fbset implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This is a from-scratch implementation of fbset; but the de facto fbset
+ * implementation was a good reference. fbset (original) is released under
+ * the GPL, and is (c) 1995-1999 by: 
+ *     Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+#define DEFAULTFBDEV  "/dev/fb0"
+#define DEFAULTFBMODE "/etc/fb.modes"
+
+static const int OPT_CHANGE   = (1 << 0);
+static const int OPT_INFO     = (1 << 1);
+static const int OPT_READMODE = (1 << 2);
+
+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_CHANGE = 13,
+
+#ifdef BB_FEATURE_FBSET_FANCY
+       CMD_XRES = 100,
+       CMD_YRES = 101,
+       CMD_VXRES = 102,
+       CMD_VYRES = 103,
+       CMD_DEPTH = 104,
+       CMD_MATCH = 105,
+       CMD_PIXCLOCK = 106,
+       CMD_LEFT = 107,
+       CMD_RIGHT = 108,
+       CMD_UPPER = 109,
+       CMD_LOWER = 110,
+       CMD_HSLEN = 111,
+       CMD_VSLEN = 112,
+       CMD_CSYNC = 113,
+       CMD_GSYNC = 114,
+       CMD_EXTSYNC = 115,
+       CMD_BCAST = 116,
+       CMD_RGBA = 117,
+       CMD_STEP = 118,
+       CMD_MOVE = 119,
+#endif
+};
+
+static unsigned int g_options = 0;
+
+/* Stuff stolen from the kernel's fb.h */
+static const int FBIOGET_VSCREENINFO = 0x4600;
+static const int FBIOPUT_VSCREENINFO = 0x4601;
+#define __u32                  u_int32_t
+struct fb_bitfield {
+       __u32 offset;                   /* beginning of bitfield        */
+       __u32 length;                   /* length of bitfield           */
+       __u32 msb_right;                /* != 0 : Most significant bit is */ 
+                                       /* right */ 
+};
+struct fb_var_screeninfo {
+       __u32 xres;                     /* visible resolution           */
+       __u32 yres;
+       __u32 xres_virtual;             /* virtual resolution           */
+       __u32 yres_virtual;
+       __u32 xoffset;                  /* offset from virtual to visible */
+       __u32 yoffset;                  /* resolution                   */
+
+       __u32 bits_per_pixel;           /* guess what                   */
+       __u32 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                 */      
+
+       __u32 nonstd;                   /* != 0 Non standard pixel format */
+
+       __u32 activate;                 /* see FB_ACTIVATE_*            */
+
+       __u32 height;                   /* height of picture in mm    */
+       __u32 width;                    /* width of picture in mm     */
+
+       __u32 accel_flags;              /* acceleration flags (hints)   */
+
+       /* Timing: All values in pixclocks, except pixclock (of course) */
+       __u32 pixclock;                 /* pixel clock in ps (pico seconds) */
+       __u32 left_margin;              /* time from sync to picture    */
+       __u32 right_margin;             /* time from picture to sync    */
+       __u32 upper_margin;             /* time from sync to picture    */
+       __u32 lower_margin;
+       __u32 hsync_len;                /* length of horizontal sync    */
+       __u32 vsync_len;                /* length of vertical sync      */
+       __u32 sync;                     /* see FB_SYNC_*                */
+       __u32 vmode;                    /* see FB_VMODE_*               */
+       __u32 reserved[6];              /* Reserved for future compatibility */
+};
+
+
+static struct cmdoptions_t {
+       char *name;
+       unsigned char param_count;
+       unsigned char code;
+} g_cmdoptions[] = {
+       {
+       "-fb", 1, CMD_FB}, {
+       "-db", 1, CMD_DB}, {
+       "-a", 0, CMD_ALL}, {
+       "-i", 0, CMD_INFO}, {
+       "-g", 5, CMD_GEOMETRY}, {
+       "-t", 7, CMD_TIMING}, {
+       "-accel", 1, CMD_ACCEL}, {
+       "-hsync", 1, CMD_HSYNC}, {
+       "-vsync", 1, CMD_VSYNC}, {
+       "-laced", 1, CMD_LACED}, {
+       "-double", 1, CMD_DOUBLE}, {
+       "-n", 0, CMD_CHANGE}, {
+#ifdef BB_FEATURE_FBSET_FANCY
+       "-all", 0, CMD_ALL}, {
+       "-xres", 1, CMD_XRES}, {
+       "-yres", 1, CMD_YRES}, {
+       "-vxres", 1, CMD_VXRES}, {
+       "-vyres", 1, CMD_VYRES}, {
+       "-depth", 1, CMD_DEPTH}, {
+       "-match", 0, CMD_MATCH}, {
+       "-geometry", 5, CMD_GEOMETRY}, {
+       "-pixclock", 1, CMD_PIXCLOCK}, {
+       "-left", 1, CMD_LEFT}, {
+       "-right", 1, CMD_RIGHT}, {
+       "-upper", 1, CMD_UPPER}, {
+       "-lower", 1, CMD_LOWER}, {
+       "-hslen", 1, CMD_HSLEN}, {
+       "-vslen", 1, CMD_VSLEN}, {
+       "-timings", 7, CMD_TIMING}, {
+       "-csync", 1, CMD_CSYNC}, {
+       "-gsync", 1, CMD_GSYNC}, {
+       "-extsync", 1, CMD_EXTSYNC}, {
+       "-bcast", 1, CMD_BCAST}, {
+       "-rgba", 1, CMD_RGBA}, {
+       "-step", 1, CMD_STEP}, {
+       "-move", 1, CMD_MOVE}, {
+#endif
+       0, 0, 0}
+};
+
+#ifdef BB_FEATURE_FBSET_READMODE
+/* taken from linux/fb.h */
+static const int FB_VMODE_INTERLACED = 1;      /* interlaced   */
+static const int FB_VMODE_DOUBLE = 2;  /* double scan */
+static const int FB_SYNC_HOR_HIGH_ACT = 1;     /* horizontal sync high active  */
+static const int FB_SYNC_VERT_HIGH_ACT = 2;    /* vertical sync high active    */
+static const int FB_SYNC_EXT = 4;      /* external sync                */
+static const int FB_SYNC_COMP_HIGH_ACT = 8;    /* composite sync high active   */
+#endif
+static int readmode(struct fb_var_screeninfo *base, const char *fn,
+                                       const char *mode)
+{
+#ifdef BB_FEATURE_FBSET_READMODE
+       FILE *f;
+       char buf[256];
+       char *p = buf;
+
+       f = xfopen(fn, "r");
+       while (!feof(f)) {
+               fgets(buf, sizeof(buf), f);
+               if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) {
+                       p += 5;
+                       if ((p = strstr(buf, mode))) {
+                               p += strlen(mode);
+                               if (!isspace(*p) && (*p != 0) && (*p != '"')
+                                       && (*p != '\r') && (*p != '\n'))
+                                       continue;       /* almost, but not quite */
+                               while (!feof(f)) {
+                                       fgets(buf, sizeof(buf), f);
+
+                    if ((p = strstr(buf, "geometry "))) {
+                        p += 9;
+
+                        sscanf(p, "%d %d %d %d %d", 
+                                &(base->xres), &(base->yres), 
+                                &(base->xres_virtual), &(base->yres_virtual), 
+                                &(base->bits_per_pixel));
+                    } else if ((p = strstr(buf, "timings "))) {
+                        p += 8;
+                        
+                        sscanf(p, "%d %d %d %d %d %d %d",
+                                &(base->pixclock),
+                                &(base->left_margin), &(base->right_margin),
+                                &(base->upper_margin), &(base->lower_margin),
+                                &(base->hsync_len), &(base->vsync_len));
+                    } else if ((p = strstr(buf, "laced "))) {
+                        p += 6;
+
+                        if (strstr(buf, "false")) {
+                            base->vmode &= ~FB_VMODE_INTERLACED;
+                        } else {
+                            base->vmode |= FB_VMODE_INTERLACED;
+                        }
+                    } else if ((p = strstr(buf, "double "))) {
+                        p += 7;
+
+                        if (strstr(buf, "false")) {
+                            base->vmode &= ~FB_VMODE_DOUBLE;
+                        } else {
+                            base->vmode |= FB_VMODE_DOUBLE;
+                        }
+                    } else if ((p = strstr(buf, "vsync "))) {
+                        p += 6;
+
+                        if (strstr(buf, "low")) {
+                            base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+                        } else {
+                            base->sync |= FB_SYNC_VERT_HIGH_ACT;
+                        }
+                    } else if ((p = strstr(buf, "hsync "))) {
+                        p += 6;
+
+                        if (strstr(buf, "low")) {
+                            base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+                        } else {
+                            base->sync |= FB_SYNC_HOR_HIGH_ACT;
+                        }
+                    } else if ((p = strstr(buf, "csync "))) {
+                        p += 6;
+
+                        if (strstr(buf, "low")) {
+                            base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
+                        } else {
+                            base->sync |= FB_SYNC_COMP_HIGH_ACT;
+                        }
+                    } else if ((p = strstr(buf, "extsync "))) {
+                        p += 8;
+
+                        if (strstr(buf, "false")) {
+                            base->sync &= ~FB_SYNC_EXT;
+                        } else {
+                            base->sync |= FB_SYNC_EXT;
+                        }
+                    }
+                    
+                                       if (strstr(buf, "endmode"))
+                                               return 1;
+                               }
+                       }
+               }
+       }
+#else
+       error_msg( "mode reading not compiled in");
+#endif
+       return 0;
+}
+
+static void setmode(struct fb_var_screeninfo *base,
+                                       struct fb_var_screeninfo *set)
+{
+       if ((int) set->xres > 0)
+               base->xres = set->xres;
+       if ((int) set->yres > 0)
+               base->yres = set->yres;
+       if ((int) set->xres_virtual > 0)
+               base->xres_virtual = set->xres_virtual;
+       if ((int) set->yres_virtual > 0)
+               base->yres_virtual = set->yres_virtual;
+       if ((int) set->bits_per_pixel > 0)
+               base->bits_per_pixel = set->bits_per_pixel;
+}
+
+static 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", v->xres, v->yres, (int) (vrate + 0.5));
+#ifdef BB_FEATURE_FBSET_FANCY
+       printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6,
+                  hrate / 1e3, vrate);
+#endif
+       printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres,
+                  v->xres_virtual, v->yres_virtual, v->bits_per_pixel);
+       printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin,
+                  v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len,
+                  v->vsync_len);
+       printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false"));
+       printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length,
+                  v->red.offset, v->green.length, v->green.offset, v->blue.length,
+                  v->blue.offset, v->transp.length, v->transp.offset);
+       printf("endmode\n\n");
+}
+
+#ifdef STANDALONE
+int main(int argc, char **argv)
+#else
+extern int fbset_main(int argc, char **argv)
+#endif
+{
+       struct fb_var_screeninfo var, varset;
+       int fh, i;
+       char *fbdev = DEFAULTFBDEV;
+       char *modefile = DEFAULTFBMODE;
+       char *thisarg, *mode = NULL;
+
+       memset(&varset, 0xFF, sizeof(varset));
+
+       /* parse cmd args.... why do they have to make things so difficult? */
+       argv++;
+       argc--;
+       for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
+               for (i = 0; g_cmdoptions[i].name; i++) {
+                       if (!strcmp(thisarg, g_cmdoptions[i].name)) {
+                               if (argc - 1 < g_cmdoptions[i].param_count)
+                                       show_usage();
+                               switch (g_cmdoptions[i].code) {
+                               case CMD_FB:
+                                       fbdev = argv[1];
+                                       break;
+                               case CMD_DB:
+                                       modefile = argv[1];
+                                       break;
+                               case CMD_GEOMETRY:
+                                       varset.xres = strtoul(argv[1], 0, 0);
+                                       varset.yres = strtoul(argv[2], 0, 0);
+                                       varset.xres_virtual = strtoul(argv[3], 0, 0);
+                                       varset.yres_virtual = strtoul(argv[4], 0, 0);
+                                       varset.bits_per_pixel = strtoul(argv[5], 0, 0);
+                                       break;
+                               case CMD_TIMING:
+                                       varset.pixclock = strtoul(argv[1], 0, 0);
+                                       varset.left_margin = strtoul(argv[2], 0, 0);
+                                       varset.right_margin = strtoul(argv[3], 0, 0);
+                                       varset.upper_margin = strtoul(argv[4], 0, 0);
+                                       varset.lower_margin = strtoul(argv[5], 0, 0);
+                                       varset.hsync_len = strtoul(argv[6], 0, 0);
+                                       varset.vsync_len = strtoul(argv[7], 0, 0);
+                                       break;
+                case CMD_CHANGE:
+                    g_options |= OPT_CHANGE;
+                    break;
+#ifdef BB_FEATURE_FBSET_FANCY
+                               case CMD_XRES:
+                                       varset.xres = strtoul(argv[1], 0, 0);
+                                       break;
+                               case CMD_YRES:
+                                       varset.yres = strtoul(argv[1], 0, 0);
+                                       break;
+                               case CMD_DEPTH:
+                                       varset.bits_per_pixel = strtoul(argv[1], 0, 0);
+                                       break;
+#endif
+                               }
+                               argc -= g_cmdoptions[i].param_count;
+                               argv += g_cmdoptions[i].param_count;
+                               break;
+                       }
+               }
+               if (!g_cmdoptions[i].name) {
+                       if (argc == 1) {
+                               mode = *argv;
+                               g_options |= OPT_READMODE;
+                       } else {
+                               show_usage();
+                       }
+               }
+       }
+
+       if ((fh = open(fbdev, O_RDONLY)) < 0)
+               perror_msg_and_die("fbset(open)");
+       if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
+               perror_msg_and_die("fbset(ioctl)");
+       if (g_options & OPT_READMODE) {
+               if (!readmode(&var, modefile, mode)) {
+                       error_msg("Unknown video mode `%s'", mode);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       setmode(&var, &varset);
+       if (g_options & OPT_CHANGE)
+               if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
+                       perror_msg_and_die("fbset(ioctl)");
+       showmode(&var);
+       /* Don't close the file, as exiting will take care of that */
+       /* close(fh); */
+
+       return EXIT_SUCCESS;
+}
diff --git a/fdflush.c b/fdflush.c
new file mode 100644 (file)
index 0000000..28f5cb6
--- /dev/null
+++ b/fdflush.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini fdflush implementation for busybox
+ *
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+/* From <linux/fd.h> */
+#define FDFLUSH  _IO(2,0x4b)
+
+extern int fdflush_main(int argc, char **argv)
+{
+       int fd;
+
+       if (argc <= 1 || **(++argv) == '-')
+               show_usage();
+
+       if ((fd = open(*argv, 0)) < 0)
+               perror_msg_and_die("%s", *argv);
+
+       if (ioctl(fd, FDFLUSH, 0))
+               perror_msg_and_die("%s", *argv);
+
+       return EXIT_SUCCESS;
+}
diff --git a/find.c b/find.c
new file mode 100644 (file)
index 0000000..46dd914
--- /dev/null
+++ b/find.c
@@ -0,0 +1,220 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini find implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * Reworked by David Douthitt <n9ubh@callsign.net> and
+ *  Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <time.h>
+#include <ctype.h>
+#include "busybox.h"
+
+
+static char *pattern;
+
+#ifdef BB_FEATURE_FIND_TYPE
+static int type_mask = 0;
+#endif
+
+#ifdef BB_FEATURE_FIND_PERM
+static char perm_char = 0;
+static int perm_mask = 0;
+#endif
+
+#ifdef BB_FEATURE_FIND_MTIME
+static char mtime_char;
+static int mtime_days;
+#endif
+
+#ifdef BB_FEATURE_FIND_NEWER
+time_t newer_mtime;
+#endif
+
+static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+       if (pattern != NULL) {
+               const char *tmp = strrchr(fileName, '/');
+
+               if (tmp == NULL)
+                       tmp = fileName;
+               else
+                       tmp++;
+               if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
+                       goto no_match;
+       }
+#ifdef BB_FEATURE_FIND_TYPE
+       if (type_mask != 0) {
+               if (!((statbuf->st_mode & S_IFMT) == type_mask))
+                       goto no_match;
+       }
+#endif
+#ifdef BB_FEATURE_FIND_PERM
+       if (perm_mask != 0) {
+               if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
+                        (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
+                        (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
+                       goto no_match;
+       }
+#endif
+#ifdef BB_FEATURE_FIND_MTIME
+       if (mtime_char != 0) {
+               time_t file_age = time(NULL) - statbuf->st_mtime;
+               time_t mtime_secs = mtime_days * 24 * 60 * 60;
+               if (!((isdigit(mtime_char) && file_age >= mtime_secs &&
+                                               file_age < mtime_secs + 24 * 60 * 60) ||
+                                       (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) ||
+                                       (mtime_char == '-' && file_age < mtime_secs)))
+                       goto no_match;
+       }
+#endif
+#ifdef BB_FEATURE_FIND_NEWER
+       if (newer_mtime != 0) {
+               time_t file_age = newer_mtime - statbuf->st_mtime;
+               if (file_age >= 0)
+                       goto no_match;
+       }
+#endif
+       puts(fileName);
+no_match:
+       return (TRUE);
+}
+
+#ifdef BB_FEATURE_FIND_TYPE
+static int find_type(char *type)
+{
+       int mask = 0;
+
+       switch (type[0]) {
+               case 'b':
+                       mask = S_IFBLK;
+                       break;
+               case 'c':
+                       mask = S_IFCHR;
+                       break;
+               case 'd':
+                       mask = S_IFDIR;
+                       break;
+               case 'p':
+                       mask = S_IFIFO;
+                       break;
+               case 'f':
+                       mask = S_IFREG;
+                       break;
+               case 'l':
+                       mask = S_IFLNK;
+                       break;
+               case 's':
+                       mask = S_IFSOCK;
+                       break;
+       }
+
+       if (mask == 0 || type[1] != '\0')
+               error_msg_and_die("invalid argument `%s' to `-type'", type);
+
+       return mask;
+}
+#endif
+
+int find_main(int argc, char **argv)
+{
+       int dereference = FALSE;
+       int i, firstopt, status = EXIT_SUCCESS;
+
+       for (firstopt = 1; firstopt < argc; firstopt++) {
+               if (argv[firstopt][0] == '-')
+                       break;
+       }
+
+       /* Parse any options */
+       for (i = firstopt; i < argc; i++) {
+               if (strcmp(argv[i], "-follow") == 0)
+                       dereference = TRUE;
+               else if (strcmp(argv[i], "-print") == 0) {
+                       ;
+                       }
+               else if (strcmp(argv[i], "-name") == 0) {
+                       if (++i == argc)
+                               error_msg_and_die("option `-name' requires an argument");
+                       pattern = argv[i];
+#ifdef BB_FEATURE_FIND_TYPE
+               } else if (strcmp(argv[i], "-type") == 0) {
+                       if (++i == argc)
+                               error_msg_and_die("option `-type' requires an argument");
+                       type_mask = find_type(argv[i]);
+#endif
+#ifdef BB_FEATURE_FIND_PERM
+               } else if (strcmp(argv[i], "-perm") == 0) {
+                       char *end;
+                       if (++i == argc)
+                               error_msg_and_die("option `-perm' requires an argument");
+                       perm_mask = strtol(argv[i], &end, 8);
+                       if (end[0] != '\0')
+                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
+                       if (perm_mask > 07777)
+                               error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]);
+                       if ((perm_char = argv[i][0]) == '-')
+                               perm_mask = -perm_mask;
+#endif
+#ifdef BB_FEATURE_FIND_MTIME
+               } else if (strcmp(argv[i], "-mtime") == 0) {
+                       char *end;
+                       if (++i == argc)
+                               error_msg_and_die("option `-mtime' requires an argument");
+                       mtime_days = strtol(argv[i], &end, 10);
+                       if (end[0] != '\0')
+                               error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]);
+                       if ((mtime_char = argv[i][0]) == '-')
+                               mtime_days = -mtime_days;
+#endif
+#ifdef BB_FEATURE_FIND_NEWER
+               } else if (strcmp(argv[i], "-newer") == 0) {
+                       struct stat stat_newer;
+                       if (++i == argc)
+                               error_msg_and_die("option `-newer' requires an argument");
+                   if (stat (argv[i], &stat_newer) != 0)
+                               error_msg_and_die("file %s not found", argv[i]);
+                       newer_mtime = stat_newer.st_mtime;
+#endif
+               } else
+                       show_usage();
+       }
+
+       if (firstopt == 1) {
+               if (recursive_action(".", TRUE, dereference, FALSE, fileAction,
+                                       fileAction, NULL) == FALSE)
+                       status = EXIT_FAILURE;
+       } else {
+               for (i = 1; i < firstopt; i++) {
+                       if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
+                                               fileAction, NULL) == FALSE)
+                               status = EXIT_FAILURE;
+               }
+       }
+
+       return status;
+}
diff --git a/free.c b/free.c
new file mode 100644 (file)
index 0000000..4a5469b
--- /dev/null
+++ b/free.c
@@ -0,0 +1,85 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini free implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int free_main(int argc, char **argv)
+{
+       struct sysinfo info;
+       sysinfo(&info);
+
+       /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
+       if (info.mem_unit==0) {
+               info.mem_unit=1;
+       }
+       if ( info.mem_unit == 1 ) {
+               info.mem_unit=1024;
+
+               /* TODO:  Make all this stuff not overflow when mem >= 4 Gib */
+               info.totalram/=info.mem_unit;
+               info.freeram/=info.mem_unit;
+#ifndef __uClinux__
+               info.totalswap/=info.mem_unit;
+               info.freeswap/=info.mem_unit;
+#endif
+               info.sharedram/=info.mem_unit;
+               info.bufferram/=info.mem_unit;
+       } else {
+               info.mem_unit/=1024;
+               /* TODO:  Make all this stuff not overflow when mem >= 4 Gib */
+               info.totalram*=info.mem_unit;
+               info.freeram*=info.mem_unit;
+#ifndef __uClinux__
+               info.totalswap*=info.mem_unit;
+               info.freeswap*=info.mem_unit;
+#endif
+               info.sharedram*=info.mem_unit;
+               info.bufferram*=info.mem_unit;
+       }
+
+       if (argc > 1 && **(argv + 1) == '-')
+               show_usage();
+
+       printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", 
+                       "shared", "buffers");
+
+       printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, 
+                       info.totalram-info.freeram, info.freeram, 
+                       info.sharedram, info.bufferram);
+
+#ifndef __uClinux__
+       printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap,
+                       info.totalswap-info.freeswap, info.freeswap);
+
+       printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap,
+                       (info.totalram-info.freeram)+(info.totalswap-info.freeswap),
+                       info.freeram+info.freeswap);
+#endif
+       return EXIT_SUCCESS;
+}
+
diff --git a/freeramdisk.c b/freeramdisk.c
new file mode 100644 (file)
index 0000000..cf25fae
--- /dev/null
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * freeramdisk implementation for busybox
+ *
+ * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
+ * Adjusted a bit by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+
+/* From linux/fs.h */
+#define BLKFLSBUF  _IO(0x12,97)        /* flush buffer cache */
+
+extern int
+freeramdisk_main(int argc, char **argv)
+{
+       int   f;
+
+       if (argc != 2 || *argv[1] == '-') {
+               show_usage();
+       }
+
+       if ((f = open(argv[1], O_RDWR)) == -1) {
+               perror_msg_and_die("cannot open %s", argv[1]);
+       }
+       if (ioctl(f, BLKFLSBUF) < 0) {
+               perror_msg_and_die("failed ioctl on %s", argv[1]);
+       }
+       /* Don't bother closing.  Exit does
+        * that, so we can save a few bytes */
+       /* close(f); */
+       return EXIT_SUCCESS;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
diff --git a/fsck_minix.c b/fsck_minix.c
new file mode 100644 (file)
index 0000000..952968d
--- /dev/null
@@ -0,0 +1,1478 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fsck.c - a file system consistency checker for Linux.
+ *
+ * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
+ * as per the GNU copyleft.
+ */
+
+/*
+ * 09.11.91  -  made the first rudimetary functions
+ *
+ * 10.11.91  -  updated, does checking, no repairs yet.
+ *             Sent out to the mailing-list for testing.
+ *
+ * 14.11.91  - Testing seems to have gone well. Added some
+ *             correction-code, and changed some functions.
+ *
+ * 15.11.91  -  More correction code. Hopefully it notices most
+ *             cases now, and tries to do something about them.
+ *
+ * 16.11.91  -  More corrections (thanks to Mika Jalava). Most
+ *             things seem to work now. Yeah, sure.
+ *
+ *
+ * 19.04.92  - Had to start over again from this old version, as a
+ *             kernel bug ate my enhanced fsck in february.
+ *
+ * 28.02.93  - added support for different directory entry sizes..
+ *
+ * Sat Mar  6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
+ *                           super-block information
+ *
+ * Sat Oct  9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
+ *                           to that required by fsutil
+ *
+ * Mon Jan  3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
+ *                           Added support for file system valid flag.  Also
+ *                           added program_version variable and output of
+ *                           program name and version number when program
+ *                           is executed.
+ *
+ * 30.10.94 - added support for v2 filesystem
+ *            (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ *
+ * 10.12.94  -  added test to prevent checking of mounted fs adapted
+ *              from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
+ *              program.  (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 01.07.96  - Fixed the v2 fs stuff to use the right #defines and such
+ *            for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 02.07.96  - Added C bit fiddling routines from rmk@ecs.soton.ac.uk 
+ *             (Russell King).  He made them for ARM.  It would seem
+ *            that the ARM is powerful enough to do this in C whereas
+ *             i386 and m64k must use assembly to get it fast >:-)
+ *            This should make minix fsck systemindependent.
+ *            (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 04.11.96  - Added minor fixes from Andreas Schwab to avoid compiler
+ *             warnings.  Added mc68k bitops from 
+ *            Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
+ *
+ * 06.11.96  - Added v2 code submitted by Joerg Dorchain, but written by
+ *             Andreas Schwab.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ *
+ * I've had no time to add comments - hopefully the function names
+ * are comments enough. As with all file system checkers, this assumes
+ * the file system is quiescent - don't use it on a mounted device
+ * unless you can be sure nobody is writing to it (and remember that the
+ * kernel can write to it when it searches for files).
+ *
+ * Usuage: fsck [-larvsm] device
+ *     -l for a listing of all the filenames
+ *     -a for automatic repairs (not implemented)
+ *     -r for repairs (interactive) (not implemented)
+ *     -v for verbose (tells how many files)
+ *     -s for super-block info
+ *     -m for minix-like "mode not cleared" warnings
+ *     -f force filesystem check even if filesystem marked as valid
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-). 
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <mntent.h>
+#include <sys/param.h>
+#include "busybox.h"
+
+static const int MINIX_ROOT_INO = 1;
+static const int MINIX_LINK_MAX = 250;
+static const int MINIX2_LINK_MAX = 65530;
+
+static const int MINIX_I_MAP_SLOTS = 8;
+static const int MINIX_Z_MAP_SLOTS = 64;
+static const int MINIX_SUPER_MAGIC = 0x137F;           /* original minix fs */
+static const int MINIX_SUPER_MAGIC2 = 0x138F;          /* minix fs, 30 char names */
+static const int MINIX2_SUPER_MAGIC = 0x2468;          /* minix V2 fs */
+static const int MINIX2_SUPER_MAGIC2 = 0x2478;         /* minix V2 fs, 30 char names */
+static const int MINIX_VALID_FS = 0x0001;              /* Clean fs. */
+static const int MINIX_ERROR_FS = 0x0002;              /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+static const int MINIX_V1 = 0x0001;            /* original minix fs */
+static const int MINIX_V2 = 0x0002;            /* minix V2 fs */
+
+#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+       u_int16_t i_mode;
+       u_int16_t i_uid;
+       u_int32_t i_size;
+       u_int32_t i_time;
+       u_int8_t  i_gid;
+       u_int8_t  i_nlinks;
+       u_int16_t i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+       u_int16_t i_mode;
+       u_int16_t i_nlinks;
+       u_int16_t i_uid;
+       u_int16_t i_gid;
+       u_int32_t i_size;
+       u_int32_t i_atime;
+       u_int32_t i_mtime;
+       u_int32_t i_ctime;
+       u_int32_t i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+       u_int16_t s_ninodes;
+       u_int16_t s_nzones;
+       u_int16_t s_imap_blocks;
+       u_int16_t s_zmap_blocks;
+       u_int16_t s_firstdatazone;
+       u_int16_t s_log_zone_size;
+       u_int32_t s_max_size;
+       u_int16_t s_magic;
+       u_int16_t s_state;
+       u_int32_t s_zones;
+};
+
+struct minix_dir_entry {
+       u_int16_t inode;
+       char name[0];
+};
+
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+#define NAME_MAX         255   /* # chars in a file name */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96)    /* return device size */
+#endif
+
+#ifndef __linux__
+#define volatile
+#endif
+
+static const int ROOT_INO = 1;
+
+#define UPPER(size,n) ((size+((n)-1))/(n))
+#define INODE_SIZE (sizeof(struct minix_inode))
+#ifdef BB_FEATURE_MINIX2
+#define INODE_SIZE2 (sizeof(struct minix2_inode))
+#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
+                                   : MINIX_INODES_PER_BLOCK))
+#else
+#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
+#endif
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+
+#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
+
+static char *program_version = "1.2 - 11/11/96";
+static char *device_name = NULL;
+static int IN;
+static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
+       0, warn_mode = 0, force = 0;
+static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
+       0, symlinks = 0, total = 0;
+
+static int changed = 0;                        /* flags if the filesystem has been changed */
+static int errors_uncorrected = 0;     /* flag if some error was not corrected */
+static int dirsize = 16;
+static int namelen = 14;
+static int version2 = 0;
+static struct termios termios;
+static int termios_set = 0;
+
+/* File-name data */
+static const int MAX_DEPTH = 32;
+static int name_depth = 0;
+// static char name_list[MAX_DEPTH][BUFSIZ + 1];
+static char **name_list = NULL;
+
+static char *inode_buffer = NULL;
+
+#define Inode (((struct minix_inode *) inode_buffer)-1)
+#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
+static char super_block_buffer[BLOCK_SIZE];
+
+#define Super (*(struct minix_super_block *)super_block_buffer)
+#define INODES ((unsigned long)Super.s_ninodes)
+#ifdef BB_FEATURE_MINIX2
+#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
+#else
+#define ZONES ((unsigned long)(Super.s_nzones))
+#endif
+#define IMAPS ((unsigned long)Super.s_imap_blocks)
+#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
+#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
+#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
+#define MAXSIZE ((unsigned long)Super.s_max_size)
+#define MAGIC (Super.s_magic)
+#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
+
+static char *inode_map;
+static char *zone_map;
+
+static unsigned char *inode_count = NULL;
+static unsigned char *zone_count = NULL;
+
+static void recursive_check(unsigned int ino);
+#ifdef BB_FEATURE_MINIX2
+static void recursive_check2(unsigned int ino);
+#endif
+
+static inline int bit(char * a,unsigned int i)
+{
+         return (a[i >> 3] & (1<<(i & 7))) != 0;
+}
+#define inode_in_use(x) (bit(inode_map,(x)))
+#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
+
+#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
+#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
+
+#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
+#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
+
+static void leave(int) __attribute__ ((noreturn));
+static void leave(int status)
+{
+       if (termios_set)
+               tcsetattr(0, TCSANOW, &termios);
+       exit(status);
+}
+
+static void die(const char *str)
+{
+       error_msg("%s", str);
+       leave(8);
+}
+
+/*
+ * This simply goes through the file-name data and prints out the
+ * current file.
+ */
+static void print_current_name(void)
+{
+       int i = 0;
+
+       while (i < name_depth)
+               printf("/%.*s", namelen, name_list[i++]);
+       if (i == 0)
+               printf("/");
+}
+
+static int ask(const char *string, int def)
+{
+       int c;
+
+       if (!repair) {
+               printf("\n");
+               errors_uncorrected = 1;
+               return 0;
+       }
+       if (automatic) {
+               printf("\n");
+               if (!def)
+                       errors_uncorrected = 1;
+               return def;
+       }
+       printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
+       for (;;) {
+               fflush(stdout);
+               if ((c = getchar()) == EOF) {
+                       if (!def)
+                               errors_uncorrected = 1;
+                       return def;
+               }
+               c = toupper(c);
+               if (c == 'Y') {
+                       def = 1;
+                       break;
+               } else if (c == 'N') {
+                       def = 0;
+                       break;
+               } else if (c == ' ' || c == '\n')
+                       break;
+       }
+       if (def)
+               printf("y\n");
+       else {
+               printf("n\n");
+               errors_uncorrected = 1;
+       }
+       return def;
+}
+
+/*
+ * Make certain that we aren't checking a filesystem that is on a
+ * mounted partition.  Code adapted from e2fsck, Copyright (C) 1993,
+ * 1994 Theodore Ts'o.  Also licensed under GPL.
+ */
+static void check_mount(void)
+{
+       FILE *f;
+       struct mntent *mnt;
+       int cont;
+       int fd;
+
+       if ((f = setmntent(MOUNTED, "r")) == NULL)
+               return;
+       while ((mnt = getmntent(f)) != NULL)
+               if (strcmp(device_name, mnt->mnt_fsname) == 0)
+                       break;
+       endmntent(f);
+       if (!mnt)
+               return;
+
+       /*
+        * If the root is mounted read-only, then /etc/mtab is
+        * probably not correct; so we won't issue a warning based on
+        * it.
+        */
+       fd = open(MOUNTED, O_RDWR);
+       if (fd < 0 && errno == EROFS)
+               return;
+       else
+               close(fd);
+
+       printf("%s is mounted.   ", device_name);
+       if (isatty(0) && isatty(1))
+               cont = ask("Do you really want to continue", 0);
+       else
+               cont = 0;
+       if (!cont) {
+               printf("check aborted.\n");
+               exit(0);
+       }
+       return;
+}
+
+/*
+ * 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_nr(unsigned short *nr, int *corrected)
+{
+       if (!*nr)
+               return 0;
+       if (*nr < FIRSTZONE)
+               printf("Zone nr < FIRSTZONE in file `");
+       else if (*nr >= ZONES)
+               printf("Zone nr >= ZONES in file `");
+       else
+               return *nr;
+       print_current_name();
+       printf("'.");
+       if (ask("Remove block", 1)) {
+               *nr = 0;
+               *corrected = 1;
+       }
+       return 0;
+}
+
+#ifdef BB_FEATURE_MINIX2
+static int check_zone_nr2(unsigned int *nr, int *corrected)
+{
+       if (!*nr)
+               return 0;
+       if (*nr < FIRSTZONE)
+               printf("Zone nr < FIRSTZONE in file `");
+       else if (*nr >= ZONES)
+               printf("Zone nr >= ZONES in file `");
+       else
+               return *nr;
+       print_current_name();
+       printf("'.");
+       if (ask("Remove block", 1)) {
+               *nr = 0;
+               *corrected = 1;
+       }
+       return 0;
+}
+#endif
+
+/*
+ * read-block reads block nr into the buffer at addr.
+ */
+static void read_block(unsigned int nr, char *addr)
+{
+       if (!nr) {
+               memset(addr, 0, BLOCK_SIZE);
+               return;
+       }
+       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
+               printf("Read error: unable to seek to block in file '");
+               print_current_name();
+               printf("'\n");
+               memset(addr, 0, BLOCK_SIZE);
+               errors_uncorrected = 1;
+       } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
+               printf("Read error: bad block in file '");
+               print_current_name();
+               printf("'\n");
+               memset(addr, 0, BLOCK_SIZE);
+               errors_uncorrected = 1;
+       }
+}
+
+/*
+ * write_block writes block nr to disk.
+ */
+static void write_block(unsigned int nr, char *addr)
+{
+       if (!nr)
+               return;
+       if (nr < FIRSTZONE || nr >= ZONES) {
+               printf("Internal error: trying to write bad block\n"
+                          "Write request ignored\n");
+               errors_uncorrected = 1;
+               return;
+       }
+       if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
+               die("seek failed in write_block");
+       if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
+               printf("Write error: bad block in file '");
+               print_current_name();
+               printf("'\n");
+               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 minix_inode *inode, unsigned int blknr)
+{
+       unsigned short ind[BLOCK_SIZE >> 1];
+       unsigned short dind[BLOCK_SIZE >> 1];
+       int blk_chg, block, result;
+
+       if (blknr < 7)
+               return check_zone_nr(inode->i_zone + blknr, &changed);
+       blknr -= 7;
+       if (blknr < 512) {
+               block = check_zone_nr(inode->i_zone + 7, &changed);
+               read_block(block, (char *) ind);
+               blk_chg = 0;
+               result = check_zone_nr(blknr + ind, &blk_chg);
+               if (blk_chg)
+                       write_block(block, (char *) ind);
+               return result;
+       }
+       blknr -= 512;
+       block = check_zone_nr(inode->i_zone + 8, &changed);
+       read_block(block, (char *) dind);
+       blk_chg = 0;
+       result = check_zone_nr(dind + (blknr / 512), &blk_chg);
+       if (blk_chg)
+               write_block(block, (char *) dind);
+       block = result;
+       read_block(block, (char *) ind);
+       blk_chg = 0;
+       result = check_zone_nr(ind + (blknr % 512), &blk_chg);
+       if (blk_chg)
+               write_block(block, (char *) ind);
+       return result;
+}
+
+#ifdef BB_FEATURE_MINIX2
+static int map_block2(struct minix2_inode *inode, unsigned int blknr)
+{
+       unsigned int ind[BLOCK_SIZE >> 2];
+       unsigned int dind[BLOCK_SIZE >> 2];
+       unsigned int tind[BLOCK_SIZE >> 2];
+       int blk_chg, block, result;
+
+       if (blknr < 7)
+               return check_zone_nr2(inode->i_zone + blknr, &changed);
+       blknr -= 7;
+       if (blknr < 256) {
+               block = check_zone_nr2(inode->i_zone + 7, &changed);
+               read_block(block, (char *) ind);
+               blk_chg = 0;
+               result = check_zone_nr2(blknr + ind, &blk_chg);
+               if (blk_chg)
+                       write_block(block, (char *) ind);
+               return result;
+       }
+       blknr -= 256;
+       if (blknr >= 256 * 256) {
+               block = check_zone_nr2(inode->i_zone + 8, &changed);
+               read_block(block, (char *) dind);
+               blk_chg = 0;
+               result = check_zone_nr2(dind + blknr / 256, &blk_chg);
+               if (blk_chg)
+                       write_block(block, (char *) dind);
+               block = result;
+               read_block(block, (char *) ind);
+               blk_chg = 0;
+               result = check_zone_nr2(ind + blknr % 256, &blk_chg);
+               if (blk_chg)
+                       write_block(block, (char *) ind);
+               return result;
+       }
+       blknr -= 256 * 256;
+       block = check_zone_nr2(inode->i_zone + 9, &changed);
+       read_block(block, (char *) tind);
+       blk_chg = 0;
+       result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
+       if (blk_chg)
+               write_block(block, (char *) tind);
+       block = result;
+       read_block(block, (char *) dind);
+       blk_chg = 0;
+       result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
+       if (blk_chg)
+               write_block(block, (char *) dind);
+       block = result;
+       read_block(block, (char *) ind);
+       blk_chg = 0;
+       result = check_zone_nr2(ind + blknr % 256, &blk_chg);
+       if (blk_chg)
+               write_block(block, (char *) ind);
+       return result;
+}
+#endif
+
+static void write_super_block(void)
+{
+       /*
+        * Set the state of the filesystem based on whether or not there
+        * are uncorrected errors.  The filesystem valid flag is
+        * unconditionally set if we get this far.
+        */
+       Super.s_state |= MINIX_VALID_FS;
+       if (errors_uncorrected)
+               Super.s_state |= MINIX_ERROR_FS;
+       else
+               Super.s_state &= ~MINIX_ERROR_FS;
+
+       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
+               die("seek failed in write_super_block");
+       if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
+               die("unable to write super-block");
+
+       return;
+}
+
+static void write_tables(void)
+{
+       write_super_block();
+
+       if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
+               die("Unable to write inode map");
+       if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
+               die("Unable to write zone map");
+       if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
+               die("Unable to write inodes");
+}
+
+static void get_dirsize(void)
+{
+       int block;
+       char blk[BLOCK_SIZE];
+       int size;
+
+#ifdef BB_FEATURE_MINIX2
+       if (version2)
+               block = Inode2[ROOT_INO].i_zone[0];
+       else
+#endif
+               block = Inode[ROOT_INO].i_zone[0];
+       read_block(block, blk);
+       for (size = 16; size < BLOCK_SIZE; size <<= 1) {
+               if (strcmp(blk + size + 2, "..") == 0) {
+                       dirsize = size;
+                       namelen = size - 2;
+                       return;
+               }
+       }
+       /* use defaults */
+}
+
+static void read_superblock(void)
+{
+       if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
+               die("seek failed");
+       if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
+               die("unable to read super block");
+       if (MAGIC == MINIX_SUPER_MAGIC) {
+               namelen = 14;
+               dirsize = 16;
+               version2 = 0;
+       } else if (MAGIC == MINIX_SUPER_MAGIC2) {
+               namelen = 30;
+               dirsize = 32;
+               version2 = 0;
+#ifdef BB_FEATURE_MINIX2
+       } else if (MAGIC == MINIX2_SUPER_MAGIC) {
+               namelen = 14;
+               dirsize = 16;
+               version2 = 1;
+       } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
+               namelen = 30;
+               dirsize = 32;
+               version2 = 1;
+#endif
+       } else
+               die("bad magic number in super-block");
+       if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
+               die("Only 1k blocks/zones supported");
+       if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
+               die("bad s_imap_blocks field in super-block");
+       if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
+               die("bad s_zmap_blocks field in super-block");
+}
+
+static void read_tables(void)
+{
+       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
+       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
+       memset(inode_map, 0, sizeof(inode_map));
+       memset(zone_map, 0, sizeof(zone_map));
+       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
+       inode_count = xmalloc(INODES + 1);
+       zone_count = xmalloc(ZONES);
+       if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
+               die("Unable to read inode map");
+       if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
+               die("Unable to read zone map");
+       if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
+               die("Unable to read inodes");
+       if (NORM_FIRSTZONE != FIRSTZONE) {
+               printf("Warning: Firstzone != Norm_firstzone\n");
+               errors_uncorrected = 1;
+       }
+       get_dirsize();
+       if (show) {
+               printf("%ld inodes\n", INODES);
+               printf("%ld blocks\n", ZONES);
+               printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
+               printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
+               printf("Maxsize=%ld\n", MAXSIZE);
+               printf("Filesystem state=%d\n", Super.s_state);
+               printf("namelen=%d\n\n", namelen);
+       }
+}
+
+static struct minix_inode *get_inode(unsigned int nr)
+{
+       struct minix_inode *inode;
+
+       if (!nr || nr > INODES)
+               return NULL;
+       total++;
+       inode = Inode + nr;
+       if (!inode_count[nr]) {
+               if (!inode_in_use(nr)) {
+                       printf("Inode %d marked not used, but used for file '", nr);
+                       print_current_name();
+                       printf("'\n");
+                       if (repair) {
+                               if (ask("Mark in use", 1))
+                                       mark_inode(nr);
+                       } else {
+                               errors_uncorrected = 1;
+                       }
+               }
+               if (S_ISDIR(inode->i_mode))
+                       directory++;
+               else if (S_ISREG(inode->i_mode))
+                       regular++;
+               else if (S_ISCHR(inode->i_mode))
+                       chardev++;
+               else if (S_ISBLK(inode->i_mode))
+                       blockdev++;
+               else if (S_ISLNK(inode->i_mode))
+                       symlinks++;
+               else if (S_ISSOCK(inode->i_mode));
+               else if (S_ISFIFO(inode->i_mode));
+               else {
+                       print_current_name();
+                       printf(" has mode %05o\n", inode->i_mode);
+               }
+
+       } else
+               links++;
+       if (!++inode_count[nr]) {
+               printf("Warning: inode count too big.\n");
+               inode_count[nr]--;
+               errors_uncorrected = 1;
+       }
+       return inode;
+}
+
+#ifdef BB_FEATURE_MINIX2
+static struct minix2_inode *get_inode2(unsigned int nr)
+{
+       struct minix2_inode *inode;
+
+       if (!nr || nr > INODES)
+               return NULL;
+       total++;
+       inode = Inode2 + nr;
+       if (!inode_count[nr]) {
+               if (!inode_in_use(nr)) {
+                       printf("Inode %d marked not used, but used for file '", nr);
+                       print_current_name();
+                       printf("'\n");
+                       if (repair) {
+                               if (ask("Mark in use", 1))
+                                       mark_inode(nr);
+                               else
+                                       errors_uncorrected = 1;
+                       }
+               }
+               if (S_ISDIR(inode->i_mode))
+                       directory++;
+               else if (S_ISREG(inode->i_mode))
+                       regular++;
+               else if (S_ISCHR(inode->i_mode))
+                       chardev++;
+               else if (S_ISBLK(inode->i_mode))
+                       blockdev++;
+               else if (S_ISLNK(inode->i_mode))
+                       symlinks++;
+               else if (S_ISSOCK(inode->i_mode));
+               else if (S_ISFIFO(inode->i_mode));
+               else {
+                       print_current_name();
+                       printf(" has mode %05o\n", inode->i_mode);
+               }
+       } else
+               links++;
+       if (!++inode_count[nr]) {
+               printf("Warning: inode count too big.\n");
+               inode_count[nr]--;
+               errors_uncorrected = 1;
+       }
+       return inode;
+}
+#endif
+
+static void check_root(void)
+{
+       struct minix_inode *inode = Inode + ROOT_INO;
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               die("root inode isn't a directory");
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void check_root2(void)
+{
+       struct minix2_inode *inode = Inode2 + ROOT_INO;
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               die("root inode isn't a directory");
+}
+#endif
+
+static int add_zone(unsigned short *znr, int *corrected)
+{
+       int result;
+       int block;
+
+       result = 0;
+       block = check_zone_nr(znr, corrected);
+       if (!block)
+               return 0;
+       if (zone_count[block]) {
+               printf("Block has been used before. Now in file `");
+               print_current_name();
+               printf("'.");
+               if (ask("Clear", 1)) {
+                       *znr = 0;
+                       block = 0;
+                       *corrected = 1;
+               }
+       }
+       if (!block)
+               return 0;
+       if (!zone_in_use(block)) {
+               printf("Block %d in file `", block);
+               print_current_name();
+               printf("' is marked not in use.");
+               if (ask("Correct", 1))
+                       mark_zone(block);
+       }
+       if (!++zone_count[block])
+               zone_count[block]--;
+       return block;
+}
+
+#ifdef BB_FEATURE_MINIX2
+static int add_zone2(unsigned int *znr, int *corrected)
+{
+       int result;
+       int block;
+
+       result = 0;
+       block = check_zone_nr2(znr, corrected);
+       if (!block)
+               return 0;
+       if (zone_count[block]) {
+               printf("Block has been used before. Now in file `");
+               print_current_name();
+               printf("'.");
+               if (ask("Clear", 1)) {
+                       *znr = 0;
+                       block = 0;
+                       *corrected = 1;
+               }
+       }
+       if (!block)
+               return 0;
+       if (!zone_in_use(block)) {
+               printf("Block %d in file `", block);
+               print_current_name();
+               printf("' is marked not in use.");
+               if (ask("Correct", 1))
+                       mark_zone(block);
+       }
+       if (!++zone_count[block])
+               zone_count[block]--;
+       return block;
+}
+#endif
+
+static void add_zone_ind(unsigned short *znr, int *corrected)
+{
+       static char blk[BLOCK_SIZE];
+       int i, chg_blk = 0;
+       int block;
+
+       block = add_zone(znr, corrected);
+       if (!block)
+               return;
+       read_block(block, blk);
+       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+               add_zone(i + (unsigned short *) blk, &chg_blk);
+       if (chg_blk)
+               write_block(block, blk);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void add_zone_ind2(unsigned int *znr, int *corrected)
+{
+       static char blk[BLOCK_SIZE];
+       int i, chg_blk = 0;
+       int block;
+
+       block = add_zone2(znr, corrected);
+       if (!block)
+               return;
+       read_block(block, blk);
+       for (i = 0; i < BLOCK_SIZE >> 2; i++)
+               add_zone2(i + (unsigned int *) blk, &chg_blk);
+       if (chg_blk)
+               write_block(block, blk);
+}
+#endif
+
+static void add_zone_dind(unsigned short *znr, int *corrected)
+{
+       static char blk[BLOCK_SIZE];
+       int i, blk_chg = 0;
+       int block;
+
+       block = add_zone(znr, corrected);
+       if (!block)
+               return;
+       read_block(block, blk);
+       for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+               add_zone_ind(i + (unsigned short *) blk, &blk_chg);
+       if (blk_chg)
+               write_block(block, blk);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void add_zone_dind2(unsigned int *znr, int *corrected)
+{
+       static char blk[BLOCK_SIZE];
+       int i, blk_chg = 0;
+       int block;
+
+       block = add_zone2(znr, corrected);
+       if (!block)
+               return;
+       read_block(block, blk);
+       for (i = 0; i < BLOCK_SIZE >> 2; i++)
+               add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
+       if (blk_chg)
+               write_block(block, blk);
+}
+
+static void add_zone_tind2(unsigned int *znr, int *corrected)
+{
+       static char blk[BLOCK_SIZE];
+       int i, blk_chg = 0;
+       int block;
+
+       block = add_zone2(znr, corrected);
+       if (!block)
+               return;
+       read_block(block, blk);
+       for (i = 0; i < BLOCK_SIZE >> 2; i++)
+               add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
+       if (blk_chg)
+               write_block(block, blk);
+}
+#endif
+
+static void check_zones(unsigned int i)
+{
+       struct minix_inode *inode;
+
+       if (!i || i > INODES)
+               return;
+       if (inode_count[i] > 1)         /* have we counted this file already? */
+               return;
+       inode = Inode + 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);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void check_zones2(unsigned int 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 minix_inode *dir, unsigned int offset)
+{
+       static char blk[BLOCK_SIZE];
+       struct minix_inode *inode;
+       int ino;
+       char *name;
+       int block;
+
+       block = map_block(dir, offset / BLOCK_SIZE);
+       read_block(block, blk);
+       name = blk + (offset % BLOCK_SIZE) + 2;
+       ino = *(unsigned short *) (name - 2);
+       if (ino > INODES) {
+               print_current_name();
+               printf(" contains a bad inode number for file '");
+               printf("%.*s'.", namelen, name);
+               if (ask(" Remove", 1)) {
+                       *(unsigned short *) (name - 2) = 0;
+                       write_block(block, blk);
+               }
+               ino = 0;
+       }
+       if (name_depth < MAX_DEPTH)
+               strncpy(name_list[name_depth], name, namelen);
+       name_depth++;
+       inode = get_inode(ino);
+       name_depth--;
+       if (!offset) {
+               if (!inode || strcmp(".", name)) {
+                       print_current_name();
+                       printf(": bad directory: '.' isn't first\n");
+                       errors_uncorrected = 1;
+               } else
+                       return;
+       }
+       if (offset == dirsize) {
+               if (!inode || strcmp("..", name)) {
+                       print_current_name();
+                       printf(": bad directory: '..' isn't second\n");
+                       errors_uncorrected = 1;
+               } else
+                       return;
+       }
+       if (!inode)
+               return;
+       if (name_depth < MAX_DEPTH)
+               strncpy(name_list[name_depth], name, namelen);
+       name_depth++;
+       if (list) {
+               if (verbose)
+                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+               print_current_name();
+               if (S_ISDIR(inode->i_mode))
+                       printf(":\n");
+               else
+                       printf("\n");
+       }
+       check_zones(ino);
+       if (inode && S_ISDIR(inode->i_mode))
+               recursive_check(ino);
+       name_depth--;
+       return;
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void check_file2(struct minix2_inode *dir, unsigned int offset)
+{
+       static char blk[BLOCK_SIZE];
+       struct minix2_inode *inode;
+       int ino;
+       char *name;
+       int block;
+
+       block = map_block2(dir, offset / BLOCK_SIZE);
+       read_block(block, blk);
+       name = blk + (offset % BLOCK_SIZE) + 2;
+       ino = *(unsigned short *) (name - 2);
+       if (ino > INODES) {
+               print_current_name();
+               printf(" contains a bad inode number for file '");
+               printf("%.*s'.", namelen, name);
+               if (ask(" Remove", 1)) {
+                       *(unsigned short *) (name - 2) = 0;
+                       write_block(block, blk);
+               }
+               ino = 0;
+       }
+       if (name_depth < MAX_DEPTH)
+               strncpy(name_list[name_depth], name, namelen);
+       name_depth++;
+       inode = get_inode2(ino);
+       name_depth--;
+       if (!offset) {
+               if (!inode || strcmp(".", name)) {
+                       print_current_name();
+                       printf(": bad directory: '.' isn't first\n");
+                       errors_uncorrected = 1;
+               } else
+                       return;
+       }
+       if (offset == dirsize) {
+               if (!inode || strcmp("..", name)) {
+                       print_current_name();
+                       printf(": bad directory: '..' isn't second\n");
+                       errors_uncorrected = 1;
+               } else
+                       return;
+       }
+       if (!inode)
+               return;
+       name_depth++;
+       if (list) {
+               if (verbose)
+                       printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+               print_current_name();
+               if (S_ISDIR(inode->i_mode))
+                       printf(":\n");
+               else
+                       printf("\n");
+       }
+       check_zones2(ino);
+       if (inode && S_ISDIR(inode->i_mode))
+               recursive_check2(ino);
+       name_depth--;
+       return;
+}
+#endif
+
+static void recursive_check(unsigned int ino)
+{
+       struct minix_inode *dir;
+       unsigned int offset;
+
+       dir = Inode + ino;
+       if (!S_ISDIR(dir->i_mode))
+               die("internal error");
+       if (dir->i_size < 2 * dirsize) {
+               print_current_name();
+               printf(": bad directory: size<32");
+               errors_uncorrected = 1;
+       }
+       for (offset = 0; offset < dir->i_size; offset += dirsize)
+               check_file(dir, offset);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void recursive_check2(unsigned int ino)
+{
+       struct minix2_inode *dir;
+       unsigned int offset;
+
+       dir = Inode2 + ino;
+       if (!S_ISDIR(dir->i_mode))
+               die("internal error");
+       if (dir->i_size < 2 * dirsize) {
+               print_current_name();
+               printf(": bad directory: size < 32");
+               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[1024];
+
+       if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
+               die("seek failed in bad_zone");
+       return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
+}
+
+static void check_counts(void)
+{
+       int i;
+
+       for (i = 1; i <= INODES; i++) {
+               if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
+                       printf("Inode %d mode not cleared.", i);
+                       if (ask("Clear", 1)) {
+                               Inode[i].i_mode = 0;
+                               changed = 1;
+                       }
+               }
+               if (!inode_count[i]) {
+                       if (!inode_in_use(i))
+                               continue;
+                       printf("Inode %d not used, marked used in the bitmap.", i);
+                       if (ask("Clear", 1))
+                               unmark_inode(i);
+                       continue;
+               }
+               if (!inode_in_use(i)) {
+                       printf("Inode %d used, marked unused in the bitmap.", i);
+                       if (ask("Set", 1))
+                               mark_inode(i);
+               }
+               if (Inode[i].i_nlinks != inode_count[i]) {
+                       printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
+                                  i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]);
+                       if (ask("Set i_nlinks to count", 1)) {
+                               Inode[i].i_nlinks = inode_count[i];
+                               changed = 1;
+                       }
+               }
+       }
+       for (i = FIRSTZONE; i < ZONES; i++) {
+               if (zone_in_use(i) == zone_count[i])
+                       continue;
+               if (!zone_count[i]) {
+                       if (bad_zone(i))
+                               continue;
+                       printf("Zone %d: marked in use, 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]);
+       }
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void check_counts2(void)
+{
+       int i;
+
+       for (i = 1; i <= INODES; i++) {
+               if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
+                       printf("Inode %d mode not cleared.", i);
+                       if (ask("Clear", 1)) {
+                               Inode2[i].i_mode = 0;
+                               changed = 1;
+                       }
+               }
+               if (!inode_count[i]) {
+                       if (!inode_in_use(i))
+                               continue;
+                       printf("Inode %d not used, marked used in the bitmap.", i);
+                       if (ask("Clear", 1))
+                               unmark_inode(i);
+                       continue;
+               }
+               if (!inode_in_use(i)) {
+                       printf("Inode %d used, marked 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) == zone_count[i])
+                       continue;
+               if (!zone_count[i]) {
+                       if (bad_zone(i))
+                               continue;
+                       printf("Zone %d: marked in use, 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(ROOT_INO);
+       recursive_check(ROOT_INO);
+       check_counts();
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void check2(void)
+{
+       memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
+       memset(zone_count, 0, ZONES * sizeof(*zone_count));
+       check_zones2(ROOT_INO);
+       recursive_check2(ROOT_INO);
+       check_counts2();
+}
+#endif
+
+/* Wed Feb  9 15:17:06 MST 2000 */
+/* dynamically allocate name_list (instead of making it static) */
+static void alloc_name_list(void)
+{
+       int i;
+
+       name_list = xmalloc(sizeof(char *) * MAX_DEPTH);
+       for (i = 0; i < MAX_DEPTH; i++)
+               name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
+}
+
+#ifdef BB_FEATURE_CLEAN_UP
+/* execute this atexit() to deallocate name_list[] */
+/* piptigger was here */
+static void free_name_list(void)
+{
+       int i;
+
+       if (name_list) { 
+               for (i = 0; i < MAX_DEPTH; i++) {
+                       if (name_list[i]) {
+                               free(name_list[i]);
+                       }
+               }
+               free(name_list);
+       }
+}
+#endif
+
+extern int fsck_minix_main(int argc, char **argv)
+{
+       struct termios tmp;
+       int count;
+       int retcode = 0;
+
+       alloc_name_list();
+#ifdef BB_FEATURE_CLEAN_UP
+       /* Don't bother to free memory.  Exit does
+        * that automagically, so we can save a few bytes */
+       atexit(free_name_list);
+#endif
+
+       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
+               die("bad inode size");
+#ifdef BB_FEATURE_MINIX2
+       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
+               die("bad v2 inode size");
+#endif
+       while (argc-- > 1) {
+               argv++;
+               if (argv[0][0] != '-') {
+                       if (device_name)
+                               show_usage();
+                       else
+                               device_name = argv[0];
+               } else
+                       while (*++argv[0])
+                               switch (argv[0][0]) {
+                               case 'l':
+                                       list = 1;
+                                       break;
+                               case 'a':
+                                       automatic = 1;
+                                       repair = 1;
+                                       break;
+                               case 'r':
+                                       automatic = 0;
+                                       repair = 1;
+                                       break;
+                               case 'v':
+                                       verbose = 1;
+                                       break;
+                               case 's':
+                                       show = 1;
+                                       break;
+                               case 'm':
+                                       warn_mode = 1;
+                                       break;
+                               case 'f':
+                                       force = 1;
+                                       break;
+                               default:
+                                       show_usage();
+                               }
+       }
+       if (!device_name)
+               show_usage();
+       check_mount();                          /* trying to check a mounted filesystem? */
+       if (repair && !automatic) {
+               if (!isatty(0) || !isatty(1))
+                       die("need terminal for interactive repairs");
+       }
+       IN = open(device_name, repair ? O_RDWR : O_RDONLY);
+       if (IN < 0){
+               fprintf(stderr,"unable to open device '%s'.\n",device_name);
+               leave(8);
+       }
+       for (count = 0; count < 3; count++)
+               sync();
+       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, program_version);
+       if (!(Super.s_state & MINIX_ERROR_FS) &&
+               (Super.s_state & MINIX_VALID_FS) && !force) {
+               if (repair)
+                       printf("%s is clean, no check.\n", device_name);
+               return retcode;
+       } else if (force)
+               printf("Forcing filesystem check on %s.\n", device_name);
+       else if (repair)
+               printf("Filesystem on %s is dirty, needs checking.\n",
+                          device_name);
+
+       read_tables();
+
+       if (repair && !automatic) {
+               tcgetattr(0, &termios);
+               tmp = termios;
+               tmp.c_lflag &= ~(ICANON | ECHO);
+               tcsetattr(0, TCSANOW, &tmp);
+               termios_set = 1;
+       }
+#ifdef BB_FEATURE_MINIX2
+       if (version2) {
+               check_root2();
+               check2();
+       } else
+#endif
+       {
+               check_root();
+               check();
+       }
+       if (verbose) {
+               int i, free_cnt;
+
+               for (i = 1, free_cnt = 0; i <= INODES; i++)
+                       if (!inode_in_use(i))
+                               free_cnt++;
+               printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt),
+                          100 * (INODES - free_cnt) / INODES);
+               for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
+                       if (!zone_in_use(i))
+                               free_cnt++;
+               printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt),
+                          100 * (ZONES - free_cnt) / ZONES);
+               printf("\n%6d regular files\n"
+                          "%6d directories\n"
+                          "%6d character device files\n"
+                          "%6d block device files\n"
+                          "%6d links\n"
+                          "%6d symbolic links\n"
+                          "------\n"
+                          "%6d files\n",
+                          regular, directory, chardev, blockdev,
+                          links - 2 * directory + 1, symlinks,
+                          total - 2 * directory + 1);
+       }
+       if (changed) {
+               write_tables();
+               printf("----------------------------\n"
+                          "FILE SYSTEM HAS BEEN CHANGED\n"
+                          "----------------------------\n");
+               for (count = 0; count < 3; count++)
+                       sync();
+       } else if (repair)
+               write_super_block();
+
+       if (repair && !automatic)
+               tcsetattr(0, TCSANOW, &termios);
+
+       if (changed)
+               retcode += 3;
+       if (errors_uncorrected)
+               retcode += 4;
+       return retcode;
+}
diff --git a/getopt.c b/getopt.c
new file mode 100644 (file)
index 0000000..95ecba6
--- /dev/null
+++ b/getopt.c
@@ -0,0 +1,402 @@
+/*
+ * getopt.c - Enhanced implementation of BSD getopt(1)
+ *   Copyright (c) 1997, 1998, 1999, 2000  Frodo Looijaard <frodol@dds.nl>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Version 1.0-b4: Tue Sep 23 1997. First public release.
+ * Version 1.0: Wed Nov 19 1997.
+ *   Bumped up the version number to 1.0
+ *   Fixed minor typo (CSH instead of TCSH)
+ * Version 1.0.1: Tue Jun 3 1998
+ *   Fixed sizeof instead of strlen bug
+ *   Bumped up the version number to 1.0.1
+ * Version 1.0.2: Thu Jun 11 1998 (not present)
+ *   Fixed gcc-2.8.1 warnings
+ *   Fixed --version/-V option (not present)
+ * Version 1.0.5: Tue Jun 22 1999
+ *   Make -u option work (not present)
+ * Version 1.0.6: Tue Jun 27 2000
+ *   No important changes
+ * Version 1.1.0: Tue Jun 30 2000
+ *   Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
+ *     <misiek@misiek.eu.org>)
+ * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
+ *  Removed --version/-V and --help/-h in
+ *  Removed prase_error(), using error_msg() from Busybox instead
+ *  Replaced our_malloc with xmalloc and our_realloc with xrealloc
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <getopt.h>
+
+#include "busybox.h"
+
+/* NON_OPT is the code that is returned when a non-option is found in '+'
+   mode */
+static const int NON_OPT = 1;
+/* LONG_OPT is the code that is returned when a long option is found. */
+static const int LONG_OPT = 2;
+
+/* The shells recognized. */
+typedef enum {BASH,TCSH} shell_t;
+
+
+/* Some global variables that tells us how to parse. */
+static shell_t shell=BASH; /* The shell we generate output for. */
+static int quiet_errors=0; /* 0 is not quiet. */
+static int quiet_output=0; /* 0 is not quiet. */
+static int quote=1; /* 1 is do quote. */
+static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
+
+/* Function prototypes */
+static const char *normalize(const char *arg);
+static int generate_output(char * argv[],int argc,const char *optstr,
+                    const struct option *longopts);
+static void add_long_options(char *options);
+static void add_longopt(const char *name,int has_arg);
+static void set_shell(const char *new_shell);
+
+
+/*
+ * This function 'normalizes' a single argument: it puts single quotes around
+ * it and escapes other special characters. If quote is false, it just
+ * returns its argument.
+ * Bash only needs special treatment for single quotes; tcsh also recognizes
+ * exclamation marks within single quotes, and nukes whitespace.
+ * This function returns a pointer to a buffer that is overwritten by
+ * each call.
+ */
+const char *normalize(const char *arg)
+{
+        static char *BUFFER=NULL;
+        const char *argptr=arg;
+        char *bufptr;
+
+        if (BUFFER != NULL)
+                free(BUFFER);
+
+        if (!quote) { /* Just copy arg */
+                BUFFER=xmalloc(strlen(arg)+1);
+
+                strcpy(BUFFER,arg);
+                return BUFFER;
+        }
+
+        /* Each character in arg may take upto four characters in the result:
+           For a quote we need a closing quote, a backslash, a quote and an
+           opening quote! We need also the global opening and closing quote,
+           and one extra character for '\0'. */
+        BUFFER=xmalloc(strlen(arg)*4+3);
+
+        bufptr=BUFFER;
+        *bufptr++='\'';
+
+        while (*argptr) {
+                if (*argptr == '\'') {
+                        /* Quote: replace it with: '\'' */
+                        *bufptr++='\'';
+                        *bufptr++='\\';
+                        *bufptr++='\'';
+                        *bufptr++='\'';
+                } else if (shell==TCSH && *argptr=='!') {
+                        /* Exclamation mark: replace it with: \! */
+                        *bufptr++='\'';
+                        *bufptr++='\\';
+                        *bufptr++='!';
+                        *bufptr++='\'';
+                } else if (shell==TCSH && *argptr=='\n') {
+                        /* Newline: replace it with: \n */
+                        *bufptr++='\\';
+                        *bufptr++='n';
+                } else if (shell==TCSH && isspace(*argptr)) {
+                        /* Non-newline whitespace: replace it with \<ws> */
+                        *bufptr++='\'';
+                        *bufptr++='\\';
+                        *bufptr++=*argptr;
+                        *bufptr++='\'';
+                } else
+                        /* Just copy */
+                        *bufptr++=*argptr;
+                argptr++;
+        }
+        *bufptr++='\'';
+        *bufptr++='\0';
+        return BUFFER;
+}
+
+/*
+ * Generate the output. argv[0] is the program name (used for reporting errors).
+ * argv[1..] contains the options to be parsed. argc must be the number of
+ * elements in argv (ie. 1 if there are no options, only the program name),
+ * optstr must contain the short options, and longopts the long options.
+ * Other settings are found in global variables.
+ */
+int generate_output(char * argv[],int argc,const char *optstr,
+                    const struct option *longopts)
+{
+        int exit_code = 0; /* We assume everything will be OK */
+        int opt;
+        int longindex;
+        const char *charptr;
+
+        if (quiet_errors) /* No error reporting from getopt(3) */
+                opterr=0;
+        optind=0; /* Reset getopt(3) */
+
+        while ((opt = (alternative?
+                       getopt_long_only(argc,argv,optstr,longopts,&longindex):
+                       getopt_long(argc,argv,optstr,longopts,&longindex)))
+               != EOF)
+                if (opt == '?' || opt == ':' )
+                        exit_code = 1;
+                else if (!quiet_output) {
+                        if (opt == LONG_OPT) {
+                                printf(" --%s",longopts[longindex].name);
+                                if (longopts[longindex].has_arg)
+                                        printf(" %s",
+                                               normalize(optarg?optarg:""));
+                        } else if (opt == NON_OPT)
+                                printf(" %s",normalize(optarg));
+                        else {
+                                printf(" -%c",opt);
+                                charptr = strchr(optstr,opt);
+                                if (charptr != NULL && *++charptr == ':')
+                                        printf(" %s",
+                                               normalize(optarg?optarg:""));
+                        }
+                }
+
+        if (! quiet_output) {
+                printf(" --");
+                while (optind < argc)
+                        printf(" %s",normalize(argv[optind++]));
+                printf("\n");
+        }
+        return exit_code;
+}
+
+static struct option *long_options=NULL;
+static int long_options_length=0; /* Length of array */
+static int long_options_nr=0; /* Nr of used elements in array */
+static const int LONG_OPTIONS_INCR = 10;
+#define init_longopt() add_longopt(NULL,0)
+
+/* Register a long option. The contents of name is copied. */
+void add_longopt(const char *name,int has_arg)
+{
+        char *tmp;
+        if (!name) { /* init */
+                free(long_options);
+                long_options=NULL;
+                long_options_length=0;
+                long_options_nr=0;
+        }
+
+        if (long_options_nr == long_options_length) {
+                long_options_length += LONG_OPTIONS_INCR;
+                long_options=xrealloc(long_options,
+                                         sizeof(struct option) *
+                                         long_options_length);
+        }
+
+        long_options[long_options_nr].name=NULL;
+        long_options[long_options_nr].has_arg=0;
+        long_options[long_options_nr].flag=NULL;
+        long_options[long_options_nr].val=0;
+
+        if (long_options_nr) { /* Not for init! */
+                long_options[long_options_nr-1].has_arg=has_arg;
+                long_options[long_options_nr-1].flag=NULL;
+                long_options[long_options_nr-1].val=LONG_OPT;
+                tmp = xmalloc(strlen(name)+1);
+                strcpy(tmp,name);
+                long_options[long_options_nr-1].name=tmp;
+        }
+        long_options_nr++;
+}
+
+
+/*
+ * Register several long options. options is a string of long options,
+ * separated by commas or whitespace.
+ * This nukes options!
+ */
+void add_long_options(char *options)
+{
+        int arg_opt, tlen;
+        char *tokptr=strtok(options,", \t\n");
+        while (tokptr) {
+                arg_opt=no_argument;
+               tlen=strlen(tokptr);
+                if (tlen > 0) {
+                        if (tokptr[tlen-1] == ':') {
+                                if (tlen > 1 && tokptr[tlen-2] == ':') {
+                                        tokptr[tlen-2]='\0';
+                                       tlen -= 2;
+                                        arg_opt=optional_argument;
+                                } else {
+                                        tokptr[tlen-1]='\0';
+                                       tlen -= 1;
+                                        arg_opt=required_argument;
+                                }
+                                if (tlen == 0)
+                                        error_msg("empty long option after -l or --long argument");
+                        }
+                        add_longopt(tokptr,arg_opt);
+                }
+                tokptr=strtok(NULL,", \t\n");
+        }
+}
+
+void set_shell(const char *new_shell)
+{
+        if (!strcmp(new_shell,"bash"))
+                shell=BASH;
+        else if (!strcmp(new_shell,"tcsh"))
+                shell=TCSH;
+        else if (!strcmp(new_shell,"sh"))
+                shell=BASH;
+        else if (!strcmp(new_shell,"csh"))
+                shell=TCSH;
+        else
+                error_msg("unknown shell after -s or --shell argument");
+}
+
+
+/* Exit codes:
+ *   0) No errors, succesful operation.
+ *   1) getopt(3) returned an error.
+ *   2) A problem with parameter parsing for getopt(1).
+ *   3) Internal error, out of memory
+ *   4) Returned for -T
+ */
+
+static struct option longopts[]=
+{
+        {"options",required_argument,NULL,'o'},
+        {"longoptions",required_argument,NULL,'l'},
+        {"quiet",no_argument,NULL,'q'},
+        {"quiet-output",no_argument,NULL,'Q'},
+        {"shell",required_argument,NULL,'s'},
+        {"test",no_argument,NULL,'T'},
+        {"unquoted",no_argument,NULL,'u'},
+        {"alternative",no_argument,NULL,'a'},
+        {"name",required_argument,NULL,'n'},
+        {NULL,0,NULL,0}
+};
+
+/* Stop scanning as soon as a non-option argument is found! */
+static const char *shortopts="+ao:l:n:qQs:Tu";
+
+
+int getopt_main(int argc, char *argv[])
+{
+        char *optstr=NULL;
+        char *name=NULL;
+        int opt;
+        int compatible=0;
+
+        init_longopt();
+
+        if (getenv("GETOPT_COMPATIBLE"))
+                compatible=1;
+
+        if (argc == 1) {
+                if (compatible) {
+                        /* For some reason, the original getopt gave no error
+                           when there were no arguments. */
+                        printf(" --\n");
+                        exit(0);
+                } else
+                        error_msg_and_die("missing optstring argument");
+        }
+
+        if (argv[1][0] != '-' || compatible) {
+                quote=0;
+                optstr=xmalloc(strlen(argv[1])+1);
+                strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
+                argv[1]=argv[0];
+                exit(generate_output(argv+1,argc-1,optstr,long_options));
+        }
+
+        while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
+                switch (opt) {
+                case 'a':
+                        alternative=1;
+                        break;
+                case 'o':
+                        if (optstr)
+                                free(optstr);
+                        optstr=xmalloc(strlen(optarg)+1);
+                        strcpy(optstr,optarg);
+                        break;
+                case 'l':
+                        add_long_options(optarg);
+                        break;
+                case 'n':
+                        if (name)
+                                free(name);
+                        name=xmalloc(strlen(optarg)+1);
+                        strcpy(name,optarg);
+                        break;
+                case 'q':
+                        quiet_errors=1;
+                        break;
+                case 'Q':
+                        quiet_output=1;
+                        break;
+                case 's':
+                        set_shell(optarg);
+                        break;
+                case 'T':
+                        exit(4);
+                case 'u':
+                        quote=0;
+                        break;
+                default:
+                        show_usage();
+                }
+
+        if (!optstr) {
+                if (optind >= argc)
+                        error_msg_and_die("missing optstring argument");
+                else {
+                        optstr=xmalloc(strlen(argv[optind])+1);
+                        strcpy(optstr,argv[optind]);
+                        optind++;
+                }
+        }
+        if (name)
+                argv[optind-1]=name;
+        else
+                argv[optind-1]=argv[0];
+        exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options));
+}
+
+/*
+  Local Variables:
+  c-file-style: "linux"
+  c-basic-offset: 4
+  tab-width: 4
+  End:
+*/
diff --git a/grep.c b/grep.c
new file mode 100644 (file)
index 0000000..712d8dc
--- /dev/null
+++ b/grep.c
@@ -0,0 +1,372 @@
+/*
+ * Mini grep implementation for busybox using libc regex.
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley
+ * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org> 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <regex.h>
+#include <string.h> /* for strerror() */
+#include <errno.h>
+#include "busybox.h"
+
+
+extern int optind; /* in unistd.h */
+extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */
+
+/* options */
+static int reflags            = REG_NOSUB; 
+static int print_filename     = 0;
+static int print_line_num     = 0;
+static int print_match_counts = 0;
+static int be_quiet           = 0;
+static int invert_search      = 0;
+static int suppress_err_msgs  = 0;
+static int print_files_with_matches  = 0;
+
+#ifdef BB_FEATURE_GREP_CONTEXT
+extern char *optarg; /* in getopt.h */
+static int lines_before      = 0;
+static int lines_after       = 0;
+static char **before_buf     = NULL;
+static int last_line_printed = 0;
+#endif /* BB_FEATURE_GREP_CONTEXT */
+
+/* globals used internally */
+static regex_t *regexes = NULL; /* growable array of compiled regular expressions */
+static int nregexes = 0; /* number of elements in above arrary */
+static int matched; /* keeps track of whether we ever matched */
+static char *cur_file = NULL; /* the current file we are reading */
+
+
+static void print_line(const char *line, int linenum, char decoration)
+{
+#ifdef BB_FEATURE_GREP_CONTEXT
+       /* possibly print the little '--' seperator */
+       if ((lines_before || lines_after) && last_line_printed &&
+                       last_line_printed < linenum - 1) {
+               puts("--");
+       }
+       last_line_printed = linenum;
+#endif
+       if (print_filename)
+               printf("%s%c", cur_file, decoration);
+       if (print_line_num)
+               printf("%i%c", linenum, decoration);
+       puts(line);
+}
+
+
+static void grep_file(FILE *file)
+{
+       char *line = NULL;
+       int ret;
+       int linenum = 0;
+       int nmatches = 0;
+       int i;
+#ifdef BB_FEATURE_GREP_CONTEXT
+       int print_n_lines_after = 0;
+       int curpos = 0; /* track where we are in the circular 'before' buffer */
+       int idx = 0; /* used for iteration through the circular buffer */
+#endif /* BB_FEATURE_GREP_CONTEXT */ 
+
+       while ((line = get_line_from_file(file)) != NULL) {
+               chomp(line);
+               linenum++;
+
+               for (i = 0; i < nregexes; i++) {
+                       /*
+                        * test for a postitive-assertion match (regexec returns success (0)
+                        * and the user did not specify invert search), or a negative-assertion
+                        * match (regexec returns failure (REG_NOMATCH) and the user specified
+                        * invert search)
+                        */
+                       ret = regexec(&regexes[i], line, 0, NULL, 0);
+                       if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) {
+
+                               /* if we found a match but were told to be quiet, stop here and
+                                * return success */
+                               if (be_quiet)
+                                       exit(0);
+
+                               /* keep track of matches */
+                               nmatches++;
+
+                               /* if we're just printing filenames, we stop after the first match */
+                               if (print_files_with_matches)
+                                       break;
+
+                               /* print the matched line */
+                               if (print_match_counts == 0) {
+#ifdef BB_FEATURE_GREP_CONTEXT
+                                       int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
+
+                                       /* if we were told to print 'before' lines and there is at least
+                                        * one line in the circular buffer, print them */
+                                       if (lines_before && before_buf[prevpos] != NULL) {
+                                               int first_buf_entry_line_num = linenum - lines_before;
+
+                                               /* advance to the first entry in the circular buffer, and
+                                                * figure out the line number is of the first line in the
+                                                * buffer */
+                                               idx = curpos;
+                                               while (before_buf[idx] == NULL) {
+                                                       idx = (idx + 1) % lines_before;
+                                                       first_buf_entry_line_num++;
+                                               }
+
+                                               /* now print each line in the buffer, clearing them as we go */
+                                               while (before_buf[idx] != NULL) {
+                                                       print_line(before_buf[idx], first_buf_entry_line_num, '-');
+                                                       free(before_buf[idx]);
+                                                       before_buf[idx] = NULL;
+                                                       idx = (idx + 1) % lines_before;
+                                                       first_buf_entry_line_num++;
+                                               }
+                                       }
+
+                                       /* make a note that we need to print 'after' lines */
+                                       print_n_lines_after = lines_after;
+#endif /* BB_FEATURE_GREP_CONTEXT */ 
+                                       print_line(line, linenum, ':');
+                               }
+                       }
+#ifdef BB_FEATURE_GREP_CONTEXT
+                       else { /* no match */
+                               /* Add the line to the circular 'before' buffer */
+                               if(lines_before) {
+                                       if(before_buf[curpos])
+                                               free(before_buf[curpos]);
+                                       before_buf[curpos] = xstrdup(line);
+                                       curpos = (curpos + 1) % lines_before;
+                               }
+                       }
+
+                       /* if we need to print some context lines after the last match, do so */
+                       if (print_n_lines_after && (last_line_printed != linenum)) {
+                               print_line(line, linenum, '-');
+                               print_n_lines_after--;
+                       }
+#endif /* BB_FEATURE_GREP_CONTEXT */ 
+               } /* for */
+               free(line);
+       }
+
+
+       /* special-case file post-processing for options where we don't print line
+        * matches, just filenames and possibly match counts */
+
+       /* grep -c: print [filename:]count, even if count is zero */
+       if (print_match_counts) {
+               if (print_filename)
+                       printf("%s:", cur_file);
+               if (print_files_with_matches && nmatches > 0)
+                       printf("1\n");
+               else
+                   printf("%d\n", nmatches);
+       }
+
+       /* grep -l: print just the filename, but only if we grepped the line in the file  */
+       if (print_files_with_matches && nmatches > 0) {
+               puts(cur_file);
+       }
+
+
+       /* remember if we matched */
+       if (nmatches != 0)
+               matched = 1;
+}
+
+
+static void add_regex(const char *restr)
+{
+       regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes));
+       xregcomp(&regexes[nregexes-1], restr, reflags);
+}
+
+
+static void    load_regexes_from_file(const char *filename)
+{
+       char *line;
+       FILE *f = xfopen(filename, "r");
+       while ((line = get_line_from_file(f)) != NULL) {
+               chomp(line);
+               add_regex(line);
+               free(line);
+       }
+}
+
+
+#ifdef BB_FEATURE_CLEAN_UP
+static void destroy_regexes()
+{
+       if (regexes == NULL)
+               return;
+
+       /* destroy all the elments in the array */
+       while (--nregexes >= 0) {
+               regfree(&(regexes[nregexes]));
+       }
+       if (regexes)
+           free(regexes);
+}
+#endif
+
+
+extern int grep_main(int argc, char **argv)
+{
+       int opt;
+#if defined BB_FEATURE_GREP_CONTEXT || defined BB_FEATURE_GREP_EGREP_ALIAS
+       char *junk;
+#endif
+
+#ifdef BB_FEATURE_CLEAN_UP
+       /* destroy command strings on exit */
+       atexit(destroy_regexes);
+#endif
+
+#ifdef BB_FEATURE_GREP_EGREP_ALIAS
+       junk = get_last_path_component(argv[0]);
+       if (junk && strcmp(junk, "egrep") == 0)
+               reflags |= REG_EXTENDED;
+#endif
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "iHhlnqvsce:f:"
+#ifdef BB_FEATURE_GREP_CONTEXT
+"A:B:C:"
+#endif
+#ifdef BB_FEATURE_GREP_EGREP_ALIAS
+"E"
+#endif
+)) > 0) {
+               switch (opt) {
+                       case 'i':
+                               reflags |= REG_ICASE;
+                               break;
+                       case 'l':
+                               print_files_with_matches++;
+                               break;
+                       case 'H':
+                               print_filename++;
+                               break;
+                       case 'h':
+                               print_filename--;
+                               break;
+                       case 'n':
+                               print_line_num++;
+                               break;
+                       case 'q':
+                               be_quiet++;
+                               break;
+                       case 'v':
+                               invert_search++;
+                               break;
+                       case 's':
+                               suppress_err_msgs++;
+                               break;
+                       case 'c':
+                               print_match_counts++;
+                               break;
+                       case 'e':
+                               add_regex(optarg);
+                               break;
+#ifdef BB_FEATURE_GREP_EGREP_ALIAS
+                       case 'E':
+                               reflags |= REG_EXTENDED;
+                               break;
+#endif
+                       case 'f':
+                               load_regexes_from_file(optarg);
+                               break;
+#ifdef BB_FEATURE_GREP_CONTEXT
+                       case 'A':
+                               lines_after = strtoul(optarg, &junk, 10);
+                               if(*junk != '\0')
+                                       error_msg_and_die("invalid context length argument");
+                               break;
+                       case 'B':
+                               lines_before = strtoul(optarg, &junk, 10);
+                               if(*junk != '\0')
+                                       error_msg_and_die("invalid context length argument");
+                               before_buf = (char **)xcalloc(lines_before, sizeof(char *));
+                               break;
+                       case 'C':
+                               lines_after = lines_before = strtoul(optarg, &junk, 10);
+                               if(*junk != '\0')
+                                       error_msg_and_die("invalid context length argument");
+                               before_buf = (char **)xcalloc(lines_before, sizeof(char *));
+                               break;
+#endif /* BB_FEATURE_GREP_CONTEXT */
+                       default:
+                               show_usage();
+               }
+       }
+
+       /* if we didn't get a pattern from a -e and no command file was specified,
+        * argv[optind] should be the pattern. no pattern, no worky */
+       if (nregexes == 0) {
+               if (argv[optind] == NULL)
+                       show_usage();
+               else {
+                       add_regex(argv[optind]);
+                       optind++;
+               }
+       }
+
+       /* sanity checks */
+       if (print_match_counts || be_quiet || print_files_with_matches) {
+               print_line_num = 0;
+#ifdef BB_FEATURE_GREP_CONTEXT
+               lines_before = 0;
+               lines_after = 0;
+#endif
+       }
+
+       /* argv[(optind)..(argc-1)] should be names of file to grep through. If
+        * there is more than one file to grep, we will print the filenames */
+       if ((argc-1) - (optind) > 0)
+               print_filename++;
+
+       /* If no files were specified, or '-' was specified, take input from
+        * stdin. Otherwise, we grep through all the files specified. */
+       if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
+               grep_file(stdin);
+       }
+       else {
+               int i;
+               FILE *file;
+               for (i = optind; i < argc; i++) {
+                       cur_file = argv[i];
+                       file = fopen(cur_file, "r");
+                       if (file == NULL) {
+                               if (!suppress_err_msgs)
+                                       perror_msg("%s", cur_file);
+                       }
+                       else {
+                               grep_file(file);
+                               fclose(file);
+                       }
+               }
+       }
+
+       return !matched; /* invert return value 0 = success, 1 = failed */
+}
diff --git a/gunzip.c b/gunzip.c
new file mode 100644 (file)
index 0000000..5a7b103
--- /dev/null
+++ b/gunzip.c
@@ -0,0 +1,203 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersee@debian.org> to support files as
+ * well as stdin/stdout, and to generally behave itself wrt command line
+ * handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath <bug1@optushome.com.au>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#if 0
+static char *license_msg[] = {
+       "   Copyright (C) 1992-1993 Jean-loup Gailly",
+       "   This program is free software; you can redistribute it and/or modify",
+       "   it under the terms of the GNU General Public License as published by",
+       "   the Free Software Foundation; either version 2, or (at your option)",
+       "   any later version.",
+       "",
+       "   This program is distributed in the hope that it will be useful,",
+       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
+       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
+       "   GNU General Public License for more details.",
+       "",
+       "   You should have received a copy of the GNU General Public License",
+       "   along with this program; if not, write to the Free Software",
+       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+       0
+};
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "busybox.h"
+
+const int gunzip_to_stdout = 1;
+const int gunzip_force = 2;
+const int gunzip_test = 4;
+const int gunzip_verbose = 8;
+
+static int gunzip_file (const char *path, int flags)
+{
+       FILE *in_file, *out_file;
+       struct stat stat_buf;
+       const char *delete_path = NULL;
+       char *out_path = NULL;
+
+       if (path == NULL || strcmp (path, "-") == 0) {
+               in_file = stdin;
+               flags |= gunzip_to_stdout;
+       } else {
+               if ((in_file = wfopen(path, "r")) == NULL)
+                       return -1;
+
+               if (flags & gunzip_verbose) {
+                       fprintf(stderr, "%s:\t", path);
+               }
+
+               /* set the buffer size */
+               setvbuf(in_file, NULL, _IOFBF, 0x8000);
+
+               /* Get the time stamp on the input file. */
+               if (stat(path, &stat_buf) < 0) {
+                       error_msg_and_die("Couldn't stat file %s", path);
+               }
+       }
+
+       /* Check that the input is sane.  */
+       if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0)
+               error_msg_and_die("compressed data not read from terminal.  Use -f to force it.");
+
+       /* Set output filename and number */
+       if (flags & gunzip_test) {
+               out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
+       } else if (flags & gunzip_to_stdout) {
+               out_file = stdout;
+       } else {
+               char *extension;
+               int length = strlen(path);
+
+               extension = strrchr(path, '.');
+               if (extension && strcmp(extension, ".gz") == 0) {
+                       length -= 3;
+               } else if (extension && strcmp(extension, ".tgz") == 0) {
+                       length -= 4;
+               } else {
+                       error_msg_and_die("Invalid extension");
+               }
+               out_path = (char *) xcalloc(sizeof(char), length + 1);
+               strncpy(out_path, path, length);
+
+               /* Open output file */
+               out_file = xfopen(out_path, "w");
+
+               /* Set permissions on the file */
+               chmod(out_path, stat_buf.st_mode);
+       }
+
+       /* do the decompression, and cleanup */
+       if (unzip(in_file, out_file) == 0) {
+               /* Success, remove .gz file */
+               if ( !(flags & gunzip_to_stdout ))
+                       delete_path = path;
+               if (flags & gunzip_verbose) {
+                       fprintf(stderr, "OK\n");
+               }
+       } else {
+               /* remove failed attempt */
+               delete_path = out_path;
+       }
+
+       fclose(out_file);
+       fclose(in_file);
+
+       if (delete_path && !(flags & gunzip_test)) {
+               if (unlink(delete_path) < 0) {
+                       error_msg_and_die("Couldn't remove %s", delete_path);
+               }
+       }
+
+       free(out_path);
+
+       return 0;
+}
+
+extern int gunzip_main(int argc, char **argv)
+{
+       int flags = 0;
+       int i, opt;
+       int status = EXIT_SUCCESS;
+
+       /* if called as zcat */
+       if (strcmp(applet_name, "zcat") == 0)
+               flags |= gunzip_to_stdout;
+
+       while ((opt = getopt(argc, argv, "ctfhdqv")) != -1) {
+               switch (opt) {
+                       case 'c':
+                               flags |= gunzip_to_stdout;
+                               break;
+                       case 'f':
+                               flags |= gunzip_force;
+                               break;
+                       case 't':
+                               flags |= gunzip_test;
+                               break;
+                       case 'v':
+                               flags |= gunzip_verbose;
+                               break;
+                       case 'd': /* Used to convert gzip to gunzip. */
+                               break;
+                       case 'q':
+                               error_msg("-q option not supported, ignored");
+                               break;
+                       case 'h':
+                       default:
+                               show_usage(); /* exit's inside usage */
+               }
+       }
+
+       if (optind == argc) {
+               if (gunzip_file (NULL, flags) < 0)
+                       status = EXIT_FAILURE;
+       } else
+               for (i = optind; i < argc; i++)
+                       if (gunzip_file (argv[i], flags) < 0)
+                               status = EXIT_FAILURE;
+
+       return status;
+}
diff --git a/gzip.c b/gzip.c
new file mode 100644 (file)
index 0000000..413ebd5
--- /dev/null
+++ b/gzip.c
@@ -0,0 +1,2552 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com>
+ *             "this is a stripped down version of gzip I put into busybox, it does
+ *             only standard in to standard out with -9 compression.  It also requires
+ *             the zcat module for some important functions."
+ *
+ * Adjusted further by Erik Andersen <andersee@debian.org>
+ * to support files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* These defines are very important for BusyBox.  Without these,
+ * huge chunks of ram are pre-allocated making the BusyBox bss 
+ * size Freaking Huge(tm), which is a bad thing.*/
+#define SMALL_MEM
+#define DYN_ALLOC
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <utime.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <time.h>
+#include "busybox.h"
+
+#define memzero(s, n)     memset ((void *)(s), 0, (n))
+
+#ifndef RETSIGTYPE
+#  define RETSIGTYPE void
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK      0
+#define ERROR   1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+/* Only STORED and DEFLATED are supported by this BusyBox module */
+#define STORED      0
+/* methods 4 to 7 reserved */
+#define DEFLATED    8
+static int method;                             /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate:  prev+head   window      d_buf  l_buf  outbuf
+ * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef        INBUFSIZ
+#  ifdef SMALL_MEM
+#    define INBUFSIZ  0x2000   /* input buffer size */
+#  else
+#    define INBUFSIZ  0x8000   /* input buffer size */
+#  endif
+#endif
+#define INBUF_EXTRA  64                        /* required by unlzw() */
+
+#ifndef        OUTBUFSIZ
+#  ifdef SMALL_MEM
+#    define OUTBUFSIZ   8192   /* output buffer size */
+#  else
+#    define OUTBUFSIZ  16384   /* output buffer size */
+#  endif
+#endif
+#define OUTBUF_EXTRA 2048              /* required by unlzw() */
+
+#ifndef DIST_BUFSIZE
+#  ifdef SMALL_MEM
+#    define DIST_BUFSIZE 0x2000        /* buffer for distances, see trees.c */
+#  else
+#    define DIST_BUFSIZE 0x8000        /* buffer for distances, see trees.c */
+#  endif
+#endif
+
+#ifdef DYN_ALLOC
+#  define DECLARE(type, array, size)  static type * array
+#  define ALLOC(type, array, size) { \
+      array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
+      if (array == NULL) error_msg(memory_exhausted); \
+   }
+#  define FREE(array) {if (array != NULL) free(array), array=NULL;}
+#else
+#  define DECLARE(type, array, size)  static type array[size]
+#  define ALLOC(type, array, size)
+#  define FREE(array)
+#endif
+
+#define tab_suffix window
+#define tab_prefix prev                /* hash link (see deflate.c) */
+#define head (prev+WSIZE)              /* hash head (see deflate.c) */
+
+static long bytes_in;                  /* number of input bytes */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+typedef int file_t;                            /* Do not use stdio */
+
+#define NO_FILE  (-1)                  /* in memory compression */
+
+
+#define        PACK_MAGIC     "\037\036"       /* Magic header for packed files */
+#define        GZIP_MAGIC     "\037\213"       /* Magic header for gzip files, 1F 8B */
+#define        OLD_GZIP_MAGIC "\037\236"       /* Magic header for gzip 0.5 = freeze 1.x */
+#define        LZH_MAGIC      "\037\240"       /* Magic header for SCO LZH Compress files */
+#define PKZIP_MAGIC    "\120\113\003\004"      /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01              /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02              /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04              /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08              /* bit 3 set: original file name present */
+#define COMMENT      0x10              /* bit 4 set: file comment present */
+#define RESERVED     0xC0              /* bit 6,7:   reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY  0
+#define ASCII   1
+
+#ifndef WSIZE
+#  define WSIZE 0x8000                 /* window size--must be a power of two, and */
+#endif                                                 /*  at least 32K for zip's deflate method */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+/* put_byte is used for the compressed output */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+   flush_outbuf();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+    outbuf[outcnt++] = (uch) ((w) & 0xff); \
+    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+  } else { \
+    put_byte((uch)((w) & 0xff)); \
+    put_byte((uch)((ush)(w) >> 8)); \
+  } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+    put_short((n) & 0xffff); \
+    put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable()    0                        /* force sequential output */
+#define translate_eol 0                        /* no option -a yet */
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error_msg(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+                  if (exit_code == OK) exit_code = WARNING;}
+
+#ifndef MAX_PATH_LEN
+#  define MAX_PATH_LEN   1024  /* max pathname length */
+#endif
+
+
+
+       /* from zip.c: */
+static int zip (int in, int out);
+static int file_read (char *buf, unsigned size);
+
+       /* from gzip.c */
+static RETSIGTYPE abort_gzip (void);
+
+               /* from deflate.c */
+static void lm_init (ush * flags);
+static ulg deflate (void);
+
+               /* from trees.c */
+static void ct_init (ush * attr, int *methodp);
+static int ct_tally (int dist, int lc);
+static ulg flush_block (char *buf, ulg stored_len, int eof);
+
+               /* from bits.c */
+static void bi_init (file_t zipfile);
+static void send_bits (int value, int length);
+static unsigned bi_reverse (unsigned value, int length);
+static void bi_windup (void);
+static void copy_block (char *buf, unsigned len, int header);
+static int (*read_buf) (char *buf, unsigned size);
+
+       /* from util.c: */
+static void flush_outbuf (void);
+
+/* lzw.h -- define the lzw functions.
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if !defined(OF) && defined(lint)
+#  include "gzip.h"
+#endif
+
+#ifndef BITS
+#  define BITS 16
+#endif
+#define INIT_BITS 9                            /* Initial number of bits per code */
+
+#define BIT_MASK    0x1f               /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+/* tailor.h -- target dependent definitions
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* The target dependent definitions should be defined here only.
+ * The target dependent functions should be defined in tailor.c.
+ */
+
+
+       /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03                        /* assume Unix */
+#endif
+
+#ifndef PATH_SEP
+#  define PATH_SEP '/'
+#endif
+
+#ifndef OPTIONS_VAR
+#  define OPTIONS_VAR "GZIP"
+#endif
+
+#ifndef Z_SUFFIX
+#  define Z_SUFFIX ".gz"
+#endif
+
+#ifdef MAX_EXT_CHARS
+#  define MAX_SUFFIX  MAX_EXT_CHARS
+#else
+#  define MAX_SUFFIX  30
+#endif
+
+               /* global buffers */
+
+DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
+DECLARE(ush, d_buf, DIST_BUFSIZE);
+DECLARE(uch, window, 2L * WSIZE);
+DECLARE(ush, tab_prefix, 1L << BITS);
+
+static int crc_table_empty = 1;
+
+static int foreground;                                 /* set if program run in foreground */
+static int method = DEFLATED;  /* compression method */
+static int exit_code = OK;             /* program exit code */
+static int part_nb;                                    /* number of parts in .gz file */
+static long time_stamp;                                /* original time stamp (modification time) */
+static long ifile_size;                                /* input file size, -1 for devices (debug only) */
+
+static char ifname[MAX_PATH_LEN];              /* input file name */
+static char ofname[MAX_PATH_LEN];              /* output file name */
+static int ifd;                                                /* input file descriptor */
+static int ofd;                                                /* output file descriptor */
+static unsigned insize;                                /* valid bytes in inbuf */
+static unsigned outcnt;                                /* bytes in output buffer */
+
+/* ========================================================================
+ * Signal and error handler.
+ */
+static void abort_gzip()
+{
+       exit(ERROR);
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+static void clear_bufs(void)
+{
+       outcnt = 0;
+       insize = 0;
+       bytes_in = 0L;
+}
+
+static void write_error_msg()
+{
+       fprintf(stderr, "\n");
+       perror("");
+       abort_gzip();
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ */
+static void write_buf(int fd, void *buf, unsigned cnt)
+{
+       unsigned n;
+
+       while ((n = write(fd, buf, cnt)) != cnt) {
+               if (n == (unsigned) (-1)) {
+                       write_error_msg();
+               }
+               cnt -= n;
+               buf = (void *) ((char *) buf + n);
+       }
+}
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+static ulg updcrc(uch *s, unsigned n)
+{
+       static ulg crc = (ulg) 0xffffffffL;     /* shift register contents */
+       register ulg c;                         /* temporary variable */
+       static unsigned long crc_32_tab[256];
+       if (crc_table_empty) {
+               unsigned long csr;      /* crc shift register */
+               unsigned long e=0;      /* polynomial exclusive-or pattern */
+               int i;                /* counter for all possible eight bit values */
+               int k;                /* byte being shifted into crc apparatus */
+
+               /* terms of polynomial defining this crc (except x^32): */
+               static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+               /* Make exclusive-or pattern from polynomial (0xedb88320) */
+               for (i = 0; i < sizeof(p)/sizeof(int); i++)
+                       e |= 1L << (31 - p[i]);
+
+               /* Compute and print table of CRC's, five per line */
+               crc_32_tab[0] = 0x00000000L;
+               for (i = 1; i < 256; i++) {
+                       csr = i;
+                  /* The idea to initialize the register with the byte instead of
+                    * zero was stolen from Haruhiko Okumura's ar002
+                    */
+                       for (k = 8; k; k--)
+                               csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1;
+                       crc_32_tab[i]=csr;
+               }
+       }
+
+       if (s == NULL) {
+               c = 0xffffffffL;
+       } else {
+               c = crc;
+               if (n)
+                       do {
+                               c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8);
+                       } while (--n);
+       }
+       crc = c;
+       return c ^ 0xffffffffL;         /* (instead of ~c for 64-bit machines) */
+}
+
+/* bits.c -- output variable-length bit strings
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+/*
+ *  PURPOSE
+ *
+ *      Output variable-length bit strings. Compression can be done
+ *      to a file or to memory. (The latter is not supported in this version.)
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflate" file format interprets compressed file data
+ *      as a sequence of bits.  Multi-bit strings in the file may cross
+ *      byte boundaries without restriction.
+ *
+ *      The first bit of each byte is the low-order bit.
+ *
+ *      The routines in this file allow a variable-length bit value to
+ *      be output right-to-left (useful for literal values). For
+ *      left-to-right output (useful for code strings from the tree routines),
+ *      the bits must have been reversed first with bi_reverse().
+ *
+ *      For in-memory compression, the compressed bit stream goes directly
+ *      into the requested output buffer. The input data is read in blocks
+ *      by the mem_read() function. The buffer is limited to 64K on 16 bit
+ *      machines.
+ *
+ *  INTERFACE
+ *
+ *      void bi_init (FILE *zipfile)
+ *          Initialize the bit string routines.
+ *
+ *      void send_bits (int value, int length)
+ *          Write out a bit string, taking the source bits right to
+ *          left.
+ *
+ *      int bi_reverse (int value, int length)
+ *          Reverse the bits of a bit string, taking the source bits left to
+ *          right and emitting them right to left.
+ *
+ *      void bi_windup (void)
+ *          Write out any remaining bits in an incomplete byte.
+ *
+ *      void copy_block(char *buf, unsigned len, int header)
+ *          Copy a stored block to the zip file, storing first the length and
+ *          its one's complement if requested.
+ *
+ */
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+static file_t zfile;                           /* output gzip file */
+
+static unsigned short bi_buf;
+
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+static int bi_valid;
+
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+ulg bits_sent;                                 /* bit length of the compressed data */
+#endif
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+static void bi_init(file_t zipfile)
+{
+       zfile = zipfile;
+       bi_buf = 0;
+       bi_valid = 0;
+#ifdef DEBUG
+       bits_sent = 0L;
+#endif
+
+       /* Set the defaults for file compression. They are set by memcompress
+        * for in-memory compression.
+        */
+       if (zfile != NO_FILE) {
+               read_buf = file_read;
+       }
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+static void send_bits(int value, int length)
+{
+#ifdef DEBUG
+       Tracev((stderr, " l %2d v %4x ", length, value));
+       Assert(length > 0 && length <= 15, "invalid length");
+       bits_sent += (ulg) length;
+#endif
+       /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+        * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+        * unused bits in value.
+        */
+       if (bi_valid > (int) Buf_size - length) {
+               bi_buf |= (value << bi_valid);
+               put_short(bi_buf);
+               bi_buf = (ush) value >> (Buf_size - bi_valid);
+               bi_valid += length - Buf_size;
+       } else {
+               bi_buf |= value << bi_valid;
+               bi_valid += length;
+       }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static unsigned bi_reverse(unsigned code, int len)
+{
+       register unsigned res = 0;
+
+       do {
+               res |= code & 1;
+               code >>= 1, res <<= 1;
+       } while (--len > 0);
+       return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+static void bi_windup()
+{
+       if (bi_valid > 8) {
+               put_short(bi_buf);
+       } else if (bi_valid > 0) {
+               put_byte(bi_buf);
+       }
+       bi_buf = 0;
+       bi_valid = 0;
+#ifdef DEBUG
+       bits_sent = (bits_sent + 7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+static void copy_block(char *buf, unsigned len, int header)
+{
+       bi_windup();                            /* align on byte boundary */
+
+       if (header) {
+               put_short((ush) len);
+               put_short((ush) ~ len);
+#ifdef DEBUG
+               bits_sent += 2 * 16;
+#endif
+       }
+#ifdef DEBUG
+       bits_sent += (ulg) len << 3;
+#endif
+       while (len--) {
+               put_byte(*buf++);
+       }
+}
+
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Identify new text as repetitions of old text within a fixed-
+ *      length sliding window trailing behind the new text.
+ *
+ *  DISCUSSION
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many info-zippers for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ *  INTERFACE
+ *
+ *      void lm_init (int pack_level, ush *flags)
+ *          Initialize the "longest match" routines for a new file
+ *
+ *      ulg deflate (void)
+ *          Processes a new input file and return its compressed length. Sets
+ *          the compressed length, crc, deflate flags and internal file
+ *          attributes.
+ */
+
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+#   define HASH_BITS  13               /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+#   define HASH_BITS  14
+#endif
+#ifndef HASH_BITS
+#   define HASH_BITS  15
+   /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
+ * window with tab_suffix. Check that we can do this:
+ */
+#if (WSIZE<<1) > (1<<BITS)
+#  error cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+#  error cannot overlay head with tab_prefix1
+#endif
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK     (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+#define NIL 0
+/* Tail of hash chains */
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+typedef ush Pos;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+/* DECLARE(uch, window, 2L*WSIZE); */
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+
+/* DECLARE(Pos, prev, WSIZE); */
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+/* DECLARE(Pos, head, 1<<HASH_BITS); */
+/* Heads of the hash chains or NIL. */
+
+static const ulg window_size = (ulg) 2 * WSIZE;
+
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+static long block_start;
+
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+static unsigned ins_h;                 /* hash index of string to be inserted */
+
+#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ *   H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+static unsigned int prev_length;
+
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+static unsigned strstart;                      /* start of string to insert */
+static unsigned match_start;           /* start of matching string */
+static int eofile;                             /* flag set at end of input file */
+static unsigned lookahead;             /* number of valid bytes ahead in window */
+
+static const unsigned max_chain_length=4096;
+
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+static const unsigned int max_lazy_match=258;
+
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+#define max_insert_length  max_lazy_match
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+static const unsigned good_match=32;
+
+/* Use a faster search when the previous match is longer than this */
+
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+static const int nice_match=258;                       /* Stop searching when current match exceeds this */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ *  Prototypes for local functions.
+ */
+static void fill_window (void);
+
+static int longest_match (IPos cur_match);
+
+#ifdef DEBUG
+static void check_match (IPos start, IPos match, int length);
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of s are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+   (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+    prev[(s) & WMASK] = match_head = head[ins_h], \
+    head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+static void lm_init(ush *flags)
+{
+       register unsigned j;
+
+       /* Initialize the hash table. */
+       memzero((char *) head, HASH_SIZE * sizeof(*head));
+       /* prev will be initialized on the fly */
+
+       *flags |= SLOW;
+       /* ??? reduce max_chain_length for binary files */
+
+       strstart = 0;
+       block_start = 0L;
+
+       lookahead = read_buf((char *) window,
+                                                sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE);
+
+       if (lookahead == 0 || lookahead == (unsigned) EOF) {
+               eofile = 1, lookahead = 0;
+               return;
+       }
+       eofile = 0;
+       /* Make sure that we always have enough lookahead. This is important
+        * if input comes from a device such as a tty.
+        */
+       while (lookahead < MIN_LOOKAHEAD && !eofile)
+               fill_window();
+
+       ins_h = 0;
+       for (j = 0; j < MIN_MATCH - 1; j++)
+               UPDATE_HASH(ins_h, window[j]);
+       /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+        * not important since only literal bytes will be emitted.
+        */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+static int longest_match(IPos cur_match)
+{
+       unsigned chain_length = max_chain_length;       /* max hash chain length */
+       register uch *scan = window + strstart; /* current string */
+       register uch *match;            /* matched string */
+       register int len;                       /* length of current match */
+       int best_len = prev_length;     /* best match length so far */
+       IPos limit =
+
+               strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL;
+       /* Stop when cur_match becomes <= limit. To simplify the code,
+        * we prevent matches with the string of window index 0.
+        */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+#  error Code too clever
+#endif
+       register uch *strend = window + strstart + MAX_MATCH;
+       register uch scan_end1 = scan[best_len - 1];
+       register uch scan_end = scan[best_len];
+
+       /* Do not waste too much time if we already have a good match: */
+       if (prev_length >= good_match) {
+               chain_length >>= 2;
+       }
+       Assert(strstart <= window_size - MIN_LOOKAHEAD,
+                  "insufficient lookahead");
+
+       do {
+               Assert(cur_match < strstart, "no future");
+               match = window + cur_match;
+
+               /* Skip to next match if the match length cannot increase
+                * or if the match length is less than 2:
+                */
+               if (match[best_len] != scan_end ||
+                       match[best_len - 1] != scan_end1 ||
+                       *match != *scan || *++match != scan[1])
+                       continue;
+
+               /* The check at best_len-1 can be removed because it will be made
+                * again later. (This heuristic is not always a win.)
+                * It is not necessary to compare scan[2] and match[2] since they
+                * are always equal when the other bytes match, given that
+                * the hash keys are equal and that HASH_BITS >= 8.
+                */
+               scan += 2, match++;
+
+               /* We check for insufficient lookahead only every 8th comparison;
+                * the 256th check will be made at strstart+258.
+                */
+               do {
+               } while (*++scan == *++match && *++scan == *++match &&
+                                *++scan == *++match && *++scan == *++match &&
+                                *++scan == *++match && *++scan == *++match &&
+                                *++scan == *++match && *++scan == *++match &&
+                                scan < strend);
+
+               len = MAX_MATCH - (int) (strend - scan);
+               scan = strend - MAX_MATCH;
+
+               if (len > best_len) {
+                       match_start = cur_match;
+                       best_len = len;
+                       if (len >= nice_match)
+                               break;
+                       scan_end1 = scan[best_len - 1];
+                       scan_end = scan[best_len];
+               }
+       } while ((cur_match = prev[cur_match & WMASK]) > limit
+                        && --chain_length != 0);
+
+       return best_len;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+static void check_match(IPos start, IPos match, int length)
+{
+       /* check that the match is indeed a match */
+       if (memcmp((char *) window + match,
+                          (char *) window + start, length) != EQUAL) {
+               fprintf(stderr,
+                               " start %d, match %d, length %d\n", start, match, length);
+               error_msg("invalid match");
+       }
+       if (verbose > 1) {
+               fprintf(stderr, "\\[%d,%d]", start - match, length);
+               do {
+                       putc(window[start++], stderr);
+               } while (--length != 0);
+       }
+}
+#else
+#  define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ *    file reads are performed for at least two bytes (required for the
+ *    translate_eol option).
+ */
+static void fill_window()
+{
+       register unsigned n, m;
+       unsigned more =
+
+               (unsigned) (window_size - (ulg) lookahead - (ulg) strstart);
+       /* Amount of free space at the end of the window. */
+
+       /* If the window is almost full and there is insufficient lookahead,
+        * move the upper half to the lower one to make room in the upper half.
+        */
+       if (more == (unsigned) EOF) {
+               /* Very unlikely, but possible on 16 bit machine if strstart == 0
+                * and lookahead == 1 (input done one byte at time)
+                */
+               more--;
+       } else if (strstart >= WSIZE + MAX_DIST) {
+               /* By the IN assertion, the window is not empty so we can't confuse
+                * more == 0 with more == 64K on a 16 bit machine.
+                */
+               Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM");
+
+               memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE);
+               match_start -= WSIZE;
+               strstart -= WSIZE;              /* we now have strstart >= MAX_DIST: */
+
+               block_start -= (long) WSIZE;
+
+               for (n = 0; n < HASH_SIZE; n++) {
+                       m = head[n];
+                       head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
+               }
+               for (n = 0; n < WSIZE; n++) {
+                       m = prev[n];
+                       prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
+                       /* If n is not on any hash chain, prev[n] is garbage but
+                        * its value will never be used.
+                        */
+               }
+               more += WSIZE;
+       }
+       /* At this point, more >= 2 */
+       if (!eofile) {
+               n = read_buf((char *) window + strstart + lookahead, more);
+               if (n == 0 || n == (unsigned) EOF) {
+                       eofile = 1;
+               } else {
+                       lookahead += n;
+               }
+       }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+                (char*)NULL, (long)strstart - block_start, (eof))
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+static ulg deflate()
+{
+       IPos hash_head;                         /* head of hash chain */
+       IPos prev_match;                        /* previous match */
+       int flush;                                      /* set if current block must be flushed */
+       int match_available = 0;        /* set if previous match exists */
+       register unsigned match_length = MIN_MATCH - 1; /* length of best match */
+
+       /* Process the input block. */
+       while (lookahead != 0) {
+               /* Insert the string window[strstart .. strstart+2] in the
+                * dictionary, and set hash_head to the head of the hash chain:
+                */
+               INSERT_STRING(strstart, hash_head);
+
+               /* Find the longest match, discarding those <= prev_length.
+                */
+               prev_length = match_length, prev_match = match_start;
+               match_length = MIN_MATCH - 1;
+
+               if (hash_head != NIL && prev_length < max_lazy_match &&
+                       strstart - hash_head <= MAX_DIST) {
+                       /* To simplify the code, we prevent matches with the string
+                        * of window index 0 (in particular we have to avoid a match
+                        * of the string with itself at the start of the input file).
+                        */
+                       match_length = longest_match(hash_head);
+                       /* longest_match() sets match_start */
+                       if (match_length > lookahead)
+                               match_length = lookahead;
+
+                       /* Ignore a length 3 match if it is too distant: */
+                       if (match_length == MIN_MATCH
+                               && strstart - match_start > TOO_FAR) {
+                               /* If prev_match is also MIN_MATCH, match_start is garbage
+                                * but we will ignore the current match anyway.
+                                */
+                               match_length--;
+                       }
+               }
+               /* If there was a match at the previous step and the current
+                * match is not better, output the previous match:
+                */
+               if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+
+                       check_match(strstart - 1, prev_match, prev_length);
+
+                       flush =
+                               ct_tally(strstart - 1 - prev_match,
+                                                prev_length - MIN_MATCH);
+
+                       /* Insert in hash table all strings up to the end of the match.
+                        * strstart-1 and strstart are already inserted.
+                        */
+                       lookahead -= prev_length - 1;
+                       prev_length -= 2;
+                       do {
+                               strstart++;
+                               INSERT_STRING(strstart, hash_head);
+                               /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                                * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                                * these bytes are garbage, but it does not matter since the
+                                * next lookahead bytes will always be emitted as literals.
+                                */
+                       } while (--prev_length != 0);
+                       match_available = 0;
+                       match_length = MIN_MATCH - 1;
+                       strstart++;
+                       if (flush)
+                               FLUSH_BLOCK(0), block_start = strstart;
+
+               } else if (match_available) {
+                       /* If there was no match at the previous position, output a
+                        * single literal. If there was a match but the current match
+                        * is longer, truncate the previous match to a single literal.
+                        */
+                       Tracevv((stderr, "%c", window[strstart - 1]));
+                       if (ct_tally(0, window[strstart - 1])) {
+                               FLUSH_BLOCK(0), block_start = strstart;
+                       }
+                       strstart++;
+                       lookahead--;
+               } else {
+                       /* There is no previous match to compare with, wait for
+                        * the next step to decide.
+                        */
+                       match_available = 1;
+                       strstart++;
+                       lookahead--;
+               }
+               Assert(strstart <= isize && lookahead <= isize, "a bit too far");
+
+               /* Make sure that we always have enough lookahead, except
+                * at the end of the input file. We need MAX_MATCH bytes
+                * for the next match, plus MIN_MATCH bytes to insert the
+                * string following the next match.
+                */
+               while (lookahead < MIN_LOOKAHEAD && !eofile)
+                       fill_window();
+       }
+       if (match_available)
+               ct_tally(0, window[strstart - 1]);
+
+       return FLUSH_BLOCK(1);          /* eof */
+}
+
+/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+/* Compress files with zip algorithm and 'compress' interface.
+ * See usage() and help() functions below for all options.
+ * Outputs:
+ *        file.gz:   compressed file with same mode, owner, and utimes
+ *     or stdout with -c option or if stdin used as input.
+ * If the output file name had to be truncated, the original name is kept
+ * in the compressed file.
+ */
+
+               /* configuration */
+
+typedef struct dirent dir_type;
+
+typedef RETSIGTYPE(*sig_type) (int);
+
+
+/* ======================================================================== */
+// int main (argc, argv)
+//    int argc;
+//    char **argv;
+int gzip_main(int argc, char **argv)
+{
+       int result;
+       int inFileNum;
+       int outFileNum;
+       struct stat statBuf;
+       char *delFileName;
+       int tostdout = 0;
+       int force = 0;
+       int opt;
+
+       while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) {
+               switch (opt) {
+               case 'c':
+                       tostdout = 1;
+                       break;
+               case 'f':
+                       force = 1;
+                       break;
+               /* Ignore 1-9 (compression level) options */
+               case '1': case '2': case '3': case '4': case '5':
+               case '6': case '7': case '8': case '9':
+                       break;
+               case 'q':
+                       break;
+#ifdef BB_GUNZIP
+               case 'd':
+                       optind = 1;
+                       return gunzip_main(argc, argv);
+#endif
+               default:
+                       show_usage();
+               }
+       }
+       if (optind == argc) {
+               optind--;
+               argv[optind] = "-";
+       }
+
+       for(opt = optind; opt < argc; opt++)
+               if (strcmp(argv[opt], "-") == 0)
+                       tostdout |= 2;
+
+       if (tostdout && force==0 && isatty(fileno(stdout)))
+               error_msg_and_die( "compressed data not written to terminal. Use -f to force it.");
+
+       foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
+       if (foreground) {
+               (void) signal(SIGINT, (sig_type) abort_gzip);
+       }
+#ifdef SIGTERM
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+               (void) signal(SIGTERM, (sig_type) abort_gzip);
+       }
+#endif
+#ifdef SIGHUP
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+               (void) signal(SIGHUP, (sig_type) abort_gzip);
+       }
+#endif
+
+       /* Allocate all global buffers (for DYN_ALLOC option) */
+       ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
+       ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
+       ALLOC(ush, d_buf, DIST_BUFSIZE);
+       ALLOC(uch, window, 2L * WSIZE);
+       ALLOC(ush, tab_prefix, 1L << BITS);
+
+               while (optind < argc) {
+               if (strcmp(argv[optind++], "-") == 0) {
+                               strcpy(ofname, "stdin");
+
+                               inFileNum = fileno(stdin);
+                               time_stamp = 0;                 /* time unknown by default */
+                               ifile_size = -1L;               /* convention for unknown size */
+                       tostdout |= 2;
+                       } else {
+                       tostdout &= ~2;
+                               /* Open up the input file */
+                               strncpy(ifname, argv[optind++], MAX_PATH_LEN);
+
+                               /* Open input file */
+                               inFileNum = open(ifname, O_RDONLY);
+                               if (inFileNum < 0)
+                                       perror_msg_and_die("%s", ifname);
+                               /* Get the time stamp on the input file. */
+                               if (stat(ifname, &statBuf) < 0)
+                                       perror_msg_and_die("%s", ifname);
+                               time_stamp = statBuf.st_ctime;
+                               ifile_size = statBuf.st_size;
+                       }
+
+
+               if (tostdout) {
+                               /* And get to work */
+                               strcpy(ofname, "stdout");
+                               outFileNum = fileno(stdout);
+
+                               clear_bufs();                   /* clear input and output buffers */
+                               part_nb = 0;
+
+                               /* Actually do the compression/decompression. */
+                               zip(inFileNum, outFileNum);
+
+                       } else {
+
+                               /* And get to work */
+                               strncpy(ofname, ifname, MAX_PATH_LEN - 4);
+                               strcat(ofname, ".gz");
+
+
+                               /* Open output fille */
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+                               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW);
+#else
+                               outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL);
+#endif
+                               if (outFileNum < 0)
+                                       perror_msg_and_die("%s", ofname);
+                               /* Set permissions on the file */
+                               fchmod(outFileNum, statBuf.st_mode);
+
+                               clear_bufs();                   /* clear input and output buffers */
+                               part_nb = 0;
+
+                               /* Actually do the compression/decompression. */
+                               result = zip(inFileNum, outFileNum);
+                               close(outFileNum);
+                               close(inFileNum);
+                               /* Delete the original file */
+                               if (result == OK)
+                                       delFileName = ifname;
+                               else
+                                       delFileName = ofname;
+
+                               if (unlink(delFileName) < 0)
+                                       perror_msg_and_die("%s", delFileName);
+                       }
+               }      /* while () */
+
+       return(exit_code);
+}
+
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Encode various sets of source values using variable-length
+ *      binary code trees.
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in the ZIP file in a compressed form
+ *      which is itself a Huffman encoding of the lengths of
+ *      all the code strings (in ascending order by source values).
+ *      The actual code strings are reconstructed from the lengths in
+ *      the UNZIP process, as described in the "application note"
+ *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ *  REFERENCES
+ *
+ *      Lynch, Thomas J.
+ *          Data Compression:  Techniques and Applications, pp. 53-55.
+ *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ *  INTERFACE
+ *
+ *      void ct_init (ush *attr, int *methodp)
+ *          Allocate the match buffer, initialize the various tables and save
+ *          the location of the internal file attribute (ascii/binary) and
+ *          method (DEFLATE/STORE)
+ *
+ *      void ct_tally (int dist, int lc);
+ *          Save the match info and tally the frequency counts.
+ *
+ *      long flush_block (char *buf, ulg stored_len, int eof)
+ *          Determine the best encoding for the current block: dynamic trees,
+ *          static trees or store, and output the encoded block to the zip
+ *          file. Returns the total compressed length for the file so far.
+ *
+ */
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+
+static const int extra_lbits[LENGTH_CODES]     /* extra bits for each length code */
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
+               4, 4, 5, 5, 5, 5, 0 };
+
+static const int extra_dbits[D_CODES]  /* extra bits for each distance code */
+       = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+               10, 10, 11, 11, 12, 12, 13, 13 };
+
+static const int extra_blbits[BL_CODES]        /* extra bits for each bit length code */
+= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 };
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+#  ifdef SMALL_MEM
+#    define LIT_BUFSIZE  0x2000
+#  else
+#  ifdef MEDIUM_MEM
+#    define LIT_BUFSIZE  0x4000
+#  else
+#    define LIT_BUFSIZE  0x8000
+#  endif
+#  endif
+#endif
+#ifndef DIST_BUFSIZE
+#  define DIST_BUFSIZE  LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances.  There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ *   - frequencies can be kept in 16 bit counters
+ *   - if compression is not successful for the first block, all input data is
+ *     still in the window so we can still emit a stored block even when input
+ *     comes from standard input.  (This can also be done for all blocks if
+ *     LIT_BUFSIZE is not greater than 32K.)
+ *   - if compression is not successful for a file smaller than 64K, we can
+ *     even emit a stored file instead of a stored block (saving 5 bytes).
+ *   - creating new Huffman trees less frequently may not provide fast
+ *     adaptation to changes in the input data statistics. (Take for
+ *     example a binary file with poorly compressible code followed by
+ *     a highly compressible string table.) Smaller buffer sizes give
+ *     fast adaptation but have of course the overhead of transmitting trees
+ *     more frequently.
+ *   - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#if LIT_BUFSIZE > INBUFSIZ
+error cannot overlay l_buf and inbuf
+#endif
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) *//* ===========================================================================
+ * Local data
+ *//* Data structure describing a single value and its code string. */ typedef struct ct_data {
+       union {
+               ush freq;                               /* frequency count */
+               ush code;                               /* bit string */
+       } fc;
+       union {
+               ush dad;                                /* father node in Huffman tree */
+               ush len;                                /* length of bit string */
+       } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+static ct_data dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+static ct_data dyn_dtree[2 * D_CODES + 1];     /* distance tree */
+
+static ct_data static_ltree[L_CODES + 2];
+
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+static ct_data static_dtree[D_CODES];
+
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+static ct_data bl_tree[2 * BL_CODES + 1];
+
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+       ct_data *dyn_tree;              /* the dynamic tree */
+       ct_data *static_tree;   /* corresponding static tree or NULL */
+       const int *extra_bits;          /* extra bits for each code or NULL */
+       int extra_base;                         /* base index for extra_bits */
+       int elems;                                      /* max number of elements in the tree */
+       int max_length;                         /* max bit length for the codes */
+       int max_code;                           /* largest code with non zero frequency */
+} tree_desc;
+
+static tree_desc l_desc =
+       { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES,
+               MAX_BITS, 0 };
+
+static tree_desc d_desc =
+       { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 };
+
+static tree_desc bl_desc =
+       { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS,
+               0 };
+
+
+static ush bl_count[MAX_BITS + 1];
+
+/* number of codes at each bit length for an optimal tree */
+
+static const uch bl_order[BL_CODES]
+= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+static int heap[2 * L_CODES + 1];      /* heap used to build the Huffman trees */
+static int heap_len;                           /* number of elements in the heap */
+static int heap_max;                           /* element of largest frequency */
+
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+static uch depth[2 * L_CODES + 1];
+
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+static uch length_code[MAX_MATCH - MIN_MATCH + 1];
+
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+static uch dist_code[512];
+
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+static int base_length[LENGTH_CODES];
+
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+static int base_dist[D_CODES];
+
+/* First normalized distance for each code (0 = distance of 1) */
+
+#define l_buf inbuf
+/* DECLARE(uch, l_buf, LIT_BUFSIZE);  buffer for literals or lengths */
+
+/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
+
+static uch flag_buf[(LIT_BUFSIZE / 8)];
+
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+static unsigned last_lit;              /* running index in l_buf */
+static unsigned last_dist;             /* running index in d_buf */
+static unsigned last_flags;            /* running index in flag_buf */
+static uch flags;                              /* current flags not yet saved in flag_buf */
+static uch flag_bit;                           /* current bit used in flags */
+
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+static ulg opt_len;                            /* bit length of current block with optimal trees */
+static ulg static_len;                 /* bit length of current block with static trees */
+
+static ulg compressed_len;             /* total bit length of compressed file */
+
+
+static ush *file_type;                                 /* pointer to UNKNOWN, BINARY or ASCII */
+static int *file_method;                               /* pointer to DEFLATE or STORE */
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+static void init_block (void);
+static void pqdownheap (ct_data * tree, int k);
+static void gen_bitlen (tree_desc * desc);
+static void gen_codes (ct_data * tree, int max_code);
+static void build_tree (tree_desc * desc);
+static void scan_tree (ct_data * tree, int max_code);
+static void send_tree (ct_data * tree, int max_code);
+static int build_bl_tree (void);
+static void send_all_trees (int lcodes, int dcodes, int blcodes);
+static void compress_block (ct_data * ltree, ct_data * dtree);
+static void set_file_type (void);
+
+
+#ifndef DEBUG
+#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else                                                  /* DEBUG */
+#  define send_code(c, tree) \
+     { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+static void ct_init(ush *attr, int *methodp)
+{
+       int n;                                          /* iterates over tree elements */
+       int bits;                                       /* bit counter */
+       int length;                                     /* length value */
+       int code;                                       /* code value */
+       int dist;                                       /* distance index */
+
+       file_type = attr;
+       file_method = methodp;
+       compressed_len = 0L;
+
+       if (static_dtree[0].Len != 0)
+               return;                                 /* ct_init already called */
+
+       /* Initialize the mapping length (0..255) -> length code (0..28) */
+       length = 0;
+       for (code = 0; code < LENGTH_CODES - 1; code++) {
+               base_length[code] = length;
+               for (n = 0; n < (1 << extra_lbits[code]); n++) {
+                       length_code[length++] = (uch) code;
+               }
+       }
+       Assert(length == 256, "ct_init: length != 256");
+       /* Note that the length 255 (match length 258) can be represented
+        * in two different ways: code 284 + 5 bits or code 285, so we
+        * overwrite length_code[255] to use the best encoding:
+        */
+       length_code[length - 1] = (uch) code;
+
+       /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+       dist = 0;
+       for (code = 0; code < 16; code++) {
+               base_dist[code] = dist;
+               for (n = 0; n < (1 << extra_dbits[code]); n++) {
+                       dist_code[dist++] = (uch) code;
+               }
+       }
+       Assert(dist == 256, "ct_init: dist != 256");
+       dist >>= 7;                                     /* from now on, all distances are divided by 128 */
+       for (; code < D_CODES; code++) {
+               base_dist[code] = dist << 7;
+               for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
+                       dist_code[256 + dist++] = (uch) code;
+               }
+       }
+       Assert(dist == 256, "ct_init: 256+dist != 512");
+
+       /* Construct the codes of the static literal tree */
+       for (bits = 0; bits <= MAX_BITS; bits++)
+               bl_count[bits] = 0;
+       n = 0;
+       while (n <= 143)
+               static_ltree[n++].Len = 8, bl_count[8]++;
+       while (n <= 255)
+               static_ltree[n++].Len = 9, bl_count[9]++;
+       while (n <= 279)
+               static_ltree[n++].Len = 7, bl_count[7]++;
+       while (n <= 287)
+               static_ltree[n++].Len = 8, bl_count[8]++;
+       /* Codes 286 and 287 do not exist, but we must include them in the
+        * tree construction to get a canonical Huffman tree (longest code
+        * all ones)
+        */
+       gen_codes((ct_data *) static_ltree, L_CODES + 1);
+
+       /* The static distance tree is trivial: */
+       for (n = 0; n < D_CODES; n++) {
+               static_dtree[n].Len = 5;
+               static_dtree[n].Code = bi_reverse(n, 5);
+       }
+
+       /* Initialize the first block of the first file: */
+       init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+static void init_block()
+{
+       int n;                                          /* iterates over tree elements */
+
+       /* Initialize the trees. */
+       for (n = 0; n < L_CODES; n++)
+               dyn_ltree[n].Freq = 0;
+       for (n = 0; n < D_CODES; n++)
+               dyn_dtree[n].Freq = 0;
+       for (n = 0; n < BL_CODES; n++)
+               bl_tree[n].Freq = 0;
+
+       dyn_ltree[END_BLOCK].Freq = 1;
+       opt_len = static_len = 0L;
+       last_lit = last_dist = last_flags = 0;
+       flags = 0;
+       flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+    top = heap[SMALLEST]; \
+    heap[SMALLEST] = heap[heap_len--]; \
+    pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+static void pqdownheap(ct_data *tree, int k)
+{
+       int v = heap[k];
+       int j = k << 1;                         /* left son of k */
+
+       while (j <= heap_len) {
+               /* Set j to the smallest of the two sons: */
+               if (j < heap_len && smaller(tree, heap[j + 1], heap[j]))
+                       j++;
+
+               /* Exit if v is smaller than both sons */
+               if (smaller(tree, v, heap[j]))
+                       break;
+
+               /* Exchange v with the smallest son */
+               heap[k] = heap[j];
+               k = j;
+
+               /* And continue down the tree, setting j to the left son of k */
+               j <<= 1;
+       }
+       heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+static void gen_bitlen(tree_desc *desc)
+{
+       ct_data *tree = desc->dyn_tree;
+       const int *extra = desc->extra_bits;
+       int base = desc->extra_base;
+       int max_code = desc->max_code;
+       int max_length = desc->max_length;
+       ct_data *stree = desc->static_tree;
+       int h;                                          /* heap index */
+       int n, m;                                       /* iterate over the tree elements */
+       int bits;                                       /* bit length */
+       int xbits;                                      /* extra bits */
+       ush f;                                          /* frequency */
+       int overflow = 0;                       /* number of elements with bit length too large */
+
+       for (bits = 0; bits <= MAX_BITS; bits++)
+               bl_count[bits] = 0;
+
+       /* In a first pass, compute the optimal bit lengths (which may
+        * overflow in the case of the bit length tree).
+        */
+       tree[heap[heap_max]].Len = 0;   /* root of the heap */
+
+       for (h = heap_max + 1; h < HEAP_SIZE; h++) {
+               n = heap[h];
+               bits = tree[tree[n].Dad].Len + 1;
+               if (bits > max_length)
+                       bits = max_length, overflow++;
+               tree[n].Len = (ush) bits;
+               /* We overwrite tree[n].Dad which is no longer needed */
+
+               if (n > max_code)
+                       continue;                       /* not a leaf node */
+
+               bl_count[bits]++;
+               xbits = 0;
+               if (n >= base)
+                       xbits = extra[n - base];
+               f = tree[n].Freq;
+               opt_len += (ulg) f *(bits + xbits);
+
+               if (stree)
+                       static_len += (ulg) f *(stree[n].Len + xbits);
+       }
+       if (overflow == 0)
+               return;
+
+       Trace((stderr, "\nbit length overflow\n"));
+       /* This happens for example on obj2 and pic of the Calgary corpus */
+
+       /* Find the first bit length which could increase: */
+       do {
+               bits = max_length - 1;
+               while (bl_count[bits] == 0)
+                       bits--;
+               bl_count[bits]--;               /* move one leaf down the tree */
+               bl_count[bits + 1] += 2;        /* move one overflow item as its brother */
+               bl_count[max_length]--;
+               /* The brother of the overflow item also moves one step up,
+                * but this does not affect bl_count[max_length]
+                */
+               overflow -= 2;
+       } while (overflow > 0);
+
+       /* Now recompute all bit lengths, scanning in increasing frequency.
+        * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+        * lengths instead of fixing only the wrong ones. This idea is taken
+        * from 'ar' written by Haruhiko Okumura.)
+        */
+       for (bits = max_length; bits != 0; bits--) {
+               n = bl_count[bits];
+               while (n != 0) {
+                       m = heap[--h];
+                       if (m > max_code)
+                               continue;
+                       if (tree[m].Len != (unsigned) bits) {
+                               Trace(
+                                         (stderr, "code %d bits %d->%d\n", m, tree[m].Len,
+                                          bits));
+                               opt_len +=
+                                       ((long) bits -
+                                        (long) tree[m].Len) * (long) tree[m].Freq;
+                               tree[m].Len = (ush) bits;
+                       }
+                       n--;
+               }
+       }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+static void gen_codes(ct_data *tree, int max_code)
+{
+       ush next_code[MAX_BITS + 1];    /* next code value for each bit length */
+       ush code = 0;                           /* running code value */
+       int bits;                                       /* bit index */
+       int n;                                          /* code index */
+
+       /* The distribution counts are first used to generate the code values
+        * without bit reversal.
+        */
+       for (bits = 1; bits <= MAX_BITS; bits++) {
+               next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
+       }
+       /* Check that the bit counts in bl_count are consistent. The last code
+        * must be all ones.
+        */
+       Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
+                  "inconsistent bit counts");
+       Tracev((stderr, "\ngen_codes: max_code %d ", max_code));
+
+       for (n = 0; n <= max_code; n++) {
+               int len = tree[n].Len;
+
+               if (len == 0)
+                       continue;
+               /* Now reverse the bits */
+               tree[n].Code = bi_reverse(next_code[len]++, len);
+
+               Tracec(tree != static_ltree,
+                          (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
+                               (isgraph(n) ? n : ' '), len, tree[n].Code,
+                               next_code[len] - 1));
+       }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+static void build_tree(tree_desc *desc)
+{
+       ct_data *tree = desc->dyn_tree;
+       ct_data *stree = desc->static_tree;
+       int elems = desc->elems;
+       int n, m;                                       /* iterate over heap elements */
+       int max_code = -1;                      /* largest code with non zero frequency */
+       int node = elems;                       /* next internal node of the tree */
+
+       /* Construct the initial heap, with least frequent element in
+        * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+        * heap[0] is not used.
+        */
+       heap_len = 0, heap_max = HEAP_SIZE;
+
+       for (n = 0; n < elems; n++) {
+               if (tree[n].Freq != 0) {
+                       heap[++heap_len] = max_code = n;
+                       depth[n] = 0;
+               } else {
+                       tree[n].Len = 0;
+               }
+       }
+
+       /* The pkzip format requires that at least one distance code exists,
+        * and that at least one bit should be sent even if there is only one
+        * possible code. So to avoid special checks later on we force at least
+        * two codes of non zero frequency.
+        */
+       while (heap_len < 2) {
+               int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+
+               tree[new].Freq = 1;
+               depth[new] = 0;
+               opt_len--;
+               if (stree)
+                       static_len -= stree[new].Len;
+               /* new is 0 or 1 so it does not have extra bits */
+       }
+       desc->max_code = max_code;
+
+       /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+        * establish sub-heaps of increasing lengths:
+        */
+       for (n = heap_len / 2; n >= 1; n--)
+               pqdownheap(tree, n);
+
+       /* Construct the Huffman tree by repeatedly combining the least two
+        * frequent nodes.
+        */
+       do {
+               pqremove(tree, n);              /* n = node of least frequency */
+               m = heap[SMALLEST];             /* m = node of next least frequency */
+
+               heap[--heap_max] = n;   /* keep the nodes sorted by frequency */
+               heap[--heap_max] = m;
+
+               /* Create a new node father of n and m */
+               tree[node].Freq = tree[n].Freq + tree[m].Freq;
+               depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
+               tree[n].Dad = tree[m].Dad = (ush) node;
+#ifdef DUMP_BL_TREE
+               if (tree == bl_tree) {
+                       fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
+                                       node, tree[node].Freq, n, tree[n].Freq, m,
+                                       tree[m].Freq);
+               }
+#endif
+               /* and insert the new node in the heap */
+               heap[SMALLEST] = node++;
+               pqdownheap(tree, SMALLEST);
+
+       } while (heap_len >= 2);
+
+       heap[--heap_max] = heap[SMALLEST];
+
+       /* At this point, the fields freq and dad are set. We can now
+        * generate the bit lengths.
+        */
+       gen_bitlen((tree_desc *) desc);
+
+       /* The field len is now set, we can generate the bit codes */
+       gen_codes((ct_data *) tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+static void scan_tree(ct_data *tree, int max_code)
+{
+       int n;                                          /* iterates over all tree elements */
+       int prevlen = -1;                       /* last emitted length */
+       int curlen;                                     /* length of current code */
+       int nextlen = tree[0].Len;      /* length of next code */
+       int count = 0;                          /* repeat count of the current code */
+       int max_count = 7;                      /* max repeat count */
+       int min_count = 4;                      /* min repeat count */
+
+       if (nextlen == 0)
+               max_count = 138, min_count = 3;
+       tree[max_code + 1].Len = (ush) 0xffff;  /* guard */
+
+       for (n = 0; n <= max_code; n++) {
+               curlen = nextlen;
+               nextlen = tree[n + 1].Len;
+               if (++count < max_count && curlen == nextlen) {
+                       continue;
+               } else if (count < min_count) {
+                       bl_tree[curlen].Freq += count;
+               } else if (curlen != 0) {
+                       if (curlen != prevlen)
+                               bl_tree[curlen].Freq++;
+                       bl_tree[REP_3_6].Freq++;
+               } else if (count <= 10) {
+                       bl_tree[REPZ_3_10].Freq++;
+               } else {
+                       bl_tree[REPZ_11_138].Freq++;
+               }
+               count = 0;
+               prevlen = curlen;
+               if (nextlen == 0) {
+                       max_count = 138, min_count = 3;
+               } else if (curlen == nextlen) {
+                       max_count = 6, min_count = 3;
+               } else {
+                       max_count = 7, min_count = 4;
+               }
+       }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+static void send_tree(ct_data *tree, int max_code)
+{
+       int n;                                          /* iterates over all tree elements */
+       int prevlen = -1;                       /* last emitted length */
+       int curlen;                                     /* length of current code */
+       int nextlen = tree[0].Len;      /* length of next code */
+       int count = 0;                          /* repeat count of the current code */
+       int max_count = 7;                      /* max repeat count */
+       int min_count = 4;                      /* min repeat count */
+
+/* tree[max_code+1].Len = -1; *//* guard already set */
+       if (nextlen == 0)
+               max_count = 138, min_count = 3;
+
+       for (n = 0; n <= max_code; n++) {
+               curlen = nextlen;
+               nextlen = tree[n + 1].Len;
+               if (++count < max_count && curlen == nextlen) {
+                       continue;
+               } else if (count < min_count) {
+                       do {
+                               send_code(curlen, bl_tree);
+                       } while (--count != 0);
+
+               } else if (curlen != 0) {
+                       if (curlen != prevlen) {
+                               send_code(curlen, bl_tree);
+                               count--;
+                       }
+                       Assert(count >= 3 && count <= 6, " 3_6?");
+                       send_code(REP_3_6, bl_tree);
+                       send_bits(count - 3, 2);
+
+               } else if (count <= 10) {
+                       send_code(REPZ_3_10, bl_tree);
+                       send_bits(count - 3, 3);
+
+               } else {
+                       send_code(REPZ_11_138, bl_tree);
+                       send_bits(count - 11, 7);
+               }
+               count = 0;
+               prevlen = curlen;
+               if (nextlen == 0) {
+                       max_count = 138, min_count = 3;
+               } else if (curlen == nextlen) {
+                       max_count = 6, min_count = 3;
+               } else {
+                       max_count = 7, min_count = 4;
+               }
+       }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+static const int build_bl_tree()
+{
+       int max_blindex;                        /* index of last bit length code of non zero freq */
+
+       /* Determine the bit length frequencies for literal and distance trees */
+       scan_tree((ct_data *) dyn_ltree, l_desc.max_code);
+       scan_tree((ct_data *) dyn_dtree, d_desc.max_code);
+
+       /* Build the bit length tree: */
+       build_tree((tree_desc *) (&bl_desc));
+       /* opt_len now includes the length of the tree representations, except
+        * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+        */
+
+       /* Determine the number of bit length codes to send. The pkzip format
+        * requires that at least 4 bit length codes be sent. (appnote.txt says
+        * 3 but the actual value used is 4.)
+        */
+       for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+               if (bl_tree[bl_order[max_blindex]].Len != 0)
+                       break;
+       }
+       /* Update opt_len to include the bit length tree and counts */
+       opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+       Tracev(
+                  (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len,
+                       static_len));
+
+       return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+static void send_all_trees(int lcodes, int dcodes, int blcodes)
+{
+       int rank;                                       /* index in bl_order */
+
+       Assert(lcodes >= 257 && dcodes >= 1
+                  && blcodes >= 4, "not enough codes");
+       Assert(lcodes <= L_CODES && dcodes <= D_CODES
+                  && blcodes <= BL_CODES, "too many codes");
+       Tracev((stderr, "\nbl counts: "));
+       send_bits(lcodes - 257, 5);     /* not +255 as stated in appnote.txt */
+       send_bits(dcodes - 1, 5);
+       send_bits(blcodes - 4, 4);      /* not -3 as stated in appnote.txt */
+       for (rank = 0; rank < blcodes; rank++) {
+               Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+               send_bits(bl_tree[bl_order[rank]].Len, 3);
+       }
+       Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
+
+       send_tree((ct_data *) dyn_ltree, lcodes - 1);   /* send the literal tree */
+       Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
+
+       send_tree((ct_data *) dyn_dtree, dcodes - 1);   /* send the distance tree */
+       Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+static ulg flush_block(char *buf, ulg stored_len, int eof)
+{
+       ulg opt_lenb, static_lenb;      /* opt_len and static_len in bytes */
+       int max_blindex;                        /* index of last bit length code of non zero freq */
+
+       flag_buf[last_flags] = flags;   /* Save the flags for the last 8 items */
+
+       /* Check if the file is ascii or binary */
+       if (*file_type == (ush) UNKNOWN)
+               set_file_type();
+
+       /* Construct the literal and distance trees */
+       build_tree((tree_desc *) (&l_desc));
+       Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+       build_tree((tree_desc *) (&d_desc));
+       Tracev(
+                  (stderr, "\ndist data: dyn %ld, stat %ld", opt_len,
+                       static_len));
+       /* At this point, opt_len and static_len are the total bit lengths of
+        * the compressed block data, excluding the tree representations.
+        */
+
+       /* Build the bit length tree for the above two trees, and get the index
+        * in bl_order of the last bit length code to send.
+        */
+       max_blindex = build_bl_tree();
+
+       /* Determine the best encoding. Compute first the block length in bytes */
+       opt_lenb = (opt_len + 3 + 7) >> 3;
+       static_lenb = (static_len + 3 + 7) >> 3;
+
+       Trace(
+                 (stderr,
+                  "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+                  opt_lenb, opt_len, static_lenb, static_len, stored_len,
+                  last_lit, last_dist));
+
+       if (static_lenb <= opt_lenb)
+               opt_lenb = static_lenb;
+
+       /* If compression failed and this is the first and last block,
+        * and if the zip file can be seeked (to rewrite the local header),
+        * the whole file is transformed into a stored file:
+        */
+       if (stored_len <= opt_lenb && eof && compressed_len == 0L
+               && seekable()) {
+               /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+               if (buf == (char *) 0)
+                       error_msg("block vanished");
+
+               copy_block(buf, (unsigned) stored_len, 0);      /* without header */
+               compressed_len = stored_len << 3;
+               *file_method = STORED;
+
+       } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) {
+               /* 4: two words for the lengths */
+               /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+                * Otherwise we can't have processed more than WSIZE input bytes since
+                * the last block flush, because compression would have been
+                * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+                * transform a block into a stored block.
+                */
+               send_bits((STORED_BLOCK << 1) + eof, 3);        /* send block type */
+               compressed_len = (compressed_len + 3 + 7) & ~7L;
+               compressed_len += (stored_len + 4) << 3;
+
+               copy_block(buf, (unsigned) stored_len, 1);      /* with header */
+
+       } else if (static_lenb == opt_lenb) {
+               send_bits((STATIC_TREES << 1) + eof, 3);
+               compress_block((ct_data *) static_ltree,
+                                          (ct_data *) static_dtree);
+               compressed_len += 3 + static_len;
+       } else {
+               send_bits((DYN_TREES << 1) + eof, 3);
+               send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1,
+                                          max_blindex + 1);
+               compress_block((ct_data *) dyn_ltree,
+                                          (ct_data *) dyn_dtree);
+               compressed_len += 3 + opt_len;
+       }
+       Assert(compressed_len == bits_sent, "bad compressed size");
+       init_block();
+
+       if (eof) {
+               bi_windup();
+               compressed_len += 7;    /* align on byte boundary */
+       }
+       Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3,
+                       compressed_len - 7 * eof));
+
+       return compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+static int ct_tally(int dist, int lc)
+{
+       l_buf[last_lit++] = (uch) lc;
+       if (dist == 0) {
+               /* lc is the unmatched char */
+               dyn_ltree[lc].Freq++;
+       } else {
+               /* Here, lc is the match length - MIN_MATCH */
+               dist--;                                 /* dist = match distance - 1 */
+               Assert((ush) dist < (ush) MAX_DIST &&
+                          (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) &&
+                          (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match");
+
+               dyn_ltree[length_code[lc] + LITERALS + 1].Freq++;
+               dyn_dtree[d_code(dist)].Freq++;
+
+               d_buf[last_dist++] = (ush) dist;
+               flags |= flag_bit;
+       }
+       flag_bit <<= 1;
+
+       /* Output the flags if they fill a byte: */
+       if ((last_lit & 7) == 0) {
+               flag_buf[last_flags++] = flags;
+               flags = 0, flag_bit = 1;
+       }
+       /* Try to guess if it is profitable to stop the current block here */
+       if ((last_lit & 0xfff) == 0) {
+               /* Compute an upper bound for the compressed length */
+               ulg out_length = (ulg) last_lit * 8L;
+               ulg in_length = (ulg) strstart - block_start;
+               int dcode;
+
+               for (dcode = 0; dcode < D_CODES; dcode++) {
+                       out_length +=
+                               (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
+               }
+               out_length >>= 3;
+               Trace(
+                         (stderr,
+                          "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+                          last_lit, last_dist, in_length, out_length,
+                          100L - out_length * 100L / in_length));
+               if (last_dist < last_lit / 2 && out_length < in_length / 2)
+                       return 1;
+       }
+       return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE);
+       /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+        * on 16 bit machines and because stored blocks are restricted to
+        * 64K-1 bytes.
+        */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+static void compress_block(ct_data *ltree, ct_data *dtree)
+{
+       unsigned dist;                          /* distance of matched string */
+       int lc;                                         /* match length or unmatched char (if dist == 0) */
+       unsigned lx = 0;                        /* running index in l_buf */
+       unsigned dx = 0;                        /* running index in d_buf */
+       unsigned fx = 0;                        /* running index in flag_buf */
+       uch flag = 0;                           /* current flags */
+       unsigned code;                          /* the code to send */
+       int extra;                                      /* number of extra bits to send */
+
+       if (last_lit != 0)
+               do {
+                       if ((lx & 7) == 0)
+                               flag = flag_buf[fx++];
+                       lc = l_buf[lx++];
+                       if ((flag & 1) == 0) {
+                               send_code(lc, ltree);   /* send a literal byte */
+                               Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
+                       } else {
+                               /* Here, lc is the match length - MIN_MATCH */
+                               code = length_code[lc];
+                               send_code(code + LITERALS + 1, ltree);  /* send the length code */
+                               extra = extra_lbits[code];
+                               if (extra != 0) {
+                                       lc -= base_length[code];
+                                       send_bits(lc, extra);   /* send the extra length bits */
+                               }
+                               dist = d_buf[dx++];
+                               /* Here, dist is the match distance - 1 */
+                               code = d_code(dist);
+                               Assert(code < D_CODES, "bad d_code");
+
+                               send_code(code, dtree); /* send the distance code */
+                               extra = extra_dbits[code];
+                               if (extra != 0) {
+                                       dist -= base_dist[code];
+                                       send_bits(dist, extra); /* send the extra distance bits */
+                               }
+                       }                                       /* literal or match pair ? */
+                       flag >>= 1;
+               } while (lx < last_lit);
+
+       send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+static void set_file_type()
+{
+       int n = 0;
+       unsigned ascii_freq = 0;
+       unsigned bin_freq = 0;
+
+       while (n < 7)
+               bin_freq += dyn_ltree[n++].Freq;
+       while (n < 128)
+               ascii_freq += dyn_ltree[n++].Freq;
+       while (n < LITERALS)
+               bin_freq += dyn_ltree[n++].Freq;
+       *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
+       if (*file_type == BINARY && translate_eol) {
+               error_msg("-l used on binary file");
+       }
+}
+
+/* zip.c -- compress files to the gzip or pkzip format
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+static ulg crc;                                        /* crc on uncompressed file data */
+static long header_bytes;                              /* number of bytes in gzip header */
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ *   The variables time_stamp and save_orig_name are initialized.
+ */
+static int zip(int in, int out)
+{
+       uch my_flags = 0;                               /* general purpose bit flags */
+       ush attr = 0;                           /* ascii/binary flag */
+       ush deflate_flags = 0;          /* pkzip -es, -en or -ex equivalent */
+
+       ifd = in;
+       ofd = out;
+       outcnt = 0;
+
+       /* Write the header to the gzip file. See algorithm.doc for the format */
+
+
+       method = DEFLATED;
+       put_byte(GZIP_MAGIC[0]);        /* magic header */
+       put_byte(GZIP_MAGIC[1]);
+       put_byte(DEFLATED);                     /* compression method */
+
+       put_byte(my_flags);                     /* general flags */
+       put_long(time_stamp);
+
+       /* Write deflated file to zip file */
+       crc = updcrc(0, 0);
+
+       bi_init(out);
+       ct_init(&attr, &method);
+       lm_init(&deflate_flags);
+
+       put_byte((uch) deflate_flags);  /* extra flags */
+       put_byte(OS_CODE);                      /* OS identifier */
+
+       header_bytes = (long) outcnt;
+
+       (void) deflate();
+
+       /* Write the crc and uncompressed size */
+       put_long(crc);
+       put_long(isize);
+       header_bytes += 2 * sizeof(long);
+
+       flush_outbuf();
+       return OK;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+static int file_read(char *buf, unsigned size)
+{
+       unsigned len;
+
+       Assert(insize == 0, "inbuf not empty");
+
+       len = read(ifd, buf, size);
+       if (len == (unsigned) (-1) || len == 0)
+               return (int) len;
+
+       crc = updcrc((uch *) buf, len);
+       isize += (ulg) len;
+       return (int) len;
+}
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+static void flush_outbuf()
+{
+       if (outcnt == 0)
+               return;
+
+       write_buf(ofd, (char *) outbuf, outcnt);
+       outcnt = 0;
+}
diff --git a/halt.c b/halt.c
new file mode 100644 (file)
index 0000000..8f7cc67
--- /dev/null
+++ b/halt.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini halt implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include <signal.h>
+
+extern int halt_main(int argc, char **argv)
+{
+#ifdef BB_FEATURE_LINUXRC
+       /* don't assume init's pid == 1 */
+       long *pid = find_pid_by_name("init");
+       if (!pid || *pid<=0) {
+               pid = find_pid_by_name("linuxrc");
+               if (!pid || *pid<=0)
+                       error_msg_and_die("no process killed");
+       }
+       return(kill(*pid, SIGUSR1));
+#else
+       return(kill(1, SIGUSR1));
+#endif
+}
diff --git a/head.c b/head.c
new file mode 100644 (file)
index 0000000..ad21e1b
--- /dev/null
+++ b/head.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini head implementation for busybox
+ *
+ * Copyright (C) 1999 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "busybox.h"
+
+static int head(int len, FILE *fp)
+{
+       int i;
+       char *input;
+
+       for (i = 0; i < len; i++) {
+               if ((input = get_line_from_file(fp)) == NULL)
+                       break;
+               fputs(input, stdout);
+               free(input);
+       }
+       return 0;
+}
+
+/* BusyBoxed head(1) */
+int head_main(int argc, char **argv)
+{
+       FILE *fp;
+       int need_headers, opt, len = 10, status = EXIT_SUCCESS;
+
+       if (( argc >= 2 ) && ( argv [1][0] == '-' ) && isdigit ( argv [1][1] )) {
+               len = atoi ( &argv [1][1] );
+               optind = 2;
+       }
+
+       /* parse argv[] */
+       while ((opt = getopt(argc, argv, "n:")) > 0) {
+               switch (opt) {
+               case 'n':
+                       len = atoi(optarg);
+                       if (len >= 0)
+                               break;
+                       /* fallthrough */
+               default:
+                       show_usage();
+               }
+       }
+
+       /* get rest of argv[] or stdin if nothing's left */
+       if (argv[optind] == NULL) {
+               head(len, stdin);
+               return status;
+       } 
+
+       need_headers = optind != (argc - 1);
+       while (argv[optind]) {
+               if (strcmp(argv[optind], "-") == 0) {
+                       fp = stdin;
+                       argv[optind] = "standard input";
+               } else {
+                       if ((fp = wfopen(argv[optind], "r")) == NULL)
+                               status = EXIT_FAILURE;
+               }
+               if (fp) {
+                       if (need_headers) {
+                               printf("==> %s <==\n", argv[optind]);
+                       }
+                       head(len, fp);
+                       if (ferror(fp)) {
+                               perror_msg("%s", argv[optind]);
+                               status = EXIT_FAILURE;
+                       }
+                       if (optind < argc - 1)
+                               putchar('\n');
+                       if (fp != stdin)
+                               fclose(fp);
+               }
+               optind++;
+       }
+
+       return status;
+}
diff --git a/hostid.c b/hostid.c
new file mode 100644 (file)
index 0000000..68a2cc6
--- /dev/null
+++ b/hostid.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini hostid implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int hostid_main(int argc, char **argv)
+{
+       printf("%lx\n", gethostid());
+       return EXIT_SUCCESS;
+}
diff --git a/hostname.c b/hostname.c
new file mode 100644 (file)
index 0000000..3cb357a
--- /dev/null
@@ -0,0 +1,130 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * $Id: hostname.c,v 1.32 2002/10/18 22:07:41 andersen Exp $
+ * Mini hostname implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * adjusted by Erik Andersen <andersee@debian.org> to remove
+ * use of long options and GNU getopt.  Improved the usage info.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "busybox.h"
+
+extern char *optarg; /* in unistd.h */
+extern int  optind, opterr, optopt; /* in unistd.h */
+
+static void do_sethostname(char *s, int isfile)
+{
+       FILE *f;
+       char buf[255];
+
+       if (!s)
+               return;
+       if (!isfile) {
+               if (sethostname(s, strlen(s)) < 0) {
+                       if (errno == EPERM)
+                               error_msg_and_die("you must be root to change the hostname");
+                       else
+                               perror_msg_and_die("sethostname");
+               }
+       } else {
+               f = xfopen(s, "r");
+               while (fgets(buf, 255, f) != NULL) {
+                       if (buf[0] =='#') {
+                               continue;
+                       }
+                       chomp(buf);
+                       do_sethostname(buf, 0);
+               }
+#ifdef BB_FEATURE_CLEAN_UP
+               fclose(f);
+#endif
+       }
+}
+
+int hostname_main(int argc, char **argv)
+{
+       int opt;
+       int type = 0;
+       struct hostent *hp;
+       char *filename = NULL;
+       char buf[255];
+       char *p = NULL;
+
+       if (argc < 1)
+               show_usage();
+
+        while ((opt = getopt(argc, argv, "dfisF:")) > 0) {
+                switch (opt) {
+               case 'd':
+               case 'f':
+               case 'i':
+               case 's':
+                       type = opt;
+                       break;
+               case 'F':
+                       filename = optarg;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       /* Output in desired format */
+       if (type != 0) {
+               gethostname(buf, 255);
+               hp = xgethostbyname(buf);
+               p = strchr(hp->h_name, '.');
+               if (type == 'f') {
+                       puts(hp->h_name);
+               } else if (type == 's') {
+                       if (p != NULL) {
+                               *p = 0;
+                       }
+                       puts(buf);
+               } else if (type == 'd') {
+                       if (p) puts(p + 1);
+               } else if (type == 'i') {
+                       while (hp->h_addr_list[0]) {
+                               printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++)));
+                       }
+                       printf("\n");
+               }
+       }
+       /* Set the hostname */
+       else if (filename != NULL) {
+               do_sethostname(filename, 1);
+       } else if (optind < argc) {
+               do_sethostname(argv[optind], 0);
+       }
+       /* Or if all else fails,
+        * just print the current hostname */
+        else {
+               gethostname(buf, 255);
+               puts(buf);
+       }
+       return(0);
+}
diff --git a/hush.c b/hush.c
new file mode 100644 (file)
index 0000000..56df5e0
--- /dev/null
+++ b/hush.c
@@ -0,0 +1,2971 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sh.c -- a prototype Bourne shell grammar parser
+ *      Intended to follow the original Thompson and Ritchie
+ *      "small and simple is beautiful" philosophy, which
+ *      incidentally is a good match to today's BusyBox.
+ *
+ * Copyright (C) 2000,2001  Larry Doolittle  <larry@doolittle.boa.org>
+ *
+ * Credits:
+ *      The parser routines proper are all original material, first
+ *      written Dec 2000 and Jan 2001 by Larry Doolittle.  The
+ *      execution engine, the builtins, and much of the underlying
+ *      support has been adapted from busybox-0.49pre's lash, which is
+ *      Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ *      written by Erik Andersen <andersee@debian.org>.  That, in turn,
+ *      is based in part on ladsh.c, by Michael K. Johnson and Erik W.
+ *      Troan, which they placed in the public domain.  I don't know
+ *      how much of the Johnson/Troan code has survived the repeated
+ *      rewrites.
+ *
+ * Other credits:
+ *      simple_itoa() was lifted from boa-0.93.15
+ *      b_addchr() derived from similar w_addchar function in glibc-2.2
+ *      setup_redirect(), redirect_opt_num(), and big chunks of main()
+ *        and many builtins derived from contributions by Erik Andersen
+ *      miscellaneous bugfixes from Matt Kraai
+ *
+ * There are two big (and related) architecture differences between
+ * this parser and the lash parser.  One is that this version is
+ * actually designed from the ground up to understand nearly all
+ * of the Bourne grammar.  The second, consequential change is that
+ * the parser and input reader have been turned inside out.  Now,
+ * the parser is in control, and asks for input as needed.  The old
+ * way had the input reader in control, and it asked for parsing to
+ * take place as needed.  The new way makes it much easier to properly
+ * handle the recursion implicit in the various substitutions, especially
+ * across continuation lines.
+ *
+ * Bash grammar not implemented: (how many of these were in original sh?)
+ *      $@ (those sure look like weird quoting rules)
+ *      $_
+ *      ! negation operator for pipes
+ *      &> and >& redirection of stdout+stderr
+ *      Brace Expansion
+ *      Tilde Expansion
+ *      fancy forms of Parameter Expansion
+ *      aliases
+ *      Arithmetic Expansion
+ *      <(list) and >(list) Process Substitution
+ *      reserved words: case, esac, select, function
+ *      Here Documents ( << word )
+ *      Functions
+ * Major bugs:
+ *      job handling woefully incomplete and buggy
+ *      reserved word execution woefully incomplete and buggy
+ * to-do:
+ *      port selected bugfixes from post-0.49 busybox lash - done?
+ *      finish implementing reserved words: for, while, until, do, done
+ *      change { and } from special chars to reserved words
+ *      builtins: break, continue, eval, return, set, trap, ulimit
+ *      test magic exec
+ *      handle children going into background
+ *      clean up recognition of null pipes
+ *      check setting of global_argc and global_argv
+ *      control-C handling, probably with longjmp
+ *      follow IFS rules more precisely, including update semantics
+ *      figure out what to do with backslash-newline
+ *      explain why we use signal instead of sigaction
+ *      propagate syntax errors, die on resource errors?
+ *      continuation lines, both explicit and implicit - done?
+ *      memory leak finding and plugging - done?
+ *      more testing, especially quoting rules and redirection
+ *      document how quoting rules not precisely followed for variable assignments
+ *      maybe change map[] to use 2-bit entries
+ *      (eventually) remove all the printf's
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <ctype.h>     /* isalpha, isdigit */
+#include <unistd.h>    /* getpid */
+#include <stdlib.h>    /* getenv, atoi */
+#include <string.h>    /* strchr */
+#include <stdio.h>     /* popen etc. */
+#include <glob.h>      /* glob, of course */
+#include <stdarg.h>    /* va_list */
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>    /* should be pretty obvious */
+
+#include <sys/stat.h>  /* ulimit */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+/* #include <dmalloc.h> */
+/* #define DEBUG_SHELL */
+
+#ifdef BB_VER
+#include "busybox.h"
+#include "cmdedit.h"
+#else
+#define applet_name "hush"
+#include "standalone.h"
+#define hush_main main
+#undef BB_FEATURE_SH_FANCY_PROMPT
+#endif
+#define SPECIAL_VAR_SYMBOL 03
+#define FLAG_EXIT_FROM_LOOP 1
+#define FLAG_PARSE_SEMICOLON (1 << 1)          /* symbol ';' is special for parser */
+#define FLAG_REPARSING          (1 << 2)               /* >=2nd pass */
+
+typedef enum {
+       REDIRECT_INPUT     = 1,
+       REDIRECT_OVERWRITE = 2,
+       REDIRECT_APPEND    = 3,
+       REDIRECT_HEREIS    = 4,
+       REDIRECT_IO        = 5
+} redir_type;
+
+/* The descrip member of this structure is only used to make debugging
+ * output pretty */
+struct {int mode; int default_fd; char *descrip;} redir_table[] = {
+       { 0,                         0, "()" },
+       { O_RDONLY,                  0, "<"  },
+       { O_CREAT|O_TRUNC|O_WRONLY,  1, ">"  },
+       { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
+       { O_RDONLY,                 -1, "<<" },
+       { O_RDWR,                    1, "<>" }
+};
+
+typedef enum {
+       PIPE_SEQ = 1,
+       PIPE_AND = 2,
+       PIPE_OR  = 3,
+       PIPE_BG  = 4,
+} pipe_style;
+
+/* might eventually control execution */
+typedef enum {
+       RES_NONE  = 0,
+       RES_IF    = 1,
+       RES_THEN  = 2,
+       RES_ELIF  = 3,
+       RES_ELSE  = 4,
+       RES_FI    = 5,
+       RES_FOR   = 6,
+       RES_WHILE = 7,
+       RES_UNTIL = 8,
+       RES_DO    = 9,
+       RES_DONE  = 10,
+       RES_XXXX  = 11,
+       RES_IN    = 12,
+       RES_SNTX  = 13
+} reserved_style;
+#define FLAG_END   (1<<RES_NONE)
+#define FLAG_IF    (1<<RES_IF)
+#define FLAG_THEN  (1<<RES_THEN)
+#define FLAG_ELIF  (1<<RES_ELIF)
+#define FLAG_ELSE  (1<<RES_ELSE)
+#define FLAG_FI    (1<<RES_FI)
+#define FLAG_FOR   (1<<RES_FOR)
+#define FLAG_WHILE (1<<RES_WHILE)
+#define FLAG_UNTIL (1<<RES_UNTIL)
+#define FLAG_DO    (1<<RES_DO)
+#define FLAG_DONE  (1<<RES_DONE)
+#define FLAG_IN    (1<<RES_IN)
+#define FLAG_START (1<<RES_XXXX)
+
+/* This holds pointers to the various results of parsing */
+struct p_context {
+       struct child_prog *child;
+       struct pipe *list_head;
+       struct pipe *pipe;
+       struct redir_struct *pending_redirect;
+       reserved_style w;
+       int old_flag;                           /* for figuring out valid reserved words */
+       struct p_context *stack;
+       int type;                       /* define type of parser : ";$" common or special symbol */
+       /* How about quoting status? */
+};
+
+struct redir_struct {
+       redir_type type;                        /* type of redirection */
+       int fd;                                         /* file descriptor being redirected */
+       int dup;                                        /* -1, or file descriptor being duplicated */
+       struct redir_struct *next;      /* pointer to the next redirect in the list */ 
+       glob_t word;                            /* *word.gl_pathv is the filename */
+};
+
+struct child_prog {
+       pid_t pid;                                      /* 0 if exited */
+       char **argv;                            /* program name and arguments */
+       struct pipe *group;                     /* if non-NULL, first in group or subshell */
+       int subshell;                           /* flag, non-zero if group must be forked */
+       struct redir_struct *redirects; /* I/O redirections */
+       glob_t glob_result;                     /* result of parameter globbing */
+       int is_stopped;                         /* is the program currently running? */
+       struct pipe *family;            /* pointer back to the child's parent pipe */
+       int sp;                         /* number of SPECIAL_VAR_SYMBOL */
+       int type;
+};
+
+struct pipe {
+       int jobid;                                      /* job number */
+       int num_progs;                          /* total number of programs in job */
+       int running_progs;                      /* number of programs running */
+       char *text;                                     /* name of job */
+       char *cmdbuf;                           /* buffer various argv's point into */
+       pid_t pgrp;                                     /* process group ID for the job */
+       struct child_prog *progs;       /* array of commands in pipe */
+       struct pipe *next;                      /* to track background commands */
+       int stopped_progs;                      /* number of programs alive, but stopped */
+       int job_context;                        /* bitmask defining current context */
+       pipe_style followup;            /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
+       reserved_style r_mode;          /* supports if, for, while, until */
+};
+
+struct close_me {
+       int fd;
+       struct close_me *next;
+};
+
+struct variables {
+       char *name;
+       char *value;
+       int flg_export;
+       int flg_read_only;
+       struct variables *next;
+};
+
+/* globals, connect us to the outside world
+ * the first three support $?, $#, and $1 */
+char **global_argv;
+unsigned int global_argc;
+unsigned int last_return_code;
+extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
+/* "globals" within this file */
+static char *ifs;
+static char map[256];
+static int fake_mode;
+static int interactive;
+static struct close_me *close_me_head;
+static const char *cwd;
+static struct pipe *job_list;
+static unsigned int last_bg_pid;
+static unsigned int last_jobid;
+static unsigned int shell_terminal;
+static char *PS1;
+static char *PS2;
+struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
+struct variables *top_vars = &shell_ver;
+
+
+#define B_CHUNK (100)
+#define B_NOSPAC 1
+
+typedef struct {
+       char *data;
+       int length;
+       int maxlen;
+       int quote;
+       int nonnull;
+} o_string;
+#define NULL_O_STRING {NULL,0,0,0,0}
+/* used for initialization:
+       o_string foo = NULL_O_STRING; */
+
+/* I can almost use ordinary FILE *.  Is open_memstream() universally
+ * available?  Where is it documented? */
+struct in_str {
+       const char *p;
+       char peek_buf[2];
+       int __promptme;
+       int promptmode;
+       FILE *file;
+       int (*get) (struct in_str *);
+       int (*peek) (struct in_str *);
+};
+#define b_getch(input) ((input)->get(input))
+#define b_peek(input) ((input)->peek(input))
+
+#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+
+struct built_in_command {
+       char *cmd;                                      /* name */
+       char *descr;                            /* description */
+       int (*function) (struct child_prog *);  /* function ptr */
+};
+
+/* belongs in busybox.h */
+static inline int max(int a, int b) {
+       return (a>b)?a:b;
+}
+
+/* This should be in utility.c */
+#ifdef DEBUG_SHELL
+static void debug_printf(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       vfprintf(stderr, format, args);
+       va_end(args);
+}
+#else
+static inline void debug_printf(const char *format, ...) { }
+#endif
+#define final_printf debug_printf
+
+static void __syntax(char *file, int line) {
+       error_msg("syntax error %s:%d", file, line);
+}
+#define syntax() __syntax(__FILE__, __LINE__)
+
+/* Index of subroutines: */
+/*   function prototypes for builtins */
+static int builtin_cd(struct child_prog *child);
+static int builtin_env(struct child_prog *child);
+static int builtin_eval(struct child_prog *child);
+static int builtin_exec(struct child_prog *child);
+static int builtin_exit(struct child_prog *child);
+static int builtin_export(struct child_prog *child);
+static int builtin_fg_bg(struct child_prog *child);
+static int builtin_help(struct child_prog *child);
+static int builtin_jobs(struct child_prog *child);
+static int builtin_pwd(struct child_prog *child);
+static int builtin_read(struct child_prog *child);
+static int builtin_set(struct child_prog *child);
+static int builtin_shift(struct child_prog *child);
+static int builtin_source(struct child_prog *child);
+static int builtin_umask(struct child_prog *child);
+static int builtin_unset(struct child_prog *child);
+static int builtin_not_written(struct child_prog *child);
+/*   o_string manipulation: */
+static int b_check_space(o_string *o, int len);
+static int b_addchr(o_string *o, int ch);
+static void b_reset(o_string *o);
+static int b_addqchr(o_string *o, int ch, int quote);
+static int b_adduint(o_string *o, unsigned int i);
+/*  in_str manipulations: */
+static int static_get(struct in_str *i);
+static int static_peek(struct in_str *i);
+static int file_get(struct in_str *i);
+static int file_peek(struct in_str *i);
+static void setup_file_in_str(struct in_str *i, FILE *f);
+static void setup_string_in_str(struct in_str *i, const char *s);
+/*  close_me manipulations: */
+static void mark_open(int fd);
+static void mark_closed(int fd);
+static void close_all();
+/*  "run" the final data structures: */
+static char *indenter(int i);
+static int free_pipe_list(struct pipe *head, int indent);
+static int free_pipe(struct pipe *pi, int indent);
+/*  really run the final data structures: */
+static int setup_redirects(struct child_prog *prog, int squirrel[]);
+static int run_list_real(struct pipe *pi);
+static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn));
+static int run_pipe_real(struct pipe *pi);
+/*   extended glob support: */
+static int globhack(const char *src, int flags, glob_t *pglob);
+static int glob_needed(const char *s);
+static int xglob(o_string *dest, int flags, glob_t *pglob);
+/*   variable assignment: */
+static int is_assignment(const char *s);
+/*   data structure manipulation: */
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
+static void initialize_context(struct p_context *ctx);
+static int done_word(o_string *dest, struct p_context *ctx);
+static int done_command(struct p_context *ctx);
+static int done_pipe(struct p_context *ctx, pipe_style type);
+/*   primary string parsing: */
+static int redirect_dup_num(struct in_str *input);
+static int redirect_opt_num(o_string *o);
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
+static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
+static char *lookup_param(char *src);
+static char *make_string(char **inp);
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
+static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
+static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
+/*   setup: */
+static int parse_stream_outer(struct in_str *inp, int flag);
+static int parse_string_outer(const char *s, int flag);
+static int parse_file_outer(FILE *f);
+/*   job management: */
+static int checkjobs(struct pipe* fg_pipe);
+static void insert_bg_job(struct pipe *pi);
+static void remove_bg_job(struct pipe *pi);
+/*     local variable support */
+static char **make_list_in(char **inp, char *name);
+static char *insert_var_value(char *inp);
+static char *get_local_var(const char *var);
+static void  unset_local_var(const char *name);
+static int set_local_var(const char *s, int flg_export);
+
+/* Table of built-in functions.  They can be forked or not, depending on
+ * context: within pipes, they fork.  As simple commands, they do not.
+ * When used in non-forking context, they can change global variables
+ * in the parent shell process.  If forked, of course they can not.
+ * For example, 'unset foo | whatever' will parse and run, but foo will
+ * still be set at the end. */
+static struct built_in_command bltins[] = {
+       {"bg", "Resume a job in the background", builtin_fg_bg},
+       {"break", "Exit for, while or until loop", builtin_not_written},
+       {"cd", "Change working directory", builtin_cd},
+       {"continue", "Continue for, while or until loop", builtin_not_written},
+       {"env", "Print all environment variables", builtin_env},
+       {"eval", "Construct and run shell command", builtin_eval},
+       {"exec", "Exec command, replacing this shell with the exec'd process", 
+               builtin_exec},
+       {"exit", "Exit from shell()", builtin_exit},
+       {"export", "Set environment variable", builtin_export},
+       {"fg", "Bring job into the foreground", builtin_fg_bg},
+       {"jobs", "Lists the active jobs", builtin_jobs},
+       {"pwd", "Print current directory", builtin_pwd},
+       {"read", "Input environment variable", builtin_read},
+       {"return", "Return from a function", builtin_not_written},
+       {"set", "Set/unset shell local variables", builtin_set},
+       {"shift", "Shift positional parameters", builtin_shift},
+       {"trap", "Trap signals", builtin_not_written},
+       {"ulimit","Controls resource limits", builtin_not_written},
+       {"umask","Sets file creation mask", builtin_umask},
+       {"unset", "Unset environment variable", builtin_unset},
+       {".", "Source-in and run commands in a file", builtin_source},
+       {"help", "List shell built-in commands", builtin_help},
+       {NULL, NULL, NULL}
+};
+
+static const char *set_cwd(void)
+{
+       if(cwd==unknown)
+               cwd = NULL;     /* xgetcwd(arg) called free(arg) */
+       cwd = xgetcwd((char *)cwd);
+       if (!cwd)
+               cwd = unknown;
+       return cwd;
+}
+
+/* built-in 'eval' handler */
+static int builtin_eval(struct child_prog *child)
+{
+       char *str = NULL;
+       int rcode = EXIT_SUCCESS;
+       
+       if (child->argv[1]) {
+               str = make_string(child->argv + 1);
+               parse_string_outer(str, FLAG_EXIT_FROM_LOOP | 
+                                       FLAG_PARSE_SEMICOLON);
+               free(str);
+               rcode = last_return_code;
+       }
+       return rcode;
+}
+
+/* built-in 'cd <path>' handler */
+static int builtin_cd(struct child_prog *child)
+{
+       char *newdir;
+       if (child->argv[1] == NULL)
+               newdir = getenv("HOME");
+       else
+               newdir = child->argv[1];
+       if (chdir(newdir)) {
+               printf("cd: %s: %s\n", newdir, strerror(errno));
+               return EXIT_FAILURE;
+       }
+       set_cwd();
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'env' handler */
+static int builtin_env(struct child_prog *dummy)
+{
+       char **e = environ;
+       if (e == NULL) return EXIT_FAILURE;
+       for (; *e; e++) {
+               puts(*e);
+       }
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'exec' handler */
+static int builtin_exec(struct child_prog *child)
+{
+       if (child->argv[1] == NULL)
+               return EXIT_SUCCESS;   /* Really? */
+       child->argv++;
+       pseudo_exec(child);
+       /* never returns */
+}
+
+/* built-in 'exit' handler */
+static int builtin_exit(struct child_prog *child)
+{
+       if (child->argv[1] == NULL)
+               exit(last_return_code);
+       exit (atoi(child->argv[1]));
+}
+
+/* built-in 'export VAR=value' handler */
+static int builtin_export(struct child_prog *child)
+{
+       int res = 0;
+       char *name = child->argv[1];
+
+       if (name == NULL) {
+               return (builtin_env(child));
+       }
+
+       name = strdup(name);
+
+       if(name) {
+               char *value = strchr(name, '=');
+
+               if (!value) {
+                       char *tmp;
+                       /* They are exporting something without an =VALUE */
+
+                       value = get_local_var(name);
+                       if (value) {
+                               size_t ln = strlen(name);
+
+                               tmp = realloc(name, ln+strlen(value)+2);
+                               if(tmp==NULL)
+                                       res = -1;
+                               else {
+                                       sprintf(tmp+ln, "=%s", value);
+                                       name = tmp;
+                               }
+                       } else {
+                               /* bash does not return an error when trying to export
+                                * an undefined variable.  Do likewise. */
+                               res = 1;
+                       }
+               }
+       }
+       if (res<0)
+               perror_msg("export");
+       else if(res==0)
+               res = set_local_var(name, 1);
+       else
+               res = 0;
+       free(name);
+       return res;
+}
+
+/* built-in 'fg' and 'bg' handler */
+static int builtin_fg_bg(struct child_prog *child)
+{
+       int i, jobnum;
+       struct pipe *pi=NULL;
+
+       if (!interactive)
+               return EXIT_FAILURE;
+       /* If they gave us no args, assume they want the last backgrounded task */
+       if (!child->argv[1]) {
+               for (pi = job_list; pi; pi = pi->next) {
+                       if (pi->jobid == last_jobid) {
+                               break;
+                       }
+               }
+               if (!pi) {
+                       error_msg("%s: no current job", child->argv[0]);
+                       return EXIT_FAILURE;
+               }
+       } else {
+               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+                       return EXIT_FAILURE;
+               }
+               for (pi = job_list; pi; pi = pi->next) {
+                       if (pi->jobid == jobnum) {
+                               break;
+                       }
+               }
+               if (!pi) {
+                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (*child->argv[0] == 'f') {
+               /* Put the job into the foreground.  */
+               tcsetpgrp(shell_terminal, pi->pgrp);
+       }
+
+       /* Restart the processes in the job */
+       for (i = 0; i < pi->num_progs; i++)
+               pi->progs[i].is_stopped = 0;
+
+       if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) {
+               if (i == ESRCH) {
+                       remove_bg_job(pi);
+               } else {
+                       perror_msg("kill (SIGCONT)");
+               }
+       }
+
+       pi->stopped_progs = 0;
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'help' handler */
+static int builtin_help(struct child_prog *dummy)
+{
+       struct built_in_command *x;
+
+       printf("\nBuilt-in commands:\n");
+       printf("-------------------\n");
+       for (x = bltins; x->cmd; x++) {
+               if (x->descr==NULL)
+                       continue;
+               printf("%s\t%s\n", x->cmd, x->descr);
+       }
+       printf("\n\n");
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'jobs' handler */
+static int builtin_jobs(struct child_prog *child)
+{
+       struct pipe *job;
+       char *status_string;
+
+       for (job = job_list; job; job = job->next) {
+               if (job->running_progs == job->stopped_progs)
+                       status_string = "Stopped";
+               else
+                       status_string = "Running";
+
+               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
+       }
+       return EXIT_SUCCESS;
+}
+
+
+/* built-in 'pwd' handler */
+static int builtin_pwd(struct child_prog *dummy)
+{
+       puts(set_cwd());
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'read VAR' handler */
+static int builtin_read(struct child_prog *child)
+{
+       int res;
+
+       if (child->argv[1]) {
+               char string[BUFSIZ];
+               char *var = 0;
+
+               string[0] = 0;  /* In case stdin has only EOF */
+               /* read string */
+               fgets(string, sizeof(string), stdin);
+               chomp(string);
+               var = malloc(strlen(child->argv[1])+strlen(string)+2);
+               if(var) {
+                       sprintf(var, "%s=%s", child->argv[1], string);
+                       res = set_local_var(var, 0);
+               } else
+                       res = -1;
+               if (res)
+                       fprintf(stderr, "read: %m\n");
+               free(var);      /* So not move up to avoid breaking errno */
+               return res;
+       } else {
+               do res=getchar(); while(res!='\n' && res!=EOF);
+               return 0;
+       }
+}
+
+/* built-in 'set VAR=value' handler */
+static int builtin_set(struct child_prog *child)
+{
+       char *temp = child->argv[1];
+       struct variables *e;
+
+       if (temp == NULL)
+               for(e = top_vars; e; e=e->next)
+                       printf("%s=%s\n", e->name, e->value);
+       else
+               set_local_var(temp, 0);
+
+               return EXIT_SUCCESS;
+}
+
+
+/* Built-in 'shift' handler */
+static int builtin_shift(struct child_prog *child)
+{
+       int n=1;
+       if (child->argv[1]) {
+               n=atoi(child->argv[1]);
+       }
+       if (n>=0 && n<global_argc) {
+               /* XXX This probably breaks $0 */
+               global_argc -= n;
+               global_argv += n;
+               return EXIT_SUCCESS;
+       } else {
+               return EXIT_FAILURE;
+       }
+}
+
+/* Built-in '.' handler (read-in and execute commands from file) */
+static int builtin_source(struct child_prog *child)
+{
+       FILE *input;
+       int status;
+
+       if (child->argv[1] == NULL)
+               return EXIT_FAILURE;
+
+       /* XXX search through $PATH is missing */
+       input = fopen(child->argv[1], "r");
+       if (!input) {
+               error_msg("Couldn't open file '%s'", child->argv[1]);
+               return EXIT_FAILURE;
+       }
+
+       /* Now run the file */
+       /* XXX argv and argc are broken; need to save old global_argv
+        * (pointer only is OK!) on this stack frame,
+        * set global_argv=child->argv+1, recurse, and restore. */
+       mark_open(fileno(input));
+       status = parse_file_outer(input);
+       mark_closed(fileno(input));
+       fclose(input);
+       return (status);
+}
+
+static int builtin_umask(struct child_prog *child)
+{
+       mode_t new_umask;
+       const char *arg = child->argv[1];
+       char *end;
+       if (arg) {
+               new_umask=strtoul(arg, &end, 8);
+               if (*end!='\0' || end == arg) {
+                       return EXIT_FAILURE;
+               }
+       } else {
+               printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
+       }
+       umask(new_umask);
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'unset VAR' handler */
+static int builtin_unset(struct child_prog *child)
+{
+       /* bash returned already true */
+       unset_local_var(child->argv[1]);
+       return EXIT_SUCCESS;
+}
+
+static int builtin_not_written(struct child_prog *child)
+{
+       printf("builtin_%s not written\n",child->argv[0]);
+       return EXIT_FAILURE;
+}
+
+static int b_check_space(o_string *o, int len)
+{
+       /* It would be easy to drop a more restrictive policy
+        * in here, such as setting a maximum string length */
+       if (o->length + len > o->maxlen) {
+               char *old_data = o->data;
+               /* assert (data == NULL || o->maxlen != 0); */
+               o->maxlen += max(2*len, B_CHUNK);
+               o->data = realloc(o->data, 1 + o->maxlen);
+               if (o->data == NULL) {
+                       free(old_data);
+               }
+       }
+       return o->data == NULL;
+}
+
+static int b_addchr(o_string *o, int ch)
+{
+       debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
+       if (b_check_space(o, 1)) return B_NOSPAC;
+       o->data[o->length] = ch;
+       o->length++;
+       o->data[o->length] = '\0';
+       return 0;
+}
+
+static void b_reset(o_string *o)
+{
+       o->length = 0;
+       o->nonnull = 0;
+       if (o->data != NULL) *o->data = '\0';
+}
+
+static void b_free(o_string *o)
+{
+       b_reset(o);
+       if (o->data != NULL) free(o->data);
+       o->data = NULL;
+       o->maxlen = 0;
+}
+
+/* My analysis of quoting semantics tells me that state information
+ * is associated with a destination, not a source.
+ */
+static int b_addqchr(o_string *o, int ch, int quote)
+{
+       if (quote && strchr("*?[\\",ch)) {
+               int rc;
+               rc = b_addchr(o, '\\');
+               if (rc) return rc;
+       }
+       return b_addchr(o, ch);
+}
+
+/* belongs in utility.c */
+char *simple_itoa(unsigned int i)
+{
+       /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+       static char local[22];
+       char *p = &local[21];
+       *p-- = '\0';
+       do {
+               *p-- = '0' + i % 10;
+               i /= 10;
+       } while (i > 0);
+       return p + 1;
+}
+
+static int b_adduint(o_string *o, unsigned int i)
+{
+       int r;
+       char *p = simple_itoa(i);
+       /* no escape checking necessary */
+       do r=b_addchr(o, *p++); while (r==0 && *p);
+       return r;
+}
+
+static int static_get(struct in_str *i)
+{
+       int ch=*i->p++;
+       if (ch=='\0') return EOF;
+       return ch;
+}
+
+static int static_peek(struct in_str *i)
+{
+       return *i->p;
+}
+
+static inline void cmdedit_set_initial_prompt(void)
+{
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       PS1 = NULL;
+#else
+       PS1 = getenv("PS1");
+       if(PS1==0)
+               PS1 = "\\w \\$ ";
+#endif 
+}
+
+static inline void setup_prompt_string(int promptmode, char **prompt_str)
+{
+       debug_printf("setup_prompt_string %d ",promptmode);
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       /* Set up the prompt */
+       if (promptmode == 1) {
+               if (PS1)
+                       free(PS1);
+               PS1=xmalloc(strlen(cwd)+4);
+               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
+               *prompt_str = PS1;
+       } else {
+               *prompt_str = PS2;
+       }
+#else
+       *prompt_str = (promptmode==1)? PS1 : PS2;
+#endif
+       debug_printf("result %s\n",*prompt_str);
+}
+
+static void get_user_input(struct in_str *i)
+{
+       char *prompt_str;
+       static char the_command[BUFSIZ];
+
+       setup_prompt_string(i->promptmode, &prompt_str);
+#ifdef BB_FEATURE_COMMAND_EDITING
+       /*
+        ** enable command line editing only while a command line
+        ** is actually being read; otherwise, we'll end up bequeathing
+        ** atexit() handlers and other unwanted stuff to our
+        ** child processes (rob@sysgo.de)
+        */
+       cmdedit_read_input(prompt_str, the_command);
+#else
+       fputs(prompt_str, stdout);
+       fflush(stdout);
+       the_command[0]=fgetc(i->file);
+       the_command[1]='\0';
+#endif
+       fflush(stdout);
+       i->p = the_command;
+}
+
+/* This is the magic location that prints prompts 
+ * and gets data back from the user */
+static int file_get(struct in_str *i)
+{
+       int ch;
+
+       ch = 0;
+       /* If there is data waiting, eat it up */
+       if (i->p && *i->p) {
+               ch=*i->p++;
+       } else {
+               /* need to double check i->file because we might be doing something
+                * more complicated by now, like sourcing or substituting. */
+               if (i->__promptme && interactive && i->file == stdin) {
+                       while(! i->p || (interactive && strlen(i->p)==0) ) {
+                               get_user_input(i);
+                       }
+                       i->promptmode=2;
+                       i->__promptme = 0;
+                       if (i->p && *i->p) {
+                               ch=*i->p++;
+                       }
+               } else {
+                       ch = fgetc(i->file);
+               }
+
+               debug_printf("b_getch: got a %d\n", ch);
+       }
+       if (ch == '\n') i->__promptme=1;
+       return ch;
+}
+
+/* All the callers guarantee this routine will never be
+ * used right after a newline, so prompting is not needed.
+ */
+static int file_peek(struct in_str *i)
+{
+       if (i->p && *i->p) {
+               return *i->p;
+       } else {
+               i->peek_buf[0] = fgetc(i->file);
+               i->peek_buf[1] = '\0';
+               i->p = i->peek_buf;
+               debug_printf("b_peek: got a %d\n", *i->p);
+               return *i->p;
+       }
+}
+
+static void setup_file_in_str(struct in_str *i, FILE *f)
+{
+       i->peek = file_peek;
+       i->get = file_get;
+       i->__promptme=1;
+       i->promptmode=1;
+       i->file = f;
+       i->p = NULL;
+}
+
+static void setup_string_in_str(struct in_str *i, const char *s)
+{
+       i->peek = static_peek;
+       i->get = static_get;
+       i->__promptme=1;
+       i->promptmode=1;
+       i->p = s;
+}
+
+static void mark_open(int fd)
+{
+       struct close_me *new = xmalloc(sizeof(struct close_me));
+       new->fd = fd;
+       new->next = close_me_head;
+       close_me_head = new;
+}
+
+static void mark_closed(int fd)
+{
+       struct close_me *tmp;
+       if (close_me_head == NULL || close_me_head->fd != fd)
+               error_msg_and_die("corrupt close_me");
+       tmp = close_me_head;
+       close_me_head = close_me_head->next;
+       free(tmp);
+}
+
+static void close_all()
+{
+       struct close_me *c;
+       for (c=close_me_head; c; c=c->next) {
+               close(c->fd);
+       }
+       close_me_head = NULL;
+}
+
+/* squirrel != NULL means we squirrel away copies of stdin, stdout,
+ * and stderr if they are redirected. */
+static int setup_redirects(struct child_prog *prog, int squirrel[])
+{
+       int openfd, mode;
+       struct redir_struct *redir;
+
+       for (redir=prog->redirects; redir; redir=redir->next) {
+               if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
+                       /* something went wrong in the parse.  Pretend it didn't happen */
+                       continue;
+               }
+               if (redir->dup == -1) {
+                       mode=redir_table[redir->type].mode;
+                       openfd = open(redir->word.gl_pathv[0], mode, 0666);
+                       if (openfd < 0) {
+                       /* this could get lost if stderr has been redirected, but
+                          bash and ash both lose it as well (though zsh doesn't!) */
+                               perror_msg("error opening %s", redir->word.gl_pathv[0]);
+                               return 1;
+                       }
+               } else {
+                       openfd = redir->dup;
+               }
+
+               if (openfd != redir->fd) {
+                       if (squirrel && redir->fd < 3) {
+                               squirrel[redir->fd] = dup(redir->fd);
+                       }
+                       if (openfd == -3) {
+                               close(openfd);
+                       } else {
+                               dup2(openfd, redir->fd);
+                               if (redir->dup == -1)
+                                       close (openfd);
+                       }
+               }
+       }
+       return 0;
+}
+
+static void restore_redirects(int squirrel[])
+{
+       int i, fd;
+       for (i=0; i<3; i++) {
+               fd = squirrel[i];
+               if (fd != -1) {
+                       /* No error checking.  I sure wouldn't know what
+                        * to do with an error if I found one! */
+                       dup2(fd, i);
+                       close(fd);
+               }
+       }
+}
+
+/* never returns */
+/* XXX no exit() here.  If you don't exec, use _exit instead.
+ * The at_exit handlers apparently confuse the calling process,
+ * in particular stdin handling.  Not sure why? */
+static void pseudo_exec(struct child_prog *child)
+{
+       int i, rcode;
+       char *p;
+       struct built_in_command *x;
+       if (child->argv) {
+               for (i=0; is_assignment(child->argv[i]); i++) {
+                       debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
+                       p = insert_var_value(child->argv[i]);
+                       putenv(strdup(p));
+                       if (p != child->argv[i]) free(p);
+               }
+               child->argv+=i;  /* XXX this hack isn't so horrible, since we are about
+                                       to exit, and therefore don't need to keep data
+                                       structures consistent for free() use. */
+               /* If a variable is assigned in a forest, and nobody listens,
+                * was it ever really set?
+                */
+               if (child->argv[0] == NULL) {
+                       _exit(EXIT_SUCCESS);
+               }
+
+               /*
+                * Check if the command matches any of the builtins.
+                * Depending on context, this might be redundant.  But it's
+                * easier to waste a few CPU cycles than it is to figure out
+                * if this is one of those cases.
+                */
+               for (x = bltins; x->cmd; x++) {
+                       if (strcmp(child->argv[0], x->cmd) == 0 ) {
+                               debug_printf("builtin exec %s\n", child->argv[0]);
+                               rcode = x->function(child);
+                               fflush(stdout);
+                               _exit(rcode);
+                       }
+               }
+
+               /* Check if the command matches any busybox internal commands
+                * ("applets") here.  
+                * FIXME: This feature is not 100% safe, since
+                * BusyBox is not fully reentrant, so we have no guarantee the things
+                * from the .bss are still zeroed, or that things from .data are still
+                * at their defaults.  We could exec ourself from /proc/self/exe, but I
+                * really dislike relying on /proc for things.  We could exec ourself
+                * from global_argv[0], but if we are in a chroot, we may not be able
+                * to find ourself... */ 
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+               {
+                       int argc_l;
+                       char** argv_l=child->argv;
+                       char *name = child->argv[0];
+
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+                       /* Following discussions from November 2000 on the busybox mailing
+                        * list, the default configuration, (without
+                        * get_last_path_component()) lets the user force use of an
+                        * external command by specifying the full (with slashes) filename.
+                        * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets
+                        * _aways_ override external commands, so if you want to run
+                        * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the
+                        * filesystem and is _not_ busybox.  Some systems may want this,
+                        * most do not.  */
+                       name = get_last_path_component(name);
+#endif
+                       /* Count argc for use in a second... */
+                       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+                       optind = 1;
+                       debug_printf("running applet %s\n", name);
+                       run_applet_by_name(name, argc_l, child->argv);
+               }
+#endif
+               debug_printf("exec of %s\n",child->argv[0]);
+               execvp(child->argv[0],child->argv);
+               perror_msg("couldn't exec: %s",child->argv[0]);
+               _exit(1);
+       } else if (child->group) {
+               debug_printf("runtime nesting to group\n");
+               interactive=0;    /* crucial!!!! */
+               rcode = run_list_real(child->group);
+               /* OK to leak memory by not calling free_pipe_list,
+                * since this process is about to exit */
+               _exit(rcode);
+       } else {
+               /* Can happen.  See what bash does with ">foo" by itself. */
+               debug_printf("trying to pseudo_exec null command\n");
+               _exit(EXIT_SUCCESS);
+       }
+}
+
+static void insert_bg_job(struct pipe *pi)
+{
+       struct pipe *thejob;
+
+       /* Linear search for the ID of the job to use */
+       pi->jobid = 1;
+       for (thejob = job_list; thejob; thejob = thejob->next)
+               if (thejob->jobid >= pi->jobid)
+                       pi->jobid = thejob->jobid + 1;
+
+       /* add thejob to the list of running jobs */
+       if (!job_list) {
+               thejob = job_list = xmalloc(sizeof(*thejob));
+       } else {
+               for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
+               thejob->next = xmalloc(sizeof(*thejob));
+               thejob = thejob->next;
+       }
+
+       /* physically copy the struct job */
+       memcpy(thejob, pi, sizeof(struct pipe));
+       thejob->next = NULL;
+       thejob->running_progs = thejob->num_progs;
+       thejob->stopped_progs = 0;
+       thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
+
+       //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
+       {
+               char *bar=thejob->text;
+               char **foo=pi->progs[0].argv;
+               while(foo && *foo) {
+                       bar += sprintf(bar, "%s ", *foo++);
+               }
+       }
+
+       /* we don't wait for background thejobs to return -- append it 
+          to the list of backgrounded thejobs and leave it alone */
+       printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
+       last_bg_pid = thejob->progs[0].pid;
+       last_jobid = thejob->jobid;
+}
+
+/* remove a backgrounded job */
+static void remove_bg_job(struct pipe *pi)
+{
+       struct pipe *prev_pipe;
+
+       if (pi == job_list) {
+               job_list = pi->next;
+       } else {
+               prev_pipe = job_list;
+               while (prev_pipe->next != pi)
+                       prev_pipe = prev_pipe->next;
+               prev_pipe->next = pi->next;
+       }
+       if (job_list)
+               last_jobid = job_list->jobid;
+       else
+               last_jobid = 0;
+
+       pi->stopped_progs = 0;
+       free_pipe(pi, 0);
+       free(pi);
+}
+
+/* Checks to see if any processes have exited -- if they 
+   have, figure out why and see if a job has completed */
+static int checkjobs(struct pipe* fg_pipe)
+{
+       int attributes;
+       int status;
+       int prognum = 0;
+       struct pipe *pi;
+       pid_t childpid;
+
+       attributes = WUNTRACED;
+       if (fg_pipe==NULL) {
+               attributes |= WNOHANG;
+       }
+
+       while ((childpid = waitpid(-1, &status, attributes)) > 0) {
+               if (fg_pipe) {
+                       int i, rcode = 0;
+                       for (i=0; i < fg_pipe->num_progs; i++) {
+                               if (fg_pipe->progs[i].pid == childpid) {
+                                       if (i==fg_pipe->num_progs-1) 
+                                               rcode=WEXITSTATUS(status);
+                                       (fg_pipe->num_progs)--;
+                                       return(rcode);
+                               }
+                       }
+               }
+
+               for (pi = job_list; pi; pi = pi->next) {
+                       prognum = 0;
+                       while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
+                               prognum++;
+                       }
+                       if (prognum < pi->num_progs)
+                               break;
+               }
+
+               if(pi==NULL) {
+                       debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
+                       continue;
+               }
+
+               if (WIFEXITED(status) || WIFSIGNALED(status)) {
+                       /* child exited */
+                       pi->running_progs--;
+                       pi->progs[prognum].pid = 0;
+
+                       if (!pi->running_progs) {
+                               printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
+                               remove_bg_job(pi);
+                       }
+               } else {
+                       /* child stopped */
+                       pi->stopped_progs++;
+                       pi->progs[prognum].is_stopped = 1;
+
+#if 0
+                       /* Printing this stuff is a pain, since it tends to
+                        * overwrite the prompt an inconveinient moments.  So
+                        * don't do that.  */
+                       if (pi->stopped_progs == pi->num_progs) {
+                               printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
+                       }
+#endif 
+               }
+       }
+
+       if (childpid == -1 && errno != ECHILD)
+               perror_msg("waitpid");
+
+       /* move the shell to the foreground */
+       //if (interactive && tcsetpgrp(shell_terminal, getpgid(0)))
+       //      perror_msg("tcsetpgrp-2");
+       return -1;
+}
+
+/* Figure out our controlling tty, checking in order stderr,
+ * stdin, and stdout.  If check_pgrp is set, also check that
+ * we belong to the foreground process group associated with
+ * that tty.  The value of shell_terminal is needed in order to call
+ * tcsetpgrp(shell_terminal, ...); */
+void controlling_tty(int check_pgrp)
+{
+       pid_t curpgrp;
+
+       if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0
+                       && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0
+                       && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0)
+               goto shell_terminal_error;
+
+       if (check_pgrp && curpgrp != getpgid(0))
+               goto shell_terminal_error;
+
+       return;
+
+shell_terminal_error:
+               shell_terminal = -1;
+               return;
+}
+
+/* run_pipe_real() starts all the jobs, but doesn't wait for anything
+ * to finish.  See checkjobs().
+ *
+ * return code is normally -1, when the caller has to wait for children
+ * to finish to determine the exit status of the pipe.  If the pipe
+ * is a simple builtin command, however, the action is done by the
+ * time run_pipe_real returns, and the exit code is provided as the
+ * return value.
+ *
+ * The input of the pipe is always stdin, the output is always
+ * stdout.  The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
+ * because it tries to avoid running the command substitution in
+ * subshell, when that is in fact necessary.  The subshell process
+ * now has its stdout directed to the input of the appropriate pipe,
+ * so this routine is noticeably simpler.
+ */
+static int run_pipe_real(struct pipe *pi)
+{
+       int i;
+       int nextin, nextout;
+       int pipefds[2];                         /* pipefds[0] is for reading */
+       struct child_prog *child;
+       struct built_in_command *x;
+       char *p;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &i;
+       (void) &nextin;
+       (void) &nextout;
+       (void) &child;
+#endif
+
+       nextin = 0;
+       pi->pgrp = -1;
+
+       /* Check if this is a simple builtin (not part of a pipe).
+        * Builtins within pipes have to fork anyway, and are handled in
+        * pseudo_exec.  "echo foo | read bar" doesn't work on bash, either.
+        */
+       if (pi->num_progs == 1) child = & (pi->progs[0]);
+       if (pi->num_progs == 1 && child->group && child->subshell == 0) {
+               int squirrel[] = {-1, -1, -1};
+               int rcode;
+               debug_printf("non-subshell grouping\n");
+               setup_redirects(child, squirrel);
+               /* XXX could we merge code with following builtin case,
+                * by creating a pseudo builtin that calls run_list_real? */
+               rcode = run_list_real(child->group);
+               restore_redirects(squirrel);
+               return rcode;
+       } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
+               for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
+               if (i!=0 && child->argv[i]==NULL) {
+                       /* assignments, but no command: set the local environment */
+                       for (i=0; child->argv[i]!=NULL; i++) {
+
+                               /* Ok, this case is tricky.  We have to decide if this is a
+                                * local variable, or an already exported variable.  If it is
+                                * already exported, we have to export the new value.  If it is
+                                * not exported, we need only set this as a local variable. 
+                                * This junk is all to decide whether or not to export this
+                                * variable. */
+                               int export_me=0;
+                               char *name, *value;
+                               name = xstrdup(child->argv[i]);
+                               debug_printf("Local environment set: %s\n", name);
+                               value = strchr(name, '=');
+                               if (value)
+                                       *value=0;
+                               if ( get_local_var(name)) {
+                                       export_me=1;
+                               }
+                               free(name);
+                               p = insert_var_value(child->argv[i]);
+                               set_local_var(p, export_me);
+                               if (p != child->argv[i]) free(p);
+                       }
+                       return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
+               }
+               for (i = 0; is_assignment(child->argv[i]); i++) {
+                       p = insert_var_value(child->argv[i]);
+                       putenv(strdup(p));
+                       if (p != child->argv[i]) {
+                               child->sp--;
+                               free(p);
+                       }
+               }
+               if (child->sp) {
+                       char * str = NULL;
+                       
+                       str = make_string((child->argv + i));
+                       parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
+                       free(str);
+                       return last_return_code;
+               }
+               for (x = bltins; x->cmd; x++) {
+                       if (strcmp(child->argv[i], x->cmd) == 0 ) {
+                               int squirrel[] = {-1, -1, -1};
+                               int rcode;
+                               if (x->function == builtin_exec && child->argv[i+1]==NULL) {
+                                       debug_printf("magic exec\n");
+                                       setup_redirects(child,NULL);
+                                       return EXIT_SUCCESS;
+                               }
+                               debug_printf("builtin inline %s\n", child->argv[0]);
+                               /* XXX setup_redirects acts on file descriptors, not FILEs.
+                                * This is perfect for work that comes after exec().
+                                * Is it really safe for inline use?  Experimentally,
+                                * things seem to work with glibc. */
+                               setup_redirects(child, squirrel);
+                               child->argv+=i;  /* XXX horrible hack */
+                               rcode = x->function(child);
+                               child->argv-=i;  /* XXX restore hack so free() can work right */
+                               restore_redirects(squirrel);
+                               return rcode;
+                       }
+               }
+       }
+
+       for (i = 0; i < pi->num_progs; i++) {
+               child = & (pi->progs[i]);
+
+               /* pipes are inserted between pairs of commands */
+               if ((i + 1) < pi->num_progs) {
+                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
+                       nextout = pipefds[1];
+               } else {
+                       nextout=1;
+                       pipefds[0] = -1;
+               }
+
+               /* XXX test for failed fork()? */
+               if (!(child->pid = fork()))
+               {
+                       /* Set the handling for job control signals back to the default.  */
+                       signal(SIGINT, SIG_DFL);
+                       signal(SIGQUIT, SIG_DFL);
+                       signal(SIGTERM, SIG_DFL);
+                       signal(SIGTSTP, SIG_DFL);
+                       signal(SIGTTIN, SIG_DFL);
+                       signal(SIGTTOU, SIG_DFL);
+                       signal(SIGCHLD, SIG_DFL);
+                       
+                       close_all();
+
+                       if (nextin != 0) {
+                               dup2(nextin, 0);
+                               close(nextin);
+                       }
+                       if (nextout != 1) {
+                               dup2(nextout, 1);
+                               close(nextout);
+                       }
+                       if (pipefds[0]!=-1) {
+                               close(pipefds[0]);  /* opposite end of our output pipe */
+                       }
+
+                       /* Like bash, explicit redirects override pipes,
+                        * and the pipe fd is available for dup'ing. */
+                       setup_redirects(child,NULL);
+
+                       if (interactive && pi->followup!=PIPE_BG) {
+                               /* If we (the child) win the race, put ourselves in the process
+                                * group whose leader is the first process in this pipe. */
+                               if (pi->pgrp < 0) {
+                                       pi->pgrp = getpid();
+                               }
+                               if (setpgid(0, pi->pgrp) == 0) {
+                                       tcsetpgrp(2, pi->pgrp);
+                               }
+                       }
+
+                       pseudo_exec(child);
+               }
+               
+
+               /* put our child in the process group whose leader is the
+                  first process in this pipe */
+               if (pi->pgrp < 0) {
+                       pi->pgrp = child->pid;
+               }
+               /* Don't check for errors.  The child may be dead already,
+                * in which case setpgid returns error code EACCES. */
+               setpgid(child->pid, pi->pgrp);
+
+               if (nextin != 0)
+                       close(nextin);
+               if (nextout != 1)
+                       close(nextout);
+
+               /* If there isn't another process, nextin is garbage 
+                  but it doesn't matter */
+               nextin = pipefds[0];
+       }
+       return -1;
+}
+
+static int run_list_real(struct pipe *pi)
+{
+       char *save_name = NULL;
+       char **list = NULL;
+       char **save_list = NULL;
+       struct pipe *rpipe;
+       int flag_rep = 0;
+       int save_num_progs;
+       int rcode=0, flag_skip=1;
+       int flag_restore = 0;
+       int if_code=0, next_if_code=0;  /* need double-buffer to handle elif */
+       reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
+       /* check syntax for "for" */
+       for (rpipe = pi; rpipe; rpipe = rpipe->next) {
+               if ((rpipe->r_mode == RES_IN ||
+                   rpipe->r_mode == RES_FOR) &&
+                   (rpipe->next == NULL)) {
+                               syntax();
+                               return 1;
+               }               
+               if ((rpipe->r_mode == RES_IN && 
+                       (rpipe->next->r_mode == RES_IN && 
+                       rpipe->next->progs->argv != NULL))||
+                       (rpipe->r_mode == RES_FOR &&
+                       rpipe->next->r_mode != RES_IN)) { 
+                               syntax();
+                               return 1;
+               }
+       }
+       for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
+               if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
+                       pi->r_mode == RES_FOR) {
+                               flag_restore = 0;
+                               if (!rpipe) {
+                                       flag_rep = 0;
+                                       rpipe = pi;
+                               }
+               }
+               rmode = pi->r_mode;
+               debug_printf("rmode=%d  if_code=%d  next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
+               if (rmode == skip_more_in_this_rmode && flag_skip) {
+                       if (pi->followup == PIPE_SEQ) flag_skip=0;
+                       continue;
+               }
+               flag_skip = 1;
+               skip_more_in_this_rmode = RES_XXXX;
+               if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
+               if (rmode == RES_THEN &&  if_code) continue;
+               if (rmode == RES_ELSE && !if_code) continue;
+               if (rmode == RES_ELIF && !if_code) continue;
+               if (rmode == RES_FOR && pi->num_progs) {
+                       if (!list) {
+                               /* if no variable values after "in" we skip "for" */            
+                               if (!pi->next->progs->argv) continue;
+                               /* create list of variable values */
+                               list = make_list_in(pi->next->progs->argv,
+                                       pi->progs->argv[0]);
+                               save_list = list;
+                               save_name = pi->progs->argv[0];
+                               pi->progs->argv[0] = NULL;
+                               flag_rep = 1;
+                       }       
+                       if (!(*list)) {
+                               free(pi->progs->argv[0]);
+                               free(save_list);
+                               list = NULL;
+                               flag_rep = 0;
+                               pi->progs->argv[0] = save_name;
+                               pi->progs->glob_result.gl_pathv[0] =
+                                       pi->progs->argv[0];
+                               continue;
+                       } else {                        
+                               /* insert new value from list for variable */
+                               if (pi->progs->argv[0]) 
+                                       free(pi->progs->argv[0]);
+                               pi->progs->argv[0] = *list++;
+                               pi->progs->glob_result.gl_pathv[0] =
+                                       pi->progs->argv[0];
+                       }
+               }               
+               if (rmode == RES_IN) continue;
+               if (rmode == RES_DO) {
+                       if (!flag_rep) continue;
+               }           
+               if ((rmode == RES_DONE)) {
+                       if (flag_rep) {
+                               flag_restore = 1;
+                       } else {
+                               rpipe = NULL;
+                       }
+               }               
+               if (pi->num_progs == 0) continue;
+               save_num_progs = pi->num_progs; /* save number of programs */
+               rcode = run_pipe_real(pi);
+               debug_printf("run_pipe_real returned %d\n",rcode);
+               if (rcode!=-1) {
+                       /* We only ran a builtin: rcode was set by the return value
+                        * of run_pipe_real(), and we don't need to wait for anything. */
+               } else if (pi->followup==PIPE_BG) {
+                       /* XXX check bash's behavior with nontrivial pipes */
+                       /* XXX compute jobid */
+                       /* XXX what does bash do with attempts to background builtins? */
+                       insert_bg_job(pi);
+                       rcode = EXIT_SUCCESS;
+               } else {
+                       if (interactive) {
+                               /* move the new process group into the foreground */
+                               if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
+                                       perror_msg("tcsetpgrp-3");
+                               rcode = checkjobs(pi);
+                               /* move the shell to the foreground */
+                               if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY)
+                                       perror_msg("tcsetpgrp-4");
+                       } else {
+                               rcode = checkjobs(pi);
+                       }
+                       debug_printf("checkjobs returned %d\n",rcode);
+               }
+               last_return_code=rcode;
+               pi->num_progs = save_num_progs; /* restore number of programs */
+               if ( rmode == RES_IF || rmode == RES_ELIF )
+                       next_if_code=rcode;  /* can be overwritten a number of times */
+               if (rmode == RES_WHILE) 
+                       flag_rep = !last_return_code;
+               if (rmode == RES_UNTIL) 
+                       flag_rep = last_return_code;
+               if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
+                    (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
+                       skip_more_in_this_rmode=rmode;
+               checkjobs(NULL);
+       }
+       return rcode;
+}
+
+/* broken, of course, but OK for testing */
+static char *indenter(int i)
+{
+       static char blanks[]="                                    ";
+       return &blanks[sizeof(blanks)-i-1];
+}
+
+/* return code is the exit status of the pipe */
+static int free_pipe(struct pipe *pi, int indent)
+{
+       char **p;
+       struct child_prog *child;
+       struct redir_struct *r, *rnext;
+       int a, i, ret_code=0;
+       char *ind = indenter(indent);
+
+       if (pi->stopped_progs > 0)
+               return ret_code;
+       final_printf("%s run pipe: (pid %d)\n",ind,getpid());
+       for (i=0; i<pi->num_progs; i++) {
+               child = &pi->progs[i];
+               final_printf("%s  command %d:\n",ind,i);
+               if (child->argv) {
+                       for (a=0,p=child->argv; *p; a++,p++) {
+                               final_printf("%s   argv[%d] = %s\n",ind,a,*p);
+                       }
+                       globfree(&child->glob_result);
+                       child->argv=NULL;
+               } else if (child->group) {
+                       final_printf("%s   begin group (subshell:%d)\n",ind, child->subshell);
+                       ret_code = free_pipe_list(child->group,indent+3);
+                       final_printf("%s   end group\n",ind);
+               } else {
+                       final_printf("%s   (nil)\n",ind);
+               }
+               for (r=child->redirects; r; r=rnext) {
+                       final_printf("%s   redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
+                       if (r->dup == -1) {
+                               /* guard against the case >$FOO, where foo is unset or blank */
+                               if (r->word.gl_pathv) {
+                                       final_printf(" %s\n", *r->word.gl_pathv);
+                                       globfree(&r->word);
+                               }
+                       } else {
+                               final_printf("&%d\n", r->dup);
+                       }
+                       rnext=r->next;
+                       free(r);
+               }
+               child->redirects=NULL;
+       }
+       free(pi->progs);   /* children are an array, they get freed all at once */
+       pi->progs=NULL;
+       return ret_code;
+}
+
+static int free_pipe_list(struct pipe *head, int indent)
+{
+       int rcode=0;   /* if list has no members */
+       struct pipe *pi, *next;
+       char *ind = indenter(indent);
+       for (pi=head; pi; pi=next) {
+               final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
+               rcode = free_pipe(pi, indent);
+               final_printf("%s pipe followup code %d\n", ind, pi->followup);
+               next=pi->next;
+               pi->next=NULL;
+               free(pi);
+       }
+       return rcode;   
+}
+
+/* Select which version we will use */
+static int run_list(struct pipe *pi)
+{
+       int rcode=0;
+       if (fake_mode==0) {
+               rcode = run_list_real(pi);
+       } 
+       /* free_pipe_list has the side effect of clearing memory
+        * In the long run that function can be merged with run_list_real,
+        * but doing that now would hobble the debugging effort. */
+       free_pipe_list(pi,0);
+       return rcode;
+}
+
+/* The API for glob is arguably broken.  This routine pushes a non-matching
+ * string into the output structure, removing non-backslashed backslashes.
+ * If someone can prove me wrong, by performing this function within the
+ * original glob(3) api, feel free to rewrite this routine into oblivion.
+ * Return code (0 vs. GLOB_NOSPACE) matches glob(3).
+ * XXX broken if the last character is '\\', check that before calling.
+ */
+static int globhack(const char *src, int flags, glob_t *pglob)
+{
+       int cnt=0, pathc;
+       const char *s;
+       char *dest;
+       for (cnt=1, s=src; s && *s; s++) {
+               if (*s == '\\') s++;
+               cnt++;
+       }
+       dest = malloc(cnt);
+       if (!dest) return GLOB_NOSPACE;
+       if (!(flags & GLOB_APPEND)) {
+               pglob->gl_pathv=NULL;
+               pglob->gl_pathc=0;
+               pglob->gl_offs=0;
+               pglob->gl_offs=0;
+       }
+       pathc = ++pglob->gl_pathc;
+       pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
+       if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
+       pglob->gl_pathv[pathc-1]=dest;
+       pglob->gl_pathv[pathc]=NULL;
+       for (s=src; s && *s; s++, dest++) {
+               if (*s == '\\') s++;
+               *dest = *s;
+       }
+       *dest='\0';
+       return 0;
+}
+
+/* XXX broken if the last character is '\\', check that before calling */
+static int glob_needed(const char *s)
+{
+       for (; *s; s++) {
+               if (*s == '\\') s++;
+               if (strchr("*[?",*s)) return 1;
+       }
+       return 0;
+}
+
+#if 0
+static void globprint(glob_t *pglob)
+{
+       int i;
+       debug_printf("glob_t at %p:\n", pglob);
+       debug_printf("  gl_pathc=%d  gl_pathv=%p  gl_offs=%d  gl_flags=%d\n",
+               pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
+       for (i=0; i<pglob->gl_pathc; i++)
+               debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
+                       pglob->gl_pathv[i], pglob->gl_pathv[i]);
+}
+#endif
+
+static int xglob(o_string *dest, int flags, glob_t *pglob)
+{
+       int gr;
+
+       /* short-circuit for null word */
+       /* we can code this better when the debug_printf's are gone */
+       if (dest->length == 0) {
+               if (dest->nonnull) {
+                       /* bash man page calls this an "explicit" null */
+                       gr = globhack(dest->data, flags, pglob);
+                       debug_printf("globhack returned %d\n",gr);
+               } else {
+                       return 0;
+               }
+       } else if (glob_needed(dest->data)) {
+               gr = glob(dest->data, flags, NULL, pglob);
+               debug_printf("glob returned %d\n",gr);
+               if (gr == GLOB_NOMATCH) {
+                       /* quote removal, or more accurately, backslash removal */
+                       gr = globhack(dest->data, flags, pglob);
+                       debug_printf("globhack returned %d\n",gr);
+               }
+       } else {
+               gr = globhack(dest->data, flags, pglob);
+               debug_printf("globhack returned %d\n",gr);
+       }
+       if (gr == GLOB_NOSPACE)
+               error_msg_and_die("out of memory during glob");
+       if (gr != 0) { /* GLOB_ABORTED ? */
+               error_msg("glob(3) error %d",gr);
+       }
+       /* globprint(glob_target); */
+       return gr;
+}
+
+/* This is used to get/check local shell variables */
+static char *get_local_var(const char *s)
+{
+       struct variables *cur;
+
+       if (!s)
+               return NULL;
+       for (cur = top_vars; cur; cur=cur->next)
+               if(strcmp(cur->name, s)==0)
+                       return cur->value;
+       return NULL;
+}
+
+/* This is used to set local shell variables
+   flg_export==0 if only local (not exporting) variable
+   flg_export==1 if "new" exporting environ
+   flg_export>1  if current startup environ (not call putenv()) */
+static int set_local_var(const char *s, int flg_export)
+{
+       char *name, *value;
+       int result=0;
+       struct variables *cur;
+
+       name=strdup(s);
+
+       /* Assume when we enter this function that we are already in
+        * NAME=VALUE format.  So the first order of business is to
+        * split 's' on the '=' into 'name' and 'value' */ 
+       value = strchr(name, '=');
+       if (value==0 && ++value==0) {
+               free(name);
+               return -1;
+       }
+       *value++ = 0;
+
+       for(cur = top_vars; cur; cur = cur->next) {
+               if(strcmp(cur->name, name)==0)
+                       break;
+       }
+
+       if(cur) {
+               if(strcmp(cur->value, value)==0) {
+                       if(flg_export>0 && cur->flg_export==0)
+                               cur->flg_export=flg_export;
+                       else
+                               result++;
+               } else {
+                       if(cur->flg_read_only) {
+                               error_msg("%s: readonly variable", name);
+                               result = -1;
+                       } else {
+                               if(flg_export>0 || cur->flg_export>1)
+                                       cur->flg_export=1;
+                               free(cur->value);
+
+                               cur->value = strdup(value);
+                       }
+               }
+       } else {
+               cur = malloc(sizeof(struct variables));
+               if(!cur) {
+                       result = -1;
+               } else {
+                       cur->name = strdup(name);
+                       if(cur->name == 0) {
+                               free(cur);
+                               result = -1;
+                       } else {
+                               struct variables *bottom = top_vars;
+                               cur->value = strdup(value);
+                               cur->next = 0;
+                               cur->flg_export = flg_export;
+                               cur->flg_read_only = 0;
+                               while(bottom->next) bottom=bottom->next;
+                               bottom->next = cur;
+                       }
+               }
+       }
+
+       if(result==0 && cur->flg_export==1) {
+               *(value-1) = '=';
+               result = putenv(name);
+       } else {
+               free(name);
+               if(result>0)            /* equivalent to previous set */
+                       result = 0;
+       }
+       return result;
+}
+
+static void unset_local_var(const char *name)
+{
+       struct variables *cur;
+
+       if (name) {
+               for (cur = top_vars; cur; cur=cur->next) {
+                       if(strcmp(cur->name, name)==0)
+                               break;
+               }
+               if(cur!=0) {
+                       struct variables *next = top_vars;
+                       if(cur->flg_read_only) {
+                               error_msg("%s: readonly variable", name);
+                               return;
+                       } else {
+                               if(cur->flg_export)
+                                       unsetenv(cur->name);
+                               free(cur->name);
+                               free(cur->value);
+                               while (next->next != cur)
+                                       next = next->next;
+                               next->next = cur->next;
+                       }
+                       free(cur);
+               }
+       }
+}
+
+static int is_assignment(const char *s)
+{
+       if (s==NULL || !isalpha(*s)) return 0;
+       ++s;
+       while(isalnum(*s) || *s=='_') ++s;
+       return *s=='=';
+}
+
+/* the src parameter allows us to peek forward to a possible &n syntax
+ * for file descriptor duplication, e.g., "2>&1".
+ * Return code is 0 normally, 1 if a syntax error is detected in src.
+ * Resource errors (in xmalloc) cause the process to exit */
+static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
+       struct in_str *input)
+{
+       struct child_prog *child=ctx->child;
+       struct redir_struct *redir = child->redirects;
+       struct redir_struct *last_redir=NULL;
+
+       /* Create a new redir_struct and drop it onto the end of the linked list */
+       while(redir) {
+               last_redir=redir;
+               redir=redir->next;
+       }
+       redir = xmalloc(sizeof(struct redir_struct));
+       redir->next=NULL;
+       redir->word.gl_pathv=NULL;
+       if (last_redir) {
+               last_redir->next=redir;
+       } else {
+               child->redirects=redir;
+       }
+
+       redir->type=style;
+       redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
+
+       debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
+
+       /* Check for a '2>&1' type redirect */ 
+       redir->dup = redirect_dup_num(input);
+       if (redir->dup == -2) return 1;  /* syntax error */
+       if (redir->dup != -1) {
+               /* Erik had a check here that the file descriptor in question
+                * is legit; I postpone that to "run time"
+                * A "-" representation of "close me" shows up as a -3 here */
+               debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
+       } else {
+               /* We do _not_ try to open the file that src points to,
+                * since we need to return and let src be expanded first.
+                * Set ctx->pending_redirect, so we know what to do at the
+                * end of the next parsed word.
+                */
+               ctx->pending_redirect = redir;
+       }
+       return 0;
+}
+
+struct pipe *new_pipe(void) {
+       struct pipe *pi;
+       pi = xmalloc(sizeof(struct pipe));
+       pi->num_progs = 0;
+       pi->progs = NULL;
+       pi->next = NULL;
+       pi->followup = 0;  /* invalid */
+       return pi;
+}
+
+static void initialize_context(struct p_context *ctx)
+{
+       ctx->pipe=NULL;
+       ctx->pending_redirect=NULL;
+       ctx->child=NULL;
+       ctx->list_head=new_pipe();
+       ctx->pipe=ctx->list_head;
+       ctx->w=RES_NONE;
+       ctx->stack=NULL;
+       ctx->old_flag=0;
+       done_command(ctx);   /* creates the memory for working child */
+}
+
+/* normal return is 0
+ * if a reserved word is found, and processed, return 1
+ * should handle if, then, elif, else, fi, for, while, until, do, done.
+ * case, function, and select are obnoxious, save those for later.
+ */
+int reserved_word(o_string *dest, struct p_context *ctx)
+{
+       struct reserved_combo {
+               char *literal;
+               int code;
+               long flag;
+       };
+       /* Mostly a list of accepted follow-up reserved words.
+        * FLAG_END means we are done with the sequence, and are ready
+        * to turn the compound list into a command.
+        * FLAG_START means the word must start a new compound list.
+        */
+       static struct reserved_combo reserved_list[] = {
+               { "if",    RES_IF,    FLAG_THEN | FLAG_START },
+               { "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },
+               { "elif",  RES_ELIF,  FLAG_THEN },
+               { "else",  RES_ELSE,  FLAG_FI   },
+               { "fi",    RES_FI,    FLAG_END  },
+               { "for",   RES_FOR,   FLAG_IN   | FLAG_START },
+               { "while", RES_WHILE, FLAG_DO   | FLAG_START },
+               { "until", RES_UNTIL, FLAG_DO   | FLAG_START },
+               { "in",    RES_IN,    FLAG_DO   },
+               { "do",    RES_DO,    FLAG_DONE },
+               { "done",  RES_DONE,  FLAG_END  }
+       };
+       struct reserved_combo *r;
+       for (r=reserved_list;
+#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)
+               r<reserved_list+NRES; r++) {
+               if (strcmp(dest->data, r->literal) == 0) {
+                       debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
+                       if (r->flag & FLAG_START) {
+                               struct p_context *new = xmalloc(sizeof(struct p_context));
+                               debug_printf("push stack\n");
+                               if (ctx->w == RES_IN || ctx->w == RES_FOR) {
+                                       syntax();
+                                       free(new);
+                                       ctx->w = RES_SNTX;
+                                       b_reset(dest);
+                                       return 1;
+                               }
+                               *new = *ctx;   /* physical copy */
+                               initialize_context(ctx);
+                               ctx->stack=new;
+                       } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
+                               syntax();
+                               ctx->w = RES_SNTX;
+                               b_reset(dest);
+                               return 1;
+                       }
+                       ctx->w=r->code;
+                       ctx->old_flag = r->flag;
+                       if (ctx->old_flag & FLAG_END) {
+                               struct p_context *old;
+                               debug_printf("pop stack\n");
+                               done_pipe(ctx,PIPE_SEQ);
+                               old = ctx->stack;
+                               old->child->group = ctx->list_head;
+                               old->child->subshell = 0;
+                               *ctx = *old;   /* physical copy */
+                               free(old);
+                       }
+                       b_reset (dest);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* normal return is 0.
+ * Syntax or xglob errors return 1. */
+static int done_word(o_string *dest, struct p_context *ctx)
+{
+       struct child_prog *child=ctx->child;
+       glob_t *glob_target;
+       int gr, flags = 0;
+
+       debug_printf("done_word: %s %p\n", dest->data, child);
+       if (dest->length == 0 && !dest->nonnull) {
+               debug_printf("  true null, ignored\n");
+               return 0;
+       }
+       if (ctx->pending_redirect) {
+               glob_target = &ctx->pending_redirect->word;
+       } else {
+               if (child->group) {
+                       syntax();
+                       return 1;  /* syntax error, groups and arglists don't mix */
+               }
+               if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
+                       debug_printf("checking %s for reserved-ness\n",dest->data);
+                       if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
+               }
+               glob_target = &child->glob_result;
+               if (child->argv) flags |= GLOB_APPEND;
+       }
+       gr = xglob(dest, flags, glob_target);
+       if (gr != 0) return 1;
+
+       b_reset(dest);
+       if (ctx->pending_redirect) {
+               ctx->pending_redirect=NULL;
+               if (glob_target->gl_pathc != 1) {
+                       error_msg("ambiguous redirect");
+                       return 1;
+               }
+       } else {
+               child->argv = glob_target->gl_pathv;
+       }
+       if (ctx->w == RES_FOR) {
+               done_word(dest,ctx);
+               done_pipe(ctx,PIPE_SEQ);
+       }
+       return 0;
+}
+
+/* The only possible error here is out of memory, in which case
+ * xmalloc exits. */
+static int done_command(struct p_context *ctx)
+{
+       /* The child is really already in the pipe structure, so
+        * advance the pipe counter and make a new, null child.
+        * Only real trickiness here is that the uncommitted
+        * child structure, to which ctx->child points, is not
+        * counted in pi->num_progs. */
+       struct pipe *pi=ctx->pipe;
+       struct child_prog *prog=ctx->child;
+
+       if (prog && prog->group == NULL
+                && prog->argv == NULL
+                && prog->redirects == NULL) {
+               debug_printf("done_command: skipping null command\n");
+               return 0;
+       } else if (prog) {
+               pi->num_progs++;
+               debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
+       } else {
+               debug_printf("done_command: initializing\n");
+       }
+       pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
+
+       prog = pi->progs + pi->num_progs;
+       prog->redirects = NULL;
+       prog->argv = NULL;
+       prog->is_stopped = 0;
+       prog->group = NULL;
+       prog->glob_result.gl_pathv = NULL;
+       prog->family = pi;
+       prog->sp = 0;
+       ctx->child = prog;
+       prog->type = ctx->type;
+
+       /* but ctx->pipe and ctx->list_head remain unchanged */
+       return 0;
+}
+
+static int done_pipe(struct p_context *ctx, pipe_style type)
+{
+       struct pipe *new_p;
+       done_command(ctx);  /* implicit closure of previous command */
+       debug_printf("done_pipe, type %d\n", type);
+       ctx->pipe->followup = type;
+       ctx->pipe->r_mode = ctx->w;
+       new_p=new_pipe();
+       ctx->pipe->next = new_p;
+       ctx->pipe = new_p;
+       ctx->child = NULL;
+       done_command(ctx);  /* set up new pipe to accept commands */
+       return 0;
+}
+
+/* peek ahead in the in_str to find out if we have a "&n" construct,
+ * as in "2>&1", that represents duplicating a file descriptor.
+ * returns either -2 (syntax error), -1 (no &), or the number found.
+ */
+static int redirect_dup_num(struct in_str *input)
+{
+       int ch, d=0, ok=0;
+       ch = b_peek(input);
+       if (ch != '&') return -1;
+
+       b_getch(input);  /* get the & */
+       ch=b_peek(input);
+       if (ch == '-') {
+               b_getch(input);
+               return -3;  /* "-" represents "close me" */
+       }
+       while (isdigit(ch)) {
+               d = d*10+(ch-'0');
+               ok=1;
+               b_getch(input);
+               ch = b_peek(input);
+       }
+       if (ok) return d;
+
+       error_msg("ambiguous redirect");
+       return -2;
+}
+
+/* If a redirect is immediately preceded by a number, that number is
+ * supposed to tell which file descriptor to redirect.  This routine
+ * looks for such preceding numbers.  In an ideal world this routine
+ * needs to handle all the following classes of redirects...
+ *     echo 2>foo     # redirects fd  2 to file "foo", nothing passed to echo
+ *     echo 49>foo    # redirects fd 49 to file "foo", nothing passed to echo
+ *     echo -2>foo    # redirects fd  1 to file "foo",    "-2" passed to echo
+ *     echo 49x>foo   # redirects fd  1 to file "foo",   "49x" passed to echo
+ * A -1 output from this program means no valid number was found, so the
+ * caller should use the appropriate default for this redirection.
+ */
+static int redirect_opt_num(o_string *o)
+{
+       int num;
+
+       if (o->length==0) return -1;
+       for(num=0; num<o->length; num++) {
+               if (!isdigit(*(o->data+num))) {
+                       return -1;
+               }
+       }
+       /* reuse num (and save an int) */
+       num=atoi(o->data);
+       b_reset(o);
+       return num;
+}
+
+FILE *generate_stream_from_list(struct pipe *head)
+{
+       FILE *pf;
+#if 1
+       int pid, channel[2];
+       if (pipe(channel)<0) perror_msg_and_die("pipe");
+       pid=fork();
+       if (pid<0) {
+               perror_msg_and_die("fork");
+       } else if (pid==0) {
+               close(channel[0]);
+               if (channel[1] != 1) {
+                       dup2(channel[1],1);
+                       close(channel[1]);
+               }
+#if 0
+#define SURROGATE "surrogate response"
+               write(1,SURROGATE,sizeof(SURROGATE));
+               _exit(run_list(head));
+#else
+               _exit(run_list_real(head));   /* leaks memory */
+#endif
+       }
+       debug_printf("forked child %d\n",pid);
+       close(channel[1]);
+       pf = fdopen(channel[0],"r");
+       debug_printf("pipe on FILE *%p\n",pf);
+#else
+       free_pipe_list(head,0);
+       pf=popen("echo surrogate response","r");
+       debug_printf("started fake pipe on FILE *%p\n",pf);
+#endif
+       return pf;
+}
+
+/* this version hacked for testing purposes */
+/* return code is exit status of the process that is run. */
+static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end)
+{
+       int retcode;
+       o_string result=NULL_O_STRING;
+       struct p_context inner;
+       FILE *p;
+       struct in_str pipe_str;
+       initialize_context(&inner);
+
+       /* recursion to generate command */
+       retcode = parse_stream(&result, &inner, input, subst_end);
+       if (retcode != 0) return retcode;  /* syntax error or EOF */
+       done_word(&result, &inner);
+       done_pipe(&inner, PIPE_SEQ);
+       b_free(&result);
+
+       p=generate_stream_from_list(inner.list_head);
+       if (p==NULL) return 1;
+       mark_open(fileno(p));
+       setup_file_in_str(&pipe_str, p);
+
+       /* now send results of command back into original context */
+       retcode = parse_stream(dest, ctx, &pipe_str, '\0');
+       /* XXX In case of a syntax error, should we try to kill the child?
+        * That would be tough to do right, so just read until EOF. */
+       if (retcode == 1) {
+               while (b_getch(&pipe_str)!=EOF) { /* discard */ };
+       }
+
+       debug_printf("done reading from pipe, pclose()ing\n");
+       /* This is the step that wait()s for the child.  Should be pretty
+        * safe, since we just read an EOF from its stdout.  We could try
+        * to better, by using wait(), and keeping track of background jobs
+        * at the same time.  That would be a lot of work, and contrary
+        * to the KISS philosophy of this program. */
+       mark_closed(fileno(p));
+       retcode=pclose(p);
+       free_pipe_list(inner.list_head,0);
+       debug_printf("pclosed, retcode=%d\n",retcode);
+       /* XXX this process fails to trim a single trailing newline */
+       return retcode;
+}
+
+static int parse_group(o_string *dest, struct p_context *ctx,
+       struct in_str *input, int ch)
+{
+       int rcode, endch=0;
+       struct p_context sub;
+       struct child_prog *child = ctx->child;
+       if (child->argv) {
+               syntax();
+               return 1;  /* syntax error, groups and arglists don't mix */
+       }
+       initialize_context(&sub);
+       switch(ch) {
+               case '(': endch=')'; child->subshell=1; break;
+               case '{': endch='}'; break;
+               default: syntax();   /* really logic error */
+       }
+       rcode=parse_stream(dest,&sub,input,endch);
+       done_word(dest,&sub); /* finish off the final word in the subcontext */
+       done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
+       child->group = sub.list_head;
+       return rcode;
+       /* child remains "open", available for possible redirects */
+}
+
+/* basically useful version until someone wants to get fancier,
+ * see the bash man page under "Parameter Expansion" */
+static char *lookup_param(char *src)
+{
+       char *p=NULL;
+       if (src) { 
+               p = getenv(src);
+               if (!p) 
+                       p = get_local_var(src);
+       }
+       return p;
+}
+
+/* return code: 0 for OK, 1 for syntax error */
+static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
+{
+       int i, advance=0;
+       char sep[]=" ";
+       int ch = input->peek(input);  /* first character after the $ */
+       debug_printf("handle_dollar: ch=%c\n",ch);
+       if (isalpha(ch)) {
+               b_addchr(dest, SPECIAL_VAR_SYMBOL);
+               ctx->child->sp++;
+               while(ch=b_peek(input),isalnum(ch) || ch=='_') {
+                       b_getch(input);
+                       b_addchr(dest,ch);
+               }
+               b_addchr(dest, SPECIAL_VAR_SYMBOL);
+       } else if (isdigit(ch)) {
+               i = ch-'0';  /* XXX is $0 special? */
+               if (i<global_argc) {
+                       parse_string(dest, ctx, global_argv[i]); /* recursion */
+               }
+               advance = 1;
+       } else switch (ch) {
+               case '$':
+                       b_adduint(dest,getpid());
+                       advance = 1;
+                       break;
+               case '!':
+                       if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
+                       advance = 1;
+                       break;
+               case '?':
+                       b_adduint(dest,last_return_code);
+                       advance = 1;
+                       break;
+               case '#':
+                       b_adduint(dest,global_argc ? global_argc-1 : 0);
+                       advance = 1;
+                       break;
+               case '{':
+                       b_addchr(dest, SPECIAL_VAR_SYMBOL);
+                       ctx->child->sp++;
+                       b_getch(input);
+                       /* XXX maybe someone will try to escape the '}' */
+                       while(ch=b_getch(input),ch!=EOF && ch!='}') {
+                               b_addchr(dest,ch);
+                       }
+                       if (ch != '}') {
+                               syntax();
+                               return 1;
+                       }
+                       b_addchr(dest, SPECIAL_VAR_SYMBOL);
+                       break;
+               case '(':
+                       b_getch(input);
+                       process_command_subs(dest, ctx, input, ')');
+                       break;
+               case '*':
+                       sep[0]=ifs[0];
+                       for (i=1; i<global_argc; i++) {
+                               parse_string(dest, ctx, global_argv[i]);
+                               if (i+1 < global_argc) parse_string(dest, ctx, sep);
+                       }
+                       break;
+               case '@':
+               case '-':
+               case '_':
+                       /* still unhandled, but should be eventually */
+                       error_msg("unhandled syntax: $%c",ch);
+                       return 1;
+                       break;
+               default:
+                       b_addqchr(dest,'$',dest->quote);
+       }
+       /* Eat the character if the flag was set.  If the compiler
+        * is smart enough, we could substitute "b_getch(input);"
+        * for all the "advance = 1;" above, and also end up with
+        * a nice size-optimized program.  Hah!  That'll be the day.
+        */
+       if (advance) b_getch(input);
+       return 0;
+}
+
+int parse_string(o_string *dest, struct p_context *ctx, const char *src)
+{
+       struct in_str foo;
+       setup_string_in_str(&foo, src);
+       return parse_stream(dest, ctx, &foo, '\0');
+}
+
+/* return code is 0 for normal exit, 1 for syntax error */
+int parse_stream(o_string *dest, struct p_context *ctx,
+       struct in_str *input, int end_trigger)
+{
+       unsigned int ch, m;
+       int redir_fd;
+       redir_type redir_style;
+       int next;
+
+       /* Only double-quote state is handled in the state variable dest->quote.
+        * A single-quote triggers a bypass of the main loop until its mate is
+        * found.  When recursing, quote state is passed in via dest->quote. */
+
+       debug_printf("parse_stream, end_trigger=%d\n",end_trigger);
+       while ((ch=b_getch(input))!=EOF) {
+               m = map[ch];
+               next = (ch == '\n') ? 0 : b_peek(input);
+               debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
+                       ch,ch,m,dest->quote);
+               if (m==0 || ((m==1 || m==2) && dest->quote)) {
+                       b_addqchr(dest, ch, dest->quote);
+               } else {
+                       if (m==2) {  /* unquoted IFS */
+                               if (done_word(dest, ctx)) {
+                                       return 1;
+                               }       
+                               /* If we aren't performing a substitution, treat a newline as a
+                                * command separator.  */
+                               if (end_trigger != '\0' && ch=='\n')
+                                       done_pipe(ctx,PIPE_SEQ);
+                       }
+                       if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
+                               debug_printf("leaving parse_stream (triggered)\n");
+                               return 0;
+                       }
+#if 0
+                       if (ch=='\n') {
+                               /* Yahoo!  Time to run with it! */
+                               done_pipe(ctx,PIPE_SEQ);
+                               run_list(ctx->list_head);
+                               initialize_context(ctx);
+                       }
+#endif
+                       if (m!=2) switch (ch) {
+               case '#':
+                       if (dest->length == 0 && !dest->quote) {
+                               while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); }
+                       } else {
+                               b_addqchr(dest, ch, dest->quote);
+                       }
+                       break;
+               case '\\':
+                       if (next == EOF) {
+                               syntax();
+                               return 1;
+                       }
+                       b_addqchr(dest, '\\', dest->quote);
+                       b_addqchr(dest, b_getch(input), dest->quote);
+                       break;
+               case '$':
+                       if (handle_dollar(dest, ctx, input)!=0) return 1;
+                       break;
+               case '\'':
+                       dest->nonnull = 1;
+                       while(ch=b_getch(input),ch!=EOF && ch!='\'') {
+                               b_addchr(dest,ch);
+                       }
+                       if (ch==EOF) {
+                               syntax();
+                               return 1;
+                       }
+                       break;
+               case '"':
+                       dest->nonnull = 1;
+                       dest->quote = !dest->quote;
+                       break;
+               case '`':
+                       process_command_subs(dest, ctx, input, '`');
+                       break;
+               case '>':
+                       redir_fd = redirect_opt_num(dest);
+                       done_word(dest, ctx);
+                       redir_style=REDIRECT_OVERWRITE;
+                       if (next == '>') {
+                               redir_style=REDIRECT_APPEND;
+                               b_getch(input);
+                       } else if (next == '(') {
+                               syntax();   /* until we support >(list) Process Substitution */
+                               return 1;
+                       }
+                       setup_redirect(ctx, redir_fd, redir_style, input);
+                       break;
+               case '<':
+                       redir_fd = redirect_opt_num(dest);
+                       done_word(dest, ctx);
+                       redir_style=REDIRECT_INPUT;
+                       if (next == '<') {
+                               redir_style=REDIRECT_HEREIS;
+                               b_getch(input);
+                       } else if (next == '>') {
+                               redir_style=REDIRECT_IO;
+                               b_getch(input);
+                       } else if (next == '(') {
+                               syntax();   /* until we support <(list) Process Substitution */
+                               return 1;
+                       }
+                       setup_redirect(ctx, redir_fd, redir_style, input);
+                       break;
+               case ';':
+                       done_word(dest, ctx);
+                       done_pipe(ctx,PIPE_SEQ);
+                       break;
+               case '&':
+                       done_word(dest, ctx);
+                       if (next=='&') {
+                               b_getch(input);
+                               done_pipe(ctx,PIPE_AND);
+                       } else {
+                               done_pipe(ctx,PIPE_BG);
+                       }
+                       break;
+               case '|':
+                       done_word(dest, ctx);
+                       if (next=='|') {
+                               b_getch(input);
+                               done_pipe(ctx,PIPE_OR);
+                       } else {
+                               /* we could pick up a file descriptor choice here
+                                * with redirect_opt_num(), but bash doesn't do it.
+                                * "echo foo 2| cat" yields "foo 2". */
+                               done_command(ctx);
+                       }
+                       break;
+               case '(':
+               case '{':
+                       if (parse_group(dest, ctx, input, ch)!=0) return 1;
+                       break;
+               case ')':
+               case '}':
+                       syntax();   /* Proper use of this character caught by end_trigger */
+                       return 1;
+                       break;
+               default:
+                       syntax();   /* this is really an internal logic error */
+                       return 1;
+                       }
+               }
+       }
+       /* complain if quote?  No, maybe we just finished a command substitution
+        * that was quoted.  Example:
+        * $ echo "`cat foo` plus more" 
+        * and we just got the EOF generated by the subshell that ran "cat foo"
+        * The only real complaint is if we got an EOF when end_trigger != '\0',
+        * that is, we were really supposed to get end_trigger, and never got
+        * one before the EOF.  Can't use the standard "syntax error" return code,
+        * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
+       debug_printf("leaving parse_stream (EOF)\n");
+       if (end_trigger != '\0') return -1;
+       return 0;
+}
+
+void mapset(const unsigned char *set, int code)
+{
+       const unsigned char *s;
+       for (s=set; *s; s++) map[*s] = code;
+}
+
+void update_ifs_map(void)
+{
+       /* char *ifs and char map[256] are both globals. */
+       ifs = getenv("IFS");
+       if (ifs == NULL) ifs=" \t\n";
+       /* Precompute a list of 'flow through' behavior so it can be treated
+        * quickly up front.  Computation is necessary because of IFS.
+        * Special case handling of IFS == " \t\n" is not implemented.
+        * The map[] array only really needs two bits each, and on most machines
+        * that would be faster because of the reduced L1 cache footprint.
+        */
+       memset(map,0,sizeof(map)); /* most characters flow through always */
+       mapset("\\$'\"`", 3);      /* never flow through */
+       mapset("<>;&|(){}#", 1);   /* flow through if quoted */
+       mapset(ifs, 2);            /* also flow through if quoted */
+}
+
+/* most recursion does not come through here, the exeception is
+ * from builtin_source() */
+int parse_stream_outer(struct in_str *inp, int flag)
+{
+
+       struct p_context ctx;
+       o_string temp=NULL_O_STRING;
+       int rcode;
+       do {
+               ctx.type = flag;
+               initialize_context(&ctx);
+               update_ifs_map();
+               if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0);
+               inp->promptmode=1;
+               rcode = parse_stream(&temp, &ctx, inp, '\n');
+               if (rcode != 1 && ctx.old_flag != 0) {
+                       syntax();
+               }
+               if (rcode != 1 && ctx.old_flag == 0) {
+                       done_word(&temp, &ctx);
+                       done_pipe(&ctx,PIPE_SEQ);
+                       run_list(ctx.list_head);
+               } else {
+                       if (ctx.old_flag != 0) {
+                               free(ctx.stack);
+                               b_reset(&temp);
+                       }       
+                       temp.nonnull = 0;
+                       temp.quote = 0;
+                       inp->p = NULL;
+                       free_pipe_list(ctx.list_head,0);
+               }
+               b_free(&temp);
+       } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
+       return 0;
+}
+
+static int parse_string_outer(const char *s, int flag)
+{
+       struct in_str input;
+       setup_string_in_str(&input, s);
+       return parse_stream_outer(&input, flag);
+}
+
+static int parse_file_outer(FILE *f)
+{
+       int rcode;
+       struct in_str input;
+       setup_file_in_str(&input, f);
+       rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
+       return rcode;
+}
+
+/* Make sure we have a controlling tty.  If we get started under a job
+ * aware app (like bash for example), make sure we are now in charge so
+ * we don't fight over who gets the foreground */
+static void setup_job_control()
+{
+       static pid_t shell_pgrp;
+       /* Loop until we are in the foreground.  */
+       while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
+               kill (- shell_pgrp, SIGTTIN);
+
+       /* Ignore interactive and job-control signals.  */
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       signal(SIGTERM, SIG_IGN);
+       signal(SIGTSTP, SIG_IGN);
+       signal(SIGTTIN, SIG_IGN);
+       signal(SIGTTOU, SIG_IGN);
+       signal(SIGCHLD, SIG_IGN);
+
+       /* Put ourselves in our own process group.  */
+       setsid();
+       shell_pgrp = getpid ();
+       setpgid (shell_pgrp, shell_pgrp);
+
+       /* Grab control of the terminal.  */
+       tcsetpgrp(shell_terminal, shell_pgrp);
+}
+
+int hush_main(int argc, char **argv)
+{
+       int opt;
+       FILE *input;
+       char **e = environ;
+
+       /* XXX what should these be while sourcing /etc/profile? */
+       global_argc = argc;
+       global_argv = argv;
+       
+       /* (re?) initialize globals.  Sometimes hush_main() ends up calling
+        * hush_main(), therefore we cannot rely on the BSS to zero out this 
+        * stuff.  Reset these to 0 every time. */
+       ifs = NULL;
+       /* map[] is taken care of with call to update_ifs_map() */
+       fake_mode = 0;
+       interactive = 0;
+       close_me_head = NULL;
+       last_bg_pid = 0;
+       job_list = NULL;
+       last_jobid = 0;
+
+       /* Initialize some more globals to non-zero values */
+       set_cwd();
+#ifdef BB_FEATURE_COMMAND_EDITING
+       cmdedit_set_initial_prompt();
+#else
+       PS1 = NULL;
+#endif
+       PS2 = "> ";
+
+       /* initialize our shell local variables with the values 
+        * currently living in the environment */
+       if (e) {
+               for (; *e; e++)
+                       set_local_var(*e, 2);   /* without call putenv() */
+       }
+
+       last_return_code=EXIT_SUCCESS;
+
+
+       if (argv[0] && argv[0][0] == '-') {
+               debug_printf("\nsourcing /etc/profile\n");
+               if ((input = fopen("/etc/profile", "r")) != NULL) {
+                       mark_open(fileno(input));
+                       parse_file_outer(input);
+                       mark_closed(fileno(input));
+                       fclose(input);
+               }
+       }
+       input=stdin;
+       
+       while ((opt = getopt(argc, argv, "c:xif")) > 0) {
+               switch (opt) {
+                       case 'c':
+                               {
+                                       global_argv = argv+optind;
+                                       global_argc = argc-optind;
+                                       opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
+                                       goto final_return;
+                               }
+                               break;
+                       case 'i':
+                               interactive++;
+                               break;
+                       case 'f':
+                               fake_mode++;
+                               break;
+                       default:
+#ifndef BB_VER
+                               fprintf(stderr, "Usage: sh [FILE]...\n"
+                                               "   or: sh -c command [args]...\n\n");
+                               exit(EXIT_FAILURE);
+#else
+                               show_usage();
+#endif
+               }
+       }
+       /* A shell is interactive if the `-i' flag was given, or if all of
+        * the following conditions are met:
+        *        no -c command
+        *    no arguments remaining or the -s flag given
+        *    standard input is a terminal
+        *    standard output is a terminal
+        *    Refer to Posix.2, the description of the `sh' utility. */
+       if (argv[optind]==NULL && input==stdin &&
+                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
+               interactive++;
+       }
+
+       debug_printf("\ninteractive=%d\n", interactive);
+       if (interactive) {
+               /* Looks like they want an interactive shell */
+               fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
+               setup_job_control();
+       }
+       
+       if (argv[optind]==NULL) {
+               opt=parse_file_outer(stdin);
+               goto final_return;
+       }
+
+       debug_printf("\nrunning script '%s'\n", argv[optind]);
+       global_argv = argv+optind;
+       global_argc = argc-optind;
+       input = xfopen(argv[optind], "r");
+       opt = parse_file_outer(input);
+
+#ifdef BB_FEATURE_CLEAN_UP
+       fclose(input);
+       if (cwd && cwd != unknown)
+               free((char*)cwd);
+       {
+               struct variables *cur, *tmp;
+               for(cur = top_vars; cur; cur = tmp) {
+                       tmp = cur->next;
+                       if (!cur->flg_read_only) {
+                               free(cur->name);
+                               free(cur->value);
+                               free(cur);
+                       }
+               }
+       }
+#endif
+
+final_return:
+       return(opt?opt:last_return_code);
+}
+
+static char *insert_var_value(char *inp)
+{
+       int res_str_len = 0;
+       int len;
+       int done = 0;
+       char *p, *p1, *res_str = NULL;
+       
+       while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
+               if (p != inp) {
+                       len = p - inp;
+                       res_str = xrealloc(res_str, (res_str_len + len));
+                       strncpy((res_str + res_str_len), inp, len);
+                       res_str_len += len;
+               }
+               inp = ++p;
+               p = strchr(inp, SPECIAL_VAR_SYMBOL);
+               *p = '\0';
+               if ((p1 = lookup_param(inp))) {
+                       len = res_str_len + strlen(p1);
+                       res_str = xrealloc(res_str, (1 + len));
+                       strcpy((res_str + res_str_len), p1);
+                       res_str_len = len;
+               } 
+               *p = SPECIAL_VAR_SYMBOL;
+               inp = ++p;
+               done = 1;
+       }
+       if (done) {
+               res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
+               strcpy((res_str + res_str_len), inp);
+               while ((p = strchr(res_str, '\n'))) {
+                       *p = ' ';
+               }
+       }
+       return (res_str == NULL) ? inp : res_str;
+}
+
+static char **make_list_in(char **inp, char *name)
+{
+       int len, i;
+       int name_len = strlen(name);
+       int n = 0;
+       char **list;
+       char *p1, *p2, *p3;
+       
+       /* create list of variable values */    
+       list = xmalloc(sizeof(*list));
+       for (i = 0; inp[i]; i++) {
+               p3 = insert_var_value(inp[i]);
+               p1 = p3;
+               while (*p1) {
+                       if ((*p1 == ' ')) {
+                               p1++;
+                               continue;
+                       }
+                       if ((p2 = strchr(p1, ' '))) {
+                               len = p2 - p1;
+                       } else {        
+                               len = strlen(p1);
+                               p2 = p1 + len;
+                       }
+                       /* we use n + 2 in realloc for list,because we add 
+                        * new element and then we will add NULL element */
+                       list = xrealloc(list, sizeof(*list) * (n + 2));                 
+                       list[n] = xmalloc(2 + name_len + len);
+                       strcpy(list[n], name);
+                       strcat(list[n], "=");
+                       strncat(list[n], p1, len);
+                       list[n++][name_len + len + 1] = '\0';
+                       p1 = p2;
+               }
+               if (p3 != inp[i]) free(p3);
+       }
+       list[n] = NULL;
+       return list;
+}      
+
+/* Make new string for parser */
+static char * make_string(char ** inp)
+{
+       char *p;
+       char *str = NULL;
+       int n;
+       int len = 2;
+
+       for (n = 0; inp[n]; n++) {
+               p = insert_var_value(inp[n]);
+               str = xrealloc(str, (len + strlen(p)));
+               if (n) {
+                       strcat(str, " ");
+               } else {
+                       *str = '\0';
+               }
+               strcat(str, p);
+               len = strlen(str) + 3;
+               if (p != inp[n]) free(p);
+       }
+       len = strlen(str);
+       *(str + len) = '\n';
+       *(str + len + 1) = '\0';
+       return str;
+}
diff --git a/id.c b/id.c
new file mode 100644 (file)
index 0000000..85b288c
--- /dev/null
+++ b/id.c
@@ -0,0 +1,97 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini id implementation for busybox
+ *
+ * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <sys/types.h>
+
+extern int id_main(int argc, char **argv)
+{
+       int no_user = 0, no_group = 0, print_real = 0;
+       int name_not_number = 0;
+       char user[9], group[9];
+       long gid;
+       long pwnam, grnam;
+       int opt;
+       
+       gid = 0;
+
+       while ((opt = getopt(argc, argv, "ugrn")) > 0) {
+               switch (opt) {
+                       case 'u':
+                               no_group++;
+                               break;
+                       case 'g':
+                               no_user++;
+                               break;
+                       case 'r':
+                               print_real++;
+                               break;
+                       case 'n':
+                               name_not_number++;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (no_user && no_group) show_usage();
+
+       if (argv[optind] == NULL) {
+               if (print_real) {
+                       my_getpwuid(user, getuid());
+                       my_getgrgid(group, getgid());
+               } else {
+                       my_getpwuid(user, geteuid());
+                       my_getgrgid(group, getegid());
+               }
+       } else {
+               strncpy(user, argv[optind], 8);
+               user[8] = '\0';
+           gid = my_getpwnamegid(user);
+               my_getgrgid(group, gid);
+       }
+
+       pwnam=my_getpwnam(user);
+       grnam=my_getgrnam(group);
+
+       if (no_group) {
+               if(name_not_number && user)
+                       puts(user);
+               else
+                       printf("%ld\n", pwnam);
+       } else if (no_user) {
+               if(name_not_number && group)
+                       puts(group);
+               else
+                       printf("%ld\n", grnam);
+       } else {
+               printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group);
+       }
+       return(0);
+}
+
+
+/* END CODE */
diff --git a/ifconfig.c b/ifconfig.c
new file mode 100644 (file)
index 0000000..1986ada
--- /dev/null
@@ -0,0 +1,493 @@
+/* ifconfig
+ *
+ * Similar to the standard Unix ifconfig, but with only the necessary
+ * parts for AF_INET, and without any printing of if info (for now).
+ *
+ * Bjorn Wesen, Axis Communications AB
+ *
+ *
+ * Authors of the original ifconfig was:      
+ *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * This program is free software; you can redistribute it
+ * and/or  modify it under  the terms of  the GNU General
+ * Public  License as  published  by  the  Free  Software
+ * Foundation;  either  version 2 of the License, or  (at
+ * your option) any later version.
+ *
+ * $Id: ifconfig.c,v 1.16 2003/11/14 03:04:56 andersen Exp $
+ *
+ */
+
+/*
+ * Heavily modified by Manuel Novoa III       Mar 6, 2001
+ *
+ * From initial port to busybox, removed most of the redundancy by
+ * converting to a table-driven approach.  Added several (optional)
+ * args missing from initial port.
+ *
+ * Still missing:  media, tunnel.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>   // strcmp and friends
+#include <ctype.h>    // isdigit and friends
+#include <stddef.h>                            /* offsetof */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+#include "busybox.h"
+
+#ifdef BB_FEATURE_IFCONFIG_SLIP
+#include <linux/if_slip.h>
+#endif
+
+/* I don't know if this is needed for busybox or not.  Anyone? */
+#define QUESTIONABLE_ALIAS_CASE
+
+
+/* Defines for glibc2.0 users. */
+#ifndef SIOCSIFTXQLEN
+#define SIOCSIFTXQLEN      0x8943
+#define SIOCGIFTXQLEN      0x8942
+#endif
+
+/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
+#ifndef ifr_qlen
+#define ifr_qlen        ifr_ifru.ifru_mtu
+#endif
+
+#ifndef IFF_DYNAMIC
+#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
+#endif
+
+/*
+ * Here are the bit masks for the "flags" member of struct options below.
+ * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
+ * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
+ */
+#define N_CLR            0x01
+#define M_CLR            0x02
+#define N_SET            0x04
+#define M_SET            0x08
+#define N_ARG            0x10
+#define M_ARG            0x20
+
+#define M_MASK           (M_CLR | M_SET | M_ARG)
+#define N_MASK           (N_CLR | N_SET | N_ARG)
+#define SET_MASK         (N_SET | M_SET)
+#define CLR_MASK         (N_CLR | M_CLR)
+#define SET_CLR_MASK     (SET_MASK | CLR_MASK)
+#define ARG_MASK         (M_ARG | N_ARG)
+
+/*
+ * Here are the bit masks for the "arg_flags" member of struct options below.
+ */
+
+/*
+ * cast type:
+ *   00 int
+ *   01 char *
+ *   02 HOST_COPY in_ether
+ *   03 HOST_COPY INET_resolve
+ */
+#define A_CAST_TYPE      0x03
+/*
+ * map type:
+ *   00 not a map type (mem_start, io_addr, irq)
+ *   04 memstart (unsigned long)
+ *   08 io_addr  (unsigned short)
+ *   0C irq      (unsigned char)
+ */
+#define A_MAP_TYPE       0x0C
+#define A_ARG_REQ        0x10  /* Set if an arg is required. */
+#define A_NETMASK        0x20  /* Set if netmask (check for multiple sets). */
+#define A_SET_AFTER      0x40  /* Set a flag at the end. */
+#define A_COLON_CHK      0x80  /* Is this needed?  See below. */
+
+/*
+ * These defines are for dealing with the A_CAST_TYPE field.
+ */
+#define A_CAST_CHAR_PTR  0x01
+#define A_CAST_RESOLVE   0x01
+#define A_CAST_HOST_COPY 0x02
+#define A_CAST_HOST_COPY_IN_ETHER    A_CAST_HOST_COPY
+#define A_CAST_HOST_COPY_RESOLVE     (A_CAST_HOST_COPY | A_CAST_RESOLVE)
+
+/*
+ * These defines are for dealing with the A_MAP_TYPE field.
+ */
+#define A_MAP_ULONG      0x04  /* memstart */
+#define A_MAP_USHORT     0x08  /* io_addr */
+#define A_MAP_UCHAR      0x0C  /* irq */
+
+/*
+ * Define the bit masks signifying which operations to perform for each arg.
+ */
+
+#define ARG_METRIC       (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_MTU          (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_TXQUEUELEN   (A_ARG_REQ /*| A_CAST_INT*/)
+#define ARG_MEM_START    (A_ARG_REQ | A_MAP_ULONG)
+#define ARG_IO_ADDR      (A_ARG_REQ | A_MAP_ULONG)
+#define ARG_IRQ          (A_ARG_REQ | A_MAP_UCHAR)
+#define ARG_DSTADDR      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
+#define ARG_NETMASK      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
+#define ARG_BROADCAST    (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
+#define ARG_HW           (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
+#define ARG_POINTOPOINT  (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
+#define ARG_KEEPALIVE    (A_ARG_REQ | A_CAST_CHAR_PTR)
+#define ARG_OUTFILL      (A_ARG_REQ | A_CAST_CHAR_PTR)
+#define ARG_HOSTNAME     (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
+
+
+/*
+ * Set up the tables.  Warning!  They must have corresponding order!
+ */
+
+struct arg1opt {
+       const char *name;
+       unsigned short selector;
+       unsigned short ifr_offset;
+};
+
+struct options {
+       const char *name;
+       const unsigned char flags;
+       const unsigned char arg_flags;
+       const unsigned short selector;
+};
+
+#define ifreq_offsetof(x)  offsetof(struct ifreq, x)
+
+static const struct arg1opt Arg1Opt[] = {
+       {"SIOCSIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric)},
+       {"SIOCSIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu)},
+       {"SIOCSIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen)},
+       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
+       {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
+       {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
+#ifdef BB_FEATURE_IFCONFIG_HW
+       {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
+#endif
+       {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
+#ifdef SIOCSKEEPALIVE
+       {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
+#endif
+#ifdef SIOCSOUTFILL
+       {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
+#endif
+#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
+       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
+       {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)},
+#endif
+       /* Last entry if for unmatched (possibly hostname) arg. */
+       {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)},
+};
+
+static const struct options OptArray[] = {
+       {"metric",       N_ARG,         ARG_METRIC,      0},
+    {"mtu",          N_ARG,         ARG_MTU,         0},
+       {"txqueuelen",   N_ARG,         ARG_TXQUEUELEN,  0},
+       {"dstaddr",      N_ARG,         ARG_DSTADDR,     0},
+       {"netmask",      N_ARG,         ARG_NETMASK,     0},
+       {"broadcast",    N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
+#ifdef BB_FEATURE_IFCONFIG_HW
+       {"hw",           N_ARG,         ARG_HW,          0},
+#endif
+       {"pointopoint",  N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
+#ifdef SIOCSKEEPALIVE
+       {"keepalive",    N_ARG,         ARG_KEEPALIVE,   0},
+#endif
+#ifdef SIOCSOUTFILL
+       {"outfill",      N_ARG,         ARG_OUTFILL,     0},
+#endif
+#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+       {"mem_start",    N_ARG,         ARG_MEM_START,   0},
+       {"io_addr",      N_ARG,         ARG_IO_ADDR,     0},
+       {"irq",          N_ARG,         ARG_IRQ,         0},
+#endif
+       {"arp",          N_CLR | M_SET, 0,               IFF_NOARP},
+       {"trailers",     N_CLR | M_SET, 0,               IFF_NOTRAILERS},
+       {"promisc",      N_SET | M_CLR, 0,               IFF_PROMISC},
+       {"multicast",    N_SET | M_CLR, 0,               IFF_MULTICAST},
+       {"allmulti",     N_SET | M_CLR, 0,               IFF_ALLMULTI},
+       {"dynamic",      N_SET | M_CLR, 0,               IFF_DYNAMIC},
+       {"up",           N_SET        , 0,               (IFF_UP | IFF_RUNNING)},
+       {"down",         N_CLR        , 0,               IFF_UP},
+       { NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING)}
+};
+
+/*
+ * A couple of prototypes.
+ */
+
+#ifdef BB_FEATURE_IFCONFIG_HW
+static int in_ether(char *bufp, struct sockaddr *sap);
+#endif
+
+#ifdef BB_FEATURE_IFCONFIG_STATUS
+extern int interface_opt_a;
+extern int display_interfaces(char *ifname);
+#endif
+
+/*
+ * Our main function.
+ */
+
+int ifconfig_main(int argc, char **argv)
+{
+       struct ifreq ifr;
+       struct sockaddr_in sai;
+#ifdef BB_FEATURE_IFCONFIG_HW
+       struct sockaddr sa;
+#endif
+       const struct arg1opt *a1op;
+       const struct options *op;
+       int sockfd;  /* socket fd we use to manipulate stuff with */
+       int goterr;
+       int selector;
+       char *p;
+       char host[128];
+       unsigned char mask;
+       unsigned char did_flags;
+
+       goterr = 0;
+       did_flags = 0;
+
+       /* skip argv[0] */
+       ++argv;
+       --argc;
+
+#ifdef BB_FEATURE_IFCONFIG_STATUS
+       if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
+               interface_opt_a = 1;
+               --argc;
+               ++argv;
+       }
+#endif
+
+       if(argc <= 1) {
+#ifdef BB_FEATURE_IFCONFIG_STATUS
+               return display_interfaces(argc ? *argv : NULL);
+#else
+               error_msg_and_die( "ifconfig was not compiled with interface status display support.");
+#endif
+       }
+
+       /* Create a channel to the NET kernel. */
+       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror_msg_and_die("socket");
+       }
+
+       /* get interface name */
+       safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
+
+       /* Process the remaining arguments. */
+       while (*++argv != (char *) NULL) {
+               p = *argv;
+               mask = N_MASK;
+               if (*p == '-') {                /* If the arg starts with '-'... */
+                       ++p;                            /*    advance past it and */
+                       mask = M_MASK;          /*    set the appropriate mask. */
+               }
+               for (op = OptArray ; op->name ; op++) { /* Find table entry. */
+                       if (strcmp(p,op->name) == 0) { /* If name matches... */
+                               if ((mask &= op->flags)) { /* set the mask and go. */
+                                   goto FOUND_ARG;;
+                               }
+                               /* If we get here, there was a valid arg with an */
+                               /* invalid '-' prefix. */
+                               ++goterr;
+                               goto LOOP;
+                       }
+               }
+               
+               /* We fell through, so treat as possible hostname. */
+               a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
+               mask = op->arg_flags;
+               goto HOSTNAME;
+
+       FOUND_ARG:
+               if (mask & ARG_MASK) {
+                       mask = op->arg_flags;
+                       a1op = Arg1Opt + (op - OptArray);
+                       if (mask & A_NETMASK & did_flags) {
+                               show_usage();
+                       }
+                       if (*++argv == NULL) {
+                               if (mask & A_ARG_REQ) {
+                                       show_usage();
+                               } else {
+                                       --argv;
+                                       mask &= A_SET_AFTER; /* just for broadcast */
+                               }
+                       } else {                        /* got an arg so process it */
+                       HOSTNAME:
+                               did_flags |= (mask & A_NETMASK);
+                               if (mask & A_CAST_HOST_COPY) {
+#ifdef BB_FEATURE_IFCONFIG_HW
+                                       if (mask & A_CAST_RESOLVE) {
+#endif
+                                               safe_strncpy(host, *argv, (sizeof host));
+                                               sai.sin_family = AF_INET;
+                                               sai.sin_port = 0;
+                                               if (!strcmp(host, "default")) {
+                                                       /* Default is special, meaning 0.0.0.0. */
+                                                       sai.sin_addr.s_addr = INADDR_ANY;
+                                               } else if (inet_aton(host, &sai.sin_addr) == 0) {
+                                                       /* It's not a dotted quad. */
+                                                       ++goterr;
+                                                       continue;
+                                               }
+                                               p = (char *) &sai;
+#ifdef BB_FEATURE_IFCONFIG_HW
+                                       } else { /* A_CAST_HOST_COPY_IN_ETHER */
+                                               /* This is the "hw" arg case. */
+                                               if (strcmp("ether", *argv) || (*++argv == NULL)) {
+                                                       show_usage();
+                                               }
+                                               safe_strncpy(host, *argv, (sizeof host));
+                                               if (in_ether(host, &sa)) {
+                                                       fprintf(stderr, "invalid hw-addr %s\n", host);
+                                                       ++goterr;
+                                                       continue;
+                                               }
+                                               p = (char *) &sa;
+                                       }
+#endif
+                                       memcpy((((char *)(&ifr)) + a1op->ifr_offset),
+                                                  p, sizeof(struct sockaddr));
+                               } else {
+                                       unsigned int i = strtoul(*argv,NULL,0);
+                                       p = ((char *)(&ifr)) + a1op->ifr_offset;
+#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+                                       if (mask & A_MAP_TYPE) {
+                                               if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
+                                                       ++goterr;
+                                                       continue;
+                                               }
+                                               if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
+                                                       *((unsigned char *) p) = i;
+                                               } else if (mask & A_MAP_USHORT) {
+                                                       *((unsigned short *) p) = i;
+                                               } else {
+                                                       *((unsigned long *) p) = i;
+                                               }
+                                       } else
+#endif
+                                       if (mask & A_CAST_CHAR_PTR) {
+                                               *((caddr_t *) p) = (caddr_t) i;
+                                       } else { /* A_CAST_INT */
+                                               *((int *) p) = i;
+                                       }
+                               }
+                                               
+                               if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
+                                       perror(a1op->name);
+                                       ++goterr;
+                                       continue;
+                               }
+
+#ifdef QUESTIONABLE_ALIAS_CASE
+                               if (mask & A_COLON_CHK) {
+                                       /*
+                                        * Don't do the set_flag() if the address is an alias with
+                                        * a - at the end, since it's deleted already! - Roman
+                                        *
+                                        * Should really use regex.h here, not sure though how well
+                                        * it'll go with the cross-platform support etc. 
+                                        */
+                                       char *ptr;
+                                       short int found_colon = 0;
+                                       for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
+                                               if (*ptr == ':') {
+                                                       found_colon++;
+                                               }
+                                       }
+                       
+                                       if (found_colon && *(ptr - 1) == '-') {
+                                               continue;
+                                       }
+                               }
+#endif
+                       }
+                       if (!(mask & A_SET_AFTER)) {
+                               continue;
+                       }
+                       mask = N_SET;
+               }
+
+               if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+                       perror("SIOCGIFFLAGS"); 
+                       ++goterr;
+               } else {
+                       selector = op->selector;
+                       if (mask & SET_MASK) {
+                               ifr.ifr_flags |= selector;
+                       } else {
+                               ifr.ifr_flags &= ~selector;
+                       }
+                       if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+                               perror("SIOCSIFFLAGS"); 
+                               ++goterr;
+                       }
+               }
+       LOOP:
+               continue;
+       } /* end of while-loop */
+
+       return goterr;
+}
+
+#ifdef BB_FEATURE_IFCONFIG_HW
+/* Input an Ethernet address and convert to binary. */
+static int
+in_ether(char *bufp, struct sockaddr *sap)
+{
+       unsigned char *ptr;
+       int i, j;
+       unsigned char val;
+       unsigned char c;
+       
+       sap->sa_family = ARPHRD_ETHER;
+       ptr = sap->sa_data;
+       
+       for (i = 0 ; i < ETH_ALEN ; i++) {
+               val = 0;
+
+               /* We might get a semicolon here - not required. */
+               if (i && (*bufp == ':')) {
+                       bufp++;
+               }
+
+               for (j=0 ; j<2 ; j++) {
+                       c = *bufp;
+                       if (c >= '0' && c <= '9') {
+                               c -= '0';
+                       } else if (c >= 'a' && c <= 'f') {
+                               c -= ('a' - 10);
+                       } else if (c >= 'A' && c <= 'F') {
+                               c -= ('A' - 10);
+                       } else if (j && (c == ':' || c == 0)) {
+                               break;
+                       } else {
+                               return -1;
+                       }
+                       ++bufp;
+                       val <<= 4;
+                       val += c;
+               }
+               *ptr++ = val;
+       }
+
+       return (int) (*bufp);           /* Error if we don't end at end of string. */
+}
+#endif
diff --git a/init.c b/init.c
new file mode 100644 (file)
index 0000000..7e4145a
--- /dev/null
+++ b/init.c
@@ -0,0 +1,1206 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini init implementation for busybox
+ *
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
+ * Adjusted by so many folks, it's impossible to keep track.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Turn this on to disable all the dangerous 
+   rebooting stuff when debugging.
+#define DEBUG_INIT
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "busybox.h"
+#ifdef BB_SYSLOGD
+# include <sys/syslog.h>
+#endif
+#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
+#include <sys/reboot.h>
+#endif
+
+
+#define INIT_BUFFS_SIZE 256
+
+/* From <linux/vt.h> */
+struct vt_stat {
+       unsigned short v_active;        /* active vt */
+       unsigned short v_signal;        /* signal to send */
+       unsigned short v_state;         /* vt bitmask */
+};
+static const int VT_GETSTATE = 0x5603;  /* get global vt state info */
+
+/* From <linux/serial.h> */
+struct serial_struct {
+       int     type;
+       int     line;
+       unsigned int    port;
+       int     irq;
+       int     flags;
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     baud_base;
+       unsigned short  close_delay;
+       char    io_type;
+       char    reserved_char[1];
+       int     hub6;
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+       unsigned char   *iomem_base;
+       unsigned short  iomem_reg_shift;
+       unsigned int    port_high;
+       unsigned long   iomap_base;     /* cookie passed into ioremap */
+       int     reserved[1];
+};
+
+
+#ifndef _PATH_STDPATH
+#define _PATH_STDPATH  "/usr/bin:/bin:/usr/sbin:/sbin"
+#endif
+
+#if defined BB_FEATURE_INIT_COREDUMPS
+/*
+ * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called 
+ * before processes are spawned to set core file size as unlimited.
+ * This is for debugging only.  Don't use this is production, unless
+ * you want core dumps lying about....
+ */
+#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
+#include <sys/resource.h>
+#include <sys/time.h>
+#endif
+
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+#if __GNU_LIBRARY__ > 5
+       #include <sys/kdaemon.h>
+#else
+       extern int bdflush (int func, long int data);
+#endif
+
+#define SHELL        "/bin/sh"      /* Default shell */
+#define LOGIN_SHELL  "-" SHELL      /* Default login shell */
+#define INITTAB      "/etc/inittab"  /* inittab file location */
+#ifndef INIT_SCRIPT
+#define INIT_SCRIPT  "/etc/init.d/rcS"   /* Default sysinit script. */
+#endif
+
+#define MAXENV 16              /* Number of env. vars */
+
+/* Allowed init action types */
+#define SYSINIT     0x001
+#define RESPAWN     0x002
+#define ASKFIRST    0x004
+#define WAIT        0x008
+#define ONCE        0x010
+#define CTRLALTDEL  0x020
+#define SHUTDOWN    0x040
+#define RESTART     0x080
+
+/* A mapping between "inittab" action name strings and action type codes. */
+struct init_action_type {
+       const char *name;
+       int action;
+};
+
+static const struct init_action_type actions[] = {
+       {"sysinit", SYSINIT},
+       {"respawn", RESPAWN},
+       {"askfirst", ASKFIRST},
+       {"wait", WAIT},
+       {"once", ONCE},
+       {"ctrlaltdel", CTRLALTDEL},
+       {"shutdown", SHUTDOWN},
+       {"restart", RESTART},
+       {0, 0}
+};
+
+/* Set up a linked list of init_actions, to be read from inittab */
+struct init_action {
+       pid_t pid;
+       char command[INIT_BUFFS_SIZE];
+       char terminal[INIT_BUFFS_SIZE];
+       struct init_action *next;
+       int action;
+};
+
+/* Static variables */
+static struct init_action *init_action_list = NULL;
+static int  kernelVersion  = 0;
+static char termType[32]   = "TERM=linux";
+static char console[32]    = _PATH_CONSOLE;
+#ifndef BB_SYSLOGD
+static char *log           = VC_5;
+#endif
+static sig_atomic_t got_cont = 0;
+static const int LOG = 0x1;
+static const int CONSOLE = 0x2;
+#if defined BB_FEATURE_EXTRA_QUIET
+static const int MAYBE_CONSOLE = 0x0;
+#else
+#define MAYBE_CONSOLE  CONSOLE
+#endif
+#ifndef RB_HALT_SYSTEM
+static const int RB_HALT_SYSTEM = 0xcdef0123;
+static const int RB_ENABLE_CAD = 0x89abcdef;
+static const int RB_DISABLE_CAD = 0;
+#define RB_POWER_OFF    0x4321fedc
+static const int RB_AUTOBOOT = 0x01234567;
+#endif
+
+/* Function prototypes */
+static void delete_init_action(struct init_action *a);
+static int waitfor(struct init_action *a);
+static void halt_signal(int sig);
+
+
+static void loop_forever(void)
+{
+       while (1)
+               sleep (1);
+}
+
+/* Print a message to the specified device.
+ * Device may be bitwise-or'd from LOG | CONSOLE */
+#ifdef DEBUG_INIT
+static inline messageND(int device, char *fmt, ...) { }
+#else 
+#define messageND message
+#endif
+static void message(int device, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+static void message(int device, char *fmt, ...)
+{
+       va_list arguments;
+       int fd;
+
+#ifdef BB_SYSLOGD
+
+       /* Log the message to syslogd */
+       if (device & LOG) {
+               char msg[1024];
+
+               va_start(arguments, fmt);
+               vsnprintf(msg, sizeof(msg), fmt, arguments);
+               va_end(arguments);
+               syslog_msg(LOG_USER, LOG_INFO, msg);
+       }
+#else
+       static int log_fd = -1;
+
+       /* Take full control of the log tty, and never close it.
+        * It's mine, all mine!  Muhahahaha! */
+       if (log_fd < 0) {
+               if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
+                       log_fd = -2;
+                       fprintf(stderr, "Bummer, can't write to log on %s!\n", log);
+                       device = CONSOLE;
+               } else {
+                       fcntl(log_fd, F_SETFD, FD_CLOEXEC);
+               }
+       }
+       if ((device & LOG) && (log_fd >= 0)) {
+               va_start(arguments, fmt);
+               vdprintf(log_fd, fmt, arguments);
+               va_end(arguments);
+       }
+#endif
+
+       if (device & CONSOLE) {
+               /* Always send console messages to /dev/console so people will see them. */
+               if (
+                       (fd =
+                        device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {
+                       va_start(arguments, fmt);
+                       vdprintf(fd, fmt, arguments);
+                       va_end(arguments);
+                       close(fd);
+               } else {
+                       fprintf(stderr, "Bummer, can't print: ");
+                       va_start(arguments, fmt);
+                       vfprintf(stderr, fmt, arguments);
+                       va_end(arguments);
+               }
+       }
+}
+
+/* Set terminal settings to reasonable defaults */
+static void set_term(int fd)
+{
+       struct termios tty;
+
+       tcgetattr(fd, &tty);
+
+       /* set control chars */
+       tty.c_cc[VINTR]  = 3;   /* C-c */
+       tty.c_cc[VQUIT]  = 28;  /* C-\ */
+       tty.c_cc[VERASE] = 127; /* C-? */
+       tty.c_cc[VKILL]  = 21;  /* C-u */
+       tty.c_cc[VEOF]   = 4;   /* C-d */
+       tty.c_cc[VSTART] = 17;  /* C-q */
+       tty.c_cc[VSTOP]  = 19;  /* C-s */
+       tty.c_cc[VSUSP]  = 26;  /* C-z */
+
+       /* use line dicipline 0 */
+       tty.c_line = 0;
+
+       /* Make it be sane */
+       tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+       tty.c_cflag |= CREAD|HUPCL|CLOCAL;
+
+
+       /* input modes */
+       tty.c_iflag = ICRNL | IXON | IXOFF;
+
+       /* output modes */
+       tty.c_oflag = OPOST | ONLCR;
+
+       /* local modes */
+       tty.c_lflag =
+               ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+
+       tcsetattr(fd, TCSANOW, &tty);
+}
+
+/* How much memory does this machine have?
+   Units are kBytes to avoid overflow on 4GB machines */
+static int check_free_memory(void)
+{
+       struct sysinfo info;
+       unsigned int result, u, s=10;
+
+       if (sysinfo(&info) != 0) {
+               perror_msg("Error checking free memory");
+               return -1;
+       }
+
+       /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes.
+        * Kernels 2.4.0 return info.mem_unit in bytes. */
+       u = info.mem_unit;
+       if (u==0) u=1;
+       while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; }
+       result = (info.totalram>>s) + (info.totalswap>>s);
+       result = result*u;
+       if (result < 0) result = INT_MAX;
+       return result;
+}
+
+static void console_init(void)
+{
+       int fd;
+       int tried_devcons = 0;
+       int tried_vtprimary = 0;
+       struct vt_stat vt;
+       struct serial_struct sr;
+       char *s;
+
+       if ((s = getenv("TERM")) != NULL) {
+               snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);
+       }
+
+       if ((s = getenv("CONSOLE")) != NULL) {
+               safe_strncpy(console, s, sizeof(console));
+       }
+#if #cpu(sparc)
+       /* sparc kernel supports console=tty[ab] parameter which is also 
+        * passed to init, so catch it here */
+       else if ((s = getenv("console")) != NULL) {
+               /* remap tty[ab] to /dev/ttyS[01] */
+               if (strcmp(s, "ttya") == 0)
+                       safe_strncpy(console, SC_0, sizeof(console));
+               else if (strcmp(s, "ttyb") == 0)
+                       safe_strncpy(console, SC_1, sizeof(console));
+       }
+#endif
+       else {
+               /* 2.2 kernels: identify the real console backend and try to use it */
+               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
+                       /* this is a serial console */
+                       snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line);
+               } else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
+                       /* this is linux virtual tty */
+                       snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);
+               } else {
+                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
+                       tried_devcons++;
+               }
+       }
+
+       while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
+               /* Can't open selected console -- try /dev/console */
+               if (!tried_devcons) {
+                       tried_devcons++;
+                       safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
+                       continue;
+               }
+               /* Can't open selected console -- try vt1 */
+               if (!tried_vtprimary) {
+                       tried_vtprimary++;
+                       safe_strncpy(console, VC_1, sizeof(console));
+                       continue;
+               }
+               break;
+       }
+       if (fd < 0) {
+               /* Perhaps we should panic here? */
+               safe_strncpy(console, "/dev/null", sizeof(console));
+       } else {
+               /* check for serial console */
+               if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
+                       /* Force the TERM setting to vt102 for serial console --
+                        * if TERM is set to linux (the default) */
+                       if (strcmp( termType, "TERM=linux" ) == 0)
+                               safe_strncpy(termType, "TERM=vt102", sizeof(termType));
+               }
+               close(fd);
+       }
+       message(LOG, "console=%s\n", console);
+}
+       
+static void fixup_argv(int argc, char **argv, char *new_argv0)
+{
+       int len;
+       /* Fix up argv[0] to be certain we claim to be init */
+       len = strlen(argv[0]);
+       memset(argv[0], 0, len);
+       safe_strncpy(argv[0], new_argv0, len + 1);
+
+       /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
+       len = 1;
+       while (argc > len) {
+               memset(argv[len], 0, strlen(argv[len]));
+               len++;
+       }
+}
+
+/* Make sure there is enough memory to do something useful. *
+ * Calls "swapon -a" if needed so be sure /etc/fstab is present... */
+static void check_memory(void)
+{
+#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
+       struct stat statBuf;
+#endif
+
+       if (check_free_memory() > 1000)
+               return;
+
+#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
+       if (stat("/etc/fstab", &statBuf) == 0) {
+               /* swapon -a requires /proc typically */
+               system("/bin/mount -t proc proc /proc");
+               /* Try to turn on swap */
+               system("/sbin/swapon -a");
+               if (check_free_memory() < 1000)
+                       goto goodnight;
+       } else
+               goto goodnight;
+       return;
+  goodnight:
+#endif
+       message(CONSOLE,
+                       "\rSorry, your computer does not have enough memory.\n");
+       loop_forever();
+}
+
+static pid_t run(struct init_action *a)
+{
+       struct stat sb;
+       int i, j, junk;
+       pid_t pid, pgrp, tmp_pid;
+       char *s, *tmpCmd, *cmd[INIT_BUFFS_SIZE], *cmdpath;
+       char buf[INIT_BUFFS_SIZE+6];    /* INIT_BUFFS_SIZE+strlen("exec ")+1 */
+       sigset_t nmask, omask;
+       char *environment[MAXENV+1] = {
+               termType,
+               "HOME=/",
+               "PATH=" _PATH_STDPATH,
+               "SHELL=" SHELL,
+               "USER=root",
+               NULL
+       };
+       static const char press_enter[] =
+#ifdef CUSTOMIZED_BANNER
+#include CUSTOMIZED_BANNER
+#endif
+               "\nPlease press Enter to activate this console. ";
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &tmp_pid;
+#endif
+
+       /* inherit environment to the child, merging our values -andy */
+       for (i=0; environ[i]; i++) {
+               for (j=0; environment[j]; j++) {
+                       s = strchr(environment[j], '=');
+                       if (!strncmp(environ[i], environment[j], s - environment[j]))
+                               break;
+               }
+               if (!environment[j]) {
+                       environment[j++] = environ[i];
+                       environment[j] = NULL;
+               }
+       }
+
+       /* Block sigchild while forking.  */
+       sigemptyset(&nmask);
+       sigaddset(&nmask, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &nmask, &omask);
+
+       if ((pid = fork()) == 0) 
+       {
+               /* Clean up */
+               close(0);
+               close(1);
+               close(2);
+               sigprocmask(SIG_SETMASK, &omask, NULL);
+
+               /* Reset signal handlers that were set by the parent process */
+               signal(SIGUSR1, SIG_DFL);
+               signal(SIGUSR2, SIG_DFL);
+               signal(SIGINT,  SIG_DFL);
+               signal(SIGTERM, SIG_DFL);
+               signal(SIGHUP,  SIG_DFL);
+               signal(SIGCONT, SIG_DFL);
+               signal(SIGSTOP, SIG_DFL);
+               signal(SIGTSTP, SIG_DFL);
+
+               /* Create a new session and make ourself the process
+                * group leader */
+               setsid();
+
+               /* Open the new terminal device */
+               if ((device_open(a->terminal, O_RDWR)) < 0) {
+                       if (stat(a->terminal, &sb) != 0) {
+                               message(LOG | CONSOLE, "\rdevice '%s' does not exist.\n",
+                                               a->terminal);
+                               _exit(1);
+                       }
+                       message(LOG | CONSOLE, "\rBummer, can't open %s\n", a->terminal);
+                       _exit(1);
+               }
+
+               /* Make sure the terminal will act fairly normal for us */
+               set_term(0);
+               /* Setup stdout, stderr for the new process so
+                * they point to the supplied terminal */
+               dup(0);
+               dup(0);
+
+               /* If the init Action requires us to wait, then force the
+                * supplied terminal to be the controlling tty. */
+               if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) {
+
+                       /* Now fork off another process to just hang around */
+                       if ((pid = fork()) < 0) {
+                               message(LOG | CONSOLE, "Can't fork!\n");
+                               _exit(1);
+                       }
+
+                       if (pid > 0) {
+
+                               /* We are the parent -- wait till the child is done */
+                               signal(SIGINT, SIG_IGN);
+                               signal(SIGTSTP, SIG_IGN);
+                               signal(SIGQUIT, SIG_IGN);
+                               signal(SIGCHLD, SIG_DFL);
+
+                               /* Wait for child to exit */
+                               while ((tmp_pid = waitpid(pid, &junk, 0)) != pid)
+                                       ;
+
+                               /* See if stealing the controlling tty back is necessary */
+                               pgrp = tcgetpgrp(0);
+                               if (pgrp != getpid())
+                                       _exit(0);
+
+                               /* Use a temporary process to steal the controlling tty. */
+                               if ((pid = fork()) < 0) {
+                                       message(LOG | CONSOLE, "\rCan't fork!\n");
+                                       _exit(1);
+                               }       
+                               if (pid == 0) {
+                                       setsid();
+                                       ioctl(0, TIOCSCTTY, 1);
+                                       _exit(0);
+                               }       
+                               while((tmp_pid = waitpid(pid, &junk, 0)) != pid) {
+                                       if (tmp_pid < 0 && errno == ECHILD)
+                                               break;
+                               }
+                               _exit(0);
+                       }
+
+                       /* Now fall though to actually execute things */
+               }
+
+               /* See if any special /bin/sh requiring characters are present */
+               if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
+                       cmd[0] = SHELL;
+                       cmd[1] = "-c";
+                       strcat(strcpy(buf, "exec "), a->command);
+                       cmd[2] = buf;
+                       cmd[3] = NULL;
+               } else {
+                       /* Convert command (char*) into cmd (char**, one word per string) */
+                       strcpy(buf, a->command);
+                       s = buf;
+                       for (tmpCmd = buf, i = 0;
+                                       (tmpCmd = strsep(&s, " \t")) != NULL;) {
+                               if (*tmpCmd != '\0') {
+                                       cmd[i] = tmpCmd;
+                                       i++;
+                               }
+                       }
+                       cmd[i] = NULL;
+               }
+
+               cmdpath = cmd[0];
+
+               /*
+                  Interactive shells want to see a dash in argv[0].  This
+                  typically is handled by login, argv will be setup this 
+                  way if a dash appears at the front of the command path 
+                  (like "-/bin/sh").
+                */
+
+               if (*cmdpath == '-') {
+
+                       /* skip over the dash */
+                       ++cmdpath;
+
+                       /* find the last component in the command pathname */
+                       s = get_last_path_component(cmdpath);
+
+                       /* make a new argv[0] */
+                       if ((cmd[0] = malloc(strlen(s)+2)) == NULL) {
+                               message(LOG | CONSOLE, "malloc failed");
+                               cmd[0] = cmdpath;
+                       } else {
+                               cmd[0][0] = '-';
+                               strcpy(cmd[0]+1, s);
+                       }
+               }
+
+               if (a->action & ASKFIRST) {
+                       /*
+                        * Save memory by not exec-ing anything large (like a shell)
+                        * before the user wants it. This is critical if swap is not
+                        * enabled and the system has low memory. Generally this will
+                        * be run on the second virtual console, and the first will
+                        * be allowed to start a shell or whatever an init script 
+                        * specifies.
+                        */
+                       messageND(LOG, "Waiting for enter to start '%s' (pid %d, terminal %s)\n",
+                                       cmdpath, getpid(), a->terminal);
+                       fflush(stdout);
+                       write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
+                       getc(stdin);
+               }
+
+               /* Log the process name and args */
+               messageND(LOG, "Starting pid %d, console %s: '%s'\n",
+                               getpid(), a->terminal, cmdpath);
+
+#if defined BB_FEATURE_INIT_COREDUMPS
+               if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
+                       struct rlimit limit;
+                       limit.rlim_cur = RLIM_INFINITY;
+                       limit.rlim_max = RLIM_INFINITY;
+                       setrlimit(RLIMIT_CORE, &limit);
+               }
+#endif
+
+               /* Now run it.  The new program will take over this PID, 
+                * so nothing further in init.c should be run. */
+               execve(cmdpath, cmd, environment);
+
+               /* We're still here?  Some error happened. */
+               message(LOG | CONSOLE, "\rBummer, could not run '%s': %s\n", cmdpath,
+                               strerror(errno));
+               _exit(-1);
+       }
+       sigprocmask(SIG_SETMASK, &omask, NULL);
+       return pid;
+}
+
+static int waitfor(struct init_action *a)
+{
+       int pid; 
+       int status, wpid;
+
+       pid = run(a);
+       while (1) {
+               wpid = wait(&status);
+               if (wpid > 0 && wpid != pid) {
+                       continue;
+               }
+               if (wpid == pid)
+                       break;
+       }
+       return wpid;
+}
+
+/* Run all commands of a particular type */
+static void run_actions(int action)
+{
+       struct init_action *a, *tmp;
+
+       for (a = init_action_list; a; a = tmp) {
+               tmp = a->next;
+               if (a->action == action) {
+                       if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) {
+                               waitfor(a);
+                               delete_init_action(a);
+                       } else if (a->action & ONCE) {
+                               run(a);
+                               delete_init_action(a);
+                       } else if (a->action & (RESPAWN|ASKFIRST)) {
+                               /* Only run stuff with pid==0.  If they have
+                                * a pid, that means it is still running */
+                               if (a->pid == 0) {
+                                       a->pid = run(a);
+                               }
+                       }
+               }
+       }
+}
+
+
+#ifndef DEBUG_INIT
+static void init_reboot(unsigned long magic)
+{
+       pid_t pid;
+       /* We have to fork here, since the kernel calls do_exit(0) in
+        * linux/kernel/sys.c, which can cause the machine to panic when 
+        * the init process is killed.... */
+       if ((pid = fork()) == 0) {
+#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)
+               reboot(magic);
+#else
+               reboot(0xfee1dead, 672274793, magic);
+#endif
+               _exit(0);
+       }
+       waitpid (pid, NULL, 0);
+}
+
+static void shutdown_system(void)
+{
+       sigset_t block_signals;
+
+       /* run everything to be run at "shutdown".  This is done _prior_
+        * to killing everything, in case people wish to use scripts to
+        * shut things down gracefully... */
+       run_actions(SHUTDOWN);
+
+       /* first disable all our signals */
+       sigemptyset(&block_signals);
+       sigaddset(&block_signals, SIGHUP);
+       sigaddset(&block_signals, SIGCHLD);
+       sigaddset(&block_signals, SIGUSR1);
+       sigaddset(&block_signals, SIGUSR2);
+       sigaddset(&block_signals, SIGINT);
+       sigaddset(&block_signals, SIGTERM);
+       sigaddset(&block_signals, SIGCONT);
+       sigaddset(&block_signals, SIGSTOP);
+       sigaddset(&block_signals, SIGTSTP);
+       sigprocmask(SIG_BLOCK, &block_signals, NULL);
+
+       /* Allow Ctrl-Alt-Del to reboot system. */
+       init_reboot(RB_ENABLE_CAD);
+
+       message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n");
+       sync();
+
+       /* Send signals to every process _except_ pid 1 */
+       message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n");
+       kill(-1, SIGTERM);
+       sleep(1);
+       sync();
+
+       message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n");
+       kill(-1, SIGKILL);
+       sleep(1);
+
+       sync();
+#if 0
+       if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) {
+               /* bdflush, kupdate not needed for kernels >2.2.11 */
+               bdflush(1, 0);
+               sync();
+       }
+#endif
+}
+
+static void exec_signal(int sig)
+{
+       struct init_action *a, *tmp;
+       sigset_t unblock_signals;
+       
+       for (a = init_action_list; a; a = tmp) {
+               tmp = a->next;
+               if (a->action & RESTART) {
+                       struct stat sb;
+
+                       shutdown_system();
+
+                       /* unblock all signals, blocked in shutdown_system() */
+                       sigemptyset(&unblock_signals);
+                       sigaddset(&unblock_signals, SIGHUP);
+                       sigaddset(&unblock_signals, SIGCHLD);
+                       sigaddset(&unblock_signals, SIGUSR1);
+                       sigaddset(&unblock_signals, SIGUSR2);
+                       sigaddset(&unblock_signals, SIGINT);
+                       sigaddset(&unblock_signals, SIGTERM);
+                       sigaddset(&unblock_signals, SIGCONT);
+                       sigaddset(&unblock_signals, SIGSTOP);
+                       sigaddset(&unblock_signals, SIGTSTP);
+                       sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL);
+
+                       /* Open the new terminal device */
+                       if ((device_open(a->terminal, O_RDWR)) < 0) {
+                               if (stat(a->terminal, &sb) != 0) {
+                                       message(LOG | CONSOLE, "device '%s' does not exist.", a->terminal);
+                               } else {
+                                       message(LOG | CONSOLE, "Bummer, can't open %s", a->terminal);
+                               }
+                               halt_signal(SIGUSR1);
+                       }
+
+                       /* Make sure the terminal will act fairly normal for us */
+                       set_term(0);
+                       /* Setup stdout, stderr on the supplied terminal */
+                       dup(0);
+                       dup(0);
+
+                       message(CONSOLE|LOG, "\rTrying to re-exec %s\n", a->command);
+                       execl(a->command, a->command, NULL);
+       
+                       message(CONSOLE|LOG, "\rexec of '%s' failed: %s\n", 
+                               a->command, strerror(errno));
+                       sync();
+                       sleep(2);
+                       init_reboot(RB_HALT_SYSTEM);
+                       loop_forever();
+               }
+       }
+}
+
+static void halt_signal(int sig)
+{
+       shutdown_system();
+       message(CONSOLE|LOG,
+#if #cpu(s390)
+                       /* Seems the s390 console is Wierd(tm). */
+                       "\rThe system is halted. You may reboot now.\n"
+#else
+                       "\rThe system is halted. Press Reset or turn off power\n"
+#endif
+                  );
+       sync();
+
+       /* allow time for last message to reach serial console */
+       sleep(2);
+
+       if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0))
+               init_reboot(RB_POWER_OFF);
+       else
+               init_reboot(RB_HALT_SYSTEM);
+
+       loop_forever();
+}
+
+static void reboot_signal(int sig)
+{
+       shutdown_system();
+       message(CONSOLE|LOG, "\rPlease stand by while rebooting the system.\n");
+       sync();
+
+       /* allow time for last message to reach serial console */
+       sleep(2);
+
+       init_reboot(RB_AUTOBOOT);
+
+       loop_forever();
+}
+
+static void ctrlaltdel_signal(int sig)
+{
+       run_actions(CTRLALTDEL);
+}
+
+/* The SIGSTOP & SIGTSTP handler */
+static void stop_handler(int sig)
+{
+       int saved_errno = errno;
+
+       got_cont = 0;
+       while(!got_cont) pause();
+       got_cont = 0;
+       errno = saved_errno;
+}
+
+/* The SIGCONT handler */ 
+static void cont_handler(int sig)
+{
+       got_cont = 1;
+}
+
+/* Reap any zombie processes that are reparented to init */
+static void child_handler(int sig)
+{
+       int status;
+       while ( wait3(&status, WNOHANG, NULL) > 0 );
+}
+
+#endif                                                 /* ! DEBUG_INIT */
+
+static void new_init_action(int action, char *command, char *cons)
+{
+       struct init_action *new_action, *a;
+
+       if (*cons == '\0')
+               cons = console;
+
+       /* do not run entries if console device is not available */
+       if (access(cons, R_OK|W_OK))
+               return;
+       if (strcmp(cons, "/dev/null") == 0 && (action & ASKFIRST))
+               return;
+
+       new_action = calloc((size_t) (1), sizeof(struct init_action));
+       if (!new_action) {
+               message(LOG | CONSOLE, "\rMemory allocation failure\n");
+               loop_forever();
+       }
+
+       /* Append to the end of the list */
+       for (a = init_action_list; a && a->next; a = a->next) ;
+       if (a) {
+               a->next = new_action;
+       } else {
+               init_action_list = new_action;
+       }
+       strcpy(new_action->command, command);
+       new_action->action = action;
+       strcpy(new_action->terminal, cons);
+       new_action->pid = 0;
+//    message(LOG|CONSOLE, "command='%s' action='%d' terminal='%s'\n",
+//      new_action->command, new_action->action, new_action->terminal);
+}
+
+static void delete_init_action(struct init_action * action)
+{
+       struct init_action *a, *b = NULL;
+
+       for (a = init_action_list; a; b = a, a = a->next) {
+               if (a == action) {
+                       if (b == NULL) {
+                               init_action_list = a->next;
+                       } else {
+                               b->next = a->next;
+                       }
+                       free(a);
+                       break;
+               }
+       }
+}
+
+/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
+ * then parse_inittab() simply adds in some default
+ * actions(i.e., runs INIT_SCRIPT and then starts a pair 
+ * of "askfirst" shells).  If BB_FEATURE_USE_INITTAB 
+ * _is_ defined, but /etc/inittab is missing, this 
+ * results in the same set of default behaviors.
+ * */
+static void parse_inittab(void)
+{
+#ifdef BB_FEATURE_USE_INITTAB
+       FILE *file;
+       char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE], tmpConsole[INIT_BUFFS_SIZE];
+       char *id, *runlev, *action, *command, *eol;
+       const struct init_action_type *a = actions;
+       int foundIt;
+
+
+       file = fopen(INITTAB, "r");
+       if (file == NULL) {
+               /* No inittab file -- set up some default behavior */
+#endif
+               /* Reboot on Ctrl-Alt-Del */
+               new_init_action(CTRLALTDEL, "/sbin/reboot", console);
+               /* Umount all filesystems on halt/reboot */
+               new_init_action(SHUTDOWN, "/bin/umount -a -r", console);
+#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
+               /* Swapoff on halt/reboot */
+               new_init_action(SHUTDOWN, "/sbin/swapoff -a", console);
+#endif
+               /* Prepare to restart init when a HUP is received */
+               new_init_action(RESTART, "/sbin/init", console);
+               /* Askfirst shell on tty1-4 */
+               new_init_action(ASKFIRST, LOGIN_SHELL, console);
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_2);
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_3);
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_4);
+               /* sysinit */
+               new_init_action(SYSINIT, INIT_SCRIPT, console);
+
+               return;
+#ifdef BB_FEATURE_USE_INITTAB
+       }
+
+       while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
+               foundIt = FALSE;
+               /* Skip leading spaces */
+               for (id = buf; *id == ' ' || *id == '\t'; id++);
+
+               /* Skip the line if it's a comment */
+               if (*id == '#' || *id == '\n')
+                       continue;
+
+               /* Trim the trailing \n */
+               eol = strrchr(id, '\n');
+               if (eol != NULL)
+                       *eol = '\0';
+
+               /* Keep a copy around for posterity's sake (and error msgs) */
+               strcpy(lineAsRead, buf);
+
+               /* Separate the ID field from the runlevels */
+               runlev = strchr(id, ':');
+               if (runlev == NULL || *(runlev + 1) == '\0') {
+                       message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead);
+                       continue;
+               } else {
+                       *runlev = '\0';
+                       ++runlev;
+               }
+
+               /* Separate the runlevels from the action */
+               action = strchr(runlev, ':');
+               if (action == NULL || *(action + 1) == '\0') {
+                       message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead);
+                       continue;
+               } else {
+                       *action = '\0';
+                       ++action;
+               }
+
+               /* Separate the action from the command */
+               command = strchr(action, ':');
+               if (command == NULL || *(command + 1) == '\0') {
+                       message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead);
+                       continue;
+               } else {
+                       *command = '\0';
+                       ++command;
+               }
+
+               /* Ok, now process it */
+               a = actions;
+               while (a->name != 0) {
+                       if (strcmp(a->name, action) == 0) {
+                               if (*id != '\0') {
+                                       strcpy(tmpConsole, "/dev/");
+                                       strncat(tmpConsole, id, INIT_BUFFS_SIZE-6);
+                                       id = tmpConsole;
+                               }
+                               new_init_action(a->action, command, id);
+                               foundIt = TRUE;
+                       }
+                       a++;
+               }
+               if (foundIt == TRUE)
+                       continue;
+               else {
+                       /* Choke on an unknown action */
+                       message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead);
+               }
+       }
+       fclose(file);
+       return;
+#endif /* BB_FEATURE_USE_INITTAB */
+}
+
+
+
+extern int init_main(int argc, char **argv)
+{
+       struct init_action *a;
+       pid_t wpid;
+       int status;
+
+       if (argc > 1 && !strcmp(argv[1], "-q")) {
+               /* don't assume init's pid == 1 */
+               long *pid = find_pid_by_name("init");
+               if (!pid || *pid<=0) {
+                       pid = find_pid_by_name("linuxrc");
+                       if (!pid || *pid<=0)
+                               error_msg_and_die("no process killed");
+               }
+               kill(*pid, SIGHUP);
+               exit(0);
+       }
+
+#ifndef DEBUG_INIT
+       /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
+       if (getpid() != 1
+#ifdef BB_FEATURE_LINUXRC
+                       && strstr(applet_name, "linuxrc") == NULL
+#endif
+                         )
+       {
+                       show_usage();
+       }
+       /* Set up sig handlers  -- be sure to
+        * clear all of these in run() */
+       signal(SIGHUP,  exec_signal);
+       signal(SIGUSR1, halt_signal);
+       signal(SIGUSR2, halt_signal);
+       signal(SIGINT,  ctrlaltdel_signal);
+       signal(SIGTERM, reboot_signal);
+       signal(SIGCONT, cont_handler);
+       signal(SIGSTOP, stop_handler);
+       signal(SIGTSTP, stop_handler);
+       signal(SIGCHLD, child_handler);
+
+       /* Turn off rebooting via CTL-ALT-DEL -- we get a 
+        * SIGINT on CAD so we can shut things down gracefully... */
+       init_reboot(RB_DISABLE_CAD);
+#endif
+
+       /* Figure out what kernel this is running */
+       kernelVersion = get_kernel_revision();
+
+       /* Figure out where the default console should be */
+       console_init();
+
+       /* Close whatever files are open, and reset the console. */
+       close(0);
+       close(1);
+       close(2);
+
+       if(device_open(console, O_RDWR|O_NOCTTY)==0) {
+       set_term(0);
+               close(0);
+       }
+
+       chdir("/");
+       setsid();
+
+       /* Make sure PATH is set to something sane */
+       putenv("PATH="_PATH_STDPATH);
+
+       /* Hello world */
+       message(MAYBE_CONSOLE|LOG, "\rinit started:  %s\n", full_version);
+
+       /* Make sure there is enough memory to do something useful. */
+       check_memory();
+
+       /* Check if we are supposed to be in single user mode */
+       if (argc > 1 && (!strcmp(argv[1], "single") ||
+                                        !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
+               /* Ask first then start a shell on tty2-4 */
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_2);
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_3);
+               new_init_action(ASKFIRST, LOGIN_SHELL, VC_4);
+               /* Start a shell on tty1 */
+               new_init_action(RESPAWN, LOGIN_SHELL, console);
+       } else {
+               /* Not in single user mode -- see what inittab says */
+
+               /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
+                * then parse_inittab() simply adds in some default
+                * actions(i.e., runs INIT_SCRIPT and then starts a pair 
+                * of "askfirst" shells */
+               parse_inittab();
+       }
+
+       /* Make the command line just say "init"  -- thats all, nothing else */
+       fixup_argv(argc, argv, "init");
+
+       /* Now run everything that needs to be run */
+
+       /* First run the sysinit command */
+       run_actions(SYSINIT);
+
+       /* Next run anything that wants to block */
+       run_actions(WAIT);
+
+       /* Next run anything to be run only once */
+       run_actions(ONCE);
+
+       /* If there is nothing else to do, stop */
+       if (init_action_list == NULL) {
+               message(LOG | CONSOLE, "\rNo more tasks for init -- sleeping forever.\n");
+               loop_forever();
+       }
+
+       /* Now run the looping stuff for the rest of forever */
+       while (1) {
+               /* run the respawn stuff */
+               run_actions(RESPAWN);
+
+               /* run the askfirst stuff */
+               run_actions(ASKFIRST);
+
+               /* Don't consume all CPU time -- sleep a bit */
+               sleep(1);
+
+               /* Wait for a child process to exit */
+               wpid = wait(&status);
+               while (wpid > 0) {
+                       /* Find out who died and clean up their corpse */
+                       for (a = init_action_list; a; a = a->next) {
+                               if (a->pid == wpid) {
+                                       /* Set the pid to 0 so that the process gets
+                                        * restarted by run_actions() */
+                                       a->pid = 0;
+                                       message(LOG, "Process '%s' (pid %d) exited.  "
+                                                       "Scheduling it for restart.\n", a->command, wpid);
+                               }
+                       }
+                       /* see if anyone else is waiting to be reaped */
+                       wpid = waitpid (-1, &status, WNOHANG);
+               }
+       }
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/insmod.c b/insmod.c
new file mode 100644 (file)
index 0000000..c612e68
--- /dev/null
+++ b/insmod.c
@@ -0,0 +1,3727 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini insmod implementation for busybox
+ *
+ * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 
+ * and MIPS.
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
+ * Written by Erik Andersen and Ron Alder <alder@lineo.com>
+ *
+ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+ * and (theoretically) SH3. I have only tested SH4 in little endian mode.
+ *
+ * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+ * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI.  Only
+ * very minor changes required to also work with StrongArm and presumably
+ * all ARM based systems.
+ *
+ * Magnus Damm <damm@opensource.se> 22-May-2002.
+ *   The plt and got code are now using the same structs.
+ *   Added generic linked list code to fully support PowerPC.
+ *   Replaced the mess in arch_apply_relocation() with architecture blocks.
+ *   The arch_create_got() function got cleaned up with architecture blocks.
+ *   These blocks should be easy maintain and sync with obj_xxx.c in modutils.
+ *
+ * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
+ *   PowerPC specific code stolen from modutils-2.3.16, 
+ *   written by Paul Mackerras, Copyright 1996, 1997 Linux International.
+ *   I've only tested the code on mpc8xx platforms in big-endian mode.
+ *   Did some cleanup and added BB_USE_xxx_ENTRIES...
+ *
+ * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
+ *   based on modutils-2.4.2
+ *   MIPS specific support for Elf loading and relocation.
+ *   Copyright 1996, 1997 Linux International.
+ *   Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+ *
+ * Based almost entirely on the Linux modutils-2.3.11 implementation.
+ *   Copyright 1996, 1997 Linux International.
+ *   New implementation contributed by Richard Henderson <rth@tamu.edu>
+ *   Based on original work by Bjorn Ekwall <bj0rn@blox.se>
+ *   Restructured (and partly rewritten) by:
+ *   Björn Ekwall <bj0rn@blox.se> February 1999
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include "busybox.h"
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+# undef BB_FEATURE_OLD_MODULE_INTERFACE
+# define new_sys_init_module   init_module
+#else
+# define old_sys_init_module   init_module
+#endif
+
+#ifdef BB_FEATURE_INSMOD_LOADINKMEM
+#define LOADBITS 0     
+#else
+#define LOADBITS 1
+#endif
+
+#if defined(__arm__)
+#define BB_USE_PLT_ENTRIES
+#define BB_PLT_ENTRY_SIZE 8
+#define BB_USE_GOT_ENTRIES
+#define BB_GOT_ENTRY_SIZE 8
+#define BB_USE_SINGLE
+
+#define MATCH_MACHINE(x) (x == EM_ARM)
+#define SHT_RELM       SHT_REL
+#define Elf32_RelM     Elf32_Rel
+#define ELFCLASSM      ELFCLASS32
+#endif
+
+#if defined(__i386__)
+#define BB_USE_GOT_ENTRIES
+#define BB_GOT_ENTRY_SIZE 4
+#define BB_USE_SINGLE
+
+#ifndef EM_486
+#define MATCH_MACHINE(x) (x == EM_386)
+#else
+#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
+#endif
+
+#define SHT_RELM       SHT_REL
+#define Elf32_RelM     Elf32_Rel
+#define ELFCLASSM      ELFCLASS32
+#endif
+
+#if defined(__mc68000__) 
+#define BB_USE_GOT_ENTRIES
+#define BB_GOT_ENTRY_SIZE 4
+#define BB_USE_SINGLE
+
+#define MATCH_MACHINE(x) (x == EM_68K)
+#define SHT_RELM       SHT_RELA
+#define Elf32_RelM     Elf32_Rela
+#endif
+
+#if defined(__mips__)
+/* Account for ELF spec changes.  */
+#ifndef EM_MIPS_RS3_LE
+#ifdef EM_MIPS_RS4_BE
+#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
+#else
+#define EM_MIPS_RS3_LE 10
+#endif
+#endif /* !EM_MIPS_RS3_LE */
+
+#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
+#define SHT_RELM       SHT_REL
+#define Elf32_RelM     Elf32_Rel
+#define ELFCLASSM      ELFCLASS32
+#define ARCHDATAM       "__dbe_table"
+#endif
+
+#if defined(__powerpc__)
+#define BB_USE_PLT_ENTRIES
+#define BB_PLT_ENTRY_SIZE 16
+#define BB_USE_PLT_LIST
+#define BB_LIST_ARCHTYPE ElfW(Addr) 
+#define BB_USE_LIST
+
+#define MATCH_MACHINE(x) (x == EM_PPC)
+#define SHT_RELM       SHT_RELA
+#define Elf32_RelM     Elf32_Rela
+#define ELFCLASSM      ELFCLASS32
+#define ARCHDATAM       "__ftr_fixup"
+#endif
+
+#if defined(__sh__)
+#define BB_USE_GOT_ENTRIES
+#define BB_GOT_ENTRY_SIZE 4
+#define BB_USE_SINGLE
+
+#define MATCH_MACHINE(x) (x == EM_SH)
+#define SHT_RELM       SHT_RELA
+#define Elf32_RelM     Elf32_Rela
+#define ELFCLASSM      ELFCLASS32
+
+/* the SH changes have only been tested on the SH4 in =little endian= mode */
+/* I'm not sure about big endian, so let's warn: */
+
+#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
+#error insmod.c may require changes for use on big endian SH4/SH3
+#endif
+
+/* it may or may not work on the SH1/SH2... So let's error on those
+   also */
+#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
+#error insmod.c may require changes for non-SH3/SH4 use
+#endif
+#endif
+
+#ifndef SHT_RELM
+#error Sorry, but insmod.c does not yet support this architecture...
+#endif
+
+//----------------------------------------------------------------------------
+//--------modutils module.h, lines 45-242
+//----------------------------------------------------------------------------
+
+/* Definitions for the Linux module syscall interface.
+   Copyright 1996, 1997 Linux International.
+
+   Contributed by Richard Henderson <rth@tamu.edu>
+
+   This file is part of the Linux modutils.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2 of the License, or (at your
+   option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+#ifndef MODUTILS_MODULE_H
+#define MODUTILS_MODULE_H
+
+/* This file contains the structures used by the 2.0 and 2.1 kernels.
+   We do not use the kernel headers directly because we do not wish
+   to be dependant on a particular kernel version to compile insmod.  */
+
+
+/*======================================================================*/
+/* The structures used by Linux 2.0.  */
+
+/* The symbol format used by get_kernel_syms(2).  */
+struct old_kernel_sym
+{
+  unsigned long value;
+  char name[60];
+};
+
+struct old_module_ref
+{
+  unsigned long module;                /* kernel addresses */
+  unsigned long next;
+};
+
+struct old_module_symbol
+{
+  unsigned long addr;
+  unsigned long name;
+};
+
+struct old_symbol_table
+{
+  int size;                    /* total, including string table!!! */
+  int n_symbols;
+  int n_refs;
+  struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
+  struct old_module_ref ref[0];        /* actual size defined by n_refs */
+};
+
+struct old_mod_routines
+{
+  unsigned long init;
+  unsigned long cleanup;
+};
+
+struct old_module
+{
+  unsigned long next;
+  unsigned long ref;           /* the list of modules that refer to me */
+  unsigned long symtab;
+  unsigned long name;
+  int size;                    /* size of module in pages */
+  unsigned long addr;          /* address of module */
+  int state;
+  unsigned long cleanup;       /* cleanup routine */
+};
+
+/* Sent to init_module(2) or'ed into the code size parameter.  */
+static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */
+
+int get_kernel_syms(struct old_kernel_sym *);
+int old_sys_init_module(const char *name, char *code, unsigned codesize,
+                       struct old_mod_routines *, struct old_symbol_table *);
+
+/*======================================================================*/
+/* For sizeof() which are related to the module platform and not to the
+   environment isnmod is running in, use sizeof_xx instead of sizeof(xx).  */
+
+#define tgt_sizeof_char                sizeof(char)
+#define tgt_sizeof_short       sizeof(short)
+#define tgt_sizeof_int         sizeof(int)
+#define tgt_sizeof_long                sizeof(long)
+#define tgt_sizeof_char_p      sizeof(char *)
+#define tgt_sizeof_void_p      sizeof(void *)
+#define tgt_long               long
+
+#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
+#undef tgt_sizeof_long
+#undef tgt_sizeof_char_p
+#undef tgt_sizeof_void_p
+#undef tgt_long
+static const int tgt_sizeof_long = 8;
+static const int tgt_sizeof_char_p = 8;
+static const int tgt_sizeof_void_p = 8;
+#define tgt_long               long long
+#endif
+
+/*======================================================================*/
+/* The structures used in Linux 2.1.  */
+
+/* Note: new_module_symbol does not use tgt_long intentionally */
+struct new_module_symbol
+{
+  unsigned long value;
+  unsigned long name;
+};
+
+struct new_module_persist;
+
+struct new_module_ref
+{
+  unsigned tgt_long dep;               /* kernel addresses */
+  unsigned tgt_long ref;
+  unsigned tgt_long next_ref;
+};
+
+struct new_module
+{
+  unsigned tgt_long size_of_struct;    /* == sizeof(module) */
+  unsigned tgt_long next;
+  unsigned tgt_long name;
+  unsigned tgt_long size;
+
+  tgt_long usecount;
+  unsigned tgt_long flags;             /* AUTOCLEAN et al */
+
+  unsigned nsyms;
+  unsigned ndeps;
+
+  unsigned tgt_long syms;
+  unsigned tgt_long deps;
+  unsigned tgt_long refs;
+  unsigned tgt_long init;
+  unsigned tgt_long cleanup;
+  unsigned tgt_long ex_table_start;
+  unsigned tgt_long ex_table_end;
+#ifdef __alpha__
+  unsigned tgt_long gp;
+#endif
+  /* Everything after here is extension.  */
+  unsigned tgt_long persist_start;
+  unsigned tgt_long persist_end;
+  unsigned tgt_long can_unload;
+  unsigned tgt_long runsize;
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+  const char *kallsyms_start;     /* All symbols for kernel debugging */
+  const char *kallsyms_end;
+  const char *archdata_start;     /* arch specific data for module */
+  const char *archdata_end;
+  const char *kernel_data;        /* Reserved for kernel internal use */
+#endif
+};
+
+#ifdef ARCHDATAM
+#define ARCHDATA_SEC_NAME ARCHDATAM
+#else
+#define ARCHDATA_SEC_NAME "__archdata"
+#endif
+#define KALLSYMS_SEC_NAME "__kallsyms"
+
+
+struct new_module_info
+{
+  unsigned long addr;
+  unsigned long size;
+  unsigned long flags;
+          long usecount;
+};
+
+/* Bits of module.flags.  */
+static const int NEW_MOD_RUNNING = 1;
+static const int NEW_MOD_DELETED = 2;
+static const int NEW_MOD_AUTOCLEAN = 4;
+static const int NEW_MOD_VISITED = 8;
+static const int NEW_MOD_USED_ONCE = 16;
+
+int new_sys_init_module(const char *name, const struct new_module *);
+int query_module(const char *name, int which, void *buf, size_t bufsize,
+                size_t *ret);
+
+/* Values for query_module's which.  */
+
+static const int QM_MODULES = 1;
+static const int QM_DEPS = 2;
+static const int QM_REFS = 3;
+static const int QM_SYMBOLS = 4;
+static const int QM_INFO = 5;
+
+/*======================================================================*/
+/* The system calls unchanged between 2.0 and 2.1.  */
+
+unsigned long create_module(const char *, size_t);
+int delete_module(const char *);
+
+
+#endif /* module.h */
+
+//----------------------------------------------------------------------------
+//--------end of modutils module.h
+//----------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------
+//--------modutils obj.h, lines 253-462
+//----------------------------------------------------------------------------
+
+/* Elf object file loading and relocation routines.
+   Copyright 1996, 1997 Linux International.
+
+   Contributed by Richard Henderson <rth@tamu.edu>
+
+   This file is part of the Linux modutils.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2 of the License, or (at your
+   option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+
+#ifndef MODUTILS_OBJ_H
+static const int MODUTILS_OBJ_H = 1;
+
+/* The relocatable object is manipulated using elfin types.  */
+
+#include <stdio.h>
+#include <elf.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ELFDATAM    ELFDATA2LSB
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define ELFDATAM    ELFDATA2MSB
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+/* For some reason this is missing from libc5.  */
+#ifndef ELF32_ST_INFO
+# define ELF32_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+#endif
+
+#ifndef ELF64_ST_INFO
+# define ELF64_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+#endif
+
+struct obj_string_patch;
+struct obj_symbol_patch;
+
+struct obj_section
+{
+  ElfW(Shdr) header;
+  const char *name;
+  char *contents;
+  struct obj_section *load_next;
+  int idx;
+};
+
+struct obj_symbol
+{
+  struct obj_symbol *next;     /* hash table link */
+  const char *name;
+  unsigned long value;
+  unsigned long size;
+  int secidx;                  /* the defining section index/module */
+  int info;
+  int ksymidx;                 /* for export to the kernel symtab */
+  int referenced;              /* actually used in the link */
+};
+
+/* Hardcode the hash table size.  We shouldn't be needing so many
+   symbols that we begin to degrade performance, and we get a big win
+   by giving the compiler a constant divisor.  */
+
+#define HASH_BUCKETS  521
+
+struct obj_file
+{
+  ElfW(Ehdr) header;
+  ElfW(Addr) baseaddr;
+  struct obj_section **sections;
+  struct obj_section *load_order;
+  struct obj_section **load_order_search_start;
+  struct obj_string_patch *string_patches;
+  struct obj_symbol_patch *symbol_patches;
+  int (*symbol_cmp)(const char *, const char *);
+  unsigned long (*symbol_hash)(const char *);
+  unsigned long local_symtab_size;
+  struct obj_symbol **local_symtab;
+  struct obj_symbol *symtab[HASH_BUCKETS];
+};
+
+enum obj_reloc
+{
+  obj_reloc_ok,
+  obj_reloc_overflow,
+  obj_reloc_dangerous,
+  obj_reloc_unhandled
+};
+
+struct obj_string_patch
+{
+  struct obj_string_patch *next;
+  int reloc_secidx;
+  ElfW(Addr) reloc_offset;
+  ElfW(Addr) string_offset;
+};
+
+struct obj_symbol_patch
+{
+  struct obj_symbol_patch *next;
+  int reloc_secidx;
+  ElfW(Addr) reloc_offset;
+  struct obj_symbol *sym;
+};
+
+
+/* Generic object manipulation routines.  */
+
+static unsigned long obj_elf_hash(const char *);
+
+static unsigned long obj_elf_hash_n(const char *, unsigned long len);
+
+static struct obj_symbol *obj_find_symbol (struct obj_file *f,
+                                        const char *name);
+
+static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
+                                 struct obj_symbol *sym);
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+static void obj_set_symbol_compare(struct obj_file *f,
+                           int (*cmp)(const char *, const char *),
+                           unsigned long (*hash)(const char *));
+#endif
+
+static struct obj_section *obj_find_section (struct obj_file *f,
+                                          const char *name);
+
+static void obj_insert_section_load_order (struct obj_file *f,
+                                   struct obj_section *sec);
+
+static struct obj_section *obj_create_alloced_section (struct obj_file *f,
+                                               const char *name,
+                                               unsigned long align,
+                                               unsigned long size);
+
+static struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
+                                                     const char *name,
+                                                     unsigned long align,
+                                                     unsigned long size);
+
+static void *obj_extend_section (struct obj_section *sec, unsigned long more);
+
+static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+                    const char *string);
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+                    struct obj_symbol *sym);
+#endif
+
+static int obj_check_undefineds(struct obj_file *f);
+
+static void obj_allocate_commons(struct obj_file *f);
+
+static unsigned long obj_load_size (struct obj_file *f);
+
+static int obj_relocate (struct obj_file *f, ElfW(Addr) base);
+
+static struct obj_file *obj_load(FILE *f, int loadprogbits);
+
+static int obj_create_image (struct obj_file *f, char *image);
+
+/* Architecture specific manipulation routines.  */
+
+static struct obj_file *arch_new_file (void);
+
+static struct obj_section *arch_new_section (void);
+
+static struct obj_symbol *arch_new_symbol (void);
+
+static enum obj_reloc arch_apply_relocation (struct obj_file *f,
+                                     struct obj_section *targsec,
+                                     struct obj_section *symsec,
+                                     struct obj_symbol *sym,
+                                     ElfW(RelM) *rel, ElfW(Addr) value);
+
+static void arch_create_got (struct obj_file *f);
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+static int arch_init_module (struct obj_file *f, struct new_module *);
+#endif
+
+#endif /* obj.h */
+//----------------------------------------------------------------------------
+//--------end of modutils obj.h
+//----------------------------------------------------------------------------
+
+
+
+
+
+#define _PATH_MODULES  "/lib/modules"
+static const int STRVERSIONLEN = 32;
+
+/*======================================================================*/
+
+static int flag_force_load = 0;
+static int flag_autoclean = 0;
+static int flag_verbose = 0;
+static int flag_quiet = 0;
+static int flag_export = 1;
+
+
+/*======================================================================*/
+
+#if defined(BB_USE_LIST)
+
+struct arch_list_entry
+{
+       struct arch_list_entry *next;
+       BB_LIST_ARCHTYPE addend;
+       int offset;
+       int inited : 1;
+};
+
+#endif
+
+#if defined(BB_USE_SINGLE)
+
+struct arch_single_entry
+{
+       int offset;
+       int inited : 1;
+       int allocated : 1;
+};
+
+#endif
+
+#if defined(__mips__)
+struct mips_hi16
+{
+  struct mips_hi16 *next;
+  Elf32_Addr *addr;
+  Elf32_Addr value;
+};
+#endif
+
+struct arch_file {
+       struct obj_file root;
+#if defined(BB_USE_PLT_ENTRIES)
+       struct obj_section *plt;
+#endif
+#if defined(BB_USE_GOT_ENTRIES)
+       struct obj_section *got;
+#endif
+#if defined(__mips__)
+       struct mips_hi16 *mips_hi16_list;
+#endif
+};
+
+struct arch_symbol {
+       struct obj_symbol root;
+#if defined(BB_USE_PLT_ENTRIES)
+#if defined(BB_USE_PLT_LIST)
+       struct arch_list_entry *pltent;
+#else
+       struct arch_single_entry pltent;
+#endif
+#endif
+#if defined(BB_USE_GOT_ENTRIES)
+       struct arch_single_entry gotent;
+#endif
+};
+
+
+struct external_module {
+       const char *name;
+       ElfW(Addr) addr;
+       int used;
+       size_t nsyms;
+       struct new_module_symbol *syms;
+};
+
+static struct new_module_symbol *ksyms;
+static size_t nksyms;
+
+static struct external_module *ext_modules;
+static int n_ext_modules;
+static int n_ext_modules_used;
+extern int delete_module(const char *);
+
+static char m_filename[FILENAME_MAX];
+static char m_fullName[FILENAME_MAX];
+
+
+
+/*======================================================================*/
+
+
+static int check_module_name_match(const char *filename, struct stat *statbuf,
+                                                  void *userdata)
+{
+       char *fullname = (char *) userdata;
+
+       if (fullname[0] == '\0')
+               return (FALSE);
+       else {
+               char *tmp, *tmp1 = strdup(filename);
+               tmp = get_last_path_component(tmp1);
+               if (strcmp(tmp, fullname) == 0) {
+                       free(tmp1);
+                       /* Stop searching if we find a match */
+                       safe_strncpy(m_filename, filename, sizeof(m_filename));
+                       return (TRUE);
+               }
+               free(tmp1);
+       }
+       return (FALSE);
+}
+
+
+/*======================================================================*/
+
+static struct obj_file *arch_new_file(void)
+{
+       struct arch_file *f;
+       f = xmalloc(sizeof(*f));
+
+       memset(f, 0, sizeof(*f));
+
+       return &f->root;
+}
+
+static struct obj_section *arch_new_section(void)
+{
+       return xmalloc(sizeof(struct obj_section));
+}
+
+static struct obj_symbol *arch_new_symbol(void)
+{
+       struct arch_symbol *sym;
+       sym = xmalloc(sizeof(*sym));
+
+       memset(sym, 0, sizeof(*sym));
+
+       return &sym->root;
+}
+
+static enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+                                         struct obj_section *targsec,
+                                         struct obj_section *symsec,
+                                         struct obj_symbol *sym,
+                                     ElfW(RelM) *rel, ElfW(Addr) v)
+{
+       struct arch_file *ifile = (struct arch_file *) f;
+       enum obj_reloc ret = obj_reloc_ok;
+       ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
+       ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
+#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
+       struct arch_symbol *isym = (struct arch_symbol *) sym;
+#endif
+#if defined(BB_USE_GOT_ENTRIES)
+       ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
+#endif
+#if defined(BB_USE_PLT_ENTRIES)
+       ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
+       unsigned long *ip;
+#if defined(BB_USE_PLT_LIST)
+       struct arch_list_entry *pe;
+#else
+       struct arch_single_entry *pe;
+#endif
+#endif
+
+       switch (ELF32_R_TYPE(rel->r_info)) {
+
+#if defined(__arm__)
+       case R_ARM_NONE:
+               break;
+
+       case R_ARM_ABS32:
+               *loc += v;
+               break;
+               
+       case R_ARM_GOT32:
+               goto bb_use_got;
+
+       case R_ARM_GOTPC:
+               /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ 
+                * (which is .got) similar to branch, 
+                * but is full 32 bits relative */
+
+               assert(got);
+               *loc += got - dot;
+               break;
+
+       case R_ARM_PC24:
+       case R_ARM_PLT32:
+               goto bb_use_plt;
+
+       case R_ARM_GOTOFF: /* address relative to the got */
+               assert(got);
+               *loc += v - got;
+               break;
+
+#elif defined(__i386__)
+
+       case R_386_NONE:
+               break;
+
+       case R_386_32:
+               *loc += v;
+               break;
+
+       case R_386_PLT32:
+       case R_386_PC32:
+               *loc += v - dot;
+               break;
+
+       case R_386_GLOB_DAT:
+       case R_386_JMP_SLOT:
+               *loc = v;
+               break;
+
+       case R_386_RELATIVE:
+               *loc += f->baseaddr;
+               break;
+
+       case R_386_GOTPC:
+               assert(got != 0);
+               *loc += got - dot;
+               break;
+
+       case R_386_GOT32:
+               goto bb_use_got;
+
+       case R_386_GOTOFF:
+               assert(got != 0);
+               *loc += v - got;
+               break;
+
+#elif defined(__mc68000__)
+
+       case R_68K_NONE:
+               break;
+
+       case R_68K_32:
+               *loc += v;
+               break;
+
+       case R_68K_8:
+               if (v > 0xff) {
+                       ret = obj_reloc_overflow;
+               }
+               *(char *)loc = v;
+               break;
+
+       case R_68K_16:
+               if (v > 0xffff) {
+                       ret = obj_reloc_overflow;
+               }
+               *(short *)loc = v;
+               break;
+
+       case R_68K_PC8:
+               v -= dot;
+               if ((Elf32_Sword)v > 0x7f || 
+                   (Elf32_Sword)v < -(Elf32_Sword)0x80) {
+                       ret = obj_reloc_overflow;
+               }
+               *(char *)loc = v;
+               break;
+
+       case R_68K_PC16:
+               v -= dot;
+               if ((Elf32_Sword)v > 0x7fff || 
+                   (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
+                       ret = obj_reloc_overflow;
+               }
+               *(short *)loc = v;
+               break;
+
+       case R_68K_PC32:
+               *(int *)loc = v - dot;
+               break;
+
+       case R_68K_GLOB_DAT:
+       case R_68K_JMP_SLOT:
+               *loc = v;
+               break;
+
+       case R_68K_RELATIVE:
+               *(int *)loc += f->baseaddr;
+               break;
+
+       case R_68K_GOT32:
+               goto bb_use_got;
+
+       case R_68K_GOTOFF:
+               assert(got != 0);
+               *loc += v - got;
+               break;
+
+#elif defined(__mips__)
+
+       case R_MIPS_NONE:
+               break;
+
+       case R_MIPS_32:
+               *loc += v;
+               break;
+
+       case R_MIPS_26:
+               if (v % 4)
+                       ret = obj_reloc_dangerous;
+               if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
+                       ret = obj_reloc_overflow;
+               *loc =
+                   (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
+                                           0x03ffffff);
+               break;
+
+       case R_MIPS_HI16:
+               {
+                       struct mips_hi16 *n;
+
+                       /* We cannot relocate this one now because we don't know the value
+                          of the carry we need to add.  Save the information, and let LO16
+                          do the actual relocation.  */
+                       n = (struct mips_hi16 *) xmalloc(sizeof *n);
+                       n->addr = loc;
+                       n->value = v;
+                       n->next = ifile->mips_hi16_list;
+                       ifile->mips_hi16_list = n;
+                       break;
+               }
+
+       case R_MIPS_LO16:
+               {
+                       unsigned long insnlo = *loc;
+                       Elf32_Addr val, vallo;
+
+                       /* Sign extend the addend we extract from the lo insn.  */
+                       vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+                       if (ifile->mips_hi16_list != NULL) {
+                               struct mips_hi16 *l;
+
+                               l = ifile->mips_hi16_list;
+                               while (l != NULL) {
+                                       struct mips_hi16 *next;
+                                       unsigned long insn;
+
+                                       /* The value for the HI16 had best be the same. */
+                                       assert(v == l->value);
+
+                                       /* Do the HI16 relocation.  Note that we actually don't
+                                          need to know anything about the LO16 itself, except where
+                                          to find the low 16 bits of the addend needed by the LO16.  */
+                                       insn = *l->addr;
+                                       val =
+                                           ((insn & 0xffff) << 16) +
+                                           vallo;
+                                       val += v;
+
+                                       /* Account for the sign extension that will happen in the
+                                          low bits.  */
+                                       val =
+                                           ((val >> 16) +
+                                            ((val & 0x8000) !=
+                                             0)) & 0xffff;
+
+                                       insn = (insn & ~0xffff) | val;
+                                       *l->addr = insn;
+
+                                       next = l->next;
+                                       free(l);
+                                       l = next;
+                               }
+
+                               ifile->mips_hi16_list = NULL;
+                       }
+
+                       /* Ok, we're done with the HI16 relocs.  Now deal with the LO16.  */
+                       val = v + vallo;
+                       insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+                       *loc = insnlo;
+                       break;
+               }
+
+#elif defined(__powerpc__)
+
+       case R_PPC_ADDR16_HA:
+               *(unsigned short *)loc = (v + 0x8000) >> 16;
+               break;
+
+       case R_PPC_ADDR16_HI:
+               *(unsigned short *)loc = v >> 16;
+               break;
+
+       case R_PPC_ADDR16_LO:
+               *(unsigned short *)loc = v;
+               break;
+
+       case R_PPC_REL24:
+               goto bb_use_plt;
+
+       case R_PPC_REL32:
+               *loc = v - dot;
+               break;
+
+       case R_PPC_ADDR32:
+               *loc = v;
+               break;
+
+#elif defined(__sh__)
+
+       case R_SH_NONE:
+               break;
+
+       case R_SH_DIR32:
+               *loc += v;
+               break;
+
+       case R_SH_REL32:
+               *loc += v - dot;
+               break;
+               
+       case R_SH_PLT32:
+               *loc = v - dot;
+               break;
+
+       case R_SH_GLOB_DAT:
+       case R_SH_JMP_SLOT:
+               *loc = v;
+               break;
+
+       case R_SH_RELATIVE:
+               *loc = f->baseaddr + rel->r_addend;
+               break;
+
+       case R_SH_GOTPC:
+               assert(got != 0);
+               *loc = got - dot + rel->r_addend;
+               break;
+
+       case R_SH_GOT32:
+               goto bb_use_got;
+
+       case R_SH_GOTOFF:
+               assert(got != 0);
+               *loc = v - got;
+               break;
+
+#endif
+
+       default:
+        printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
+               ret = obj_reloc_unhandled;
+               break;
+
+#if defined(BB_USE_PLT_ENTRIES)
+
+         bb_use_plt:
+
+      /* find the plt entry and initialize it if necessary */
+      assert(isym != NULL);
+
+#if defined(BB_USE_PLT_LIST)
+      for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;)
+       pe = pe->next;
+      assert(pe != NULL);
+#else
+      pe = &isym->pltent;
+#endif
+
+      if (! pe->inited) {
+               ip = (unsigned long *) (ifile->plt->contents + pe->offset);
+
+               /* generate some machine code */
+
+#if defined(__arm__)
+               ip[0] = 0xe51ff004;                     /* ldr pc,[pc,#-4] */
+               ip[1] = v;                              /* sym@ */
+#endif
+#if defined(__powerpc__)
+         ip[0] = 0x3d600000 + ((v + 0x8000) >> 16);  /* lis r11,sym@ha */
+         ip[1] = 0x396b0000 + (v & 0xffff);          /* addi r11,r11,sym@l */
+         ip[2] = 0x7d6903a6;                         /* mtctr r11 */
+         ip[3] = 0x4e800420;                         /* bctr */
+#endif
+               pe->inited = 1;
+         }
+
+      /* relative distance to target */
+      v -= dot;
+      /* if the target is too far away.... */
+      if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
+           /* go via the plt */
+           v = plt + pe->offset - dot;
+         }
+      if (v & 3)
+           ret = obj_reloc_dangerous;
+
+      /* merge the offset into the instruction. */
+#if defined(__arm__)
+      /* Convert to words. */
+      v >>= 2;
+
+      *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
+#endif
+#if defined(__powerpc__)
+      *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
+#endif
+      break;
+#endif /* BB_USE_PLT_ENTRIES */
+
+#if defined(BB_USE_GOT_ENTRIES)
+         bb_use_got:
+
+               assert(isym != NULL);
+        /* needs an entry in the .got: set it, once */
+               if (!isym->gotent.inited) {
+                       isym->gotent.inited = 1;
+                       *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
+               }
+        /* make the reloc with_respect_to_.got */
+#if defined(__sh__)
+               *loc += isym->gotent.offset + rel->r_addend;
+#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
+               *loc += isym->gotent.offset;
+#endif
+               break;
+
+#endif /* BB_USE_GOT_ENTRIES */
+       }
+
+       return ret;
+}
+
+#if defined(BB_USE_LIST) 
+
+static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list,
+                         int offset, int size)
+{
+       struct arch_list_entry *pe;
+
+       for (pe = *list; pe != NULL; pe = pe->next) {
+               if (pe->addend == rel->r_addend) {
+                       break;
+               }
+       }
+
+       if (pe == NULL) {
+               pe = xmalloc(sizeof(struct arch_list_entry));
+               pe->next = *list;
+               pe->addend = rel->r_addend;
+               pe->offset = offset;
+               pe->inited = 0;
+               *list = pe;
+               return size;
+       }
+       return 0;
+}
+
+#endif
+
+#if defined(BB_USE_SINGLE) 
+
+static int arch_single_init(ElfW(RelM) *rel, struct arch_single_entry *single,
+                            int offset, int size)
+{
+       if (single->allocated == 0) {
+               single->allocated = 1;
+               single->offset = offset;
+               single->inited = 0;
+               return size;
+       }
+       return 0;
+}
+
+#endif
+
+#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
+
+static struct obj_section *arch_xsect_init(struct obj_file *f, char *name, 
+                                          int offset, int size)
+{
+       struct obj_section *myrelsec = obj_find_section(f, name);
+
+       if (offset == 0) {
+               offset += size;
+       }
+
+       if (myrelsec) {
+               obj_extend_section(myrelsec, offset);
+       } else {
+               myrelsec = obj_create_alloced_section(f, name, 
+                                                     size, offset);
+               assert(myrelsec);
+       }
+
+       return myrelsec;
+}
+
+#endif
+
+static void arch_create_got(struct obj_file *f)
+{
+#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
+       struct arch_file *ifile = (struct arch_file *) f;
+       int i;
+#if defined(BB_USE_GOT_ENTRIES)
+       int got_offset = 0, got_needed = 0, got_allocate;
+#endif
+#if defined(BB_USE_PLT_ENTRIES)
+       int plt_offset = 0, plt_needed = 0, plt_allocate;
+#endif
+    struct obj_section *relsec, *symsec, *strsec;
+       ElfW(RelM) *rel, *relend;
+       ElfW(Sym) *symtab, *extsym;
+       const char *strtab, *name;
+       struct arch_symbol *intsym;
+
+       for (i = 0; i < f->header.e_shnum; ++i) {
+               relsec = f->sections[i];
+
+               if (relsec->header.sh_type != SHT_RELM)
+                       continue;
+
+               symsec = f->sections[relsec->header.sh_link];
+               strsec = f->sections[symsec->header.sh_link];
+
+               rel = (ElfW(RelM) *) relsec->contents;
+               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+               symtab = (ElfW(Sym) *) symsec->contents;
+               strtab = (const char *) strsec->contents;
+
+               for (; rel < relend; ++rel) {
+                       extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+                       
+#if defined(BB_USE_GOT_ENTRIES)
+                       got_allocate = 0;
+#endif
+#if defined(BB_USE_PLT_ENTRIES)
+                       plt_allocate = 0;
+#endif
+
+                       switch (ELF32_R_TYPE(rel->r_info)) {
+
+#if defined(__arm__)
+
+                       case R_ARM_PC24:
+                       case R_ARM_PLT32:
+                               plt_allocate = 1;
+                               break;
+
+                       case R_ARM_GOTOFF:
+                       case R_ARM_GOTPC:
+                               got_needed = 1;
+                               continue;
+
+                       case R_ARM_GOT32:
+                               got_allocate = 1;
+                               break;
+
+#elif defined(__i386__)
+
+                       case R_386_GOTPC:
+                       case R_386_GOTOFF:
+                               got_needed = 1;
+                               continue;
+
+                       case R_386_GOT32:
+                               got_allocate = 1;
+                               break;
+
+#elif defined(__powerpc__)
+
+                       case R_PPC_REL24:
+                               plt_allocate = 1;
+                               break;
+
+#elif defined(__mc68000__)
+
+                       case R_68K_GOT32:
+                               got_allocate = 1;
+                               break;
+
+                       case R_68K_GOTOFF:
+                               got_needed = 1;
+                               continue;
+
+#elif defined(__sh__)
+
+                       case R_SH_GOT32:
+                               got_allocate = 1; 
+                               break;
+
+                       case R_SH_GOTPC:
+                       case R_SH_GOTOFF:
+                               got_needed = 1;
+                               continue;
+
+#endif
+                       default:
+                               continue;
+                       }
+
+                       if (extsym->st_name != 0) {
+                               name = strtab + extsym->st_name;
+                       } else {
+                               name = f->sections[extsym->st_shndx]->name;
+                       }
+                       intsym = (struct arch_symbol *) obj_find_symbol(f, name);
+#if defined(BB_USE_GOT_ENTRIES)
+                       if (got_allocate) {
+                               got_offset += arch_single_init(
+                                       rel, &intsym->gotent, 
+                                       got_offset, BB_GOT_ENTRY_SIZE);
+
+                               got_needed = 1;
+                       }
+#endif
+#if defined(BB_USE_PLT_ENTRIES)
+                       if (plt_allocate) {
+#if defined(BB_USE_PLT_LIST) 
+                               plt_offset += arch_list_add(
+                                       rel, &intsym->pltent, 
+                                       plt_offset, BB_PLT_ENTRY_SIZE);
+#else
+                               plt_offset += arch_single_init(
+                                       rel, &intsym->pltent, 
+                                       plt_offset, BB_PLT_ENTRY_SIZE);
+#endif
+                               plt_needed = 1;
+                       }
+#endif
+               }
+       }
+
+#if defined(BB_USE_GOT_ENTRIES)
+       if (got_needed) {
+               ifile->got = arch_xsect_init(f, ".got", got_offset,
+                                           BB_GOT_ENTRY_SIZE);
+       }
+#endif
+
+#if defined(BB_USE_PLT_ENTRIES)
+       if (plt_needed) {
+               ifile->plt = arch_xsect_init(f, ".plt", plt_offset,
+                                           BB_PLT_ENTRY_SIZE);
+       }
+#endif
+
+#endif /* defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) */
+}
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+static int arch_init_module(struct obj_file *f, struct new_module *mod)
+{
+       return 1;
+}
+#endif
+
+
+/*======================================================================*/
+
+/* Standard ELF hash function.  */
+static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n)
+{
+       unsigned long h = 0;
+       unsigned long g;
+       unsigned char ch;
+
+       while (n > 0) {
+               ch = *name++;
+               h = (h << 4) + ch;
+               if ((g = (h & 0xf0000000)) != 0) {
+                       h ^= g >> 24;
+                       h &= ~g;
+               }
+               n--;
+       }
+       return h;
+}
+
+static unsigned long obj_elf_hash(const char *name)
+{
+       return obj_elf_hash_n(name, strlen(name));
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+/* String comparison for non-co-versioned kernel and module.  */
+
+static int ncv_strcmp(const char *a, const char *b)
+{
+       size_t alen = strlen(a), blen = strlen(b);
+
+       if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
+               return strncmp(a, b, alen);
+       else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
+               return strncmp(a, b, blen);
+       else
+               return strcmp(a, b);
+}
+
+/* String hashing for non-co-versioned kernel and module.  Here
+   we are simply forced to drop the crc from the hash.  */
+
+static unsigned long ncv_symbol_hash(const char *str)
+{
+       size_t len = strlen(str);
+       if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
+               len -= 10;
+       return obj_elf_hash_n(str, len);
+}
+
+static void
+obj_set_symbol_compare(struct obj_file *f,
+                                          int (*cmp) (const char *, const char *),
+                                          unsigned long (*hash) (const char *))
+{
+       if (cmp)
+               f->symbol_cmp = cmp;
+       if (hash) {
+               struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+               int i;
+
+               f->symbol_hash = hash;
+
+               memcpy(tmptab, f->symtab, sizeof(tmptab));
+               memset(f->symtab, 0, sizeof(f->symtab));
+
+               for (i = 0; i < HASH_BUCKETS; ++i)
+                       for (sym = tmptab[i]; sym; sym = next) {
+                               unsigned long h = hash(sym->name) % HASH_BUCKETS;
+                               next = sym->next;
+                               sym->next = f->symtab[h];
+                               f->symtab[h] = sym;
+                       }
+       }
+}
+
+#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+static struct obj_symbol *
+obj_add_symbol(struct obj_file *f, const char *name,
+                                                                 unsigned long symidx, int info,
+                                                                 int secidx, ElfW(Addr) value,
+                                                                 unsigned long size)
+{
+       struct obj_symbol *sym;
+       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+       int n_type = ELFW(ST_TYPE) (info);
+       int n_binding = ELFW(ST_BIND) (info);
+
+       for (sym = f->symtab[hash]; sym; sym = sym->next)
+               if (f->symbol_cmp(sym->name, name) == 0) {
+                       int o_secidx = sym->secidx;
+                       int o_info = sym->info;
+                       int o_type = ELFW(ST_TYPE) (o_info);
+                       int o_binding = ELFW(ST_BIND) (o_info);
+
+                       /* A redefinition!  Is it legal?  */
+
+                       if (secidx == SHN_UNDEF)
+                               return sym;
+                       else if (o_secidx == SHN_UNDEF)
+                               goto found;
+                       else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
+                               /* Cope with local and global symbols of the same name
+                                  in the same object file, as might have been created
+                                  by ld -r.  The only reason locals are now seen at this
+                                  level at all is so that we can do semi-sensible things
+                                  with parameters.  */
+
+                               struct obj_symbol *nsym, **p;
+
+                               nsym = arch_new_symbol();
+                               nsym->next = sym->next;
+                               nsym->ksymidx = -1;
+
+                               /* Excise the old (local) symbol from the hash chain.  */
+                               for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+                                       continue;
+                               *p = sym = nsym;
+                               goto found;
+                       } else if (n_binding == STB_LOCAL) {
+                               /* Another symbol of the same name has already been defined.
+                                  Just add this to the local table.  */
+                               sym = arch_new_symbol();
+                               sym->next = NULL;
+                               sym->ksymidx = -1;
+                               f->local_symtab[symidx] = sym;
+                               goto found;
+                       } else if (n_binding == STB_WEAK)
+                               return sym;
+                       else if (o_binding == STB_WEAK)
+                               goto found;
+                       /* Don't unify COMMON symbols with object types the programmer
+                          doesn't expect.  */
+                       else if (secidx == SHN_COMMON
+                                        && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+                               return sym;
+                       else if (o_secidx == SHN_COMMON
+                                        && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+                               goto found;
+                       else {
+                               /* Don't report an error if the symbol is coming from
+                                  the kernel or some external module.  */
+                               if (secidx <= SHN_HIRESERVE)
+                                       error_msg("%s multiply defined", name);
+                               return sym;
+                       }
+               }
+
+       /* Completely new symbol.  */
+       sym = arch_new_symbol();
+       sym->next = f->symtab[hash];
+       f->symtab[hash] = sym;
+       sym->ksymidx = -1;
+
+       if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
+               if (symidx >= f->local_symtab_size)
+                       error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
+                                       name, (long) symidx, (long) f->local_symtab_size);
+               else
+                       f->local_symtab[symidx] = sym;
+       }
+
+  found:
+       sym->name = name;
+       sym->value = value;
+       sym->size = size;
+       sym->secidx = secidx;
+       sym->info = info;
+
+       return sym;
+}
+
+static struct obj_symbol *
+obj_find_symbol(struct obj_file *f, const char *name)
+{
+       struct obj_symbol *sym;
+       unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+
+       for (sym = f->symtab[hash]; sym; sym = sym->next)
+               if (f->symbol_cmp(sym->name, name) == 0)
+                       return sym;
+
+       return NULL;
+}
+
+static ElfW(Addr)
+       obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
+{
+       if (sym) {
+               if (sym->secidx >= SHN_LORESERVE)
+                       return sym->value;
+
+               return sym->value + f->sections[sym->secidx]->header.sh_addr;
+       } else {
+               /* As a special case, a NULL sym has value zero.  */
+               return 0;
+       }
+}
+
+static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
+{
+       int i, n = f->header.e_shnum;
+
+       for (i = 0; i < n; ++i)
+               if (strcmp(f->sections[i]->name, name) == 0)
+                       return f->sections[i];
+
+       return NULL;
+}
+
+static int obj_load_order_prio(struct obj_section *a)
+{
+       unsigned long af, ac;
+
+       af = a->header.sh_flags;
+
+       ac = 0;
+       if (a->name[0] != '.' || strlen(a->name) != 10 ||
+               strcmp(a->name + 5, ".init"))
+               ac |= 32;
+       if (af & SHF_ALLOC)
+               ac |= 16;
+       if (!(af & SHF_WRITE))
+               ac |= 8;
+       if (af & SHF_EXECINSTR)
+               ac |= 4;
+       if (a->header.sh_type != SHT_NOBITS)
+               ac |= 2;
+
+       return ac;
+}
+
+static void
+obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
+{
+       struct obj_section **p;
+       int prio = obj_load_order_prio(sec);
+       for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
+               if (obj_load_order_prio(*p) < prio)
+                       break;
+       sec->load_next = *p;
+       *p = sec;
+}
+
+static struct obj_section *obj_create_alloced_section(struct obj_file *f,
+                                                                                          const char *name,
+                                                                                          unsigned long align,
+                                                                                          unsigned long size)
+{
+       int newidx = f->header.e_shnum++;
+       struct obj_section *sec;
+
+       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+       f->sections[newidx] = sec = arch_new_section();
+
+       memset(sec, 0, sizeof(*sec));
+       sec->header.sh_type = SHT_PROGBITS;
+       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+       sec->header.sh_size = size;
+       sec->header.sh_addralign = align;
+       sec->name = name;
+       sec->idx = newidx;
+       if (size)
+               sec->contents = xmalloc(size);
+
+       obj_insert_section_load_order(f, sec);
+
+       return sec;
+}
+
+static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+                                                                                                        const char *name,
+                                                                                                        unsigned long align,
+                                                                                                        unsigned long size)
+{
+       int newidx = f->header.e_shnum++;
+       struct obj_section *sec;
+
+       f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
+       f->sections[newidx] = sec = arch_new_section();
+
+       memset(sec, 0, sizeof(*sec));
+       sec->header.sh_type = SHT_PROGBITS;
+       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+       sec->header.sh_size = size;
+       sec->header.sh_addralign = align;
+       sec->name = name;
+       sec->idx = newidx;
+       if (size)
+               sec->contents = xmalloc(size);
+
+       sec->load_next = f->load_order;
+       f->load_order = sec;
+       if (f->load_order_search_start == &f->load_order)
+               f->load_order_search_start = &sec->load_next;
+
+       return sec;
+}
+
+static void *obj_extend_section(struct obj_section *sec, unsigned long more)
+{
+       unsigned long oldsize = sec->header.sh_size;
+       if (more) { 
+               sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+       }
+       return sec->contents + oldsize;
+}
+
+
+/* Conditionally add the symbols from the given symbol set to the
+   new module.  */
+
+static int
+add_symbols_from(
+                                struct obj_file *f,
+                                int idx, struct new_module_symbol *syms, size_t nsyms)
+{
+       struct new_module_symbol *s;
+       size_t i;
+       int used = 0;
+
+       for (i = 0, s = syms; i < nsyms; ++i, ++s) {
+
+               /* Only add symbols that are already marked external.  If we
+                  override locals we may cause problems for argument initialization.
+                  We will also create a false dependency on the module.  */
+               struct obj_symbol *sym;
+
+               sym = obj_find_symbol(f, (char *) s->name);
+               if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
+                       sym = obj_add_symbol(f, (char *) s->name, -1,
+                                                                ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+                                                                idx, s->value, 0);
+                       /* Did our symbol just get installed?  If so, mark the
+                          module as "used".  */
+                       if (sym->secidx == idx)
+                               used = 1;
+               }
+       }
+
+       return used;
+}
+
+static void add_kernel_symbols(struct obj_file *f)
+{
+       struct external_module *m;
+       int i, nused = 0;
+
+       /* Add module symbols first.  */
+
+       for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m)
+               if (m->nsyms
+                       && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms,
+                                                               m->nsyms)) m->used = 1, ++nused;
+
+       n_ext_modules_used = nused;
+
+       /* And finally the symbols from the kernel proper.  */
+
+       if (nksyms)
+               add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
+}
+
+static char *get_modinfo_value(struct obj_file *f, const char *key)
+{
+       struct obj_section *sec;
+       char *p, *v, *n, *ep;
+       size_t klen = strlen(key);
+
+       sec = obj_find_section(f, ".modinfo");
+       if (sec == NULL)
+               return NULL;
+       p = sec->contents;
+       ep = p + sec->header.sh_size;
+       while (p < ep) {
+               v = strchr(p, '=');
+               n = strchr(p, '\0');
+               if (v) {
+                       if (p + klen == v && strncmp(p, key, klen) == 0)
+                               return v + 1;
+               } else {
+                       if (p + klen == n && strcmp(p, key) == 0)
+                               return n;
+               }
+               p = n + 1;
+       }
+
+       return NULL;
+}
+
+
+/*======================================================================*/
+/* Functions relating to module loading in pre 2.1 kernels.  */
+
+static int
+old_process_module_arguments(struct obj_file *f, int argc, char **argv)
+{
+       while (argc > 0) {
+               char *p, *q;
+               struct obj_symbol *sym;
+               int *loc;
+
+               p = *argv;
+               if ((q = strchr(p, '=')) == NULL) {
+                       argc--;
+                       continue;
+                }
+               *q++ = '\0';
+
+               sym = obj_find_symbol(f, p);
+
+               /* Also check that the parameter was not resolved from the kernel.  */
+               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+                       error_msg("symbol for parameter %s not found", p);
+                       return 0;
+               }
+
+               loc = (int *) (f->sections[sym->secidx]->contents + sym->value);
+
+               /* Do C quoting if we begin with a ".  */
+               if (*q == '"') {
+                       char *r, *str;
+
+                       str = alloca(strlen(q));
+                       for (r = str, q++; *q != '"'; ++q, ++r) {
+                               if (*q == '\0') {
+                                       error_msg("improperly terminated string argument for %s", p);
+                                       return 0;
+                               } else if (*q == '\\')
+                                       switch (*++q) {
+                                       case 'a':
+                                               *r = '\a';
+                                               break;
+                                       case 'b':
+                                               *r = '\b';
+                                               break;
+                                       case 'e':
+                                               *r = '\033';
+                                               break;
+                                       case 'f':
+                                               *r = '\f';
+                                               break;
+                                       case 'n':
+                                               *r = '\n';
+                                               break;
+                                       case 'r':
+                                               *r = '\r';
+                                               break;
+                                       case 't':
+                                               *r = '\t';
+                                               break;
+
+                                       case '0':
+                                       case '1':
+                                       case '2':
+                                       case '3':
+                                       case '4':
+                                       case '5':
+                                       case '6':
+                                       case '7':
+                                               {
+                                                       int c = *q - '0';
+                                                       if (q[1] >= '0' && q[1] <= '7') {
+                                                               c = (c * 8) + *++q - '0';
+                                                               if (q[1] >= '0' && q[1] <= '7')
+                                                                       c = (c * 8) + *++q - '0';
+                                                       }
+                                                       *r = c;
+                                               }
+                                               break;
+
+                                       default:
+                                               *r = *q;
+                                               break;
+                               } else
+                                       *r = *q;
+                       }
+                       *r = '\0';
+                       obj_string_patch(f, sym->secidx, sym->value, str);
+               } else if (*q >= '0' && *q <= '9') {
+                       do
+                               *loc++ = strtoul(q, &q, 0);
+                       while (*q++ == ',');
+               } else {
+                       char *contents = f->sections[sym->secidx]->contents;
+                       char *myloc = contents + sym->value;
+                       char *r;                        /* To search for commas */
+
+                       /* Break the string with comas */
+                       while ((r = strchr(q, ',')) != (char *) NULL) {
+                               *r++ = '\0';
+                               obj_string_patch(f, sym->secidx, myloc - contents, q);
+                               myloc += sizeof(char *);
+                               q = r;
+                       }
+
+                       /* last part */
+                       obj_string_patch(f, sym->secidx, myloc - contents, q);
+               }
+
+               argc--, argv++;
+       }
+
+       return 1;
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+static int old_is_module_checksummed(struct obj_file *f)
+{
+       return obj_find_symbol(f, "Using_Versions") != NULL;
+}
+/* Get the module's kernel version in the canonical integer form.  */
+
+static int
+old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+       struct obj_symbol *sym;
+       char *p, *q;
+       int a, b, c;
+
+       sym = obj_find_symbol(f, "kernel_version");
+       if (sym == NULL)
+               return -1;
+
+       p = f->sections[sym->secidx]->contents + sym->value;
+       safe_strncpy(str, p, STRVERSIONLEN);
+
+       a = strtoul(p, &p, 10);
+       if (*p != '.')
+               return -1;
+       b = strtoul(p + 1, &p, 10);
+       if (*p != '.')
+               return -1;
+       c = strtoul(p + 1, &q, 10);
+       if (p + 1 == q)
+               return -1;
+
+       return a << 16 | b << 8 | c;
+}
+
+#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
+
+/* Fetch all the symbols and divvy them up as appropriate for the modules.  */
+
+static int old_get_kernel_symbols(const char *m_name)
+{
+       struct old_kernel_sym *ks, *k;
+       struct new_module_symbol *s;
+       struct external_module *mod;
+       int nks, nms, nmod, i;
+
+       nks = get_kernel_syms(NULL);
+       if (nks <= 0) {
+               if (nks)
+                       perror_msg("get_kernel_syms: %s", m_name);
+               else
+                       error_msg("No kernel symbols");
+               return 0;
+       }
+
+       ks = k = xmalloc(nks * sizeof(*ks));
+
+       if (get_kernel_syms(ks) != nks) {
+               perror("inconsistency with get_kernel_syms -- is someone else "
+                          "playing with modules?");
+               free(ks);
+               return 0;
+       }
+
+       /* Collect the module information.  */
+
+       mod = NULL;
+       nmod = -1;
+
+       while (k->name[0] == '#' && k->name[1]) {
+               struct old_kernel_sym *k2;
+
+               /* Find out how many symbols this module has.  */
+               for (k2 = k + 1; k2->name[0] != '#'; ++k2)
+                       continue;
+               nms = k2 - k - 1;
+
+               mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod));
+               mod[nmod].name = k->name + 1;
+               mod[nmod].addr = k->value;
+               mod[nmod].used = 0;
+               mod[nmod].nsyms = nms;
+               mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
+
+               for (i = 0, ++k; i < nms; ++i, ++s, ++k) {
+                       s->name = (unsigned long) k->name;
+                       s->value = k->value;
+               }
+
+               k = k2;
+       }
+
+       ext_modules = mod;
+       n_ext_modules = nmod + 1;
+
+       /* Now collect the symbols for the kernel proper.  */
+
+       if (k->name[0] == '#')
+               ++k;
+
+       nksyms = nms = nks - (k - ks);
+       ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
+
+       for (i = 0; i < nms; ++i, ++s, ++k) {
+               s->name = (unsigned long) k->name;
+               s->value = k->value;
+       }
+
+       return 1;
+}
+
+/* Return the kernel symbol checksum version, or zero if not used.  */
+
+static int old_is_kernel_checksummed(void)
+{
+       /* Using_Versions is the first symbol.  */
+       if (nksyms > 0
+               && strcmp((char *) ksyms[0].name,
+                                 "Using_Versions") == 0) return ksyms[0].value;
+       else
+               return 0;
+}
+
+
+static int old_create_mod_use_count(struct obj_file *f)
+{
+       struct obj_section *sec;
+
+       sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long),
+                                                                                  sizeof(long));
+
+       obj_add_symbol(f, "mod_use_count_", -1,
+                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
+                                  sizeof(long));
+
+       return 1;
+}
+
+static int
+old_init_module(const char *m_name, struct obj_file *f,
+                               unsigned long m_size)
+{
+       char *image;
+       struct old_mod_routines routines;
+       struct old_symbol_table *symtab;
+       int ret;
+
+       /* Create the symbol table */
+       {
+               int nsyms = 0, strsize = 0, total;
+
+               /* Size things first... */
+               if (flag_export) {
+                       int i;
+                       for (i = 0; i < HASH_BUCKETS; ++i) {
+                               struct obj_symbol *sym;
+                               for (sym = f->symtab[i]; sym; sym = sym->next)
+                                       if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
+                                               && sym->secidx <= SHN_HIRESERVE) 
+                                       {
+                                               sym->ksymidx = nsyms++;
+                                               strsize += strlen(sym->name) + 1;
+                                       }
+                       }
+               }
+
+               total = (sizeof(struct old_symbol_table)
+                                + nsyms * sizeof(struct old_module_symbol)
+                                + n_ext_modules_used * sizeof(struct old_module_ref)
+                                + strsize);
+               symtab = xmalloc(total);
+               symtab->size = total;
+               symtab->n_symbols = nsyms;
+               symtab->n_refs = n_ext_modules_used;
+
+               if (flag_export && nsyms) {
+                       struct old_module_symbol *ksym;
+                       char *str;
+                       int i;
+
+                       ksym = symtab->symbol;
+                       str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol)
+                                  + n_ext_modules_used * sizeof(struct old_module_ref));
+
+                       for (i = 0; i < HASH_BUCKETS; ++i) {
+                               struct obj_symbol *sym;
+                               for (sym = f->symtab[i]; sym; sym = sym->next)
+                                       if (sym->ksymidx >= 0) {
+                                               ksym->addr = obj_symbol_final_value(f, sym);
+                                               ksym->name =
+                                                       (unsigned long) str - (unsigned long) symtab;
+
+                                               strcpy(str, sym->name);
+                                               str += strlen(sym->name) + 1;
+                                               ksym++;
+                                       }
+                       }
+               }
+
+               if (n_ext_modules_used) {
+                       struct old_module_ref *ref;
+                       int i;
+
+                       ref = (struct old_module_ref *)
+                               ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
+
+                       for (i = 0; i < n_ext_modules; ++i)
+                               if (ext_modules[i].used)
+                                       ref++->module = ext_modules[i].addr;
+               }
+       }
+
+       /* Fill in routines.  */
+
+       routines.init =
+               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+       routines.cleanup =
+               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+
+       /* Whew!  All of the initialization is complete.  Collect the final
+          module image and give it to the kernel.  */
+
+       image = xmalloc(m_size);
+       obj_create_image(f, image);
+
+       /* image holds the complete relocated module, accounting correctly for
+          mod_use_count.  However the old module kernel support assume that
+          it is receiving something which does not contain mod_use_count.  */
+       ret = old_sys_init_module(m_name, image + sizeof(long),
+                                                         m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN
+                                                                               : 0), &routines, symtab);
+       if (ret)
+               perror_msg("init_module: %s", m_name);
+
+       free(image);
+       free(symtab);
+
+       return ret == 0;
+}
+
+#else
+
+#define old_create_mod_use_count(x) TRUE
+#define old_init_module(x, y, z) TRUE
+
+#endif                                                 /* BB_FEATURE_OLD_MODULE_INTERFACE */
+
+
+
+/*======================================================================*/
+/* Functions relating to module loading after 2.1.18.  */
+
+static int
+new_process_module_arguments(struct obj_file *f, int argc, char **argv)
+{
+       while (argc > 0) {
+               char *p, *q, *key;
+               struct obj_symbol *sym;
+               char *contents, *loc;
+               int min, max, n;
+
+               p = *argv;
+               if ((q = strchr(p, '=')) == NULL) {
+                       argc--;
+                       continue;
+                }
+
+               key = alloca(q - p + 6);
+               memcpy(key, "parm_", 5);
+               memcpy(key + 5, p, q - p);
+               key[q - p + 5] = 0;
+
+               p = get_modinfo_value(f, key);
+               key += 5;
+               if (p == NULL) {
+                       error_msg("invalid parameter %s", key);
+                       return 0;
+               }
+
+               sym = obj_find_symbol(f, key);
+
+               /* Also check that the parameter was not resolved from the kernel.  */
+               if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+                       error_msg("symbol for parameter %s not found", key);
+                       return 0;
+               }
+
+               if (isdigit(*p)) {
+                       min = strtoul(p, &p, 10);
+                       if (*p == '-')
+                               max = strtoul(p + 1, &p, 10);
+                       else
+                               max = min;
+               } else
+                       min = max = 1;
+
+               contents = f->sections[sym->secidx]->contents;
+               loc = contents + sym->value;
+               n = (*++q != '\0');
+
+               while (1) {
+                       if ((*p == 's') || (*p == 'c')) {
+                               char *str;
+
+                               /* Do C quoting if we begin with a ", else slurp the lot.  */
+                               if (*q == '"') {
+                                       char *r;
+
+                                       str = alloca(strlen(q));
+                                       for (r = str, q++; *q != '"'; ++q, ++r) {
+                                               if (*q == '\0') {
+                                                       error_msg("improperly terminated string argument for %s",
+                                                                       key);
+                                                       return 0;
+                                               } else if (*q == '\\')
+                                                       switch (*++q) {
+                                                       case 'a':
+                                                               *r = '\a';
+                                                               break;
+                                                       case 'b':
+                                                               *r = '\b';
+                                                               break;
+                                                       case 'e':
+                                                               *r = '\033';
+                                                               break;
+                                                       case 'f':
+                                                               *r = '\f';
+                                                               break;
+                                                       case 'n':
+                                                               *r = '\n';
+                                                               break;
+                                                       case 'r':
+                                                               *r = '\r';
+                                                               break;
+                                                       case 't':
+                                                               *r = '\t';
+                                                               break;
+
+                                                       case '0':
+                                                       case '1':
+                                                       case '2':
+                                                       case '3':
+                                                       case '4':
+                                                       case '5':
+                                                       case '6':
+                                                       case '7':
+                                                               {
+                                                                       int c = *q - '0';
+                                                                       if (q[1] >= '0' && q[1] <= '7') {
+                                                                               c = (c * 8) + *++q - '0';
+                                                                               if (q[1] >= '0' && q[1] <= '7')
+                                                                                       c = (c * 8) + *++q - '0';
+                                                                       }
+                                                                       *r = c;
+                                                               }
+                                                               break;
+
+                                                       default:
+                                                               *r = *q;
+                                                               break;
+                                               } else
+                                                       *r = *q;
+                                       }
+                                       *r = '\0';
+                                       ++q;
+                               } else {
+                                       char *r;
+
+                                       /* In this case, the string is not quoted. We will break
+                                          it using the coma (like for ints). If the user wants to
+                                          include comas in a string, he just has to quote it */
+
+                                       /* Search the next coma */
+                                       r = strchr(q, ',');
+
+                                       /* Found ? */
+                                       if (r != (char *) NULL) {
+                                               /* Recopy the current field */
+                                               str = alloca(r - q + 1);
+                                               memcpy(str, q, r - q);
+
+                                               /* I don't know if it is usefull, as the previous case
+                                                  doesn't null terminate the string ??? */
+                                               str[r - q] = '\0';
+
+                                               /* Keep next fields */
+                                               q = r;
+                                       } else {
+                                               /* last string */
+                                               str = q;
+                                               q = "";
+                                       }
+                               }
+
+                               if (*p == 's') {
+                                       /* Normal string */
+                                       obj_string_patch(f, sym->secidx, loc - contents, str);
+                                       loc += tgt_sizeof_char_p;
+                               } else {
+                                       /* Array of chars (in fact, matrix !) */
+                                       unsigned long charssize;        /* size of each member */
+
+                                       /* Get the size of each member */
+                                       /* Probably we should do that outside the loop ? */
+                                       if (!isdigit(*(p + 1))) {
+                                               error_msg("parameter type 'c' for %s must be followed by"
+                                                               " the maximum size", key);
+                                               return 0;
+                                       }
+                                       charssize = strtoul(p + 1, (char **) NULL, 10);
+
+                                       /* Check length */
+                                       if (strlen(str) >= charssize) {
+                                               error_msg("string too long for %s (max %ld)", key,
+                                                               charssize - 1);
+                                               return 0;
+                                       }
+
+                                       /* Copy to location */
+                                       strcpy((char *) loc, str);
+                                       loc += charssize;
+                               }
+                       } else {
+                               long v = strtoul(q, &q, 0);
+                               switch (*p) {
+                               case 'b':
+                                       *loc++ = v;
+                                       break;
+                               case 'h':
+                                       *(short *) loc = v;
+                                       loc += tgt_sizeof_short;
+                                       break;
+                               case 'i':
+                                       *(int *) loc = v;
+                                       loc += tgt_sizeof_int;
+                                       break;
+                               case 'l':
+                                       *(long *) loc = v;
+                                       loc += tgt_sizeof_long;
+                                       break;
+
+                               default:
+                                       error_msg("unknown parameter type '%c' for %s", *p, key);
+                                       return 0;
+                               }
+                       }
+
+                 retry_end_of_value:
+                       switch (*q) {
+                       case '\0':
+                               goto end_of_arg;
+
+                       case ' ':
+                       case '\t':
+                       case '\n':
+                       case '\r':
+                               ++q;
+                               goto retry_end_of_value;
+
+                       case ',':
+                               if (++n > max) {
+                                       error_msg("too many values for %s (max %d)", key, max);
+                                       return 0;
+                               }
+                               ++q;
+                               break;
+
+                       default:
+                               error_msg("invalid argument syntax for %s", key);
+                               return 0;
+                       }
+               }
+
+         end_of_arg:
+               if (n < min) {
+                       error_msg("too few values for %s (min %d)", key, min);
+                       return 0;
+               }
+
+               argc--, argv++;
+       }
+
+       return 1;
+}
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+static int new_is_module_checksummed(struct obj_file *f)
+{
+       const char *p = get_modinfo_value(f, "using_checksums");
+       if (p)
+               return atoi(p);
+       else
+               return 0;
+}
+
+/* Get the module's kernel version in the canonical integer form.  */
+
+static int
+new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+       char *p, *q;
+       int a, b, c;
+
+       p = get_modinfo_value(f, "kernel_version");
+       if (p == NULL)
+               return -1;
+       safe_strncpy(str, p, STRVERSIONLEN);
+
+       a = strtoul(p, &p, 10);
+       if (*p != '.')
+               return -1;
+       b = strtoul(p + 1, &p, 10);
+       if (*p != '.')
+               return -1;
+       c = strtoul(p + 1, &q, 10);
+       if (p + 1 == q)
+               return -1;
+
+       return a << 16 | b << 8 | c;
+}
+
+#endif   /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+
+/* Fetch the loaded modules, and all currently exported symbols.  */
+
+static int new_get_kernel_symbols(void)
+{
+       char *module_names, *mn;
+       struct external_module *modules, *m;
+       struct new_module_symbol *syms, *s;
+       size_t ret, bufsize, nmod, nsyms, i, j;
+
+       /* Collect the loaded modules.  */
+
+       module_names = xmalloc(bufsize = 256);
+  retry_modules_load:
+       if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+               if (errno == ENOSPC && bufsize < ret) {
+                       module_names = xrealloc(module_names, bufsize = ret);
+                       goto retry_modules_load;
+               }
+               perror_msg("QM_MODULES");
+               return 0;
+       }
+
+       n_ext_modules = nmod = ret;
+
+       /* Collect the modules' symbols.  */
+
+       if (nmod){
+               ext_modules = modules = xmalloc(nmod * sizeof(*modules));
+               memset(modules, 0, nmod * sizeof(*modules));
+               for (i = 0, mn = module_names, m = modules;
+                        i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
+                       struct new_module_info info;
+       
+                       if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+                               if (errno == ENOENT) {
+                                       /* The module was removed out from underneath us.  */
+                                       continue;
+                               }
+                               perror_msg("query_module: QM_INFO: %s", mn);
+                               return 0;
+                       }
+       
+                       syms = xmalloc(bufsize = 1024);
+                 retry_mod_sym_load:
+                       if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+                               switch (errno) {
+                               case ENOSPC:
+                                       syms = xrealloc(syms, bufsize = ret);
+                                       goto retry_mod_sym_load;
+                               case ENOENT:
+                                       /* The module was removed out from underneath us.  */
+                                       continue;
+                               default:
+                                       perror_msg("query_module: QM_SYMBOLS: %s", mn);
+                                       return 0;
+                               }
+                       }
+                       nsyms = ret;
+       
+                       m->name = mn;
+                       m->addr = info.addr;
+                       m->nsyms = nsyms;
+                       m->syms = syms;
+       
+                       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+                               s->name += (unsigned long) syms;
+                       }
+               }
+       }
+
+       /* Collect the kernel's symbols.  */
+
+       syms = xmalloc(bufsize = 16 * 1024);
+  retry_kern_sym_load:
+       if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+               if (errno == ENOSPC && bufsize < ret) {
+                       syms = xrealloc(syms, bufsize = ret);
+                       goto retry_kern_sym_load;
+               }
+               perror_msg("kernel: QM_SYMBOLS");
+               return 0;
+       }
+       nksyms = nsyms = ret;
+       ksyms = syms;
+
+       for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+               s->name += (unsigned long) syms;
+       }
+       return 1;
+}
+
+
+/* Return the kernel symbol checksum version, or zero if not used.  */
+
+static int new_is_kernel_checksummed(void)
+{
+       struct new_module_symbol *s;
+       size_t i;
+
+       /* Using_Versions is not the first symbol, but it should be in there.  */
+
+       for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
+               if (strcmp((char *) s->name, "Using_Versions") == 0)
+                       return s->value;
+
+       return 0;
+}
+
+
+static int new_create_this_module(struct obj_file *f, const char *m_name)
+{
+       struct obj_section *sec;
+
+       sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
+                                                                                  sizeof(struct new_module));
+       memset(sec->contents, 0, sizeof(struct new_module));
+
+       obj_add_symbol(f, "__this_module", -1,
+                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
+                                  sizeof(struct new_module));
+
+       obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
+                                        m_name);
+
+       return 1;
+}
+
+
+static int new_create_module_ksymtab(struct obj_file *f)
+{
+       struct obj_section *sec;
+       int i;
+
+       /* We must always add the module references.  */
+
+       if (n_ext_modules_used) {
+               struct new_module_ref *dep;
+               struct obj_symbol *tm;
+
+               sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
+                                                                                (sizeof(struct new_module_ref)
+                                                                                 * n_ext_modules_used));
+               if (!sec)
+                       return 0;
+
+               tm = obj_find_symbol(f, "__this_module");
+               dep = (struct new_module_ref *) sec->contents;
+               for (i = 0; i < n_ext_modules; ++i)
+                       if (ext_modules[i].used) {
+                               dep->dep = ext_modules[i].addr;
+                               obj_symbol_patch(f, sec->idx,
+                                                                (char *) &dep->ref - sec->contents, tm);
+                               dep->next_ref = 0;
+                               ++dep;
+                       }
+       }
+
+       if (flag_export && !obj_find_section(f, "__ksymtab")) {
+               size_t nsyms;
+               int *loaded;
+
+               sec =
+                       obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p,
+                                                                          0);
+
+               /* We don't want to export symbols residing in sections that
+                  aren't loaded.  There are a number of these created so that
+                  we make sure certain module options don't appear twice.  */
+
+               loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+               while (--i >= 0)
+                       loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+               for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
+                       struct obj_symbol *sym;
+                       for (sym = f->symtab[i]; sym; sym = sym->next)
+                               if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
+                                       && sym->secidx <= SHN_HIRESERVE
+                                       && (sym->secidx >= SHN_LORESERVE
+                                               || loaded[sym->secidx])) {
+                                       ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
+
+                                       obj_symbol_patch(f, sec->idx, ofs, sym);
+                                       obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
+                                                                        sym->name);
+
+                                       nsyms++;
+                               }
+               }
+
+               obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
+       }
+
+       return 1;
+}
+
+
+static int
+new_init_module(const char *m_name, struct obj_file *f,
+                               unsigned long m_size)
+{
+       struct new_module *module;
+       struct obj_section *sec;
+       void *image;
+       int ret;
+       tgt_long m_addr;
+
+       sec = obj_find_section(f, ".this");
+       if (!sec || !sec->contents) { 
+               perror_msg_and_die("corrupt module %s?",m_name);
+       }
+       module = (struct new_module *) sec->contents;
+       m_addr = sec->header.sh_addr;
+
+       module->size_of_struct = sizeof(*module);
+       module->size = m_size;
+       module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
+
+       sec = obj_find_section(f, "__ksymtab");
+       if (sec && sec->header.sh_size) {
+               module->syms = sec->header.sh_addr;
+               module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
+       }
+
+       if (n_ext_modules_used) {
+               sec = obj_find_section(f, ".kmodtab");
+               module->deps = sec->header.sh_addr;
+               module->ndeps = n_ext_modules_used;
+       }
+
+       module->init =
+               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+       module->cleanup =
+               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+
+       sec = obj_find_section(f, "__ex_table");
+       if (sec) {
+               module->ex_table_start = sec->header.sh_addr;
+               module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
+       }
+
+       sec = obj_find_section(f, ".text.init");
+       if (sec) {
+               module->runsize = sec->header.sh_addr - m_addr;
+       }
+       sec = obj_find_section(f, ".data.init");
+       if (sec) {
+               if (!module->runsize ||
+                       module->runsize > sec->header.sh_addr - m_addr)
+                               module->runsize = sec->header.sh_addr - m_addr;
+       }
+       sec = obj_find_section(f, ARCHDATA_SEC_NAME);
+       if (sec && sec->header.sh_size) {
+               module->archdata_start = (void*)sec->header.sh_addr;
+               module->archdata_end = module->archdata_start + sec->header.sh_size;
+       }
+       sec = obj_find_section(f, KALLSYMS_SEC_NAME);
+       if (sec && sec->header.sh_size) {
+               module->kallsyms_start = (void*)sec->header.sh_addr;
+               module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
+       }
+
+       if (!arch_init_module(f, module))
+               return 0;
+
+       /* Whew!  All of the initialization is complete.  Collect the final
+          module image and give it to the kernel.  */
+
+       image = xmalloc(m_size);
+       obj_create_image(f, image);
+
+       ret = new_sys_init_module(m_name, (struct new_module *) image);
+       if (ret)
+               perror_msg("init_module: %s", m_name);
+
+       free(image);
+
+       return ret == 0;
+}
+
+#else
+
+#define new_init_module(x, y, z) TRUE
+#define new_create_this_module(x, y) 0
+#define new_create_module_ksymtab(x)
+#define query_module(v, w, x, y, z) -1
+
+#endif                                                 /* BB_FEATURE_NEW_MODULE_INTERFACE */
+
+
+/*======================================================================*/
+
+static int
+obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+                                const char *string)
+{
+       struct obj_string_patch *p;
+       struct obj_section *strsec;
+       size_t len = strlen(string) + 1;
+       char *loc;
+
+       p = xmalloc(sizeof(*p));
+       p->next = f->string_patches;
+       p->reloc_secidx = secidx;
+       p->reloc_offset = offset;
+       f->string_patches = p;
+
+       strsec = obj_find_section(f, ".kstrtab");
+       if (strsec == NULL) {
+               strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+               p->string_offset = 0;
+               loc = strsec->contents;
+       } else {
+               p->string_offset = strsec->header.sh_size;
+               loc = obj_extend_section(strsec, len);
+       }
+       memcpy(loc, string, len);
+
+       return 1;
+}
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+static int
+obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+                                struct obj_symbol *sym)
+{
+       struct obj_symbol_patch *p;
+
+       p = xmalloc(sizeof(*p));
+       p->next = f->symbol_patches;
+       p->reloc_secidx = secidx;
+       p->reloc_offset = offset;
+       p->sym = sym;
+       f->symbol_patches = p;
+
+       return 1;
+}
+#endif
+
+static int obj_check_undefineds(struct obj_file *f)
+{
+       unsigned long i;
+       int ret = 1;
+
+       for (i = 0; i < HASH_BUCKETS; ++i) {
+               struct obj_symbol *sym;
+               for (sym = f->symtab[i]; sym; sym = sym->next)
+                       if (sym->secidx == SHN_UNDEF) {
+                               if (ELFW(ST_BIND) (sym->info) == STB_WEAK) {
+                                       sym->secidx = SHN_ABS;
+                                       sym->value = 0;
+                               } else {
+                                       if (!flag_quiet) {
+                                               error_msg("unresolved symbol %s", sym->name);
+                                       }
+                                       ret = 0;
+                               }
+                       }
+       }
+
+       return ret;
+}
+
+static void obj_allocate_commons(struct obj_file *f)
+{
+       struct common_entry {
+               struct common_entry *next;
+               struct obj_symbol *sym;
+       } *common_head = NULL;
+
+       unsigned long i;
+
+       for (i = 0; i < HASH_BUCKETS; ++i) {
+               struct obj_symbol *sym;
+               for (sym = f->symtab[i]; sym; sym = sym->next)
+                       if (sym->secidx == SHN_COMMON) {
+                               /* Collect all COMMON symbols and sort them by size so as to
+                                  minimize space wasted by alignment requirements.  */
+                               {
+                                       struct common_entry **p, *n;
+                                       for (p = &common_head; *p; p = &(*p)->next)
+                                               if (sym->size <= (*p)->sym->size)
+                                                       break;
+
+                                       n = alloca(sizeof(*n));
+                                       n->next = *p;
+                                       n->sym = sym;
+                                       *p = n;
+                               }
+                       }
+       }
+
+       for (i = 1; i < f->local_symtab_size; ++i) {
+               struct obj_symbol *sym = f->local_symtab[i];
+               if (sym && sym->secidx == SHN_COMMON) {
+                       struct common_entry **p, *n;
+                       for (p = &common_head; *p; p = &(*p)->next)
+                               if (sym == (*p)->sym)
+                                       break;
+                               else if (sym->size < (*p)->sym->size) {
+                                       n = alloca(sizeof(*n));
+                                       n->next = *p;
+                                       n->sym = sym;
+                                       *p = n;
+                                       break;
+                               }
+               }
+       }
+
+       if (common_head) {
+               /* Find the bss section.  */
+               for (i = 0; i < f->header.e_shnum; ++i)
+                       if (f->sections[i]->header.sh_type == SHT_NOBITS)
+                               break;
+
+               /* If for some reason there hadn't been one, create one.  */
+               if (i == f->header.e_shnum) {
+                       struct obj_section *sec;
+
+                       f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec));
+                       f->sections[i] = sec = arch_new_section();
+                       f->header.e_shnum = i + 1;
+
+                       memset(sec, 0, sizeof(*sec));
+                       sec->header.sh_type = SHT_PROGBITS;
+                       sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+                       sec->name = ".bss";
+                       sec->idx = i;
+               }
+
+               /* Allocate the COMMONS.  */
+               {
+                       ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+                       ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+                       struct common_entry *c;
+
+                       for (c = common_head; c; c = c->next) {
+                               ElfW(Addr) align = c->sym->value;
+
+                               if (align > max_align)
+                                       max_align = align;
+                               if (bss_size & (align - 1))
+                                       bss_size = (bss_size | (align - 1)) + 1;
+
+                               c->sym->secidx = i;
+                               c->sym->value = bss_size;
+
+                               bss_size += c->sym->size;
+                       }
+
+                       f->sections[i]->header.sh_size = bss_size;
+                       f->sections[i]->header.sh_addralign = max_align;
+               }
+       }
+
+       /* For the sake of patch relocation and parameter initialization,
+          allocate zeroed data for NOBITS sections now.  Note that after
+          this we cannot assume NOBITS are really empty.  */
+       for (i = 0; i < f->header.e_shnum; ++i) {
+               struct obj_section *s = f->sections[i];
+               if (s->header.sh_type == SHT_NOBITS) {
+                       if (s->header.sh_size != 0)
+                       s->contents = memset(xmalloc(s->header.sh_size),
+                                                                0, s->header.sh_size);
+                       else
+                               s->contents = NULL;
+
+                       s->header.sh_type = SHT_PROGBITS;
+               }
+       }
+}
+
+static unsigned long obj_load_size(struct obj_file *f)
+{
+       unsigned long dot = 0;
+       struct obj_section *sec;
+
+       /* Finalize the positions of the sections relative to one another.  */
+
+       for (sec = f->load_order; sec; sec = sec->load_next) {
+               ElfW(Addr) align;
+
+               align = sec->header.sh_addralign;
+               if (align && (dot & (align - 1)))
+                       dot = (dot | (align - 1)) + 1;
+
+               sec->header.sh_addr = dot;
+               dot += sec->header.sh_size;
+       }
+
+       return dot;
+}
+
+static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
+{
+       int i, n = f->header.e_shnum;
+       int ret = 1;
+
+       /* Finalize the addresses of the sections.  */
+
+       f->baseaddr = base;
+       for (i = 0; i < n; ++i)
+               f->sections[i]->header.sh_addr += base;
+
+       /* And iterate over all of the relocations.  */
+
+       for (i = 0; i < n; ++i) {
+               struct obj_section *relsec, *symsec, *targsec, *strsec;
+               ElfW(RelM) * rel, *relend;
+               ElfW(Sym) * symtab;
+               const char *strtab;
+
+               relsec = f->sections[i];
+               if (relsec->header.sh_type != SHT_RELM)
+                       continue;
+
+               symsec = f->sections[relsec->header.sh_link];
+               targsec = f->sections[relsec->header.sh_info];
+               strsec = f->sections[symsec->header.sh_link];
+
+               rel = (ElfW(RelM) *) relsec->contents;
+               relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+               symtab = (ElfW(Sym) *) symsec->contents;
+               strtab = (const char *) strsec->contents;
+
+               for (; rel < relend; ++rel) {
+                       ElfW(Addr) value = 0;
+                       struct obj_symbol *intsym = NULL;
+                       unsigned long symndx;
+                       ElfW(Sym) * extsym = 0;
+                       const char *errmsg;
+
+                       /* Attempt to find a value to use for this relocation.  */
+
+                       symndx = ELFW(R_SYM) (rel->r_info);
+                       if (symndx) {
+                               /* Note we've already checked for undefined symbols.  */
+
+                               extsym = &symtab[symndx];
+                               if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) {
+                                       /* Local symbols we look up in the local table to be sure
+                                          we get the one that is really intended.  */
+                                       intsym = f->local_symtab[symndx];
+                               } else {
+                                       /* Others we look up in the hash table.  */
+                                       const char *name;
+                                       if (extsym->st_name)
+                                               name = strtab + extsym->st_name;
+                                       else
+                                               name = f->sections[extsym->st_shndx]->name;
+                                       intsym = obj_find_symbol(f, name);
+                               }
+
+                               value = obj_symbol_final_value(f, intsym);
+                               intsym->referenced = 1;
+                       }
+#if SHT_RELM == SHT_RELA
+#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+                       /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9.  */
+                       if (!extsym || !extsym->st_name ||
+                               ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL)
+#endif
+                               value += rel->r_addend;
+#endif
+
+                       /* Do it! */
+                       switch (arch_apply_relocation
+                                       (f, targsec, symsec, intsym, rel, value)) {
+                       case obj_reloc_ok:
+                               break;
+
+                       case obj_reloc_overflow:
+                               errmsg = "Relocation overflow";
+                               goto bad_reloc;
+                       case obj_reloc_dangerous:
+                               errmsg = "Dangerous relocation";
+                               goto bad_reloc;
+                       case obj_reloc_unhandled:
+                               errmsg = "Unhandled relocation";
+                         bad_reloc:
+                               if (extsym) {
+                                       error_msg("%s of type %ld for %s", errmsg,
+                                                       (long) ELFW(R_TYPE) (rel->r_info),
+                                                       strtab + extsym->st_name);
+                               } else {
+                                       error_msg("%s of type %ld", errmsg,
+                                                       (long) ELFW(R_TYPE) (rel->r_info));
+                               }
+                               ret = 0;
+                               break;
+                       }
+               }
+       }
+
+       /* Finally, take care of the patches.  */
+
+       if (f->string_patches) {
+               struct obj_string_patch *p;
+               struct obj_section *strsec;
+               ElfW(Addr) strsec_base;
+               strsec = obj_find_section(f, ".kstrtab");
+               strsec_base = strsec->header.sh_addr;
+
+               for (p = f->string_patches; p; p = p->next) {
+                       struct obj_section *targsec = f->sections[p->reloc_secidx];
+                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+                               = strsec_base + p->string_offset;
+               }
+       }
+
+       if (f->symbol_patches) {
+               struct obj_symbol_patch *p;
+
+               for (p = f->symbol_patches; p; p = p->next) {
+                       struct obj_section *targsec = f->sections[p->reloc_secidx];
+                       *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+                               = obj_symbol_final_value(f, p->sym);
+               }
+       }
+
+       return ret;
+}
+
+static int obj_create_image(struct obj_file *f, char *image)
+{
+       struct obj_section *sec;
+       ElfW(Addr) base = f->baseaddr;
+
+       for (sec = f->load_order; sec; sec = sec->load_next) {
+               char *secimg;
+
+               if (sec->contents == 0 || sec->header.sh_size == 0)
+                       continue;
+
+               secimg = image + (sec->header.sh_addr - base);
+
+               /* Note that we allocated data for NOBITS sections earlier.  */
+               memcpy(secimg, sec->contents, sec->header.sh_size);
+       }
+
+       return 1;
+}
+
+/*======================================================================*/
+
+static struct obj_file *obj_load(FILE * fp, int loadprogbits)
+{
+       struct obj_file *f;
+       ElfW(Shdr) * section_headers;
+       int shnum, i;
+       char *shstrtab;
+
+       /* Read the file header.  */
+
+       f = arch_new_file();
+       memset(f, 0, sizeof(*f));
+       f->symbol_cmp = strcmp;
+       f->symbol_hash = obj_elf_hash;
+       f->load_order_search_start = &f->load_order;
+
+       fseek(fp, 0, SEEK_SET);
+       if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
+               perror_msg("error reading ELF header");
+               return NULL;
+       }
+
+       if (f->header.e_ident[EI_MAG0] != ELFMAG0
+               || f->header.e_ident[EI_MAG1] != ELFMAG1
+               || f->header.e_ident[EI_MAG2] != ELFMAG2
+               || f->header.e_ident[EI_MAG3] != ELFMAG3) {
+               error_msg("not an ELF file");
+               return NULL;
+       }
+       if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+               || f->header.e_ident[EI_DATA] != ELFDATAM
+               || f->header.e_ident[EI_VERSION] != EV_CURRENT
+               || !MATCH_MACHINE(f->header.e_machine)) {
+               error_msg("ELF file not for this architecture");
+               return NULL;
+       }
+       if (f->header.e_type != ET_REL) {
+               error_msg("ELF file not a relocatable object");
+               return NULL;
+       }
+
+       /* Read the section headers.  */
+
+       if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
+               error_msg("section header size mismatch: %lu != %lu",
+                               (unsigned long) f->header.e_shentsize,
+                               (unsigned long) sizeof(ElfW(Shdr)));
+               return NULL;
+       }
+
+       shnum = f->header.e_shnum;
+       f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
+       memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
+
+       section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+       fseek(fp, f->header.e_shoff, SEEK_SET);
+       if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
+               perror_msg("error reading ELF section headers");
+               return NULL;
+       }
+
+       /* Read the section data.  */
+
+       for (i = 0; i < shnum; ++i) {
+               struct obj_section *sec;
+
+               f->sections[i] = sec = arch_new_section();
+               memset(sec, 0, sizeof(*sec));
+
+               sec->header = section_headers[i];
+               sec->idx = i;
+
+               if(sec->header.sh_size) switch (sec->header.sh_type) {
+               case SHT_NULL:
+               case SHT_NOTE:
+               case SHT_NOBITS:
+                       /* ignore */
+                       break;
+
+               case SHT_PROGBITS:
+#if LOADBITS
+                       if (!loadprogbits) {
+                               sec->contents = NULL;
+                               break;
+                       }
+#endif                 
+               case SHT_SYMTAB:
+               case SHT_STRTAB:
+               case SHT_RELM:
+                       if (sec->header.sh_size > 0) {
+                               sec->contents = xmalloc(sec->header.sh_size);
+                               fseek(fp, sec->header.sh_offset, SEEK_SET);
+                               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+                                       perror_msg("error reading ELF section data");
+                                       return NULL;
+                               }
+                       } else {
+                               sec->contents = NULL;
+                       }
+                       break;
+
+#if SHT_RELM == SHT_REL
+               case SHT_RELA:
+                       error_msg("RELA relocations not supported on this architecture");
+                       return NULL;
+#else
+               case SHT_REL:
+                       error_msg("REL relocations not supported on this architecture");
+                       return NULL;
+#endif
+
+               default:
+                       if (sec->header.sh_type >= SHT_LOPROC) {
+                               /* Assume processor specific section types are debug
+                                  info and can safely be ignored.  If this is ever not
+                                  the case (Hello MIPS?), don't put ifdefs here but
+                                  create an arch_load_proc_section().  */
+                               break;
+                       }
+
+                       error_msg("can't handle sections of type %ld",
+                                       (long) sec->header.sh_type);
+                       return NULL;
+               }
+       }
+
+       /* Do what sort of interpretation as needed by each section.  */
+
+       shstrtab = f->sections[f->header.e_shstrndx]->contents;
+
+       for (i = 0; i < shnum; ++i) {
+               struct obj_section *sec = f->sections[i];
+               sec->name = shstrtab + sec->header.sh_name;
+       }
+
+       for (i = 0; i < shnum; ++i) {
+               struct obj_section *sec = f->sections[i];
+
+               /* .modinfo should be contents only but gcc has no attribute for that.
+                * The kernel may have marked .modinfo as ALLOC, ignore this bit.
+                */
+               if (strcmp(sec->name, ".modinfo") == 0)
+                       sec->header.sh_flags &= ~SHF_ALLOC;
+
+               if (sec->header.sh_flags & SHF_ALLOC)
+                       obj_insert_section_load_order(f, sec);
+
+               switch (sec->header.sh_type) {
+               case SHT_SYMTAB:
+                       {
+                               unsigned long nsym, j;
+                               char *strtab;
+                               ElfW(Sym) * sym;
+
+                               if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
+                                       error_msg("symbol size mismatch: %lu != %lu",
+                                                       (unsigned long) sec->header.sh_entsize,
+                                                       (unsigned long) sizeof(ElfW(Sym)));
+                                       return NULL;
+                               }
+
+                               nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+                               strtab = f->sections[sec->header.sh_link]->contents;
+                               sym = (ElfW(Sym) *) sec->contents;
+
+                               /* Allocate space for a table of local symbols.  */
+                               j = f->local_symtab_size = sec->header.sh_info;
+                               f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *));
+
+                               /* Insert all symbols into the hash table.  */
+                               for (j = 1, ++sym; j < nsym; ++j, ++sym) {
+                                       const char *name;
+                                       if (sym->st_name)
+                                               name = strtab + sym->st_name;
+                                       else
+                                               name = f->sections[sym->st_shndx]->name;
+
+                                       obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+                                                                  sym->st_value, sym->st_size);
+                               }
+                       }
+                       break;
+
+               case SHT_RELM:
+                       if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
+                               error_msg("relocation entry size mismatch: %lu != %lu",
+                                               (unsigned long) sec->header.sh_entsize,
+                                               (unsigned long) sizeof(ElfW(RelM)));
+                               return NULL;
+                       }
+                       break;
+                       /* XXX  Relocation code from modutils-2.3.19 is not here.
+                        * Why?  That's about 20 lines of code from obj/obj_load.c,
+                        * which gets done in a second pass through the sections.
+                        * This BusyBox insmod does similar work in obj_relocate(). */
+               }
+       }
+
+       return f;
+}
+
+#ifdef BB_FEATURE_INSMOD_LOADINKMEM
+/*
+ * load the unloaded sections directly into the memory allocated by
+ * kernel for the module
+ */
+
+static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
+{
+       ElfW(Addr) base = f->baseaddr;
+       struct obj_section* sec;
+       
+       for (sec = f->load_order; sec; sec = sec->load_next) {
+
+               /* section already loaded? */
+               if (sec->contents != NULL)
+                       continue;
+               
+               if (sec->header.sh_size == 0)
+                       continue;
+
+               sec->contents = imagebase + (sec->header.sh_addr - base);
+               fseek(fp, sec->header.sh_offset, SEEK_SET);
+               if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+                       error_msg("error reading ELF section data: %s\n", strerror(errno));
+                       return 0;
+               }
+
+       }
+       return 1;
+}
+#endif
+
+static void hide_special_symbols(struct obj_file *f)
+{
+       static const char *const specials[] = {
+               "cleanup_module",
+               "init_module",
+               "kernel_version",
+               NULL
+       };
+
+       struct obj_symbol *sym;
+       const char *const *p;
+
+       for (p = specials; *p; ++p)
+               if ((sym = obj_find_symbol(f, *p)) != NULL)
+                       sym->info =
+                               ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
+}
+
+static int obj_gpl_license(struct obj_file *f, const char **license)
+{
+       struct obj_section *sec;
+       /* This list must match *exactly* the list of allowable licenses in
+        * linux/include/linux/module.h.  Checking for leading "GPL" will not
+        * work, somebody will use "GPL sucks, this is proprietary".
+        */
+       static const char *gpl_licenses[] = {
+               "GPL",
+               "GPL v2",
+               "GPL and additional rights",
+               "Dual BSD/GPL",
+               "Dual MPL/GPL",
+       };
+
+       if ((sec = obj_find_section(f, ".modinfo"))) {
+               const char *value, *ptr, *endptr;
+               ptr = sec->contents;
+               endptr = ptr + sec->header.sh_size;
+               while (ptr < endptr) {
+                       if ((value = strchr(ptr, '=')) && strncmp(ptr, "license", value-ptr) == 0) {
+                               int i;
+                               if (license)
+                                       *license = value+1;
+                               for (i = 0; i < sizeof(gpl_licenses)/sizeof(gpl_licenses[0]); ++i) {
+                                       if (strcmp(value+1, gpl_licenses[i]) == 0)
+                                               return(0);
+                               }
+                               return(2);
+                       }
+                       if (strchr(ptr, '\0'))
+                               ptr = strchr(ptr, '\0') + 1;
+                       else
+                               ptr = endptr;
+               }
+       }
+       return(1);
+}
+
+#define TAINT_FILENAME                  "/proc/sys/kernel/tainted"
+#define TAINT_PROPRIETORY_MODULE        (1<<0)
+#define TAINT_FORCED_MODULE             (1<<1)
+#define TAINT_UNSAFE_SMP                (1<<2)
+#define TAINT_URL                                              "http://www.tux.org/lkml/#export-tainted"
+
+static void set_tainted(struct obj_file *f, int fd, char *m_name, 
+               int kernel_has_tainted, int taint, const char *text1, const char *text2)
+{
+       char buf[80];
+       int oldval;
+       static int first = 1;
+       if (fd < 0 && !kernel_has_tainted)
+               return;         /* New modutils on old kernel */
+       printf("Warning: loading %s will taint the kernel: %s%s\n",
+                       m_name, text1, text2);
+       if (first) {
+               printf("  See %s for information about tainted modules\n", TAINT_URL);
+               first = 0;
+       }
+       if (fd >= 0) {
+               read(fd, buf, sizeof(buf)-1);
+               buf[sizeof(buf)-1] = '\0';
+               oldval = strtoul(buf, NULL, 10);
+               sprintf(buf, "%d\n", oldval | taint);
+               write(fd, buf, strlen(buf));
+       }
+}
+
+/* Check if loading this module will taint the kernel. */
+static void check_tainted_module(struct obj_file *f, char *m_name)
+{
+       static const char tainted_file[] = TAINT_FILENAME;
+       int fd, kernel_has_tainted;
+       const char *ptr;
+
+       kernel_has_tainted = 1;
+       if ((fd = open(tainted_file, O_RDWR)) < 0) {
+               if (errno == ENOENT)
+                       kernel_has_tainted = 0;
+               else if (errno == EACCES)
+                       kernel_has_tainted = 1;
+               else {
+                       perror(tainted_file);
+                       kernel_has_tainted = 0;
+               }
+       }
+
+       switch (obj_gpl_license(f, &ptr)) {
+               case 0:
+                       break;
+               case 1:
+                       set_tainted(f, fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", "");
+                       break;
+               case 2:
+                       /* The module has a non-GPL license so we pretend that the
+                        * kernel always has a taint flag to get a warning even on
+                        * kernels without the proc flag.
+                        */
+                       set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
+                       break;
+               default:
+                       set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
+                       break;
+       }
+
+       if (flag_force_load)
+               set_tainted(f, fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
+
+       if (fd >= 0)
+               close(fd);
+}
+
+extern int insmod_main( int argc, char **argv)
+{
+       int opt;
+       int k_crcs;
+       int k_new_syscalls;
+       int len;
+       char *tmp, *tmp1;
+       unsigned long m_size;
+       ElfW(Addr) m_addr;
+       FILE *fp;
+       struct obj_file *f;
+       struct stat st;
+       char m_name[FILENAME_MAX] = "\0";
+       int exit_status = EXIT_FAILURE;
+       int m_has_modinfo;
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+       struct utsname uts_info;
+       char m_strversion[STRVERSIONLEN];
+       int m_version;
+       int m_crcs;
+#endif
+
+       /* Parse any options */
+       while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) {
+               switch (opt) {
+                       case 'f':                       /* force loading */
+                               flag_force_load = 1;
+                               break;
+                       case 'k':                       /* module loaded by kerneld, auto-cleanable */
+                               flag_autoclean = 1;
+                               break;
+                       case 's':                       /* log to syslog */
+                               /* log to syslog -- not supported              */
+                               /* but kernel needs this for request_module(), */
+                               /* as this calls: modprobe -k -s -- <module>   */
+                               /* so silently ignore this flag                */
+                               break;
+                       case 'v':                       /* verbose output */
+                               flag_verbose = 1;
+                               break;
+                       case 'q':                       /* silent */
+                               flag_quiet = 1;
+                               break;
+                       case 'x':                       /* do not export externs */
+                               flag_export = 0;
+                               break;
+                       case 'o':                       /* name the output module */
+                               safe_strncpy(m_name, optarg, sizeof(m_name));
+                               break;
+                       case 'L':                       /* Stub warning */
+                               /* This is needed for compatibility with modprobe.
+                                * In theory, this does locking, but we don't do
+                                * that.  So be careful and plan your life around not
+                                * loading the same module 50 times concurrently. */
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+       
+       if (argv[optind] == NULL) {
+               show_usage();
+       }
+
+       /* Grab the module name */
+       tmp1 = xstrdup(argv[optind]);
+       tmp = basename(tmp1);
+       len = strlen(tmp);
+
+       if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') {
+               len-=2;
+               tmp[len] = '\0';
+       }
+       /* Make sure there is space for the terminal NULL */
+       len += 1;
+
+       if (len >= sizeof(m_fullName)) {
+               len = sizeof(m_fullName);
+       }
+       safe_strncpy(m_fullName, tmp, len);
+       if (tmp1)
+               free(tmp1);
+       if (*m_name == '\0') {
+               safe_strncpy(m_name, m_fullName, sizeof(m_name));
+       }
+       len = strlen(m_fullName);
+       if (len > (sizeof(m_fullName)-3))
+               error_msg_and_die("%s: no module by that name found", m_fullName);
+       strcat(m_fullName, ".o");
+
+       /* Get a filedesc for the module.  Check we we have a complete path */
+       if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) ||
+                       (fp = fopen(argv[optind], "r")) == NULL) {
+               struct utsname myuname;
+
+               /* Hmm.  Could not open it.  First search under /lib/modules/`uname -r`,
+                * but do not error out yet if we fail to find it... */
+               if (uname(&myuname) == 0) {
+                       char module_dir[FILENAME_MAX];
+                       char real_module_dir[FILENAME_MAX];
+                       snprintf (module_dir, sizeof(module_dir), "%s/%s", 
+                                       _PATH_MODULES, myuname.release);
+                       /* Jump through hoops in case /lib/modules/`uname -r`
+                        * is a symlink.  We do not want recursive_action to
+                        * follow symlinks, but we do want to follow the
+                        * /lib/modules/`uname -r` dir, So resolve it ourselves
+                        * if it is a link... */
+                       if (realpath (module_dir, real_module_dir) == NULL)
+                               strcpy(real_module_dir, module_dir);
+                       recursive_action(real_module_dir, TRUE, FALSE, FALSE,
+                                       check_module_name_match, 0, m_fullName);
+               }
+
+               /* Check if we have found anything yet */
+               if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) 
+               {
+                       char module_dir[FILENAME_MAX];
+                       if (realpath (_PATH_MODULES, module_dir) == NULL)
+                               strcpy(module_dir, _PATH_MODULES);
+                       /* No module found under /lib/modules/`uname -r`, this
+                        * time cast the net a bit wider.  Search /lib/modules/ */
+                       if (recursive_action(module_dir, TRUE, FALSE, FALSE,
+                                               check_module_name_match, 0, m_fullName) == FALSE) 
+                       {
+                               if (m_filename[0] == '\0'
+                                               || ((fp = fopen(m_filename, "r")) == NULL)) 
+                               {
+                                       error_msg("%s: no module by that name found", m_fullName);
+                                       return EXIT_FAILURE;
+                               }
+                       } else
+                               error_msg_and_die("%s: no module by that name found", m_fullName);
+               }
+       } else 
+               safe_strncpy(m_filename, argv[optind], sizeof(m_filename));
+
+       printf("Using %s\n", m_filename);
+
+       if ((f = obj_load(fp, LOADBITS)) == NULL)
+               perror_msg_and_die("Could not load the module");
+
+       if (get_modinfo_value(f, "kernel_version") == NULL)
+               m_has_modinfo = 0;
+       else
+               m_has_modinfo = 1;
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+       /* Version correspondence?  */
+       if (!flag_quiet) {
+               if (uname(&uts_info) < 0)
+                       uts_info.release[0] = '\0';
+               if (m_has_modinfo) {
+                       m_version = new_get_module_version(f, m_strversion);
+               } else {
+                       m_version = old_get_module_version(f, m_strversion);
+                       if (m_version == -1) {
+                               error_msg("couldn't find the kernel version the module was "
+                                               "compiled for");
+                               goto out;
+                       }
+               }
+
+               if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
+                       if (flag_force_load) {
+                               error_msg("Warning: kernel-module version mismatch\n"
+                                               "\t%s was compiled for kernel version %s\n"
+                                               "\twhile this kernel is version %s",
+                                               m_filename, m_strversion, uts_info.release);
+                       } else {
+                               error_msg("kernel-module version mismatch\n"
+                                               "\t%s was compiled for kernel version %s\n"
+                                               "\twhile this kernel is version %s.",
+                                               m_filename, m_strversion, uts_info.release);
+                               goto out;
+                       }
+               }
+       }
+       k_crcs = 0;
+#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+       k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
+
+       if (k_new_syscalls) {
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+               if (!new_get_kernel_symbols())
+                       goto out;
+               k_crcs = new_is_kernel_checksummed();
+#else
+               error_msg("Not configured to support new kernels");
+               goto out;
+#endif
+       } else {
+#ifdef BB_FEATURE_OLD_MODULE_INTERFACE
+               if (!old_get_kernel_symbols(m_name))
+                       goto out;
+               k_crcs = old_is_kernel_checksummed();
+#else
+               error_msg("Not configured to support old kernels");
+               goto out;
+#endif
+       }
+
+#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING
+       if (m_has_modinfo)
+               m_crcs = new_is_module_checksummed(f);
+       else
+               m_crcs = old_is_module_checksummed(f);
+
+       if (m_crcs != k_crcs)
+               obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
+#endif                                                 /* BB_FEATURE_INSMOD_VERSION_CHECKING */
+
+       /* Let the module know about the kernel symbols.  */
+       add_kernel_symbols(f);
+
+       /* Allocate common symbols, symbol tables, and string tables.  */
+
+       if (k_new_syscalls 
+               ? !new_create_this_module(f, m_name)
+               : !old_create_mod_use_count(f)) 
+       {
+               goto out;
+       }
+
+       if (!obj_check_undefineds(f)) {
+               goto out;
+       }
+       obj_allocate_commons(f);
+       check_tainted_module(f, m_name);
+
+       /* done with the module name, on to the optional var=value arguments */
+       ++optind;
+
+       if (optind < argc) {
+               if (m_has_modinfo
+                       ? !new_process_module_arguments(f, argc - optind, argv + optind) 
+                       : !old_process_module_arguments(f, argc - optind, argv + optind)) 
+               {
+                       goto out;
+               }
+       }
+
+       arch_create_got(f);
+       hide_special_symbols(f);
+
+       if (k_new_syscalls)
+               new_create_module_ksymtab(f);
+
+       /* Find current size of the module */
+       m_size = obj_load_size(f);
+
+
+       m_addr = create_module(m_name, m_size);
+       if (m_addr==-1) switch (errno) {
+       case EEXIST:
+               error_msg("A module named %s already exists", m_name);
+               goto out;
+       case ENOMEM:
+               error_msg("Can't allocate kernel memory for module; needed %lu bytes",
+                               m_size);
+               goto out;
+       default:
+               perror_msg("create_module: %s", m_name);
+               goto out;
+       }
+
+#if  !LOADBITS
+       /*
+        * the PROGBITS section was not loaded by the obj_load
+        * now we can load them directly into the kernel memory
+        */
+       if (!obj_load_progbits(fp, f, (char*)m_addr)) {
+               delete_module(m_name);
+               goto out;
+       }
+#endif 
+
+       if (!obj_relocate(f, m_addr)) {
+               delete_module(m_name);
+               goto out;
+       }
+
+       if (k_new_syscalls 
+               ? !new_init_module(m_name, f, m_size)
+               : !old_init_module(m_name, f, m_size)) 
+       {
+               delete_module(m_name);
+               goto out;
+       }
+
+       exit_status = EXIT_SUCCESS;
+
+out:
+       fclose(fp);
+       return(exit_status);
+}
diff --git a/install.sh b/install.sh
new file mode 100755 (executable)
index 0000000..d163a2e
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+prefix=$1
+if [ "$prefix" = "" ]; then
+    echo "No installation directory, aborting."
+    exit 1;
+fi
+if [ "$2" = "--hardlinks" ]; then
+    linkopts="-f"
+else
+    linkopts="-fs"
+fi
+h=`sort busybox.links | uniq`
+
+
+rm -f $prefix/bin/busybox || exit 1
+mkdir -p $prefix/bin || exit 1
+install -m 755 busybox $prefix/bin/busybox || exit 1
+
+for i in $h ; do
+       appdir=`dirname $i`
+       mkdir -p $prefix/$appdir || exit 1
+       if [ "$2" = "--hardlinks" ]; then
+           bb_path="$prefix/bin/busybox"
+       else
+           case "$appdir" in
+               /)
+                   bb_path="bin/busybox"
+               ;;
+               /bin)
+                   bb_path="busybox"
+               ;;
+               /sbin)
+                   bb_path="../bin/busybox"
+               ;;
+               /usr/bin|/usr/sbin)
+                   bb_path="../../bin/busybox"
+               ;;
+               *)
+               echo "Unknown installation directory: $appdir"
+               exit 1
+               ;;
+           esac
+       fi
+       echo "  $prefix$i -> $bb_path"
+       ln $linkopts $bb_path $prefix$i || exit 1
+done
+
+exit 0
diff --git a/kernel-patches/Will_devps_GoIntoTheKernel b/kernel-patches/Will_devps_GoIntoTheKernel
new file mode 100644 (file)
index 0000000..c541c0f
--- /dev/null
@@ -0,0 +1,104 @@
+I have been asked several times whether the devps patch will go into the
+mainline Linux kernel.  The following emails from Alan Cox and Linus Torvalds
+make it clear that it is not going to happen.  This does not mean this patch
+had no value -- it does.  It just means that those that like it get to apply it
+themselves...
+
+ -Erik
+
+
+-------------------------------
+
+From alan@lxorguk.ukuu.org.uk  Thu Apr 13 08:07:22 2000
+Return-Path: <alan@lxorguk.ukuu.org.uk>
+Delivered-To: andersen@dillweed.dsl.xmission.com
+Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1])
+       by dillweed.dsl.xmission.com (Postfix) with ESMTP id 1D57A11A4F5
+       for <andersen@dillweed.dsl.xmission.com>; Thu, 13 Apr 2000 08:07:22 -0600 (MDT)
+Envelope-to: andersen@xmission.com
+Received: from mail.xmission.com
+       by localhost with IMAP (fetchmail-5.3.3)
+       for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 08:07:22 -0600 (MDT)
+Received: from [194.168.151.1] (helo=the-village.bc.nu)
+       by mail.xmission.com with esmtp (Exim 3.03 #3)
+       id 12fhQk-0002OZ-00
+       for andersen@xmission.com; Thu, 13 Apr 2000 05:05:03 -0600
+Received: from alan by the-village.bc.nu with local (Exim 2.12 #1)
+       id 12fhQ9-0002nD-00
+       for andersen@xmission.com; Thu, 13 Apr 2000 12:04:25 +0100
+Subject: Re: kernel ps drivers [Was: vm locking question]
+To: andersen@xmission.com
+Date: Thu, 13 Apr 2000 12:04:23 +0100 (BST)
+In-Reply-To: <20000412224130.A2748@xmission.com> from "Erik Andersen" at Apr 12, 2000 10:41:30 PM
+X-Mailer: ELM [version 2.5 PL1]
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+Message-Id: <E12fhQ9-0002nD-00@the-village.bc.nu>
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Status: RO
+X-Status: A
+Content-Length: 242
+Lines: 6
+
+> On the subject of ps, would you be willing to accept my /dev/ps 
+> patch into the kernel?  If no, any suggestions on what should
+> be done differently (if anything) to make it worthy of inclusion?
+
+For 2.2.x no, for 2.3.x ask Linus not me
+
+
+From torvalds@transmeta.com  Thu Apr 13 09:18:16 2000
+Return-Path: <torvalds@transmeta.com>
+Delivered-To: andersen@dillweed.dsl.xmission.com
+Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1])
+       by dillweed.dsl.xmission.com (Postfix) with ESMTP id 3776411A3DF
+       for <andersen@dillweed.dsl.xmission.com>; Thu, 13 Apr 2000 09:18:16 -0600 (MDT)
+Envelope-to: andersen@xmission.com
+Received: from mail.xmission.com
+       by localhost with IMAP (fetchmail-5.3.3)
+       for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 09:18:16 -0600 (MDT)
+Received: from [209.10.217.66] (helo=neon-gw.transmeta.com)
+       by mail.xmission.com with esmtp (Exim 3.03 #3)
+       id 12flK2-0004dd-00
+       for andersen@xmission.com; Thu, 13 Apr 2000 09:14:22 -0600
+Received: (from root@localhost)
+       by neon-gw.transmeta.com (8.9.3/8.9.3) id IAA18635;
+       Thu, 13 Apr 2000 08:10:51 -0700
+Received: from mailhost.transmeta.com(10.1.1.15) by neon-gw.transmeta.com via smap (V2.1)
+       id xma018629; Thu, 13 Apr 00 08:10:25 -0700
+Received: from penguin.transmeta.com (root@penguin.transmeta.com [10.1.2.202])
+       by deepthought.transmeta.com (8.9.3/8.9.3) with ESMTP id IAA12264;
+       Thu, 13 Apr 2000 08:13:53 -0700 (PDT)
+Received: from localhost (torvalds@localhost) by penguin.transmeta.com (8.9.3/8.7.3) with ESMTP id IAA02051; Thu, 13 Apr 2000 08:13:53 -0700
+X-Authentication-Warning: penguin.transmeta.com: torvalds owned process doing -bs
+Date: Thu, 13 Apr 2000 08:13:53 -0700 (PDT)
+From: Linus Torvalds <torvalds@transmeta.com>
+To: Erik Andersen <andersen@xmission.com>
+Cc: Alan Cox <alan@redhat.com>
+Subject: Re: kernel ps drivers [Was: vm locking question]
+In-Reply-To: <20000413083127.A976@xmission.com>
+Message-ID: <Pine.LNX.4.10.10004130812170.2000-100000@penguin.transmeta.com>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=US-ASCII
+Status: RO
+Content-Length: 659
+Lines: 16
+
+
+
+On Thu, 13 Apr 2000, Erik Andersen wrote:
+> 
+> For 2.3.x would you be willing to accept my /dev/ps driver into the kernel?
+> (Assuming I remove the /dev/modules driver (since it was pointed out that there
+> is a perfectly good syscall providing that interface).  If no, is there anything
+> that could be done differently (if anything) to make it worthy of inclusion?
+
+I do dislike /dev/ps mightily. If the problem is that /proc is too large,
+then the right solution is to just clean up /proc. Which is getting done.
+And yes, /proc will be larger than /dev/ps, but I still find that
+preferable to having two incompatible ways to do the same thing.
+
+               Linus
+
+
diff --git a/kernel-patches/devps.patch.9_25_2000 b/kernel-patches/devps.patch.9_25_2000
new file mode 100644 (file)
index 0000000..d74a26a
--- /dev/null
@@ -0,0 +1,1478 @@
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Config.in linux/drivers/char/Config.in
+--- linux-2.2.18-9.virgin/drivers/char/Config.in       Mon Sep 18 15:02:30 2000
++++ linux/drivers/char/Config.in       Mon Sep 25 16:33:16 2000
+@@ -56,6 +56,8 @@
+    dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m
+    dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m
+ fi
++tristate 'Devps support' CONFIG_DEVPS
++tristate 'Devmounts support' CONFIG_DEVMTAB
+ bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+ if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+       int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Makefile linux/drivers/char/Makefile
+--- linux-2.2.18-9.virgin/drivers/char/Makefile        Mon Sep 18 15:02:30 2000
++++ linux/drivers/char/Makefile        Mon Sep 25 18:01:12 2000
+@@ -697,6 +697,22 @@
+ M_OBJS          += $(sort $(filter     $(module-list), $(obj-m)))
++ifeq ($(CONFIG_DEVPS),y)
++O_OBJS += devps.o
++else
++  ifeq ($(CONFIG_DEVPS),m)
++  M_OBJS += devps.o
++  endif
++endif
++
++ifeq ($(CONFIG_DEVMTAB),y)
++O_OBJS += devmtab.o
++else
++  ifeq ($(CONFIG_DEVMTAB),m)
++  M_OBJS += devmtab.o
++  endif
++endif
++
+ include $(TOPDIR)/Rules.make
+ fastdep:
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devmtab.c linux/drivers/char/devmtab.c
+--- linux-2.2.18-9.virgin/drivers/char/devmtab.c       Wed Dec 31 17:00:00 1969
++++ linux/drivers/char/devmtab.c       Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,295 @@
++/* vi: set sw=8 ts=8: */
++/*
++ * linux/drivers/char/devmtab.c
++ * 
++ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
++ *
++ * May be copied or modified under the terms of the GNU General Public License.
++ * See linux/COPYING for more information.
++ *
++ * This driver implements an interface whereby programs such as mount(8),
++ * umount(8), and df(1) may obtain all the process information they need to do
++ * their jobs without needing to use /proc.  This driver another step in my
++ * evil plan to completely dismantle /proc.  Muhahahaha!
++ *
++ * Suggestions are welcome. Patches that work are more welcome though. ;-)
++ *
++ *
++ * When using this driver, running:
++ *    mknod /dev/mtab c 10 22
++ * could be considered helpful.
++ *
++ * ----------------------------------
++ * 1.00  Mar 07, 2000 -- Initial version.
++ *
++ *************************************************************************/
++
++#define DEVMTAB_VERSION "1.00"
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/malloc.h>
++#include <linux/miscdevice.h>
++#include <linux/devmtab.h>
++#include <linux/wrapper.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++
++
++/* Some variables used by this device */
++static struct wait_queue *devmtab_waitq = NULL;
++static int devmtab_already_opened = 0;
++static char *mtabfile = NULL;
++static int mtab_ptr;
++static int mtab_size;
++
++
++
++/****************************************************************************
++ * Handle opening and closing of the device
++ */
++
++static long long
++devmtab_lseek (struct file *file, long long offset, int orig)
++{
++      return -ESPIPE;
++}
++
++static ssize_t
++devmtab_read (struct file *file, char *buf, size_t count, loff_t * ppos)
++{
++      int n = mtab_size - mtab_ptr;
++
++      if (mtab_size == 0) {
++              /* Make some space */
++              if (!(mtabfile = (char *) get_free_page (GFP_KERNEL)))
++                      return -ENOMEM;
++              /* Grab the mtab */
++              get_filesystem_info (mtabfile);
++              mtab_ptr = 0;
++              mtab_size = strlen (mtabfile);
++              n = mtab_size - mtab_ptr;
++      }
++
++      if (n > count)
++              n = count;
++      if (n <= 0)
++              return 0;
++
++      if (copy_to_user (buf, mtabfile, n))
++              return -EFAULT;
++      mtab_ptr += n;
++      return n;
++}
++
++static int devmtab_open (struct inode *ip, struct file *fp)
++{
++      /* Only let one process use us at any time -- putting other
++       * processes to sleep.  Those opening us O_NONBLOCK will
++       * get an EAGAIN error */
++      if ((fp->f_flags & O_NONBLOCK) && devmtab_already_opened) 
++              return -EAGAIN;
++
++      MOD_INC_USE_COUNT;
++
++      while (devmtab_already_opened) {
++              int i, got_signal=0;
++
++              /* Go to sleep until we get woken up 
++               * by devmtab_close or we receive a signal */
++              module_interruptible_sleep_on(&devmtab_waitq);
++
++              for(i=0; i<_NSIG_WORDS && !got_signal; i++)
++                      got_signal = current->signal.sig[i] & ~current->blocked.sig[i];
++
++              /* If we got a signal, decrement the use count
++               * and return to user space */
++              if (got_signal) {
++                      MOD_DEC_USE_COUNT;
++                      return -EINTR;
++              }
++      }
++
++      /* Since we got here, then devmtab_already_opened must equal 0 */
++      devmtab_already_opened=1;
++      mtab_ptr = 0;
++      mtab_size = 0;
++
++      return 0;
++}
++
++static int devmtab_release (struct inode *ip, struct file *fp)
++{
++      /* Clean up */
++      if (mtabfile != NULL) {
++              free_page ((unsigned long) mtabfile);
++              mtabfile = NULL;
++      }
++
++      /* Zero out the reference counter */
++      devmtab_already_opened=0;
++
++      /* Wake up anybody that is waiting to access this device */
++      module_wake_up(&devmtab_waitq);
++
++      MOD_DEC_USE_COUNT;
++
++      return 0;
++}
++
++static int
++devmtab_ioctl (struct inode *ip, struct file *fp,
++             unsigned int cmd, unsigned long arg)
++{
++      switch (cmd) {
++      case DEVMTAB_COUNT_FILESYSTEMS:{
++                      return(count_kfstypes());
++              }
++
++      case DEVMTAB_GET_FILESYSTEMS:{
++                      int stat, count;
++                      struct k_fstype* fstypelist;
++
++                      /* How many are there? */
++                      count = count_kfstypes();
++
++                      /* Make some space */
++                      fstypelist = (struct k_fstype *)kmalloc(sizeof(struct k_fstype) * count, GFP_KERNEL);
++                      if (!fstypelist)
++                              return -ENOMEM;
++                      memset(fstypelist, 0, sizeof(struct k_fstype) * count);
++
++                      /* Grab the mtab entries */
++                      get_kfstype_list(count, fstypelist);
++
++                      /* Make sure there is enough room */
++                      stat = verify_area (VERIFY_WRITE, (struct k_fstype *) arg,
++                                          sizeof(struct k_fstype) * count);
++                      if (stat) {
++                              printk (KERN_INFO
++                                      "devmtab: Insufficient space was provided.\n");
++                              return stat;
++                      }
++
++                      /* Send it to user space */
++                      copy_to_user_ret ((struct k_fstype *) arg, fstypelist,
++                                        sizeof(struct k_fstype) * count, 
++                                        -EFAULT);
++
++                      /* Clean up */
++                      kfree( fstypelist);
++                      return 0;
++              }
++
++      case DEVMTAB_COUNT_MOUNTS:{
++                      return(count_mounted_filesystems());
++              }
++
++      case DEVMTAB_GET_MOUNTS:{
++                      int stat, count;
++                      struct k_mntent* mntentlist;
++
++                      /* How many are there? */
++                      count = count_mounted_filesystems();
++
++                      /* Make some space */
++                      mntentlist = (struct k_mntent *)kmalloc(sizeof(struct k_mntent) * count, GFP_KERNEL);
++                      if (!mntentlist)
++                              return -ENOMEM;
++                      memset(mntentlist, 0, sizeof(struct k_mntent) * count);
++
++                      /* Grab the mtab entries */
++                      get_mtab_entries (count, mntentlist);
++
++                      /* Make sure there is enough room */
++                      stat = verify_area (VERIFY_WRITE, (void*) arg,
++                                          sizeof(struct k_mntent) * count);
++                      if (stat) {
++                              printk (KERN_INFO
++                                      "devmtab: Insufficient space was provided.\n");
++                              return stat;
++                      }
++
++                      /* Send it to user space */
++                      copy_to_user_ret ((struct k_mntent *) arg, mntentlist,
++                                        sizeof(struct k_mntent) * count, 
++                                        -EFAULT);
++
++                      /* Clean up */
++                      kfree( mntentlist);
++                      return 0;
++              }
++
++      default:
++              return -EINVAL;
++
++      }
++      return 0;
++}
++
++
++
++/****************************************************************************
++ * Set up the file operations devmtab will support
++ */
++static struct file_operations devmtab_fops = {
++      devmtab_lseek,
++      devmtab_read,
++      NULL,                   /* No write */
++      NULL,                   /* No readdir */
++      NULL,                   /* No poll */
++      devmtab_ioctl,
++      NULL,                   /* No mmap */
++      devmtab_open,
++      NULL,                   /* flush */
++      devmtab_release,
++      NULL,                   /* fsync */
++      NULL,                   /* fasync */
++      NULL,                   /* check_media_change */
++      NULL                    /* revalidate */
++};
++
++static struct miscdevice devmtab_misc_dev = {
++      DEVMTAB_MINOR,
++      "devmtab",
++      &devmtab_fops
++};
++
++/* The real driver initialization function */
++extern int devmtab_init (void)
++{
++      printk (KERN_INFO "devmtab: driver %s loaded\n", DEVMTAB_VERSION);
++
++      if (misc_register (&devmtab_misc_dev)) {
++              printk ("devmtab: can't register misc device %d\n",
++                      DEVMTAB_MINOR);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++#ifdef MODULE
++
++MODULE_AUTHOR ("Erik Andersen <andersee@debian.org>");
++MODULE_DESCRIPTION
++      ("devmtab driver -- exports filesystem and mount information to user space");
++
++/* Stub driver initialization function */
++int init_module (void)
++{
++      return (devmtab_init ());
++}
++
++void cleanup_module (void)
++{
++      printk (KERN_INFO "devmtab: driver unloaded\n");
++      misc_deregister (&devmtab_misc_dev);
++}
++
++#endif        /* MODULE */
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devps.c linux/drivers/char/devps.c
+--- linux-2.2.18-9.virgin/drivers/char/devps.c Wed Dec 31 17:00:00 1969
++++ linux/drivers/char/devps.c Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,518 @@
++/* vi: set sw=8 ts=8: */
++/*
++ * linux/drivers/char/devps.c
++ * 
++ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
++ *
++ * May be copied or modified under the terms of the GNU General Public License.
++ * See linux/COPYING for more information.
++ *
++ * This driver implements an interface whereby programs such as ps(1), top(1),
++ * killall(1) and the like may obtain all the process information they need to
++ * do their jobs.  Now you may ask, "Why not use /proc?  BSD uses /proc.".
++ * Thanks for asking.  /proc is designed as a virtual filesystem.  As such it
++ * presents all of its information in a nice, human readable format.  But not
++ * human readable enough that mere mortals can actually look at the /proc
++ * information and know what is happening on their computer (which is why we
++ * have nice programs like ps(1) to help us out.  Additionally, for ps (using
++ * /proc) to do its job, it has to do something like:
++ *
++ *    dir = opendir("/proc");
++ *    while ((entry = readdir(dir)) != NULL) { 
++ *            if (!isdigit(*entry->d_name))
++ *                    continue;
++ *            open_lots_of files();
++ *            parse_lots_of_strings();
++ *            close_lots_of_files();
++ *            print_stuff();
++ *    }
++ *
++ *
++ * This is bad, because:
++ *
++ * 1) opening and closing lots of files is slow,
++ *
++ * 2) parsing lots of strings is slow,
++ *
++ * 3) every one of those strings had to be carefully printed out and formatted
++ * by the kernel, which is slow,
++ *
++ * 4) using a virtual filesystem is not the traditional UN*X solution to
++ * getting information from the kernel out to userspace (ioctls and syscalls
++ * are the established way to do this), and worst of all
++ *
++ * 5) having a virtual filesystem around has been so inviting that everyone has
++ * put their own weird little files into it, causing /proc to become a
++ * cluttered rubbish heap of 64 flavors of strange that takes a ridiculous
++ * amount of memory.  
++ *
++ * This driver is the first step in my evil plan to completely 
++ * dismantle /proc.  Muhahahaha!
++ *
++ * Suggestions are welcome. Patches that work are more welcome though. ;-)
++ *
++ * When using this driver, running:
++ *    mknod /dev/ps c 10 21
++ * could be considered helpful.
++ *
++ * ----------------------------------
++ * 1.00  Mar 07, 2000 -- Initial version.
++ *
++ *
++ * TODO
++ * ----------------------------------
++ *
++ *  * Right now none of the vm or fd info is being returned to user space. 
++ *  * There is probably other stuff that should be exported to user space.
++ *
++ *
++ *************************************************************************/
++
++#define DEVPS_VERSION "1.00"
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/malloc.h>
++#include <linux/miscdevice.h>
++#include <linux/devps.h>
++#include <linux/wrapper.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++
++/* Some variables used by this device */
++static struct wait_queue *devps_waitq = NULL;
++static int devps_already_opened = 0;
++
++/****************************************************************************
++ * Handle opening and closing of the device
++ */
++
++static int devps_open (struct inode *ip, struct file *fp)
++{
++      /* Only let one process use us at any time -- putting other
++       * processes to sleep.  Those opening us O_NONBLOCK will
++       * get an EAGAIN error */
++      if ((fp->f_flags & O_NONBLOCK) && devps_already_opened) 
++              return -EAGAIN;
++
++      MOD_INC_USE_COUNT;
++
++      while (devps_already_opened) {
++              int i, got_signal=0;
++
++              /* Go to sleep until we get woken up 
++               * by devps_close or we receive a signal */
++              module_interruptible_sleep_on(&devps_waitq);
++
++              for(i=0; i<_NSIG_WORDS && !got_signal; i++)
++                      got_signal = current->signal.sig[i] & ~current->blocked.sig[i];
++
++              /* If we got a signal, decrement the use count
++               * and return to user space */
++              if (got_signal) {
++                      MOD_DEC_USE_COUNT;
++                      return -EINTR;
++              }
++      }
++
++      /* Since we got here, then device_already_opened must equal 0 */
++      devps_already_opened=1;
++      return 0;
++}
++
++static int devps_release (struct inode *ip, struct file *fp)
++{
++      /* Zero out the reference counter */
++      devps_already_opened=0;
++
++      /* Wake up anybody that is waiting to access this device */
++      module_wake_up(&devps_waitq);
++
++      MOD_DEC_USE_COUNT;
++      return 0;
++}
++
++
++/*
++ * This pretty-prints the pathname of a dentry,
++ * clarifying sockets etc.
++ */
++static int
++get_name_from_dentry (struct dentry *dentry, char *buffer, int buflen)
++{
++      struct inode *inode;
++      char *tmp = (char *) __get_free_page (GFP_KERNEL), *path, *pattern;
++      int len;
++
++      if (tmp == NULL)
++              return -ENOMEM;
++
++      /* Check for special dentries.. */
++      pattern = NULL;
++      inode = dentry->d_inode;
++      if (inode && dentry->d_parent == dentry) {
++              if (S_ISSOCK (inode->i_mode))
++                      pattern = "socket:[%lu]";
++              if (S_ISFIFO (inode->i_mode))
++                      pattern = "pipe:[%lu]";
++      }
++
++      if (pattern) {
++              len = sprintf (tmp, pattern, inode->i_ino);
++              path = tmp;
++      } else {
++              path = d_path (dentry, tmp, PAGE_SIZE);
++              len = tmp + PAGE_SIZE - 1 - path;
++      }
++
++      if (len < buflen)
++              buflen = len;
++      dput (dentry);
++      strncpy (buffer, path, buflen);
++      free_page ((unsigned long) tmp);
++      return buflen;
++}
++
++static unsigned long get_phys_addr (struct task_struct *p,
++                                  unsigned long ptr)
++{
++      pgd_t *page_dir;
++      pmd_t *page_middle;
++      pte_t pte;
++
++      if (!p || !p->mm || ptr >= TASK_SIZE)
++              return 0;
++      /* Check for NULL pgd .. shouldn't happen! */
++      if (!p->mm->pgd) {
++              printk ("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
++              return 0;
++      }
++
++      page_dir = pgd_offset (p->mm, ptr);
++      if (pgd_none (*page_dir))
++              return 0;
++      if (pgd_bad (*page_dir)) {
++              printk ("bad page directory entry %08lx\n",
++                      pgd_val (*page_dir));
++              pgd_clear (page_dir);
++              return 0;
++      }
++      page_middle = pmd_offset (page_dir, ptr);
++      if (pmd_none (*page_middle))
++              return 0;
++      if (pmd_bad (*page_middle)) {
++              printk ("bad page middle entry %08lx\n",
++                      pmd_val (*page_middle));
++              pmd_clear (page_middle);
++              return 0;
++      }
++      pte = *pte_offset (page_middle, ptr);
++      if (!pte_present (pte))
++              return 0;
++      return pte_page (pte) + (ptr & ~PAGE_MASK);
++}
++
++static int get_array (struct task_struct *p, unsigned long start,
++                    unsigned long end, char *buffer)
++{
++      unsigned long addr;
++      int size = 0, result = 0;
++      char c;
++
++      if (start >= end)
++              return result;
++      for (;;) {
++              addr = get_phys_addr (p, start);
++              if (!addr)
++                      return result;
++              do {
++                      c = *(char *) addr;
++                      if (!c)
++                              result = size;
++                      if (size < PAGE_SIZE)
++                              buffer[size++] = c;
++                      else
++                              return result;
++                      addr++;
++                      start++;
++                      if (!c && start >= end)
++                              return result;
++              } while (addr & ~PAGE_MASK);
++      }
++      return result;
++}
++
++static int
++devps_ioctl (struct inode *ip, struct file *fp,
++           unsigned int cmd, unsigned long arg)
++{
++      switch (cmd) {
++
++      /* Count up the total number of processes, 
++       * and then return that total */
++      case DEVPS_GET_NUM_PIDS:{
++                      struct task_struct *p;
++                      pid_t num_pids = 0;
++
++                      read_lock (&tasklist_lock);
++                      for_each_task (p) {
++                              if (!p->pid)
++                                      continue;
++                              num_pids++;
++                      }
++                      read_unlock (&tasklist_lock);
++
++                      copy_to_user_ret ((pid_t *) arg, &num_pids,
++                                        sizeof (num_pids), -EFAULT);
++                      return 0;
++              }
++
++      /* Returns an array containing all current pids, where
++         pidlist[0]=number of PIDs in the array. pidlist[0] also
++         specifies the size of the array for the kernel to
++         fill... */
++      case DEVPS_GET_PID_LIST:{
++                      struct task_struct *p;
++                      pid_t *pid_array = NULL;
++                      pid_t num_pids;
++                      int stat;
++
++                      /* Grab the first element to see how many * entries
++                         they want us to fill */
++                      stat = verify_area (VERIFY_READ, (char *) arg,
++                                           sizeof (pid_t));
++                      if (stat) {
++                              printk (KERN_INFO
++                                      "devps: can't tell how many "
++                                      "to pid's to write.\n");
++                              return stat;
++                      }
++
++                      copy_from_user (&num_pids, (void *) arg,
++                                      sizeof (num_pids));
++
++                      /* Now make sure we can write the specified amount
++                         of stuff into the array.  If we can't we might 
++                         as well quit now and save ourselves the bother. */
++                      stat = verify_area (VERIFY_WRITE, (char *) arg,
++                                           sizeof (pid_t) * num_pids);
++                      if (stat) {
++                              printk (KERN_INFO
++                                      "devps: Insufficient space was "
++                                      "provided to write %d pid's.\n",
++                                      num_pids);
++                              return stat;
++                      }
++
++                      /* Allocate some memory to hold this stuff in before
++                         * we copy it out to user-space */
++                      pid_array = (pid_t *) kmalloc (num_pids *
++                                                 sizeof (pid_t),
++                                                 GFP_KERNEL);
++                      if (pid_array == NULL)
++                              return -ENOMEM;
++
++                      /* Now march through the PID list */
++                      pid_array[0] = 0;
++                      read_lock (&tasklist_lock);
++                      for_each_task (p) {
++                              if (!p->pid)
++                                      continue;
++                              (pid_array[0])++;
++                              if (pid_array[0] >= (num_pids - 1))
++                                      continue;
++                              pid_array[pid_array[0]] = p->pid;
++                      }
++                      read_unlock (&tasklist_lock);
++
++                      /* Copy out to the user the number we actually filled 
++                       */
++                      copy_to_user_ret ((void *) arg, pid_array,
++                                        sizeof (pid_t) * pid_array[0],
++                                        -EFAULT);
++                      kfree (pid_array);
++
++                      return 0;
++              }
++
++      /* Find the details on a particular pid, and fill out a
++         struct with all the gory details. */
++      case DEVPS_GET_PID_INFO:{
++                      struct task_struct *p;
++                      struct pid_info mypidinfo;
++                      unsigned int state;
++                      /* 'R' running    */
++                      /* 'S' sleeping   */
++                      /* 'D' disk sleep */
++                      /* 'Z' zombie     */
++                      /* 'T' stopped    */
++                      /* 'W' paging     */
++                      const char *state_string = "RSDZTW";
++
++                      copy_from_user_ret (&mypidinfo,
++                                          (struct pid_info *) arg,
++                                          sizeof (mypidinfo), -EFAULT);
++
++                      read_lock (&tasklist_lock);
++                      p = find_task_by_pid (mypidinfo.pid);
++                      read_unlock (&tasklist_lock);
++
++                      /* Now copy all this crap so we can tell user space 
++                         all about it.  ick.  */
++                      memset (mypidinfo.name, 0,
++                              sizeof (mypidinfo.name));
++                      strcpy (mypidinfo.name, p->comm);
++                      mypidinfo.flags = p->flags;
++                      mypidinfo.pgrp = p->pgrp;
++                      mypidinfo.tms_cutime = p->times.tms_cutime;
++                      mypidinfo.tms_cstime = p->times.tms_cstime;
++                      mypidinfo.tms_utime = p->times.tms_utime;
++                      mypidinfo.tms_stime = p->times.tms_stime;
++                      mypidinfo.min_flt = p->min_flt;
++                      mypidinfo.cmin_flt = p->cmin_flt;
++                      mypidinfo.maj_flt = p->maj_flt;
++                      mypidinfo.cmaj_flt = p->cmaj_flt;
++                      mypidinfo.session = p->session;
++                      mypidinfo.pid = p->pid;
++                      mypidinfo.ppid = p->p_pptr->pid;
++                      mypidinfo.tty =
++                              p->tty ? kdev_t_to_nr (p->tty->device) : 0;
++                      mypidinfo.start_time = p->start_time;
++                      mypidinfo.uid = p->uid;
++                      mypidinfo.euid = p->euid;
++                      mypidinfo.suid = p->suid;
++                      mypidinfo.fsuid = p->fsuid;
++                      mypidinfo.gid = p->gid;
++                      mypidinfo.egid = p->egid;
++                      mypidinfo.sgid = p->sgid;
++                      mypidinfo.fsgid = p->fsgid;
++                      mypidinfo.priority = 20 - (p->counter * 10 + 
++                                      DEF_PRIORITY / 2) / DEF_PRIORITY;
++                      mypidinfo.nice = 20 - (mypidinfo.priority * 20 +
++                                    DEF_PRIORITY / 2) / DEF_PRIORITY;
++                      state = p-> state & (TASK_RUNNING | TASK_INTERRUPTIBLE
++                                       | TASK_UNINTERRUPTIBLE |
++                                       TASK_ZOMBIE | TASK_STOPPED |
++                                       TASK_SWAPPING);
++                      while (state) {
++                              state_string++;
++                              state >>= 1;
++                      }
++                      mypidinfo.state = *state_string;
++                      mypidinfo.processor = p->processor;
++                      mypidinfo.nswap = p->nswap;
++                      mypidinfo.cnswap = p->cnswap;
++                      if (p && p->mm) {
++                              char *page = NULL;
++
++                              /* Look for some elbow room */
++                              if (!(page = (char*)get_free_page (GFP_KERNEL)))
++                                      return -ENOMEM;
++                              /* Grab the command line */
++                              get_array (p, p->mm->arg_start,
++                                         p->mm->arg_end, page);
++                              memcpy( mypidinfo.command_line, page, sizeof( mypidinfo.command_line));
++                              mypidinfo.command_line[sizeof( mypidinfo.command_line)-1]='\0';
++
++                              /* Grab the environment */
++                              memset (page, 0, PAGE_SIZE);
++                              get_array (p, p->mm->env_start,
++                                         p->mm->env_end, page);
++                              memcpy( mypidinfo.environment, page, sizeof( mypidinfo.environment));
++                              mypidinfo.command_line[sizeof( mypidinfo.environment)-1]='\0';
++                              free_page ((unsigned long) page);
++                      }
++                      memset (mypidinfo.cwd, 0, sizeof (mypidinfo.cwd));
++                      get_name_from_dentry (dget (p->fs->pwd), mypidinfo.cwd,
++                                            sizeof (mypidinfo.cwd));
++                      memset (mypidinfo.root, 0, sizeof (mypidinfo.root));
++                      get_name_from_dentry (dget (p->fs->root),
++                                            mypidinfo.root,
++                                            sizeof (mypidinfo.root));
++
++                      copy_to_user_ret ((struct pid_info *) arg,
++                                        &mypidinfo, sizeof (mypidinfo),
++                                        -EFAULT);
++
++                      return 0;
++              }
++
++      /* Return the PID of the current process */
++      case DEVPS_GET_CURRENT_PID:{
++                      return current->pid;
++              }
++
++      default:
++              return -EINVAL;
++
++      }
++      return 0;
++}
++
++
++
++/****************************************************************************
++ * Set up the file operations devps will support
++ */
++static struct file_operations devps_fops = {
++      NULL,                   /* No lseek */
++      NULL,                   /* No read */
++      NULL,                   /* No write */
++      NULL,                   /* No readdir */
++      NULL,                   /* No poll */
++      devps_ioctl,
++      NULL,                   /* No mmap */
++      devps_open,
++      NULL,                   /* flush */
++      devps_release,
++      NULL,                   /* fsync */
++      NULL,                   /* fasync */
++      NULL,                   /* check_media_change */
++      NULL                    /* revalidate */
++};
++
++static struct miscdevice devps_misc_dev = {
++      DEVPS_MINOR,
++      "devps",
++      &devps_fops
++};
++
++/* The real driver initialization function */
++extern int devps_init (void)
++{
++      printk (KERN_INFO "devps driver %s loaded\n", DEVPS_VERSION);
++
++      if (misc_register (&devps_misc_dev)) {
++              printk ("devps: unable to get misc device %d\n",
++                      DEVPS_MINOR);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++#ifdef MODULE
++
++MODULE_AUTHOR ("Erik Andersen <andersee@debian.org>");
++MODULE_DESCRIPTION
++      ("devps driver -- exports kernel process information to user space");
++
++
++/* Stub driver initialization function */
++int init_module (void)
++{
++      return (devps_init ());
++}
++
++void cleanup_module (void)
++{
++      printk (KERN_INFO "devps driver unloaded\n");
++      misc_deregister (&devps_misc_dev);
++}
++
++#endif                                /* endif MODULE */
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/makedevps.sh linux/drivers/char/makedevps.sh
+--- linux-2.2.18-9.virgin/drivers/char/makedevps.sh    Wed Dec 31 17:00:00 1969
++++ linux/drivers/char/makedevps.sh    Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,5 @@
++#!/bin/sh -x
++
++gcc -Wall -g -I /usr/src/linux/include ps-devps.c -o ps-devps
++gcc -Wall -g -I /usr/src/linux/include mounts.c -o mounts
++
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/misc.c linux/drivers/char/misc.c
+--- linux-2.2.18-9.virgin/drivers/char/misc.c  Mon Sep 18 15:02:31 2000
++++ linux/drivers/char/misc.c  Mon Sep 25 17:00:57 2000
+@@ -85,6 +85,8 @@
+ extern int pmu_device_init(void);
+ extern int tosh_init(void);
+ extern int rng_init(void);
++extern int devps_init(void);
++extern int devmtab_init(void);
+ static int misc_read_proc(char *buf, char **start, off_t offset,
+                         int len, int *eof, void *private)
+@@ -268,6 +270,12 @@
+ #endif
+ #ifdef CONFIG_PMAC_PBOOK
+       pmu_device_init();
++#endif
++#ifdef CONFIG_DEVPS
++      devps_init();
++#endif
++#ifdef CONFIG_DEVMTAB
++      devmtab_init();
+ #endif
+ #ifdef CONFIG_SGI_NEWPORT_GFX
+       gfx_register ();
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/mounts.c linux/drivers/char/mounts.c
+--- linux-2.2.18-9.virgin/drivers/char/mounts.c        Wed Dec 31 17:00:00 1969
++++ linux/drivers/char/mounts.c        Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,116 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * devmtab tester
++ *
++ *
++ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <unistd.h>
++#include <time.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <linux/devmtab.h>
++
++
++int main (int argc, char **argv)
++{
++      char device[80] = "/dev/mtab";
++      int fd;           /* file descriptor for devmtab device */
++      int i, numfilesystems;
++      struct k_fstype *fslist;
++      struct k_mntent *mntentlist;
++
++      if (argc > 1 && **(argv + 1) == '-') {
++              fprintf(stderr, "Usage: mounts\n\nReport mounted stuff\n\nThis version of mounts accepts no options.\n\n");
++              exit(1);
++      }
++
++      /* open device */ 
++      if ((fd = open(device, O_RDONLY)) < 0) {
++              fprintf (stderr, "open failed for `%s': %s\n",
++                       device, strerror (errno));
++              exit (1);
++      }
++
++      /* How many filesystems?  We need to know to allocate 
++       * enough space for later... */
++      numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS);
++      if (numfilesystems<0) {
++              fprintf (stderr, "\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", 
++                      strerror (errno));
++              exit (1);
++      } 
++      fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype));
++
++      /* Grab the list of available filesystems */
++      if (ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist)<0) {
++              fprintf (stderr, "\nDEVMTAB_GET_FILESYSTEMS: %s\n", 
++                      strerror (errno));
++              exit (1);
++      } 
++      fprintf( stdout, "\nEquivalent of /proc/filesystems:\n");
++      for( i = 0 ; i < numfilesystems ; i++) {
++              fprintf( stdout, "%s%s\n", fslist[i].mnt_type, 
++                              (fslist[i].mnt_nodev)? " nodev" : "");
++      }
++
++
++      /* How many mounted filesystems?  We need to know to 
++       * allocate enough space for later... */
++      numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
++      if (numfilesystems<0) {
++              fprintf (stderr, "\nDEVMTAB_COUNT_MOUNTS: %s\n", 
++                      strerror (errno));
++              exit (1);
++      } 
++      mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent));
++      
++      /* Grab the list of mounted filesystems */
++      if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) {
++              fprintf (stderr, "\nDEVMTAB_GET_MOUNTS: %s\n", 
++                      strerror (errno));
++              exit (1);
++      } 
++
++      fprintf( stdout, "\nEquivalent of /proc/mounts:\n");
++      for( i = 0 ; i < numfilesystems ; i++) {
++              fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
++                              mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
++                              mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
++                              mntentlist[i].mnt_passno);
++      }
++
++
++      /* clean up */
++      free( fslist);
++      free( mntentlist);
++      if (close (fd) != 0) {
++              fprintf (stderr, "close failed for `%s': %s\n",
++                       device, strerror (errno));
++              exit (1);
++      }
++ 
++      exit (0);
++}
++
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/ps-devps.c linux/drivers/char/ps-devps.c
+--- linux-2.2.18-9.virgin/drivers/char/ps-devps.c      Wed Dec 31 17:00:00 1969
++++ linux/drivers/char/ps-devps.c      Mon Sep 25 17:32:19 2000
+@@ -0,0 +1,148 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * Mini ps implementation for use with the Linux devps driver
++ *
++ *
++ * Copyright (C) 2000 by Erik Andersen <andersee@debian.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <unistd.h>
++#include <time.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <linux/devps.h>
++#include <pwd.h>
++#include <grp.h>
++#include <sys/types.h>
++
++
++#define MAX_COLUMN    79
++
++int
++main (int argc, char **argv)
++{
++      char device[80] = "/dev/ps";
++      int i, j, len;
++      int fd;           /* file descriptor for devps device */
++      int status;       /* return status for system calls */
++      pid_t num_pids;
++      pid_t* pid_array = NULL;
++      struct pid_info info;
++      struct passwd *pwd;
++      struct group *grp;
++      char uidName[10] = "";
++      char groupName[10] = "";
++
++      if (argc > 1 && **(argv + 1) == '-') {
++              fprintf(stderr, "Usage: ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n");
++              exit(1);
++      }
++
++      /* open device */ 
++      //fd = open(device, O_RDWR);
++      fd = open(device, O_RDONLY);
++      if (fd < 0) {
++              fprintf (stderr, "open failed for `%s': %s\n",
++                       device, strerror (errno));
++              goto error;
++      }
++
++      /* Find out how many processes there are */
++      status = ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids);
++      if (status<0) {
++              fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", 
++                      strerror (errno));
++              goto error;
++      } 
++      
++      /* Allocate some memory -- grab a few extras just in case 
++       * some new processes start up while we wait. The kernel will
++       * just ignore any extras if we give it too many, and will trunc.
++       * the list if we give it too few.  */
++      pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
++      pid_array[0] = num_pids+10;
++
++      /* Now grab the pid list */
++      status = ioctl (fd, DEVPS_GET_PID_LIST, pid_array);
++      if (status<0) {
++              fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", 
++                      strerror (errno));
++              goto error;
++      } 
++
++      /* Print up a ps listing */
++      fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
++                      "State", "Command");
++
++      for (i=1; i<pid_array[0] ; i++) {
++          info.pid = pid_array[i];
++          status = ioctl (fd, DEVPS_GET_PID_INFO, &info);
++          if (status<0) {
++                  fprintf (stderr, "\nDEVPS_GET_PID_INFO: %s\n", 
++                          strerror (errno));
++                  goto error;
++          } 
++              /* Make some adjustments as needed */
++              pwd = getpwuid(info.euid);
++              if (pwd == NULL)
++                      sprintf(uidName, "%lu", info.euid);
++              else
++                      sprintf(uidName, "%s", pwd->pw_name);
++              grp = getgrgid(info.egid);
++              if (grp == NULL)
++                      sprintf(groupName, "%lu", info.egid);
++              else
++                      sprintf(groupName, "%s", grp->gr_name);
++
++              len = fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state);
++
++              if (strlen(info.command_line) > 1) {
++                      for( j=0; j<(sizeof(info.command_line)-1) && j < (MAX_COLUMN-len); j++) {
++                              if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
++                                      *(info.command_line+j) = ' ';
++                              }
++                      }
++                      *(info.command_line+j) = '\0';
++                      fprintf(stdout, "%s\n", info.command_line);
++              } else {
++                      fprintf(stdout, "[%s]\n", info.name);
++              }
++      }
++
++      /* Free memory */
++      free( pid_array);
++
++      /* close device */
++      status = close (fd);
++      if (status != 0) {
++              fprintf (stderr, "close failed for `%s': %s\n",
++                       device, strerror (errno));
++              goto error;
++      }
++ 
++      exit (0);
++error:
++      fflush(stdout);
++      fflush(stderr);
++      exit (1);
++}
++
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/Makefile linux/fs/Makefile
+--- linux-2.2.18-9.virgin/fs/Makefile  Wed Aug 25 18:29:49 1999
++++ linux/fs/Makefile  Mon Sep 25 16:33:16 2000
+@@ -11,9 +11,10 @@
+ L_OBJS    = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+ O_TARGET := fs.o
+ O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
+-              super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
++              block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
+               ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
+               dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) 
++OX_OBJS = super.o
+ MOD_LIST_NAME := FS_MODULES
+ ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/super.c linux/fs/super.c
+--- linux-2.2.18-9.virgin/fs/super.c   Mon Sep 18 15:02:34 2000
++++ linux/fs/super.c   Mon Sep 25 17:00:57 2000
+@@ -18,6 +18,7 @@
+  */
+ #include <linux/config.h>
++#include <linux/module.h>
+ #include <linux/malloc.h>
+ #include <linux/locks.h>
+ #include <linux/smp_lock.h>
+@@ -25,6 +26,7 @@
+ #include <linux/init.h>
+ #include <linux/quotaops.h>
+ #include <linux/acct.h>
++#include <linux/devmtab.h>
+ #include <asm/uaccess.h>
+@@ -311,7 +313,57 @@
+       { 0, NULL }
+ };
+-int get_filesystem_info( char *buf )
++
++extern int count_mounted_filesystems()
++{
++      struct vfsmount *tmp = vfsmntlist;
++      int count = 0;
++
++      while (tmp)
++      {
++              tmp = tmp->mnt_next;
++              count++;
++      }
++
++      return count;
++}
++EXPORT_SYMBOL(count_mounted_filesystems);
++
++
++extern void get_mtab_entries( int count, struct k_mntent* mntentlist)
++{
++      struct vfsmount *tmp = vfsmntlist;
++      struct proc_fs_info *fs_infop;
++      int i = 0, len;
++
++      while (tmp && i < count)
++      {
++              strncpy(mntentlist[i].mnt_fsname, tmp->mnt_devname, 
++                              sizeof(mntentlist[i].mnt_fsname));
++              strncpy(mntentlist[i].mnt_dir, tmp->mnt_dirname, 
++                              sizeof(mntentlist[i].mnt_dir));
++              strncpy(mntentlist[i].mnt_type, tmp->mnt_sb->s_type->name,
++                              sizeof(mntentlist[i].mnt_type));
++              len = 0;
++              len+=sprintf(mntentlist[i].mnt_opts, "%s", 
++                              tmp->mnt_flags & MS_RDONLY ? "ro" : "rw");
++              for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
++                if (tmp->mnt_flags & fs_infop->flag) {
++                  strncpy(mntentlist[i].mnt_opts+len, fs_infop->str, 
++                                  sizeof(mntentlist[i].mnt_opts)-len);
++                  len += strlen(fs_infop->str);
++                }
++              }
++
++              /* TODO -- add in NFS stuff */ 
++
++              tmp = tmp->mnt_next;
++              i++;
++      }
++}
++EXPORT_SYMBOL(get_mtab_entries);
++
++extern int get_filesystem_info( char *buf )
+ {
+       struct vfsmount *tmp = vfsmntlist;
+       struct proc_fs_info *fs_infop;
+@@ -383,8 +435,37 @@
+       return len;
+ }
++EXPORT_SYMBOL(get_filesystem_info);
++
++extern int count_kfstypes()
++{
++      struct file_system_type * tmp = file_systems;
++      int count = 0;
++
++      while (tmp) {
++              count++;
++              tmp = tmp->next;
++      }
++
++      return count;
++}
++EXPORT_SYMBOL(count_kfstypes);
++
++extern void get_kfstype_list(int count, struct k_fstype* fstypelist)
++{
++      int i = 0;
++      struct file_system_type * tmp = file_systems;
++
++      while (tmp && i < count) {
++              strncpy(fstypelist[i].mnt_type, tmp->name, sizeof(fstypelist[i].mnt_type));
++              fstypelist[i].mnt_nodev = (tmp->fs_flags & FS_REQUIRES_DEV)? 0 : 1;
++              tmp = tmp->next;
++              i++;
++      }
++}
++EXPORT_SYMBOL(get_kfstype_list);
+-int get_filesystem_list(char * buf)
++extern int get_filesystem_list(char * buf)
+ {
+       int len = 0;
+       struct file_system_type * tmp;
+@@ -398,6 +479,7 @@
+       }
+       return len;
+ }
++EXPORT_SYMBOL(get_filesystem_list);
+ struct file_system_type *get_fs_type(const char *name)
+ {
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devmtab.h linux/include/linux/devmtab.h
+--- linux-2.2.18-9.virgin/include/linux/devmtab.h      Wed Dec 31 17:00:00 1969
++++ linux/include/linux/devmtab.h      Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,55 @@
++/* vi: set sw=8 ts=8: */
++/*
++ * -- <linux/devmtab.h>
++ *  
++ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
++ * 
++ * May be copied or modified under the terms of the GNU General Public License.
++ * See linux/COPYING for more information.
++ *
++ * This driver implements an interface whereby programs such as mount(8),
++ * umount(8), and df(1) may obtain all the process information they need to do
++ * their jobs without needing to use /proc.
++ *
++ */
++ 
++#ifndef       _LINUX_DEVMTAB_H
++#define       _LINUX_DEVMTAB_H
++
++
++/*******************************************************
++ * The list of all ioctl(2) commands suported by devmtab.
++ * For the devmtab ioctls, I have commandeered some of the
++ * higher bits of byte 0xeb.
++ *******************************************************/
++#define DEVMTAB_COUNT_FILESYSTEMS  0xebaa /* Get a list of all fs */ 
++#define DEVMTAB_GET_FILESYSTEMS    0xebab /* Get a list of all fs */ 
++#define DEVMTAB_COUNT_MOUNTS       0xebac /* Returns number of mounted filesystems */
++#define DEVMTAB_GET_MOUNTS         0xebad /* Get a list of a mounted fs */
++#define DEVMTAB_SET_ROOTFS_DEVNAME 0xebae /* Replace /dev/root with real name */
++
++/*******************************************************
++ * devmtab ioctl(2) structures
++ *******************************************************/
++
++/* An array of these is returned by the DEVMTAB_GET_FILESYSTEMS ioctl.
++ */
++struct k_fstype {
++      char    mnt_type[255];   /* filesystem type: ext2, nfs, etc. */
++      int     mnt_nodev;       /* Is this a device-less filesystem? */
++};
++
++/* An array of these is returned by the DEVMTAB_GET_MOUNTS ioctl.
++ * This struct should be the same as what libc returns via the
++ * getmntent(3) function (excat this comes from the kernel, not
++ * from whatever noise is in /etc/mtab at the moment... */
++struct k_mntent {
++      char    mnt_fsname[255];    /* name of mounted file system */
++      char    mnt_dir[255];       /* path of file system mount point */
++      char    mnt_type[255];      /* filesystem type: ext2, nfs, etc. */
++      char    mnt_opts[255];      /* Comma-separated list of mount options */
++      int     mnt_freq;       /* dump frequency in days */
++      int     mnt_passno;     /* pass number for parallel fsck */
++};
++
++#endif  /* _LINUX_DEVMTAB_H */
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devps.h linux/include/linux/devps.h
+--- linux-2.2.18-9.virgin/include/linux/devps.h        Wed Dec 31 17:00:00 1969
++++ linux/include/linux/devps.h        Mon Sep 25 17:00:57 2000
+@@ -0,0 +1,78 @@
++/*
++ * -- <linux/devps.h>
++ *  
++ * Copyright (C) 2000 Erik Andersen <andersee@debian.org>
++ * 
++ * May be copied or modified under the terms of the GNU General Public License.
++ * See linux/COPYING for more information.
++ *
++ * This driver implements an interface whereby programs such as ps(1), top(1),
++ * killall(1) and the like may obtain all the process information they need to
++ * do their jobs.
++ *
++ */
++ 
++#ifndef       _LINUX_DEVPS_H
++#define       _LINUX_DEVPS_H
++
++
++/*******************************************************
++ * The list of all ioctl(2) commands suported by devps.
++ * For the devps ioctls, I have commandeered some of the
++ * higher bits of byte 0xeb.
++ *******************************************************/
++#define DEVPS_GET_NUM_PIDS    0xeba1 /* Get a list of all PIDs */ 
++#define DEVPS_GET_PID_LIST    0xeba2 /* Get a list of all PIDs */ 
++#define DEVPS_GET_PID_INFO    0xeba3 /* Get info about a specific PID */
++#define DEVPS_GET_CURRENT_PID 0xeba4 /* Get the current PID */
++
++/*******************************************************
++ * devps ioctl(2) structures
++ *******************************************************/
++
++
++struct pid_info
++{
++      char  name[16];
++      long flags;
++      pid_t pgrp;
++      clock_t tms_cutime;
++      clock_t tms_cstime;
++      clock_t tms_utime;
++      clock_t tms_stime;
++      unsigned long min_flt;
++      unsigned long cmin_flt;
++      unsigned long maj_flt;
++      unsigned long cmaj_flt;
++      pid_t session;
++      pid_t pid;
++      pid_t ppid;
++      int tty;
++      unsigned long start_time;
++      unsigned long uid,euid,suid,fsuid;
++      unsigned long gid,egid,sgid,fsgid;
++      long priority, nice;
++      char state;
++      int processor;
++      unsigned long nswap, cnswap;
++      char command_line[256];
++      char environment[256];
++      char root[256];
++      char cwd[256];
++#if 0
++      /* TODO: Add in this (and probably more) stuff */
++
++      int resident;
++      int size;
++      int share;
++      unsigned long vsize;
++      char exe[MAX_PATH];
++      unsigned long vm_total, vm_locked, vm_rss, vm_data, vm_stack, vm_exec, vm_lib;
++      unsigned long start_code, end_code, start_data, eip, esp;
++      unsigned long signal, blocked;
++#endif
++
++
++};
++
++#endif  /* _LINUX_DEVPS_H */
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/fs.h linux/include/linux/fs.h
+--- linux-2.2.18-9.virgin/include/linux/fs.h   Mon Sep 18 15:08:47 2000
++++ linux/include/linux/fs.h   Mon Sep 25 17:37:50 2000
+@@ -573,6 +573,16 @@
+       struct semaphore s_vfs_rename_sem;      /* Kludge */
+ };
++/* fs/super.c */
++#include <linux/devmtab.h>
++
++extern int count_kfstypes( void);
++extern void get_kfstype_list( int count, struct k_fstype* fstypelist); 
++extern int count_mounted_filesystems( void);
++extern int get_filesystem_info(char *buf);
++extern int get_filesystem_list(char *buf);
++extern void get_mtab_entries( int count, struct k_mntent* mntentlist);
++
+ /*
+  * VFS helper functions..
+  */
+diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/miscdevice.h linux/include/linux/miscdevice.h
+--- linux-2.2.18-9.virgin/include/linux/miscdevice.h   Mon Aug  9 13:04:41 1999
++++ linux/include/linux/miscdevice.h   Mon Sep 25 16:33:17 2000
+@@ -11,6 +11,8 @@
+ #define APOLLO_MOUSE_MINOR 7
+ #define PC110PAD_MINOR 9
+ #define MAC_MOUSE_MINOR 10
++#define DEVPS_MINOR           21
++#define DEVMTAB_MINOR         22
+ #define WATCHDOG_MINOR                130     /* Watchdog timer     */
+ #define TEMP_MINOR            131     /* Temperature Sensor */
+ #define RTC_MINOR 135
diff --git a/kill.c b/kill.c
new file mode 100644 (file)
index 0000000..499be11
--- /dev/null
+++ b/kill.c
@@ -0,0 +1,154 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini kill/killall implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+static const int KILL = 0;
+static const int KILLALL = 1;
+
+
+extern int kill_main(int argc, char **argv)
+{
+       int whichApp, sig = SIGTERM, quiet, errors;
+       const char *name;
+
+#ifdef BB_KILLALL
+       /* Figure out what we are trying to do here */
+       whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; 
+#else
+       whichApp = KILL;
+#endif
+
+       errors=0;
+       quiet=0;
+       argc--;
+       argv++;
+       /* Parse any options */
+       if (argc < 1)
+               show_usage();
+
+       while (argc > 0 && **argv == '-') {
+               while (*++(*argv)) {
+                       switch (**argv) {
+#ifdef BB_KILLALL
+                               case 'q':
+                                       quiet++;
+                                       break;
+#endif
+                               case 'l':
+                                       if(argc>1) {
+                                               for(argv++; *argv; argv++) {
+                                                       name = u_signal_names(*argv, &sig, -1);
+                                                       if(name!=NULL)
+                                                               printf("%s\n", name);
+                                               }
+                                       } else {
+                                               int col = 0;
+                                               for(sig=1; sig < NSIG; sig++) {
+                                                       name = u_signal_names(0, &sig, 1);
+                                                       if(name==NULL)  /* unnamed */
+                                                               continue;
+                                                       col += printf("%2d) %-16s", sig, name);
+                                                       if (col > 60) {
+                                                               printf("\n");
+                                                               col = 0;
+                                                       }
+                                               }
+                                               printf("\n");
+                                       }
+                                       return EXIT_SUCCESS;
+                               case '-':
+                                       show_usage();
+                               default:
+                                       name = u_signal_names(*argv, &sig, 0);
+                                       if(name==NULL)
+                                               error_msg_and_die( "bad signal name: %s", *argv);
+                                       argc--;
+                                       argv++;
+                                       goto do_it_now;
+                       }
+                       argc--;
+                       argv++;
+               }
+       }
+
+do_it_now:
+
+       if (whichApp == KILL) {
+               /* Looks like they want to do a kill. Do that */
+               while (--argc >= 0) {
+                       int pid;
+
+                       if (!isdigit(**argv))
+                               perror_msg_and_die( "Bad PID");
+                       pid = strtol(*argv, NULL, 0);
+                       if (kill(pid, sig) != 0) {
+                               perror_msg( "Could not kill pid '%d'", pid);
+                               errors++;
+                       }
+                       argv++;
+               }
+       } 
+#ifdef BB_KILLALL
+       else {
+               pid_t myPid=getpid();
+               /* Looks like they want to do a killall.  Do that */
+               while (--argc >= 0) {
+                       long* pidList;
+
+                       pidList = find_pid_by_name(*argv);
+                       if (!pidList || *pidList<=0) {
+                               errors++;
+                               if (!quiet)
+                                       error_msg( "%s: no process killed", *argv);
+                       } else {
+                               for(; *pidList!=0; pidList++) {
+                                       if (*pidList==myPid)
+                                               continue;
+                                       if (kill(*pidList, sig) != 0) {
+                                               errors++;
+                                               if (!quiet)
+                                                       perror_msg( "Could not kill pid '%d'", *pidList);
+                                       }
+                               }
+                       }
+
+                       /* Note that we don't bother to free the memory
+                        * allocated in find_pid_by_name().  It will be freed
+                        * upon exit, so we can save a byte or two */
+                       argv++;
+               }
+       }
+#endif
+
+       return errors;
+}
diff --git a/klogd.c b/klogd.c
new file mode 100644 (file)
index 0000000..75c7e10
--- /dev/null
+++ b/klogd.c
@@ -0,0 +1,160 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini klogd implementation for busybox
+ *
+ * Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>.
+ * Changes: Made this a standalone busybox module which uses standalone
+ *                                     syslog() client interface.
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@mail.com>
+ *
+ * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h> /* for our signal() handlers */
+#include <string.h> /* strncpy() */
+#include <errno.h>  /* errno and friends */
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/syslog.h>
+
+#if __GNU_LIBRARY__ < 5
+# ifdef __alpha__
+#   define klogctl syslog
+# endif
+#else
+# include <sys/klog.h>
+#endif
+
+#include "busybox.h"
+
+static void klogd_signal(int sig)
+{
+       klogctl(7, NULL, 0);
+       klogctl(0, 0, 0);
+       //logMessage(0, "Kernel log daemon exiting.");
+       syslog_msg(LOG_SYSLOG, LOG_NOTICE, "Kernel log daemon exiting.");
+       exit(TRUE);
+}
+
+static void doKlogd (void) __attribute__ ((noreturn));
+static void doKlogd (void)
+{
+       int priority = LOG_INFO;
+       char log_buffer[4096];
+       int i, n, lastc;
+       char *start;
+
+       /* Set up sig handlers */
+       signal(SIGINT, klogd_signal);
+       signal(SIGKILL, klogd_signal);
+       signal(SIGTERM, klogd_signal);
+       signal(SIGHUP, SIG_IGN);
+
+       /* "Open the log. Currently a NOP." */
+       klogctl(1, NULL, 0);
+
+       syslog_msg(LOG_SYSLOG, LOG_NOTICE, "klogd started: " BB_BANNER);
+
+       while (1) {
+               /* Use kernel syscalls */
+               memset(log_buffer, '\0', sizeof(log_buffer));
+               n = klogctl(2, log_buffer, sizeof(log_buffer));
+               if (n < 0) {
+                       char message[80];
+
+                       if (errno == EINTR)
+                               continue;
+                       snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", 
+                                                                                               errno, strerror(errno));
+                       syslog_msg(LOG_SYSLOG, LOG_ERR, message);
+                       exit(1);
+               }
+
+               /* klogctl buffer parsing modelled after code in dmesg.c */
+               start=&log_buffer[0];
+               lastc='\0';
+               for (i=0; i<n; i++) {
+                       if (lastc == '\0' && log_buffer[i] == '<') {
+                               priority = 0;
+                               i++;
+                               while (isdigit(log_buffer[i])) {
+                                       priority = priority*10+(log_buffer[i]-'0');
+                                       i++;
+                               }
+                               if (log_buffer[i] == '>') i++;
+                               start = &log_buffer[i];
+                       }
+                       if (log_buffer[i] == '\n') {
+                               log_buffer[i] = '\0';  /* zero terminate this message */
+                               syslog_msg(LOG_KERN, priority, start);
+                               start = &log_buffer[i+1];
+                               priority = LOG_INFO;
+                       }
+                       lastc = log_buffer[i];
+               }
+       }
+}
+
+extern int klogd_main(int argc, char **argv)
+{
+       /* no options, no getopt */
+       int opt;
+#ifndef __uClinux__ /* fork() not available in uClinux */
+       int doFork = TRUE;
+#endif  /* __uClinux__ */
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "n")) > 0) {
+               switch (opt) {
+                       case 'n':
+#ifndef __uClinux__    /* fork() not available in uClinux */
+                               doFork = FALSE;
+#endif  /* __uClinux__ */
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+#ifndef __uClinux__    /* fork() not available in uClinux */
+       if (doFork == TRUE) {
+               if (daemon(0, 1) < 0)
+                       perror_msg_and_die("daemon");
+       }
+#endif  /* __uClinux__ */
+
+       doKlogd();
+       
+       return EXIT_SUCCESS;
+}
+
+/*
+Local Variables
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/lash.c b/lash.c
new file mode 100644 (file)
index 0000000..eb88da3
--- /dev/null
+++ b/lash.c
@@ -0,0 +1,1650 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lash -- the BusyBox Lame-Ass SHell
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
+ *
+ * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
+ * under the following liberal license: "We have placed this source code in the
+ * public domain. Use it in any project, free or commercial."
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* This shell's parsing engine is officially at a dead-end.
+ * Future work shell work should be done using hush.c
+ */
+
+//For debugging/development on the shell only...
+//#define DEBUG_SHELL
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <termios.h>
+#include "busybox.h"
+#include "cmdedit.h"
+
+#ifdef BB_LOCALE_SUPPORT
+#include <locale.h>
+#endif
+
+#include <glob.h>
+#define expand_t       glob_t
+
+
+static const int MAX_READ = 128;       /* size of input buffer for `read' builtin */
+#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+
+
+enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
+       REDIRECT_APPEND
+};
+
+static const unsigned int DEFAULT_CONTEXT=0x1;
+static const unsigned int IF_TRUE_CONTEXT=0x2;
+static const unsigned int IF_FALSE_CONTEXT=0x4;
+static const unsigned int THEN_EXP_CONTEXT=0x8;
+static const unsigned int ELSE_EXP_CONTEXT=0x10;
+
+
+struct jobset {
+       struct job *head;                       /* head of list of running jobs */
+       struct job *fg;                         /* current foreground job */
+};
+
+struct redir_struct {
+       enum redir_type type;   /* type of redirection */
+       int fd;                                         /* file descriptor being redirected */
+       char *filename;                         /* file to redirect fd to */
+};
+
+struct child_prog {
+       pid_t pid;                                      /* 0 if exited */
+       char **argv;                            /* program name and arguments */
+       int num_redirects;                      /* elements in redirection array */
+       struct redir_struct *redirects; /* I/O redirects */
+       int is_stopped;                         /* is the program currently running? */
+       struct job *family;                     /* pointer back to the child's parent job */
+};
+
+struct job {
+       int jobid;                                      /* job number */
+       int num_progs;                          /* total number of programs in job */
+       int running_progs;                      /* number of programs running */
+       char *text;                                     /* name of job */
+       char *cmdbuf;                           /* buffer various argv's point into */
+       pid_t pgrp;                                     /* process group ID for the job */
+       struct child_prog *progs;       /* array of programs in job */
+       struct job *next;                       /* to track background commands */
+       int stopped_progs;                      /* number of programs alive, but stopped */
+       unsigned int job_context;       /* bitmask defining current context */
+       struct jobset *job_list;
+};
+
+struct built_in_command {
+       char *cmd;                                      /* name */
+       char *descr;                            /* description */
+       int (*function) (struct child_prog *);  /* function ptr */
+};
+
+struct close_me {
+       int fd;
+       struct close_me *next;
+};
+
+/* function prototypes for builtins */
+static int builtin_cd(struct child_prog *cmd);
+static int builtin_exec(struct child_prog *cmd);
+static int builtin_exit(struct child_prog *cmd);
+static int builtin_fg_bg(struct child_prog *cmd);
+static int builtin_help(struct child_prog *cmd);
+static int builtin_jobs(struct child_prog *dummy);
+static int builtin_pwd(struct child_prog *dummy);
+static int builtin_export(struct child_prog *cmd);
+static int builtin_source(struct child_prog *cmd);
+static int builtin_unset(struct child_prog *cmd);
+static int builtin_read(struct child_prog *cmd);
+
+
+/* function prototypes for shell stuff */
+static void mark_open(int fd);
+static void mark_closed(int fd);
+static void close_all(void);
+static void checkjobs(struct jobset *job_list);
+static void remove_job(struct jobset *j_list, struct job *job);
+static int get_command(FILE * source, char *command);
+static int parse_command(char **command_ptr, struct job *job, int *inbg);
+static int run_command(struct job *newjob, int inbg, int outpipe[2]);
+static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
+static int busy_loop(FILE * input);
+
+
+/* Table of built-in functions (these are non-forking builtins, meaning they
+ * can change global variables in the parent shell process but they will not
+ * work with pipes and redirects; 'unset foo | whatever' will not work) */
+static struct built_in_command bltins[] = {
+       {"bg", "Resume a job in the background", builtin_fg_bg},
+       {"cd", "Change working directory", builtin_cd},
+       {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
+       {"exit", "Exit from shell()", builtin_exit},
+       {"fg", "Bring job into the foreground", builtin_fg_bg},
+       {"jobs", "Lists the active jobs", builtin_jobs},
+       {"export", "Set environment variable", builtin_export},
+       {"unset", "Unset environment variable", builtin_unset},
+       {"read", "Input environment variable", builtin_read},
+       {".", "Source-in and run commands in a file", builtin_source},
+       /* to do: add ulimit */
+       {NULL, NULL, NULL}
+};
+
+/* Table of forking built-in functions (things that fork cannot change global
+ * variables in the parent process, such as the current working directory) */
+static struct built_in_command bltins_forking[] = {
+       {"pwd", "Print current directory", builtin_pwd},
+       {"help", "List shell built-in commands", builtin_help},
+       {NULL, NULL, NULL}
+};
+
+
+static int shell_context;  /* Type prompt trigger (PS1 or PS2) */
+
+
+/* Globals that are static to this file */
+static const char *cwd;
+static char *local_pending_command = NULL;
+static struct jobset job_list = { NULL, NULL };
+static int argc;
+static char **argv;
+static struct close_me *close_me_head;
+static int last_return_code;
+static int last_bg_pid;
+static unsigned int last_jobid;
+static int shell_terminal;
+static pid_t shell_pgrp;
+static char *PS1;
+static char *PS2 = "> ";
+
+
+#ifdef DEBUG_SHELL
+static inline void debug_printf(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       vfprintf(stderr, format, args);
+       va_end(args);
+}
+#else
+static inline void debug_printf(const char *format, ...) { }
+#endif
+
+/*
+       Most builtins need access to the struct child_prog that has
+       their arguments, previously coded as cmd->progs[0].  That coding
+       can exhibit a bug, if the builtin is not the first command in
+       a pipeline: "echo foo | exec sort" will attempt to exec foo.
+
+builtin   previous use      notes
+------ -----------------  ---------
+cd      cmd->progs[0]
+exec    cmd->progs[0]  squashed bug: didn't look for applets or forking builtins
+exit    cmd->progs[0]
+fg_bg   cmd->progs[0], job_list->head, job_list->fg
+help    0
+jobs    job_list->head
+pwd     0
+export  cmd->progs[0]
+source  cmd->progs[0]
+unset   cmd->progs[0]
+read    cmd->progs[0]
+
+I added "struct job *family;" to struct child_prog,
+and switched API to builtin_foo(struct child_prog *child);
+So   cmd->text        becomes  child->family->text
+     cmd->job_context  becomes  child->family->job_context
+     cmd->progs[0]    becomes  *child
+     job_list          becomes  child->family->job_list
+ */
+
+/* built-in 'cd <path>' handler */
+static int builtin_cd(struct child_prog *child)
+{
+       char *newdir;
+
+       if (child->argv[1] == NULL)
+               newdir = getenv("HOME");
+       else
+               newdir = child->argv[1];
+       if (chdir(newdir)) {
+               printf("cd: %s: %m\n", newdir);
+               return EXIT_FAILURE;
+       }
+       cwd = xgetcwd((char *)cwd);
+       if (!cwd)
+               cwd = unknown;
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'exec' handler */
+static int builtin_exec(struct child_prog *child)
+{
+       if (child->argv[1] == NULL)
+               return EXIT_SUCCESS;   /* Really? */
+       child->argv++;
+       close_all();
+       pseudo_exec(child);
+       /* never returns */
+}
+
+/* built-in 'exit' handler */
+static int builtin_exit(struct child_prog *child)
+{
+       if (child->argv[1] == NULL)
+               exit(EXIT_SUCCESS);
+
+       exit (atoi(child->argv[1]));
+}
+
+/* built-in 'fg' and 'bg' handler */
+static int builtin_fg_bg(struct child_prog *child)
+{
+       int i, jobnum;
+       struct job *job=NULL;
+
+       /* If they gave us no args, assume they want the last backgrounded task */
+       if (!child->argv[1]) {
+               for (job = child->family->job_list->head; job; job = job->next) {
+                       if (job->jobid == last_jobid) {
+                               break;
+                       }
+               }
+               if (!job) {
+                       error_msg("%s: no current job", child->argv[0]);
+                       return EXIT_FAILURE;
+               }
+       } else {
+               if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
+                       error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+                       return EXIT_FAILURE;
+               }
+               for (job = child->family->job_list->head; job; job = job->next) {
+                       if (job->jobid == jobnum) {
+                               break;
+                       }
+               }
+               if (!job) {
+                       error_msg("%s: %d: no such job", child->argv[0], jobnum);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (*child->argv[0] == 'f') {
+               /* Put the job into the foreground.  */
+               tcsetpgrp(shell_terminal, job->pgrp);
+
+               child->family->job_list->fg = job;
+       }
+
+       /* Restart the processes in the job */
+       for (i = 0; i < job->num_progs; i++)
+               job->progs[i].is_stopped = 0;
+
+       job->stopped_progs = 0;
+
+       if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
+               if (i == ESRCH) {
+                       remove_job(&job_list, job);
+               } else {
+                       perror_msg("kill (SIGCONT)");
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'help' handler */
+static int builtin_help(struct child_prog *dummy)
+{
+       struct built_in_command *x;
+
+       printf("\nBuilt-in commands:\n");
+       printf("-------------------\n");
+       for (x = bltins; x->cmd; x++) {
+               if (x->descr==NULL)
+                       continue;
+               printf("%s\t%s\n", x->cmd, x->descr);
+       }
+       for (x = bltins_forking; x->cmd; x++) {
+               if (x->descr==NULL)
+                       continue;
+               printf("%s\t%s\n", x->cmd, x->descr);
+       }
+       printf("\n\n");
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'jobs' handler */
+static int builtin_jobs(struct child_prog *child)
+{
+       struct job *job;
+       char *status_string;
+
+       for (job = child->family->job_list->head; job; job = job->next) {
+               if (job->running_progs == job->stopped_progs)
+                       status_string = "Stopped";
+               else
+                       status_string = "Running";
+
+               printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
+       }
+       return EXIT_SUCCESS;
+}
+
+
+/* built-in 'pwd' handler */
+static int builtin_pwd(struct child_prog *dummy)
+{
+       cwd = xgetcwd((char *)cwd);
+       if (!cwd)
+               cwd = unknown;
+       puts(cwd);
+       return EXIT_SUCCESS;
+}
+
+/* built-in 'export VAR=value' handler */
+static int builtin_export(struct child_prog *child)
+{
+       int res;
+       char *v = child->argv[1];
+
+       if (v == NULL) {
+               char **e;
+               for (e = environ; *e; e++) {
+                       puts(*e);
+               }
+               return 0;
+       }
+       res = putenv(v);
+       if (res)
+               fprintf(stderr, "export: %m\n");
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+       if (strncmp(v, "PS1=", 4)==0)
+               PS1 = getenv("PS1");
+#endif
+
+#ifdef BB_LOCALE_SUPPORT
+       if(strncmp(v, "LC_ALL=", 7)==0)
+               setlocale(LC_ALL, getenv("LC_ALL"));
+       if(strncmp(v, "LC_CTYPE=", 9)==0)
+               setlocale(LC_CTYPE, getenv("LC_CTYPE"));
+#endif
+
+       return (res);
+}
+
+/* built-in 'read VAR' handler */
+static int builtin_read(struct child_prog *child)
+{
+       int res = 0, len, newlen;
+       char *s;
+       char string[MAX_READ];
+
+       if (child->argv[1]) {
+               /* argument (VAR) given: put "VAR=" into buffer */
+               snprintf(string, sizeof(string)-1, "%s=", child->argv[1]);
+               len = strlen(string);
+               fgets(&string[len], sizeof(string) - len, stdin);       /* read string */
+               newlen = strlen(string);
+               if(newlen > len)
+                       string[--newlen] = '\0';        /* chomp trailing newline */
+               /*
+               ** string should now contain "VAR=<value>"
+               ** copy it (putenv() won't do that, so we must make sure
+               ** the string resides in a static buffer!)
+               */
+               res = -1;
+               if((s = strdup(string)))
+                       res = putenv(s);
+               if (res)
+                       fprintf(stderr, "read: %m\n");
+       }
+       else
+               fgets(string, sizeof(string), stdin);
+
+       return (res);
+}
+
+/* Built-in '.' handler (read-in and execute commands from file) */
+static int builtin_source(struct child_prog *child)
+{
+       FILE *input;
+       int status;
+       int fd;
+
+       if (child->argv[1] == NULL)
+               return EXIT_FAILURE;
+
+       input = fopen(child->argv[1], "r");
+       if (!input) {
+               printf( "Couldn't open file '%s'\n", child->argv[1]);
+               return EXIT_FAILURE;
+       }
+
+       fd=fileno(input);
+       mark_open(fd);
+       /* Now run the file */
+       status = busy_loop(input);
+       fclose(input);
+       mark_closed(fd);
+       return (status);
+}
+
+/* built-in 'unset VAR' handler */
+static int builtin_unset(struct child_prog *child)
+{
+       if (child->argv[1] == NULL) {
+               printf( "unset: parameter required.\n");
+               return EXIT_FAILURE;
+       }
+       unsetenv(child->argv[1]);
+       return EXIT_SUCCESS;
+}
+
+static void mark_open(int fd)
+{
+       struct close_me *new = xmalloc(sizeof(struct close_me));
+       new->fd = fd;
+       new->next = close_me_head;
+       close_me_head = new;
+}
+
+static void mark_closed(int fd)
+{
+       struct close_me *tmp;
+       if (close_me_head == NULL || close_me_head->fd != fd)
+               error_msg_and_die("corrupt close_me");
+       tmp = close_me_head;
+       close_me_head = close_me_head->next;
+       free(tmp);
+}
+
+static void close_all()
+{
+       struct close_me *c, *tmp;
+       for (c=close_me_head; c; c=tmp) {
+               close(c->fd);
+               tmp=c->next;
+               free(c);
+       }
+       close_me_head = NULL;
+}
+
+
+/* free up all memory from a job */
+static void free_job(struct job *cmd)
+{
+       int i;
+       struct jobset *keep;
+
+       for (i = 0; i < cmd->num_progs; i++) {
+               free(cmd->progs[i].argv);
+               if (cmd->progs[i].redirects)
+                       free(cmd->progs[i].redirects);
+       }
+       if (cmd->progs)
+               free(cmd->progs);
+       if (cmd->text)
+               free(cmd->text);
+       if (cmd->cmdbuf)
+               free(cmd->cmdbuf);
+       keep = cmd->job_list;
+       memset(cmd, 0, sizeof(struct job));
+       cmd->job_list = keep;
+}
+
+/* remove a job from a jobset */
+static void remove_job(struct jobset *j_list, struct job *job)
+{
+       struct job *prevjob;
+
+       free_job(job);
+       if (job == j_list->head) {
+               j_list->head = job->next;
+       } else {
+               prevjob = j_list->head;
+               while (prevjob->next != job)
+                       prevjob = prevjob->next;
+               prevjob->next = job->next;
+       }
+
+       if (j_list->head)
+               last_jobid = j_list->head->jobid;
+       else
+               last_jobid = 0;
+
+       free(job);
+}
+
+/* Checks to see if any background processes have exited -- if they 
+   have, figure out why and see if a job has completed */
+static void checkjobs(struct jobset *j_list)
+{
+       struct job *job;
+       pid_t childpid;
+       int status;
+       int prognum = 0;
+
+       while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
+               for (job = j_list->head; job; job = job->next) {
+                       prognum = 0;
+                       while (prognum < job->num_progs &&
+                                  job->progs[prognum].pid != childpid) prognum++;
+                       if (prognum < job->num_progs)
+                               break;
+               }
+
+               /* This happens on backticked commands */
+               if(job==NULL)
+                       return;
+
+               if (WIFEXITED(status) || WIFSIGNALED(status)) {
+                       /* child exited */
+                       job->running_progs--;
+                       job->progs[prognum].pid = 0;
+
+                       if (!job->running_progs) {
+                               printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
+                               last_jobid=0;
+                               remove_job(j_list, job);
+                       }
+               } else {
+                       /* child stopped */
+                       job->stopped_progs++;
+                       job->progs[prognum].is_stopped = 1;
+
+#if 0
+                       /* Printing this stuff is a pain, since it tends to
+                        * overwrite the prompt an inconveinient moments.  So
+                        * don't do that.  */
+                       if (job->stopped_progs == job->num_progs) {
+                               printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
+                                          job->text);
+                       }
+#endif 
+               }
+       }
+
+       if (childpid == -1 && errno != ECHILD)
+               perror_msg("waitpid");
+}
+
+/* squirrel != NULL means we squirrel away copies of stdin, stdout,
+ * and stderr if they are redirected. */
+static int setup_redirects(struct child_prog *prog, int squirrel[])
+{
+       int i;
+       int openfd;
+       int mode = O_RDONLY;
+       struct redir_struct *redir = prog->redirects;
+
+       for (i = 0; i < prog->num_redirects; i++, redir++) {
+               switch (redir->type) {
+               case REDIRECT_INPUT:
+                       mode = O_RDONLY;
+                       break;
+               case REDIRECT_OVERWRITE:
+                       mode = O_WRONLY | O_CREAT | O_TRUNC;
+                       break;
+               case REDIRECT_APPEND:
+                       mode = O_WRONLY | O_CREAT | O_APPEND;
+                       break;
+               }
+
+               openfd = open(redir->filename, mode, 0666);
+               if (openfd < 0) {
+                       /* this could get lost if stderr has been redirected, but
+                          bash and ash both lose it as well (though zsh doesn't!) */
+                       perror_msg("error opening %s", redir->filename);
+                       return 1;
+               }
+
+               if (openfd != redir->fd) {
+                       if (squirrel && redir->fd < 3) {
+                               squirrel[redir->fd] = dup(redir->fd);
+                       }
+                       dup2(openfd, redir->fd);
+                       close(openfd);
+               }
+       }
+
+       return 0;
+}
+
+static void restore_redirects(int squirrel[])
+{
+       int i, fd;
+       for (i=0; i<3; i++) {
+               fd = squirrel[i];
+               if (fd != -1) {
+                       /* No error checking.  I sure wouldn't know what
+                        * to do with an error if I found one! */
+                       dup2(fd, i);
+                       close(fd);
+               }
+       }
+}
+
+static inline void cmdedit_set_initial_prompt(void)
+{
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       PS1 = NULL;
+#else
+       PS1 = getenv("PS1");
+       if(PS1==0)
+               PS1 = "\\w \\$ ";
+#endif 
+}
+
+static inline void setup_prompt_string(char **prompt_str)
+{
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       /* Set up the prompt */
+       if (shell_context == 0) {
+               if (PS1)
+                       free(PS1);
+               PS1=xmalloc(strlen(cwd)+4);
+               sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ?  "$ ":"# ");
+               *prompt_str = PS1;
+       } else {
+               *prompt_str = PS2;
+       }
+#else
+       *prompt_str = (shell_context==0)? PS1 : PS2;
+#endif 
+}
+
+static int get_command(FILE * source, char *command)
+{
+       char *prompt_str;
+
+       if (source == NULL) {
+               if (local_pending_command) {
+                       /* a command specified (-c option): return it & mark it done */
+                       strcpy(command, local_pending_command);
+                       free(local_pending_command);
+                       local_pending_command = NULL;
+                       return 0;
+               }
+               return 1;
+       }
+
+       if (source == stdin) {
+               setup_prompt_string(&prompt_str);
+
+#ifdef BB_FEATURE_COMMAND_EDITING
+               /*
+               ** enable command line editing only while a command line
+               ** is actually being read; otherwise, we'll end up bequeathing
+               ** atexit() handlers and other unwanted stuff to our
+               ** child processes (rob@sysgo.de)
+               */
+               cmdedit_read_input(prompt_str, command);
+               return 0;
+#else
+               fputs(prompt_str, stdout);
+#endif
+       }
+
+       if (!fgets(command, BUFSIZ - 2, source)) {
+               if (source == stdin)
+                       printf("\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+static char* itoa(register int i)
+{
+       static char a[7]; /* Max 7 ints */
+       register char *b = a + sizeof(a) - 1;
+       int   sign = (i < 0);
+
+       if (sign)
+               i = -i;
+       *b = 0;
+       do
+       {
+               *--b = '0' + (i % 10);
+               i /= 10;
+       }
+       while (i);
+       if (sign)
+               *--b = '-';
+       return b;
+}
+
+char * strsep_space( char *string, int * ix)
+{
+       char *token, *begin;
+
+       begin = string;
+
+       /* Short circuit the trivial case */
+       if ( !string || ! string[*ix])
+               return NULL;
+
+       /* Find the end of the token. */
+       while( string && string[*ix] && !isspace(string[*ix]) ) {
+               (*ix)++;
+       }
+
+       /* Find the end of any whitespace trailing behind 
+        * the token and let that be part of the token */
+       while( string && string[*ix] && isspace(string[*ix]) ) {
+               (*ix)++;
+       }
+
+       if (! string && *ix==0) {
+               /* Nothing useful was found */
+               return NULL;
+       }
+
+       token = xmalloc(*ix+1);
+       token[*ix] = '\0';
+       strncpy(token, string,  *ix); 
+
+       return token;
+}
+
+static int expand_arguments(char *command)
+{
+       int total_length=0, length, i, retval, ix = 0;
+       expand_t expand_result;
+       char *tmpcmd, *cmd, *cmd_copy;
+       char *src, *dst, *var;
+       const char *out_of_space = "out of space during expansion";
+       int flags = GLOB_NOCHECK
+#ifdef GLOB_BRACE
+               | GLOB_BRACE
+#endif 
+#ifdef GLOB_TILDE
+               | GLOB_TILDE
+#endif 
+               ;
+
+       /* get rid of the terminating \n */
+       chomp(command);
+
+       /* Fix up escape sequences to be the Real Thing(tm) */
+       while( command && command[ix]) {
+               if (command[ix] == '\\') {
+                       const char *tmp = command+ix+1;
+                       command[ix] = process_escape_sequence(  &tmp );
+                       memmove(command+ix + 1, tmp, strlen(tmp)+1);
+               }
+               ix++;
+       }
+       /* Use glob and then fixup environment variables and such */
+
+       /* It turns out that glob is very stupid.  We have to feed it one word at a
+        * time since it can't cope with a full string.  Here we convert command
+        * (char*) into cmd (char**, one word per string) */
+
+       /* We need a clean copy, so strsep can mess up the copy while
+        * we write stuff into the original (in a minute) */
+       cmd = cmd_copy = strdup(command);
+       *command = '\0';
+       for (ix = 0, tmpcmd = cmd; 
+                       (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
+               if (*tmpcmd == '\0')
+                       break;
+               /* we need to trim() the result for glob! */
+               trim(tmpcmd);
+               retval = glob(tmpcmd, flags, NULL, &expand_result);
+               free(tmpcmd); /* Free mem allocated by strsep_space */
+               if (retval == GLOB_NOSPACE) {
+                       /* Mem may have been allocated... */
+                       globfree (&expand_result);
+                       error_msg(out_of_space);
+                       return FALSE;
+               } else if (retval != 0) {
+                       /* Some other error.  GLOB_NOMATCH shouldn't
+                        * happen because of the GLOB_NOCHECK flag in 
+                        * the glob call. */
+                       error_msg("syntax error");
+                       return FALSE;
+               } else {
+                       /* Convert from char** (one word per string) to a simple char*,
+                        * but don't overflow command which is BUFSIZ in length */
+                       for (i=0; i < expand_result.gl_pathc; i++) {
+                               length=strlen(expand_result.gl_pathv[i]);
+                               if (total_length+length+1 >= BUFSIZ) {
+                                       error_msg(out_of_space);
+                                       return FALSE;
+                               }
+                               strcat(command+total_length, " ");
+                               total_length+=1;
+                               strcat(command+total_length, expand_result.gl_pathv[i]);
+                               total_length+=length;
+                       }
+                       globfree (&expand_result);
+               }
+       }
+       free(cmd_copy);
+       trim(command);
+
+       /* Now do the shell variable substitutions which 
+        * wordexp can't do for us, namely $? and $! */
+       src = command;
+       while((dst = strchr(src,'$')) != NULL){
+               var = NULL;
+               switch(*(dst+1)) {
+                       case '?':
+                               var = itoa(last_return_code);
+                               break;
+                       case '!':
+                               if (last_bg_pid==-1)
+                                       *(var)='\0';
+                               else
+                                       var = itoa(last_bg_pid);
+                               break;
+                               /* Everything else like $$, $#, $[0-9], etc. should all be
+                                * expanded by wordexp(), so we can in theory skip that stuff
+                                * here, but just to be on the safe side (i.e., since uClibc
+                                * wordexp doesn't do this stuff yet), lets leave it in for
+                                * now. */
+                       case '$':
+                               var = itoa(getpid());
+                               break;
+                       case '#':
+                               var = itoa(argc-1);
+                               break;
+                       case '0':case '1':case '2':case '3':case '4':
+                       case '5':case '6':case '7':case '8':case '9':
+                               {
+                                       int ixx=*(dst + 1)-48+1;
+                                       if (ixx >= argc) {
+                                               var='\0';
+                                       } else {
+                                               var = argv[ixx];
+                                       }
+                               }
+                               break;
+
+               }
+               if (var) {
+                       /* a single character construction was found, and 
+                        * already handled in the case statement */
+                       src=dst+2;
+               } else {
+                       /* Looks like an environment variable */
+                       char delim_hold;
+                       int num_skip_chars=0;
+                       int dstlen = strlen(dst);
+                       /* Is this a ${foo} type variable? */
+                       if (dstlen >=2 && *(dst+1) == '{') {
+                               src=strchr(dst+1, '}');
+                               num_skip_chars=1;
+                       } else {
+                               src=dst+1;
+                               while(isalnum(*src) || *src=='_') src++;
+                       }
+                       if (src == NULL) {
+                               src = dst+dstlen;
+                       }
+                       delim_hold=*src;
+                       *src='\0';  /* temporary */
+                       var = getenv(dst + 1 + num_skip_chars);
+                       *src=delim_hold;
+                       src += num_skip_chars;
+               }
+               if (var == NULL) {
+                       /* Seems we got an un-expandable variable.  So delete it. */
+                       var = "";
+               }
+               {
+                       int subst_len = strlen(var);
+                       int trail_len = strlen(src);
+                       if (dst+subst_len+trail_len >= command+BUFSIZ) {
+                               error_msg(out_of_space);
+                               return FALSE;
+                       }
+                       /* Move stuff to the end of the string to accommodate
+                        * filling the created gap with the new stuff */
+                       memmove(dst+subst_len, src, trail_len+1);
+                       /* Now copy in the new stuff */
+                       memcpy(dst, var, subst_len);
+                       src = dst+subst_len;
+               }
+       }
+
+       return TRUE;
+}
+
+/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
+   line). If a valid command is found, command_ptr is set to point to
+   the beginning of the next command (if the original command had more 
+   then one job associated with it) or NULL if no more commands are 
+   present. */
+static int parse_command(char **command_ptr, struct job *job, int *inbg)
+{
+       char *command;
+       char *return_command = NULL;
+       char *src, *buf, *chptr;
+       int argc_l = 0;
+       int done = 0;
+       int argv_alloced;
+       int i, saw_quote = 0;
+       char quote = '\0';
+       int count;
+       struct child_prog *prog;
+
+       /* skip leading white space */
+       while (**command_ptr && isspace(**command_ptr))
+               (*command_ptr)++;
+
+       /* this handles empty lines or leading '#' characters */
+       if (!**command_ptr || (**command_ptr == '#')) {
+               job->num_progs=0;
+               return 0;
+       }
+
+       *inbg = 0;
+       job->num_progs = 1;
+       job->progs = xmalloc(sizeof(*job->progs));
+
+       /* We set the argv elements to point inside of this string. The 
+          memory is freed by free_job(). Allocate twice the original
+          length in case we need to quote every single character.
+
+          Getting clean memory relieves us of the task of NULL 
+          terminating things and makes the rest of this look a bit 
+          cleaner (though it is, admittedly, a tad less efficient) */
+       job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
+       job->text = NULL;
+
+       prog = job->progs;
+       prog->num_redirects = 0;
+       prog->redirects = NULL;
+       prog->is_stopped = 0;
+       prog->family = job;
+
+       argv_alloced = 5;
+       prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
+       prog->argv[0] = job->cmdbuf;
+
+       buf = command;
+       src = *command_ptr;
+       while (*src && !done) {
+               if (quote == *src) {
+                       quote = '\0';
+               } else if (quote) {
+                       if (*src == '\\') {
+                               src++;
+                               if (!*src) {
+                                       error_msg("character expected after \\");
+                                       free_job(job);
+                                       return 1;
+                               }
+
+                               /* in shell, "\'" should yield \' */
+                               if (*src != quote) {
+                                       *buf++ = '\\';
+                                       *buf++ = '\\';
+                               }
+                       } else if (*src == '*' || *src == '?' || *src == '[' ||
+                                          *src == ']') *buf++ = '\\';
+                       *buf++ = *src;
+               } else if (isspace(*src)) {
+                       if (*prog->argv[argc_l] || saw_quote) {
+                               buf++, argc_l++;
+                               /* +1 here leaves room for the NULL which ends argv */
+                               if ((argc_l + 1) == argv_alloced) {
+                                       argv_alloced += 5;
+                                       prog->argv = xrealloc(prog->argv,
+                                                                                 sizeof(*prog->argv) *
+                                                                                 argv_alloced);
+                               }
+                               prog->argv[argc_l] = buf;
+                               saw_quote = 0;
+                       }
+               } else
+                       switch (*src) {
+                       case '"':
+                       case '\'':
+                               quote = *src;
+                               saw_quote = 1;
+                               break;
+
+                       case '#':                       /* comment */
+                               if (*(src-1)== '$')
+                                       *buf++ = *src;
+                               else
+                                       done = 1;
+                               break;
+
+                       case '>':                       /* redirects */
+                       case '<':
+                               i = prog->num_redirects++;
+                               prog->redirects = xrealloc(prog->redirects,
+                                                                                         sizeof(*prog->redirects) *
+                                                                                         (i + 1));
+
+                               prog->redirects[i].fd = -1;
+                               if (buf != prog->argv[argc_l]) {
+                                       /* the stuff before this character may be the file number 
+                                          being redirected */
+                                       prog->redirects[i].fd =
+                                               strtol(prog->argv[argc_l], &chptr, 10);
+
+                                       if (*chptr && *prog->argv[argc_l]) {
+                                               buf++, argc_l++;
+                                               prog->argv[argc_l] = buf;
+                                       }
+                               }
+
+                               if (prog->redirects[i].fd == -1) {
+                                       if (*src == '>')
+                                               prog->redirects[i].fd = 1;
+                                       else
+                                               prog->redirects[i].fd = 0;
+                               }
+
+                               if (*src++ == '>') {
+                                       if (*src == '>')
+                                               prog->redirects[i].type =
+                                                       REDIRECT_APPEND, src++;
+                                       else
+                                               prog->redirects[i].type = REDIRECT_OVERWRITE;
+                               } else {
+                                       prog->redirects[i].type = REDIRECT_INPUT;
+                               }
+
+                               /* This isn't POSIX sh compliant. Oh well. */
+                               chptr = src;
+                               while (isspace(*chptr))
+                                       chptr++;
+
+                               if (!*chptr) {
+                                       error_msg("file name expected after %c", *(src-1));
+                                       free_job(job);
+                                       job->num_progs=0;
+                                       return 1;
+                               }
+
+                               prog->redirects[i].filename = buf;
+                               while (*chptr && !isspace(*chptr))
+                                       *buf++ = *chptr++;
+
+                               src = chptr - 1;        /* we src++ later */
+                               prog->argv[argc_l] = ++buf;
+                               break;
+
+                       case '|':                       /* pipe */
+                               /* finish this command */
+                               if (*prog->argv[argc_l] || saw_quote)
+                                       argc_l++;
+                               if (!argc_l) {
+                                       error_msg("empty command in pipe");
+                                       free_job(job);
+                                       job->num_progs=0;
+                                       return 1;
+                               }
+                               prog->argv[argc_l] = NULL;
+
+                               /* and start the next */
+                               job->num_progs++;
+                               job->progs = xrealloc(job->progs,
+                                                                         sizeof(*job->progs) * job->num_progs);
+                               prog = job->progs + (job->num_progs - 1);
+                               prog->num_redirects = 0;
+                               prog->redirects = NULL;
+                               prog->is_stopped = 0;
+                               prog->family = job;
+                               argc_l = 0;
+
+                               argv_alloced = 5;
+                               prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
+                               prog->argv[0] = ++buf;
+
+                               src++;
+                               while (*src && isspace(*src))
+                                       src++;
+
+                               if (!*src) {
+                                       error_msg("empty command in pipe");
+                                       free_job(job);
+                                       job->num_progs=0;
+                                       return 1;
+                               }
+                               src--;                  /* we'll ++ it at the end of the loop */
+
+                               break;
+
+                       case '&':                       /* background */
+                               *inbg = 1;
+                       case ';':                       /* multiple commands */
+                               done = 1;
+                               return_command = *command_ptr + (src - *command_ptr) + 1;
+                               break;
+
+                       case '\\':
+                               src++;
+                               if (!*src) {
+                                       error_msg("character expected after \\");
+                                       free_job(job);
+                                       return 1;
+                               }
+                               if (*src == '*' || *src == '[' || *src == ']'
+                                       || *src == '?') *buf++ = '\\';
+                               /* fallthrough */
+                       default:
+                               *buf++ = *src;
+                       }
+
+               src++;
+       }
+
+       if (*prog->argv[argc_l] || saw_quote) {
+               argc_l++;
+       }
+       if (!argc_l) {
+               free_job(job);
+               return 0;
+       }
+       prog->argv[argc_l] = NULL;
+
+       if (!return_command) {
+               job->text = xmalloc(strlen(*command_ptr) + 1);
+               strcpy(job->text, *command_ptr);
+       } else {
+               /* This leaves any trailing spaces, which is a bit sloppy */
+               count = return_command - *command_ptr;
+               job->text = xmalloc(count + 1);
+               strncpy(job->text, *command_ptr, count);
+               job->text[count] = '\0';
+       }
+
+       *command_ptr = return_command;
+       
+       return 0;
+}
+
+/* Run the child_prog, no matter what kind of command it uses.
+ */
+static int pseudo_exec(struct child_prog *child)
+{
+       struct built_in_command *x;
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       char *name;
+#endif
+
+       /* Check if the command matches any of the non-forking builtins.
+        * Depending on context, this might be redundant.  But it's
+        * easier to waste a few CPU cycles than it is to figure out
+        * if this is one of those cases.
+        */
+       for (x = bltins; x->cmd; x++) {
+               if (strcmp(child->argv[0], x->cmd) == 0 ) {
+                       _exit(x->function(child));
+               }
+       }
+
+       /* Check if the command matches any of the forking builtins. */
+       for (x = bltins_forking; x->cmd; x++) {
+               if (strcmp(child->argv[0], x->cmd) == 0) {
+                       applet_name=x->cmd;
+                       _exit (x->function(child));
+               }
+       }
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       /* Check if the command matches any busybox internal
+        * commands ("applets") here.  Following discussions from
+        * November 2000 on busybox@busybox.net, don't use
+        * get_last_path_component().  This way explicit (with
+        * slashes) filenames will never be interpreted as an
+        * applet, just like with builtins.  This way the user can
+        * override an applet with an explicit filename reference.
+        * The only downside to this change is that an explicit
+        * /bin/foo invocation will fork and exec /bin/foo, even if
+        * /bin/foo is a symlink to busybox.
+        */
+       name = child->argv[0];
+
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
+        * if you run /bin/cat, it will use BusyBox cat even if 
+        * /bin/cat exists on the filesystem and is _not_ busybox.
+        * Some systems want this, others do not.  Choose wisely.  :-)
+        */
+       name = get_last_path_component(name);
+#endif
+
+       {
+           char** argv_l=child->argv;
+           int argc_l;
+           for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+           optind = 1;
+           run_applet_by_name(name, argc_l, child->argv);
+       }
+#endif
+
+       execvp(child->argv[0], child->argv);
+
+       /* Do not use perror_msg_and_die() here, since we must not 
+        * call exit() but should call _exit() instead */
+       fprintf(stderr, "%s: %m\n", child->argv[0]);
+       _exit(EXIT_FAILURE);
+}
+
+static void insert_job(struct job *newjob, int inbg)
+{
+       struct job *thejob;
+       struct jobset *j_list=newjob->job_list;
+
+       /* find the ID for thejob to use */
+       newjob->jobid = 1;
+       for (thejob = j_list->head; thejob; thejob = thejob->next)
+               if (thejob->jobid >= newjob->jobid)
+                       newjob->jobid = thejob->jobid + 1;
+
+       /* add thejob to the list of running jobs */
+       if (!j_list->head) {
+               thejob = j_list->head = xmalloc(sizeof(*thejob));
+       } else {
+               for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
+               thejob->next = xmalloc(sizeof(*thejob));
+               thejob = thejob->next;
+       }
+
+       *thejob = *newjob;   /* physically copy the struct job */
+       thejob->next = NULL;
+       thejob->running_progs = thejob->num_progs;
+       thejob->stopped_progs = 0;
+
+       if (inbg) {
+               /* we don't wait for background thejobs to return -- append it 
+                  to the list of backgrounded thejobs and leave it alone */
+               printf("[%d] %d\n", thejob->jobid,
+                          newjob->progs[newjob->num_progs - 1].pid);
+               last_jobid = newjob->jobid;
+               last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
+       } else {
+               newjob->job_list->fg = thejob;
+
+               /* move the new process group into the foreground */
+               /* suppress messages when run from /linuxrc mag@sysgo.de */
+               if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
+                       perror_msg("tcsetpgrp");
+       }
+}
+
+static int run_command(struct job *newjob, int inbg, int outpipe[2])
+{
+       /* struct job *thejob; */
+       int i;
+       int nextin, nextout;
+       int pipefds[2];                         /* pipefd[0] is for reading */
+       struct built_in_command *x;
+       struct child_prog *child;
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &i;
+       (void) &nextin;
+       (void) &nextout;
+#endif
+
+       nextin = 0, nextout = 1;
+       for (i = 0; i < newjob->num_progs; i++) {
+               child = & (newjob->progs[i]);
+
+               if ((i + 1) < newjob->num_progs) {
+                       if (pipe(pipefds)<0) perror_msg_and_die("pipe");
+                       nextout = pipefds[1];
+               } else {
+                       if (outpipe[1]!=-1) {
+                               nextout = outpipe[1];
+                       } else {
+                               nextout = 1;
+                       }
+               }
+
+
+               /* Check if the command matches any non-forking builtins,
+                * but only if this is a simple command.
+                * Non-forking builtins within pipes have to fork anyway,
+                * and are handled in pseudo_exec.  "echo foo | read bar"
+                * is doomed to failure, and doesn't work on bash, either.
+                */
+               if (newjob->num_progs == 1) {
+                       for (x = bltins; x->cmd; x++) {
+                               if (strcmp(child->argv[0], x->cmd) == 0 ) {
+                                       int squirrel[] = {-1, -1, -1};
+                                       int rcode;
+                                       setup_redirects(child, squirrel);
+                                       rcode = x->function(child);
+                                       restore_redirects(squirrel);
+                                       return rcode;
+                               }
+                       }
+               }
+
+               if (!(child->pid = fork())) 
+               {
+                       /* Set the handling for job control signals back to the default.  */
+                       signal(SIGINT, SIG_DFL);
+                       signal(SIGQUIT, SIG_DFL);
+                       signal(SIGTSTP, SIG_DFL);
+                       signal(SIGTTIN, SIG_DFL);
+                       signal(SIGTTOU, SIG_DFL);
+                       signal(SIGCHLD, SIG_DFL);
+
+                       close_all();
+
+                       if (outpipe[1]!=-1) {
+                               close(outpipe[0]);
+                       }
+                       if (nextin != 0) {
+                               dup2(nextin, 0);
+                               close(nextin);
+                       }
+
+                       if (nextout != 1) {
+                               dup2(nextout, 1);
+                               dup2(nextout, 2);  /* Really? */
+                               close(nextout);
+                               close(pipefds[0]);
+                       }
+
+                       /* explicit redirects override pipes */
+                       setup_redirects(child,NULL);
+
+                       pseudo_exec(child);
+               }
+               if (outpipe[1]!=-1) {
+                       close(outpipe[1]);
+               }
+
+               /* put our child in the process group whose leader is the
+                  first process in this pipe */
+               setpgid(child->pid, newjob->progs[0].pid);
+               if (nextin != 0)
+                       close(nextin);
+               if (nextout != 1)
+                       close(nextout);
+
+               /* If there isn't another process, nextin is garbage 
+                  but it doesn't matter */
+               nextin = pipefds[0];
+       }
+
+       newjob->pgrp = newjob->progs[0].pid;
+
+       insert_job(newjob, inbg);
+
+       return 0;
+}
+
+static int busy_loop(FILE * input)
+{
+       char *command;
+       char *next_command = NULL;
+       struct job newjob;
+       pid_t  parent_pgrp;
+       int i;
+       int inbg;
+       int status;
+       newjob.job_list = &job_list;
+       newjob.job_context = DEFAULT_CONTEXT;
+
+       /* save current owner of TTY so we can restore it on exit */
+       parent_pgrp = tcgetpgrp(shell_terminal);
+
+       command = (char *) xcalloc(BUFSIZ, sizeof(char));
+
+       while (1) {
+               if (!job_list.fg) {
+                       /* no job is in the foreground */
+
+                       /* see if any background processes have exited */
+                       checkjobs(&job_list);
+
+                       if (!next_command) {
+                               if (get_command(input, command))
+                                       break;
+                               next_command = command;
+                       }
+
+                       if (expand_arguments(next_command) == FALSE) {
+                               free(command);
+                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
+                               next_command = NULL;
+                               continue;
+                       }
+
+                       if (!parse_command(&next_command, &newjob, &inbg) &&
+                               newjob.num_progs) {
+                               int pipefds[2] = {-1,-1};
+                               debug_printf( "job=%p fed to run_command by busy_loop()'\n", 
+                                               &newjob);
+                               run_command(&newjob, inbg, pipefds);
+                       }
+                       else {
+                               free(command);
+                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
+                               next_command = NULL;
+                       }
+               } else {
+                       /* a job is running in the foreground; wait for it */
+                       i = 0;
+                       while (!job_list.fg->progs[i].pid ||
+                                  job_list.fg->progs[i].is_stopped == 1) i++;
+
+                       if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
+                               if (errno != ECHILD) {
+                                       perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
+                               }
+                       }
+
+                       if (WIFEXITED(status) || WIFSIGNALED(status)) {
+                               /* the child exited */
+                               job_list.fg->running_progs--;
+                               job_list.fg->progs[i].pid = 0;
+
+                               last_return_code=WEXITSTATUS(status);
+
+                               if (!job_list.fg->running_progs) {
+                                       /* child exited */
+                                       remove_job(&job_list, job_list.fg);
+                                       job_list.fg = NULL;
+                               }
+                       } else {
+                               /* the child was stopped */
+                               job_list.fg->stopped_progs++;
+                               job_list.fg->progs[i].is_stopped = 1;
+
+                               if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
+                                       printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
+                                                  "Stopped", job_list.fg->text);
+                                       job_list.fg = NULL;
+                               }
+                       }
+
+                       if (!job_list.fg) {
+                               /* move the shell to the foreground */
+                               /* suppress messages when run from /linuxrc mag@sysgo.de */
+                               if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
+                                       perror_msg("tcsetpgrp"); 
+                       }
+               }
+       }
+       free(command);
+
+       /* return controlling TTY back to parent process group before exiting */
+       if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
+               perror_msg("tcsetpgrp");
+
+       /* return exit status if called with "-c" */
+       if (input == NULL && WIFEXITED(status))
+               return WEXITSTATUS(status);
+       
+       return 0;
+}
+
+
+#ifdef BB_FEATURE_CLEAN_UP
+void free_memory(void)
+{
+       if (cwd && cwd!=unknown) {
+               free((char*)cwd);
+       }
+       if (local_pending_command)
+               free(local_pending_command);
+
+       if (job_list.fg && !job_list.fg->running_progs) {
+               remove_job(&job_list, job_list.fg);
+       }
+}
+#endif
+
+/* Make sure we have a controlling tty.  If we get started under a job
+ * aware app (like bash for example), make sure we are now in charge so
+ * we don't fight over who gets the foreground */
+static void setup_job_control()
+{
+       int status;
+       
+       /* Loop until we are in the foreground.  */
+       while ((status = tcgetpgrp (shell_terminal)) >= 0) {
+               if (status == (shell_pgrp = getpgrp ())) {
+                       break;
+               }
+               kill (- shell_pgrp, SIGTTIN);
+       }
+
+       /* Ignore interactive and job-control signals.  */
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       signal(SIGTSTP, SIG_IGN);
+       signal(SIGTTIN, SIG_IGN);
+       signal(SIGTTOU, SIG_IGN);
+       signal(SIGCHLD, SIG_IGN);
+
+       /* Put ourselves in our own process group.  */
+       setsid();
+       shell_pgrp = getpid ();
+       setpgid (shell_pgrp, shell_pgrp);
+
+       /* Grab control of the terminal.  */
+       tcsetpgrp(shell_terminal, shell_pgrp);
+}
+
+int lash_main(int argc_l, char **argv_l)
+{
+       int opt, interactive=FALSE;
+       FILE *input = stdin;
+       argc = argc_l;
+       argv = argv_l;
+
+       /* These variables need re-initializing when recursing */
+       last_jobid = 0;
+       local_pending_command = NULL;
+       close_me_head = NULL;
+       job_list.head = NULL;
+       job_list.fg = NULL;
+       last_return_code=1;
+
+       if (argv[0] && argv[0][0] == '-') {
+               FILE *prof_input;
+               prof_input = fopen("/etc/profile", "r");
+               if (prof_input) {
+                       int tmp_fd = fileno(prof_input);
+                       mark_open(tmp_fd);      
+                       /* Now run the file */
+                       busy_loop(prof_input);
+                       fclose(prof_input);
+                       mark_closed(tmp_fd);
+               }
+       }
+
+       while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
+               switch (opt) {
+                       case 'c':
+                               input = NULL;
+                               if (local_pending_command != 0)
+                                       error_msg_and_die("multiple -c arguments");
+                               local_pending_command = xstrdup(argv[optind]);
+                               optind++;
+                               argv = argv+optind;
+                               break;
+                       case 'i':
+                               interactive = TRUE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+       /* A shell is interactive if the `-i' flag was given, or if all of
+        * the following conditions are met:
+        *        no -c command
+        *    no arguments remaining or the -s flag given
+        *    standard input is a terminal
+        *    standard output is a terminal
+        *    Refer to Posix.2, the description of the `sh' utility. */
+       if (argv[optind]==NULL && input==stdin &&
+                       isatty(fileno(stdin)) && isatty(fileno(stdout))) {
+               interactive=TRUE;
+       }
+       setup_job_control();
+       if (interactive==TRUE) {
+               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
+               /* Looks like they want an interactive shell */
+               printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
+               printf( "Enter 'help' for a list of built-in commands.\n\n");
+       } else if (local_pending_command==NULL) {
+               //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
+               input = xfopen(argv[optind], "r");
+               mark_open(fileno(input));  /* be lazy, never mark this closed */
+       }
+
+       /* initialize the cwd -- this is never freed...*/
+       cwd = xgetcwd(0);
+       if (!cwd)
+               cwd = unknown;
+
+#ifdef BB_FEATURE_CLEAN_UP
+       atexit(free_memory);
+#endif
+
+#ifdef BB_FEATURE_COMMAND_EDITING
+       cmdedit_set_initial_prompt();
+#else
+       PS1 = NULL;
+#endif
+       
+       return (busy_loop(input));
+}
diff --git a/length.c b/length.c
new file mode 100644 (file)
index 0000000..73becd2
--- /dev/null
+++ b/length.c
@@ -0,0 +1,13 @@
+/* vi: set sw=4 ts=4: */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "busybox.h"
+
+extern int length_main(int argc, char **argv)
+{
+       if (argc != 2 || **(argv + 1) == '-')
+               show_usage();
+       printf("%lu\n", (long)strlen(argv[1]));
+       return EXIT_SUCCESS;
+}
diff --git a/libbb/.cvsignore b/libbb/.cvsignore
new file mode 100644 (file)
index 0000000..2bbe016
--- /dev/null
@@ -0,0 +1 @@
+loop.h
diff --git a/libbb/Makefile b/libbb/Makefile
new file mode 100644 (file)
index 0000000..2c8ab2b
--- /dev/null
@@ -0,0 +1,11 @@
+# Silly wrapper makefile.  This Makefile is _not_ used by the build system for
+# busybox, it is just to make working on libbb more conveinient.
+#  -Erik Andersen
+
+all:
+       make -C .. libbb.a
+
+clean:
+       - rm -rf libbb.a
+       - find . -name \*.o -exec rm -f {} \;
+
diff --git a/libbb/README b/libbb/README
new file mode 100644 (file)
index 0000000..38934c2
--- /dev/null
@@ -0,0 +1,14 @@
+Please see the LICENSE file for copyright information.
+    
+libbb is BusyBox's utility library.  This all used to be in a single file
+(utility.c to be specific).  When I split utility.c up to create libbb, I did
+not carefully fix up the copyright and licensing information.  I'll do that for
+the next release.
+
+For now, just trust me that a bunch of people have worked on this stuff, 
+and it is all GPL'ed.
+
+       Erik Andersen 
+       <andersee@debian.org>
+       <andersen@codepoet.org>
+
diff --git a/libbb/arith.c b/libbb/arith.c
new file mode 100644 (file)
index 0000000..e5b3213
--- /dev/null
@@ -0,0 +1,376 @@
+/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
+   
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+   
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+   
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* This is my infix parser/evaluator. It is optimized for size, intended
+ * as a replacement for yacc-based parsers. However, it may well be faster
+ * than a comparable parser writen in yacc. The supported operators are
+ * listed in #defines below. Parens, order of operations, and error handling
+ * are supported. This code is threadsafe. The exact expression format should
+ * be that which POSIX specifies for shells. */
+
+/* The code uses a simple two-stack algorithm. See
+ * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
+ * for a detailed explaination of the infix-to-postfix algorithm on which
+ * this is based (this code differs in that it applies operators immediately
+ * to the stack instead of adding them to a queue to end up with an
+ * expression). */
+
+/* To use the routine, call it with an expression string and error return
+ * pointer */
+
+/*
+ * Aug 24, 2001              Manuel Novoa III
+ *
+ * Reduced the generated code size by about 30% (i386) and fixed several bugs.
+ *
+ * 1) In arith_apply():
+ *    a) Cached values of *numptr and &(numptr[-1]).
+ *    b) Removed redundant test for zero denominator.
+ *
+ * 2) In arith():
+ *    a) Eliminated redundant code for processing operator tokens by moving
+ *       to a table-based implementation.  Also folded handling of parens
+ *       into the table.
+ *    b) Combined all 3 loops which called arith_apply to reduce generated
+ *       code size at the cost of speed.
+ *
+ * 3) The following expressions were treated as valid by the original code:
+ *       1()  ,    0!  ,    1 ( *3 )   .
+ *    These bugs have been fixed by internally enclosing the expression in
+ *    parens and then checking that all binary ops and right parens are
+ *    preceded by a valid expression (NUM_TOKEN).
+ *
+ * Note: It may be desireable to replace Aaron's test for whitespace with
+ * ctype's isspace() if it is used by another busybox applet or if additional
+ * whitespace chars should be considered.  Look below the "#include"s for a
+ * precompiler test.
+ */
+
+/*
+ * Aug 26, 2001              Manuel Novoa III
+ *
+ * Return 0 for null expressions.  Pointed out by vodz.
+ *
+ * Merge in Aaron's comments previously posted to the busybox list,
+ * modified slightly to take account of my changes to the code.
+ *
+ * TODO: May want to allow access to variables in the arith code.
+ *       This would:
+ *       1) allow us to evaluate $A as 0 if A isn't set (although this
+ *          would require changes to ash.c too).
+ *       2) allow us to write expressions as $(( A + 2 )).
+ *       This could be done using a callback function passed to the
+ *       arith() function of by requiring such a function with fixed
+ *       name as an extern.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <alloca.h>
+#include "libbb.h"
+
+/* 
+ * Use "#if 1" below for Aaron's original test for whitespace.
+ * Use "#if 0" for ctype's isspace().
+ * */
+#if 1
+#undef isspace
+#define isspace(arithval) \
+       (arithval == ' ' || arithval == '\n' || arithval == '\t')
+#endif
+
+typedef char operator;
+
+/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
+ * precedence, and high 3 are an ID unique accross operators of that
+ * precedence. The ID portion is so that multiple operators can have the
+ * same precedence, ensuring that the leftmost one is evaluated first.
+ * Consider * and /. */
+
+#define tok_decl(prec,id) (((id)<<5)|(prec))
+#define PREC(op) ((op)&0x1F)
+
+#define TOK_LPAREN tok_decl(0,0)
+
+#define TOK_OR tok_decl(1,0)
+
+#define TOK_AND tok_decl(2,0)
+
+#define TOK_BOR tok_decl(3,0)
+
+#define TOK_BXOR tok_decl(4,0)
+
+#define TOK_BAND tok_decl(5,0)
+
+#define TOK_EQ tok_decl(6,0)
+#define TOK_NE tok_decl(6,1)
+
+#define TOK_LT tok_decl(7,0)
+#define TOK_GT tok_decl(7,1)
+#define TOK_GE tok_decl(7,2)
+#define TOK_LE tok_decl(7,3)
+
+#define TOK_LSHIFT tok_decl(8,0)
+#define TOK_RSHIFT tok_decl(8,1)
+
+#define TOK_ADD tok_decl(9,0)
+#define TOK_SUB tok_decl(9,1)
+
+#define TOK_MUL tok_decl(10,0)
+#define TOK_DIV tok_decl(10,1)
+#define TOK_REM tok_decl(10,2)
+
+/* For now all unary operators have the same precedence, and that's used to
+ * identify them as unary operators */
+#define UNARYPREC 14
+#define TOK_BNOT tok_decl(UNARYPREC,0)
+#define TOK_NOT tok_decl(UNARYPREC,1)
+#define TOK_UMINUS tok_decl(UNARYPREC,2)
+#define TOK_UPLUS tok_decl(UNARYPREC,3)
+
+#define TOK_NUM tok_decl(15,0)
+#define TOK_RPAREN tok_decl(15,1)
+#define TOK_ERROR  tok_decl(15,2)      /* just a place-holder really */
+
+#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr)
+#define NUMPTR (*numstackptr)
+
+/* "applying" a token means performing it on the top elements on the integer
+ * stack. For a unary operator it will only change the top element, but a
+ * binary operator will pop two arguments and push a result */
+static short arith_apply(operator    op, long *numstack, long **numstackptr)
+{
+       long numptr_val;
+       long *NUMPTR_M1;
+
+       if (NUMPTR == numstack) goto err; /* There is no operator that can work
+                                                                                without arguments */
+       NUMPTR_M1 = NUMPTR - 1;
+       if (op == TOK_UMINUS)
+               *NUMPTR_M1 *= -1;
+       else if (op == TOK_NOT)
+               *NUMPTR_M1 = !(*NUMPTR_M1);
+       else if (op == TOK_BNOT)
+               *NUMPTR_M1 = ~(*NUMPTR_M1);
+       else if (op != TOK_UPLUS) {
+               /* Binary operators */
+       if (NUMPTR_M1 == numstack) goto err; /* ... and binary operators need two
+                                                                                  arguments */
+       numptr_val = *--NUMPTR;         /* ... and they pop one */
+               NUMPTR_M1 = NUMPTR - 1;
+       if (op == TOK_BOR)
+                       *NUMPTR_M1 |= numptr_val;
+       else if (op == TOK_OR)
+                       *NUMPTR_M1 = numptr_val || *NUMPTR_M1;
+       else if (op == TOK_BAND)
+                       *NUMPTR_M1 &= numptr_val;
+       else if (op == TOK_AND)
+                       *NUMPTR_M1 = *NUMPTR_M1 && numptr_val;
+       else if (op == TOK_EQ)
+                       *NUMPTR_M1 = (*NUMPTR_M1 == numptr_val);
+       else if (op == TOK_NE)
+                       *NUMPTR_M1 = (*NUMPTR_M1 != numptr_val);
+       else if (op == TOK_GE)
+                       *NUMPTR_M1 = (*NUMPTR_M1 >= numptr_val);
+       else if (op == TOK_RSHIFT)
+                       *NUMPTR_M1 >>= numptr_val;
+       else if (op == TOK_LSHIFT)
+                       *NUMPTR_M1 <<= numptr_val;
+       else if (op == TOK_GT)
+                       *NUMPTR_M1 = (*NUMPTR_M1 > numptr_val);
+       else if (op == TOK_LT)
+                       *NUMPTR_M1 = (*NUMPTR_M1 < numptr_val);
+       else if (op == TOK_LE)
+                       *NUMPTR_M1 = (*NUMPTR_M1 <= numptr_val);
+       else if (op == TOK_MUL)
+                       *NUMPTR_M1 *= numptr_val;
+       else if (op == TOK_ADD)
+                       *NUMPTR_M1 += numptr_val;
+       else if (op == TOK_SUB)
+                       *NUMPTR_M1 -= numptr_val;
+       else if(numptr_val==0)          /* zero divisor check */
+                       return -2;
+       else if (op == TOK_DIV)
+                       *NUMPTR_M1 /= numptr_val;
+       else if (op == TOK_REM)
+                       *NUMPTR_M1 %= numptr_val;
+               /* WARNING!!!  WARNING!!!  WARNING!!! */
+               /* Any new operators should be added BEFORE the zero divisor check! */
+       }
+       return 0;
+err: return(-1);
+}
+
+static const char endexpression[] = ")";
+
+/* + and - (in that order) must be last */
+static const char op_char[] = "!<>=|&*/%~()+-";
+static const char op_token[] = {
+       /* paired with equal */
+       TOK_NE, TOK_LE, TOK_GE,
+       /* paired with self -- note: ! is special-cased below*/
+       TOK_ERROR, TOK_LSHIFT, TOK_RSHIFT, TOK_EQ, TOK_OR, TOK_AND,
+       /* singles */
+       TOK_NOT, TOK_LT, TOK_GT, TOK_ERROR, TOK_BOR, TOK_BAND,
+       TOK_MUL, TOK_DIV, TOK_REM, TOK_BNOT, TOK_LPAREN, TOK_RPAREN,
+       TOK_ADD, TOK_SUB, TOK_UPLUS, TOK_UMINUS
+};
+
+#define NUM_PAIR_EQUAL  3
+#define NUM_PAIR_SAME   6
+
+extern long arith (const char *expr, int *errcode)
+{
+       register char arithval; /* Current character under analysis */
+       operator    lasttok, op;
+       unsigned char prec;
+
+       const char *p = endexpression;
+
+       size_t datasizes = strlen(expr) + 2;
+
+       /* Stack of integers */
+       /* The proof that there can be no more than strlen(startbuf)/2+1 integers
+        * in any given correct or incorrect expression is left as an excersize to
+        * the reader. */
+       long *numstack = alloca(((datasizes)/2)*sizeof(long)),
+               *numstackptr = numstack;
+       /* Stack of operator tokens */
+       operator *stack = alloca((datasizes) * sizeof(operator)),
+               *stackptr = stack;
+
+       *numstack = 0;
+       *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
+
+  loop:
+       if ((arithval = *expr) == 0) {
+               if (p == endexpression) { /* Null expression. */
+                       *errcode = 0;
+                       return *numstack;
+               }
+
+               /* This is only reached after all tokens have been extracted from the
+                * input stream. If there are still tokens on the operator stack, they
+                * are to be applied in order. At the end, there should be a final
+                * result on the integer stack */
+
+               if (expr != endexpression + 1) {        /* If we haven't done so already, */
+                       expr = endexpression;   /* append a closing right paren */
+                       goto loop;      /* and let the loop process it. */
+               }
+               /* At this point, we're done with the expression. */
+               if (numstackptr != numstack+1) {/* ... but if there isn't, it's bad */
+                 err:
+                       return (*errcode = -1);
+                       /* NOTREACHED */
+               }
+               return *numstack;
+       } else {
+               /* Continue processing the expression.  */
+               if (isspace(arithval)) {
+                       goto prologue;          /* Skip whitespace */
+               }
+               if ((unsigned)arithval-'0' <= 9) /* isdigit */ {
+                       *numstackptr++ = strtol(expr, (char **) &expr, 10);
+                       lasttok = TOK_NUM;
+                       goto loop;
+               }
+#if 1
+               if ((p = strchr(op_char, arithval)) == NULL) {
+                       goto err;
+               }
+#else
+           for ( p=op_char ; *p != arithval ; p++ ) {
+                       if (!*p) {
+                               goto err;
+                       }
+               }
+#endif
+               p = op_token + (int)(p - op_char);
+               ++expr;
+               if ((p >= op_token + NUM_PAIR_EQUAL) || (*expr != '=')) {
+                       p += NUM_PAIR_EQUAL;
+                       if ((p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL)
+                               || (*expr != arithval) || (arithval == '!')) {
+                               --expr;
+                               if (arithval == '=') { /* single = */
+                                       goto err;
+                               }
+                               p += NUM_PAIR_SAME;
+                               /* Plus and minus are binary (not unary) _only_ if the last
+                                * token was as number, or a right paren (which pretends to be
+                                * a number, since it evaluates to one). Think about it.
+                                * It makes sense. */
+                               if ((lasttok != TOK_NUM)
+                                       && (p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL
+                                               + sizeof(op_char) - 2)) {
+                                       p += 2; /* Unary plus or minus */
+                               }
+                       }
+               }
+               op = *p;
+
+               /* We don't want a unary operator to cause recursive descent on the
+                * stack, because there can be many in a row and it could cause an
+                * operator to be evaluated before its argument is pushed onto the
+                * integer stack. */
+               /* But for binary operators, "apply" everything on the operator
+                * stack until we find an operator with a lesser priority than the
+                * one we have just extracted. */
+               /* Left paren is given the lowest priority so it will never be
+                * "applied" in this way */
+               prec = PREC(op);
+               if ((prec > 0) && (prec != UNARYPREC)) { /* not left paren or unary */
+                       if (lasttok != TOK_NUM) { /* binary op must be preceded by a num */
+                               goto err;
+                       }
+                       while (stackptr != stack) {
+                               if (op == TOK_RPAREN) {
+                                       /* The algorithm employed here is simple: while we don't
+                                        * hit an open paren nor the bottom of the stack, pop
+                                        * tokens and apply them */
+                                       if (stackptr[-1] == TOK_LPAREN) {
+                                               --stackptr;
+                                               lasttok = TOK_NUM; /* Any operator directly after a */
+                                               /* close paren should consider itself binary */
+                                               goto prologue;
+                                       }
+                               } else if (PREC(stackptr[-1]) < prec) {
+                                       break;
+                               }
+                               *errcode = ARITH_APPLY(*--stackptr);
+                               if(*errcode) return *errcode;
+                       }
+                       if (op == TOK_RPAREN) {
+                               goto err;
+                       }
+               }
+
+               /* Push this operator to the stack and remember it. */
+               *stackptr++ = lasttok = op;
+
+         prologue:
+               ++expr;
+               goto loop;
+       }
+}
diff --git a/libbb/ask_confirmation.c b/libbb/ask_confirmation.c
new file mode 100644 (file)
index 0000000..d4d943a
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+int ask_confirmation()
+{
+       int c = '\0';
+       int ret = 0;
+
+       while (c != '\n') {
+               c = getchar();
+               if ( c != '\n' ) {
+                       ret = ((c=='y')||(c=='Y')) ? 1 : 0;
+               }
+       }
+       return ret;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/chomp.c b/libbb/chomp.c
new file mode 100644 (file)
index 0000000..94404a9
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+
+
+void chomp(char *s)
+{
+       char *lc = last_char_is(s, '\n');
+       
+       if(lc)
+               *lc = 0;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
new file mode 100644 (file)
index 0000000..e62b99e
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* concatenate path and file name to new allocation buffer,
+ * not addition '/' if path name already have '/'
+*/
+
+#include <string.h>
+#include "libbb.h"
+
+extern char *concat_path_file(const char *path, const char *filename)
+{
+       char *outbuf;
+       char *lc;
+
+       if (!path)
+           path="";
+       lc = last_char_is(path, '/');
+       while (*filename == '/')
+               filename++;
+       outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
+       sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
+
+       return outbuf;
+}
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
new file mode 100644 (file)
index 0000000..f24fa01
--- /dev/null
@@ -0,0 +1,271 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libbb.h"
+
+#define CONFIG_FEATURE_PRESERVE_HARDLINKS
+
+int copy_file(const char *source, const char *dest, int flags)
+{
+       struct stat source_stat;
+       struct stat dest_stat;
+       int dest_exists = 0;
+       int status = 0;
+
+       if ((!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+                       stat(source, &source_stat) < 0) ||
+                       ((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+                        lstat(source, &source_stat) < 0)) {
+               perror_msg("%s", source);
+               return -1;
+       }
+
+       if (lstat(dest, &dest_stat) < 0) {
+               if (errno != ENOENT) {
+                       perror_msg("unable to stat `%s'", dest);
+                       return -1;
+               }
+       } else {
+               if (source_stat.st_dev == dest_stat.st_dev &&
+                       source_stat.st_ino == dest_stat.st_ino) {
+               error_msg("`%s' and `%s' are the same file", source, dest);
+               return -1;
+       }
+               dest_exists = 1;
+       }
+
+       if (S_ISDIR(source_stat.st_mode)) {
+               DIR *dp;
+               struct dirent *d;
+               mode_t saved_umask = 0;
+
+               if (!(flags & FILEUTILS_RECUR)) {
+                       error_msg("%s: omitting directory", source);
+                       return -1;
+               }
+
+               /* Create DEST.  */
+               if (dest_exists) {
+                       if (!S_ISDIR(dest_stat.st_mode)) {
+                               error_msg("`%s' is not a directory", dest);
+                               return -1;
+                       }
+               } else {
+                       mode_t mode;
+                       saved_umask = umask(0);
+
+                       mode = source_stat.st_mode;
+                       if (!(flags & FILEUTILS_PRESERVE_STATUS))
+                               mode = source_stat.st_mode & ~saved_umask;
+                       mode |= S_IRWXU;
+
+                       if (mkdir(dest, mode) < 0) {
+                               umask(saved_umask);
+                               perror_msg("cannot create directory `%s'", dest);
+                               return -1;
+                       }
+
+                       umask(saved_umask);
+               }
+
+               /* Recursively copy files in SOURCE.  */
+               if ((dp = opendir(source)) == NULL) {
+                       perror_msg("unable to open directory `%s'", source);
+                       status = -1;
+                       goto end;
+               }
+
+               while ((d = readdir(dp)) != NULL) {
+                       char *new_source, *new_dest;
+
+                       if (strcmp(d->d_name, ".") == 0 ||
+                                       strcmp(d->d_name, "..") == 0)
+                               continue;
+
+                       new_source = concat_path_file(source, d->d_name);
+                       new_dest = concat_path_file(dest, d->d_name);
+                       if (copy_file(new_source, new_dest, flags) < 0)
+                               status = -1;
+                       free(new_source);
+                       free(new_dest);
+               }
+               /* closedir have only EBADF error, but "dp" not changes */
+               closedir(dp);
+
+               if (!dest_exists &&
+                               chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
+                       perror_msg("unable to change permissions of `%s'", dest);
+                       status = -1;
+               }
+       } else if (S_ISREG(source_stat.st_mode)) {
+               FILE *sfp, *dfp=NULL;
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+               char *link_name;
+
+               if (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+                               is_in_ino_dev_hashtable(&source_stat, &link_name)) {
+                       if (link(link_name, dest) < 0) {
+                               perror_msg("unable to link `%s'", dest);
+                               return -1;
+                       }
+
+                       return 0;
+               }
+#endif
+
+               if ((sfp = wfopen(source, "r")) == NULL) {
+                       return -1;
+               }
+
+               if (dest_exists) {
+                       if (flags & FILEUTILS_INTERACTIVE) {
+                               fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest);
+                               if (!ask_confirmation()) {
+                                       fclose (sfp);
+                                       return 0;
+                               }
+                       }
+
+                       if ((dfp = fopen(dest, "w")) == NULL) {
+                               if (!(flags & FILEUTILS_FORCE)) {
+                                       perror_msg("unable to open `%s'", dest);
+                                       fclose (sfp);
+                                       return -1;
+                               }
+
+                               if (unlink(dest) < 0) {
+                                       perror_msg("unable to remove `%s'", dest);
+                                       fclose (sfp);
+                                       return -1;
+                               }
+
+                               dest_exists = 0;
+                       }
+               }
+
+               if (!dest_exists) {
+                       int fd;
+
+                       if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
+                                       (dfp = fdopen(fd, "w")) == NULL) {
+                               if (fd >= 0)
+                                       close(fd);
+                               perror_msg("unable to open `%s'", dest);
+                               fclose (sfp);
+                               return -1;
+                       }
+               }
+
+               if (copy_file_chunk(sfp, dfp, -1) < 0)
+                       status = -1;
+
+               if (fclose(dfp) < 0) {
+                       perror_msg("unable to close `%s'", dest);
+                       status = -1;
+               }
+
+               if (fclose(sfp) < 0) {
+                       perror_msg("unable to close `%s'", source);
+                       status = -1;
+               }
+                       }
+       else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+           S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ||
+           S_ISLNK(source_stat.st_mode)) {
+
+               if (dest_exists &&
+                      ((flags & FILEUTILS_FORCE) == 0 || unlink(dest) < 0)) {
+                               perror_msg("unable to remove `%s'", dest);
+                               return -1;
+
+                       }
+       } else {
+               error_msg("internal error: unrecognized file type");
+               return -1;
+               }
+       if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+           S_ISSOCK(source_stat.st_mode)) {
+               if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+                       perror_msg("unable to create `%s'", dest);
+                       return -1;
+               }
+       } else if (S_ISFIFO(source_stat.st_mode)) {
+               if (mkfifo(dest, source_stat.st_mode) < 0) {
+                       perror_msg("cannot create fifo `%s'", dest);
+                       return -1;
+               }
+       } else if (S_ISLNK(source_stat.st_mode)) {
+               char *lpath;
+
+               lpath = xreadlink(source);
+               if (symlink(lpath, dest) < 0) {
+                       perror_msg("cannot create symlink `%s'", dest);
+                       return -1;
+               }
+               free(lpath);
+
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+               if (flags & FILEUTILS_PRESERVE_STATUS)
+                       if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+                               perror_msg("unable to preserve ownership of `%s'", dest);
+#endif
+
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+               add_to_ino_dev_hashtable(&source_stat, dest);
+#endif
+
+               return 0;
+       }
+
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+       add_to_ino_dev_hashtable(&source_stat, dest);
+#endif
+
+end:
+
+       if (flags & FILEUTILS_PRESERVE_STATUS) {
+               struct utimbuf times;
+
+               times.actime = source_stat.st_atime;
+               times.modtime = source_stat.st_mtime;
+               if (utime(dest, &times) < 0)
+                       perror_msg("unable to preserve times of `%s'", dest);
+               if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+                       source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+                       perror_msg("unable to preserve ownership of `%s'", dest);
+               }
+               if (chmod(dest, source_stat.st_mode) < 0)
+                       perror_msg("unable to preserve permissions of `%s'", dest);
+       }
+
+       return status;
+}
diff --git a/libbb/copy_file_chunk.c b/libbb/copy_file_chunk.c
new file mode 100644 (file)
index 0000000..63d2ab1
--- /dev/null
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE
+ * to DST_FILE.  */
+extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize)
+{
+       size_t nread, nwritten, size;
+       char buffer[BUFSIZ];
+
+       while (chunksize != 0) {
+               if (chunksize > BUFSIZ)
+                       size = BUFSIZ;
+               else
+                       size = chunksize;
+
+               nread = fread (buffer, 1, size, src_file);
+
+               if (nread != size && ferror (src_file)) {
+                       perror_msg ("read");
+                       return -1;
+               } else if (nread == 0) {
+                       if (chunksize != -1) {
+                               error_msg ("Unable to read all data");
+                               return -1;
+                       }
+
+                       return 0;
+               }
+
+               nwritten = fwrite (buffer, 1, nread, dst_file);
+
+               if (nwritten != nread) {
+                       if (ferror (dst_file))
+                               perror_msg ("write");
+                       else
+                               error_msg ("Unable to write all data");
+                       return -1;
+               }
+
+               if (chunksize != -1)
+                       chunksize -= nwritten;
+       }
+
+       return 0;
+}
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
new file mode 100644 (file)
index 0000000..aa938d1
--- /dev/null
@@ -0,0 +1,59 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "libbb.h"
+
+
+extern int copyfd(int fd1, int fd2)
+{
+       char buf[8192];
+       ssize_t nread, nwrote;
+
+       while (1) {
+               nread = safe_read(fd1, buf, sizeof(buf));
+               if (nread == 0)
+                       break;
+               if (nread == -1) {
+                       perror_msg("read");
+                       return -1;
+               }
+
+               nwrote = full_write(fd2, buf, nread);
+               if (nwrote == -1) {
+                       perror_msg("write");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c
new file mode 100644 (file)
index 0000000..d804b39
--- /dev/null
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp protocol test permision
+ * and drop root privilegies if running setuid
+ *
+ */
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+int create_icmp_socket(void)
+{
+       struct protoent *proto;
+       int sock;
+
+       proto = getprotobyname("icmp");
+       /* if getprotobyname failed, just silently force
+        * proto->p_proto to have the correct value for "icmp" */
+       if ((sock = socket(AF_INET, SOCK_RAW,
+                       (proto ? proto->p_proto : 1))) < 0) {        /* 1 == ICMP */
+               if (errno == EPERM)
+                       error_msg_and_die("permission denied. (are you root?)");
+               else
+                       perror_msg_and_die(can_not_create_raw_socket);
+       }
+
+       /* drop root privs if running setuid */
+       setuid(getuid());
+
+       return sock;
+}
diff --git a/libbb/device_open.c b/libbb/device_open.c
new file mode 100644 (file)
index 0000000..30b33d7
--- /dev/null
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "libbb.h"
+
+
+/* try to open up the specified device */
+extern int device_open(char *device, int mode)
+{
+       int m, f, fd = -1;
+
+       m = mode | O_NONBLOCK;
+
+       /* Retry up to 5 times */
+       for (f = 0; f < 5; f++)
+               if ((fd = open(device, m, 0600)) >= 0)
+                       break;
+       if (fd < 0)
+               return fd;
+       /* Reset original flags. */
+       if (m != mode)
+               fcntl(fd, F_SETFL, mode);
+       return fd;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/dirname.c b/libbb/dirname.c
new file mode 100644 (file)
index 0000000..2aebd38
--- /dev/null
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini dirname function.
+ *
+ * Copyright (C) 2001  Matt Kraai.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+#if defined __GNU_LIBRARY___ < 5
+
+/* Return a string containing the path name of the parent
+ * directory of PATH.  */
+
+char *dirname(char *path)
+{
+       char *s;
+
+       /* Go to the end of the string.  */
+       s = path + strlen(path) - 1;
+
+       /* Strip off trailing /s (unless it is also the leading /).  */
+       while (path < s && s[0] == '/')
+               s--;
+
+       /* Strip the last component.  */
+       while (path <= s && s[0] != '/')
+               s--;
+
+       while (path < s && s[0] == '/')
+               s--;
+
+       if (s < path)
+               return ".";
+
+       s[1] = '\0';
+       return path;
+}
+
+#endif
diff --git a/libbb/error_msg.c b/libbb/error_msg.c
new file mode 100644 (file)
index 0000000..58308b6
--- /dev/null
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void error_msg(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       verror_msg(s, p);
+       va_end(p);
+       putc('\n', stderr);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c
new file mode 100644 (file)
index 0000000..67a79c3
--- /dev/null
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void error_msg_and_die(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       verror_msg(s, p);
+       va_end(p);
+       putc('\n', stderr);
+       exit(EXIT_FAILURE);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c
new file mode 100644 (file)
index 0000000..6588f94
--- /dev/null
@@ -0,0 +1,67 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libbb.h"
+
+/* Read up to (and including) TERMINATING_STRING from FILE and return it.
+ * Return NULL on EOF.  */
+
+char *fgets_str(FILE *file, const char *terminating_string)
+{
+       char *linebuf = NULL;
+       const int term_length = strlen(terminating_string);
+       int end_string_offset;
+       int linebufsz = 0;
+       int idx = 0;
+       int ch;
+
+       while (1) {
+               ch = fgetc(file);
+               if (ch == EOF) {
+                       free(linebuf);
+                       return NULL;
+               }
+
+               /* grow the line buffer as necessary */
+               while (idx > linebufsz - 2) {
+                       linebuf = xrealloc(linebuf, linebufsz += 1000);
+               }
+
+               linebuf[idx] = ch;
+               idx++;
+
+               /* Check for terminating string */
+               end_string_offset = idx - term_length;
+               if ((end_string_offset > 0) && (memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0)) {
+                       idx -= term_length;
+                       break;
+               }
+       }
+       linebuf[idx] = '\0';
+       return(linebuf);
+}
+
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
new file mode 100644 (file)
index 0000000..1eb5dc9
--- /dev/null
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+
+
+#include <mntent.h>
+/*
+ * Given a block device, find the mount table entry if that block device
+ * is mounted.
+ *
+ * Given any other file (or directory), find the mount table entry for its
+ * filesystem.
+ */
+extern struct mntent *find_mount_point(const char *name, const char *table)
+{
+       struct stat s;
+       dev_t mountDevice;
+       FILE *mountTable;
+       struct mntent *mountEntry;
+
+       if (stat(name, &s) != 0)
+               return 0;
+
+       if ((s.st_mode & S_IFMT) == S_IFBLK)
+               mountDevice = s.st_rdev;
+       else
+               mountDevice = s.st_dev;
+
+
+       if ((mountTable = setmntent(table, "r")) == 0)
+               return 0;
+
+       while ((mountEntry = getmntent(mountTable)) != 0) {
+               if (strcmp(name, mountEntry->mnt_dir) == 0
+                       || strcmp(name, mountEntry->mnt_fsname) == 0)   /* String match. */
+                       break;
+               if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice)  /* Match the device. */
+                       break;
+               if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice)      /* Match the directory's mount point. */
+                       break;
+       }
+       endmntent(mountTable);
+       return mountEntry;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
new file mode 100644 (file)
index 0000000..fc3742a
--- /dev/null
@@ -0,0 +1,183 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+#define READ_BUF_SIZE  50
+
+#define COMM_LEN 16 /* synchronize with size of comm in struct task_struct 
+                                          in /usr/include/linux/sched.h */
+
+/* For Erik's nifty devps device driver */
+#ifdef BB_FEATURE_USE_DEVPS_PATCH
+#include <linux/devps.h> 
+
+/* find_pid_by_name()
+ *  
+ *  This finds the pid of the specified process,
+ *  by using the /dev/ps device driver.
+ *
+ *  Returns a list of all matching PIDs
+ */
+extern long* find_pid_by_name( char* pidName)
+{
+       int fd, i, j;
+       char device[] = "/dev/ps";
+       pid_t num_pids;
+       pid_t* pid_array = NULL;
+       long* pidList=NULL;
+
+       /* open device */ 
+       fd = open(device, O_RDONLY);
+       if (fd < 0)
+               perror_msg_and_die("open failed for `%s'", device);
+
+       /* Find out how many processes there are */
+       if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
+               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
+       
+       /* Allocate some memory -- grab a few extras just in case 
+        * some new processes start up while we wait. The kernel will
+        * just ignore any extras if we give it too many, and will trunc.
+        * the list if we give it too few.  */
+       pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
+       pid_array[0] = num_pids+10;
+
+       /* Now grab the pid list */
+       if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
+               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
+
+       /* Now search for a match */
+       for (i=1, j=0; i<pid_array[0] ; i++) {
+               char* p;
+               struct pid_info info;
+
+           info.pid = pid_array[i];
+           if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+                       perror_msg_and_die("\nDEVPS_GET_PID_INFO");
+
+               /* Make sure we only match on the process name */
+               p=info.command_line+1;
+               while ((*p != 0) && !isspace(*(p)) && (*(p-1) != '\\')) { 
+                       (p)++;
+               }
+               if (isspace(*(p)))
+                               *p='\0';
+
+               if ((strstr(info.command_line, pidName) != NULL)
+                               && (strlen(pidName) == strlen(info.command_line))) {
+                       pidList=xrealloc( pidList, sizeof(long) * (j+2));
+                       pidList[j++]=info.pid;
+               }
+       }
+       if (pidList) {
+               pidList[j]=0;
+       } else {
+               pidList=xrealloc( pidList, sizeof(long));
+               pidList[0]=-1;
+       }
+
+       /* Free memory */
+       free(pid_array);
+
+       /* close device */
+       if (close (fd) != 0) 
+               perror_msg_and_die("close failed for `%s'", device);
+
+       return pidList;
+}
+
+#else          /* BB_FEATURE_USE_DEVPS_PATCH */
+
+/* find_pid_by_name()
+ *  
+ *  This finds the pid of the specified process.
+ *  Currently, it's implemented by rummaging through 
+ *  the proc filesystem.
+ *
+ *  Returns a list of all matching PIDs
+ */
+extern long* find_pid_by_name( char* pidName)
+{
+       DIR *dir;
+       struct dirent *next;
+       long* pidList=NULL;
+       int i=0;
+
+       dir = opendir("/proc");
+       if (!dir)
+               perror_msg_and_die("Cannot open /proc");
+       
+       while ((next = readdir(dir)) != NULL) {
+               FILE *status;
+               char filename[READ_BUF_SIZE];
+               char buffer[READ_BUF_SIZE];
+               char name[READ_BUF_SIZE];
+
+               /* Must skip ".." since that is outside /proc */
+               if (strcmp(next->d_name, "..") == 0)
+                       continue;
+
+               /* If it isn't a number, we don't want it */
+               if (!isdigit(*next->d_name))
+                       continue;
+
+               sprintf(filename, "/proc/%s/status", next->d_name);
+               if (! (status = fopen(filename, "r")) ) {
+                       continue;
+               }
+               if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) {
+                       fclose(status);
+                       continue;
+               }
+               fclose(status);
+
+               /* Buffer should contain a string like "Name:   binary_name" */
+               sscanf(buffer, "%*s %s", name);
+               if (strncmp(name, pidName, COMM_LEN-1) == 0) {
+                       pidList=xrealloc( pidList, sizeof(long) * (i+2));
+                       pidList[i++]=strtol(next->d_name, NULL, 0);
+               }
+       }
+
+       if (pidList) {
+               pidList[i]=0;
+       } else {
+               pidList=xrealloc( pidList, sizeof(long));
+               pidList[0]=-1;
+       }
+       return pidList;
+}
+#endif                                                 /* BB_FEATURE_USE_DEVPS_PATCH */
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
new file mode 100644 (file)
index 0000000..e5f6986
--- /dev/null
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * Patched by a bunch of people.  Feel free to acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+
+extern char *find_real_root_device_name(const char* name)
+{
+       DIR *dir;
+       struct dirent *entry;
+       struct stat statBuf, rootStat;
+       char *fileName = NULL;
+       dev_t dev;
+
+       if (stat("/", &rootStat) != 0) 
+               perror_msg("could not stat '/'");
+       else {
+               /* This check is here in case they pass in /dev name */
+               if ((rootStat.st_mode & S_IFMT) == S_IFBLK)
+                       dev = rootStat.st_rdev;
+               else
+                       dev = rootStat.st_dev;
+
+               dir = opendir("/dev");
+               if (!dir) 
+                       perror_msg("could not open '/dev'");
+               else {
+                       while((entry = readdir(dir)) != NULL) {
+
+                               /* Must skip ".." since that is "/", and so we 
+                                * would get a false positive on ".."  */
+                               if (strcmp(entry->d_name, "..") == 0)
+                                       continue;
+
+                               fileName = concat_path_file("/dev", entry->d_name);
+
+                               /* Some char devices have the same dev_t as block
+                                * devices, so make sure this is a block device */
+                               if (stat(fileName, &statBuf) == 0 && 
+                                               S_ISBLK(statBuf.st_mode)!=0 &&
+                                               statBuf.st_rdev == dev) 
+                                       break;
+                               free(fileName);
+                               fileName=NULL;
+                       }
+                       closedir(dir);
+               }
+       }
+       if(fileName==NULL)
+               fileName=xstrdup("/dev/root");
+       return fileName;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/full_read.c b/libbb/full_read.c
new file mode 100644 (file)
index 0000000..b91cdcb
--- /dev/null
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t full_read(int fd, void *buf, size_t len)
+{
+       ssize_t cc;
+       ssize_t total;
+
+       total = 0;
+
+       while (len > 0) {
+               cc = safe_read(fd, buf, len);
+
+               if (cc < 0)
+                       return cc;      /* read() returns -1 on failure. */
+
+               if (cc == 0)
+                       break;
+
+               buf = ((char *)buf) + cc;
+               total += cc;
+               len -= cc;
+       }
+
+       return total;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/full_write.c b/libbb/full_write.c
new file mode 100644 (file)
index 0000000..c485a24
--- /dev/null
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+/*
+ * Write all of the supplied buffer out to a file.
+ * This does multiple writes as necessary.
+ * Returns the amount written, or -1 on an error.
+ */
+ssize_t full_write(int fd, const void *buf, size_t len)
+{
+       ssize_t cc;
+       ssize_t total;
+
+       total = 0;
+
+       while (len > 0) {
+               cc = safe_write(fd, buf, len);
+
+               if (cc < 0)
+                       return cc;              /* write() returns -1 on failure. */
+
+               total += cc;
+               buf = ((const char *)buf) + cc;
+               len -= cc;
+       }
+
+       return total;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/get_console.c b/libbb/get_console.c
new file mode 100644 (file)
index 0000000..39c00e6
--- /dev/null
@@ -0,0 +1,122 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "libbb.h"
+
+
+
+
+
+/* From <linux/kd.h> */ 
+static const int KDGKBTYPE = 0x4B33;  /* get keyboard type */
+static const int KB_84 = 0x01;
+static const int KB_101 = 0x02;    /* this is what we always answer */
+
+int is_a_console(int fd)
+{
+       char arg;
+
+       arg = 0;
+       return (ioctl(fd, KDGKBTYPE, &arg) == 0
+                       && ((arg == KB_101) || (arg == KB_84)));
+}
+
+static int open_a_console(char *fnam)
+{
+       int fd;
+
+       /* try read-only */
+       fd = open(fnam, O_RDWR);
+
+       /* if failed, try read-only */
+       if (fd < 0 && errno == EACCES)
+               fd = open(fnam, O_RDONLY);
+
+       /* if failed, try write-only */
+       if (fd < 0 && errno == EACCES)
+               fd = open(fnam, O_WRONLY);
+
+       /* if failed, fail */
+       if (fd < 0)
+               return -1;
+
+       /* if not a console, fail */
+       if (!is_a_console(fd)) {
+               close(fd);
+               return -1;
+       }
+
+       /* success */
+       return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ *
+ * if tty_name is non-NULL, try this one instead.
+ */
+
+int get_console_fd(void)
+{
+       int fd;
+
+       if (-1 == (fd = open_a_console("/dev/console")))
+               return -1;
+       else
+               return fd;
+
+       fd = open_a_console(CURRENT_TTY);
+       if (fd >= 0)
+               return fd;
+
+       fd = open_a_console(CURRENT_VC);
+       if (fd >= 0)
+               return fd;
+
+       fd = open_a_console(CONSOLE_DEV);
+       if (fd >= 0)
+               return fd;
+
+       for (fd = 0; fd < 3; fd++)
+               if (is_a_console(fd))
+                       return fd;
+
+       error_msg("Couldn't get a file descriptor referring to the console");
+       return -1;                                      /* total failure */
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
new file mode 100644 (file)
index 0000000..6af726c
--- /dev/null
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * get_last_path_component implementation for busybox
+ *
+ * Copyright (C) 2001  Manuel Novoa III  <mjn3@opensource.lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Set to 1 if you want basename() behavior for NULL or "". */
+/* WARNING!!! Doing so will break basename applet at least! */
+#define EMULATE_BASENAME       0
+
+char *get_last_path_component(char *path)
+{
+#if EMULATE_BASENAME
+       static const char null_or_empty[] = ".";
+#endif
+       char *first = path;
+       char *last;
+
+#if EMULATE_BASENAME
+       if (!path || !*path) {
+               return (char *) null_or_empty;
+       }
+#endif
+
+       last = path - 1;
+
+       while (*path) {
+               if ((*path != '/') && (path > ++last)) {
+                       last = first = path;
+               }
+               ++path;
+       }
+
+       if (*first == '/') {
+               last = first;
+       }
+       last[1] = 0;
+
+       return first;
+}
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
new file mode 100644 (file)
index 0000000..0d9720b
--- /dev/null
@@ -0,0 +1,82 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+/* get_line_from_file() - This function reads an entire line from a text file,
+ * up to a newline. It returns a malloc'ed char * which must be stored and
+ * free'ed  by the caller.  If 'c' is nonzero, the trailing '\n' (if any)
+ * is removed.  In event of a read error or EOF, NULL is returned. */
+
+static char *private_get_line_from_file(FILE *file, int c)
+{
+#define GROWBY (80)            /* how large we will grow strings by */
+
+       int ch;
+       int idx = 0;
+       char *linebuf = NULL;
+       int linebufsz = 0;
+
+       while ((ch = getc(file)) != EOF) {
+               /* grow the line buffer as necessary */
+               if (idx > linebufsz - 2) {
+                       linebuf = xrealloc(linebuf, linebufsz += GROWBY);
+               }
+               linebuf[idx++] = (char)ch;
+               if (ch == '\n' || ch == '\0') {
+                       if (c) {
+                               --idx;
+                       }
+                       break;
+               }
+       }
+       if (linebuf) {
+               if (ferror(file)) {
+                       free(linebuf);
+                       return NULL;
+               }
+               linebuf[idx] = 0;
+       }
+       return linebuf;
+}
+
+extern char *get_line_from_file(FILE *file)
+{
+       return private_get_line_from_file(file, 0);
+}
+
+extern char *get_chomped_line_from_file(FILE *file)
+{
+       return private_get_line_from_file(file, 1);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/gz_open.c b/libbb/gz_open.c
new file mode 100644 (file)
index 0000000..a018753
--- /dev/null
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libbb.h"
+
+extern FILE *gz_open(FILE *compressed_file, int *pid)
+{
+       int unzip_pipe[2];
+
+       if (pipe(unzip_pipe)!=0) {
+               error_msg("pipe error");
+               return(NULL);
+       }
+#ifndef __uClinux__
+       if ((*pid = fork()) == -1) {
+               error_msg("fork failed");
+               return(NULL);
+       }
+       if (*pid==0) {
+               /* child process */
+               close(unzip_pipe[0]);
+               unzip(compressed_file, fdopen(unzip_pipe[1], "w"));
+               fflush(NULL);
+               fclose(compressed_file);
+               close(unzip_pipe[1]);
+               exit(EXIT_SUCCESS);
+       }
+#else
+       return NULL;
+#endif /* __uClinux__ */
+       close(unzip_pipe[1]);
+       if (unzip_pipe[0] == -1) {
+               error_msg("gzip stream init failed");
+       }
+       return(fdopen(unzip_pipe[0], "r"));
+}
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c
new file mode 100644 (file)
index 0000000..1081a56
--- /dev/null
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+extern void herror_msg(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       vherror_msg(s, p);
+       va_end(p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c
new file mode 100644 (file)
index 0000000..a47c7ff
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+extern void herror_msg_and_die(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       vherror_msg(s, p);
+       va_end(p);
+       exit(EXIT_FAILURE);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
new file mode 100644 (file)
index 0000000..7bdad36
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * June 30, 2001                 Manuel Novoa III
+ *
+ * All-integer version (hey, not everyone has floating point) of
+ * make_human_readable_str, modified from similar code I had written
+ * for busybox several months ago.
+ *
+ * Notes:
+ *   1) I'm using an unsigned long long to hold the product size * block_size,
+ *      as df (which calls this routine) could request a representation of a
+ *      partition size in bytes > max of unsigned long.  If long longs aren't
+ *      available, it would be possible to do what's needed using polynomial
+ *      representations (say, powers of 1024) and manipulating coefficients.
+ *      The base ten "bytes" output could be handled similarly.
+ *
+ *   2) This routine always outputs a decimal point and a tenths digit when 
+ *      display_unit != 0.  Hence, it isn't uncommon for the returned string 
+ *      to have a length of 5 or 6.
+ *
+ *      It might be nice to add a flag to indicate no decimal digits in
+ *      that case.  This could be either an additional parameter, or a
+ *      special value of display_unit.  Such a flag would also be nice for du.
+ *
+ *      Some code to omit the decimal point and tenths digit is sketched out
+ *      and "#if 0"'d below.
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+const char *make_human_readable_str(unsigned long size, 
+                                                                       unsigned long block_size,
+                                                                       unsigned long display_unit)
+{
+       /* The code will adjust for additional (appended) units. */
+       static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' };
+       static const char fmt[] = "%Lu";
+       static const char fmt_tenths[] = "%Lu.%d%c";
+
+       static char str[21];            /* Sufficient for 64 bit unsigned integers. */
+       
+       unsigned long long val;
+       int frac;
+       const char *u;
+       const char *f;
+
+       u = zero_and_units;
+       f = fmt;
+       frac = 0;
+
+       val = ((unsigned long long) size) * block_size;
+       if (val == 0) {
+               return u;
+       }
+
+       if (display_unit) {
+               val += display_unit/2;  /* Deal with rounding. */
+               val /= display_unit;    /* Don't combine with the line above!!! */
+       } else {
+               ++u;
+               while ((val >= KILOBYTE)
+                          && (u < zero_and_units + sizeof(zero_and_units) - 1)) {
+                       f = fmt_tenths;
+                       ++u;
+                       frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE;
+                       val /= KILOBYTE;
+               }
+               if (frac >= 10) {               /* We need to round up here. */
+                       ++val;
+                       frac = 0;
+               }
+#if 0
+               /* Sample code to omit decimal point and tenths digit. */
+               if ( /* no_tenths */ 1 ) {
+                       if ( frac >= 5 ) {
+                               ++val;
+                       }
+                       f = "%Lu%*c" /* fmt_no_tenths */ ;
+                       frac = 1;
+               }
+#endif
+       }
+
+       /* If f==fmt then 'frac' and 'u' are ignored. */
+       snprintf(str, sizeof(str), f, val, frac, *u);
+
+       return str;
+}
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
new file mode 100644 (file)
index 0000000..36484e6
--- /dev/null
@@ -0,0 +1,109 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libbb.h"
+
+#define HASH_SIZE      311             /* Should be prime */
+#define hash_inode(i)  ((i) % HASH_SIZE)
+
+typedef struct ino_dev_hash_bucket_struct {
+  struct ino_dev_hash_bucket_struct *next;
+  ino_t ino;
+  dev_t dev;
+  char name[1];
+} ino_dev_hashtable_bucket_t;
+
+static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
+
+/*
+ * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
+ * `ino_dev_hashtable', else return 0
+ *
+ * If NAME is a non-NULL pointer to a character pointer, and there is
+ * a match, then set *NAME to the value of the name slot in that
+ * bucket.
+ */
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
+{
+       ino_dev_hashtable_bucket_t *bucket;
+
+       bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
+       while (bucket != NULL) {
+         if ((bucket->ino == statbuf->st_ino) &&
+                 (bucket->dev == statbuf->st_dev))
+         {
+               if (name) *name = bucket->name;
+               return 1;
+         }
+         bucket = bucket->next;
+       }
+       return 0;
+}
+
+/* Add statbuf to statbuf hash table */
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+       int i;
+       size_t s;
+       ino_dev_hashtable_bucket_t *bucket;
+    
+       i = hash_inode(statbuf->st_ino);
+       s = name ? strlen(name) : 0;
+       bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
+       bucket->ino = statbuf->st_ino;
+       bucket->dev = statbuf->st_dev;
+       if (name)
+               strcpy(bucket->name, name);
+       else
+               bucket->name[0] = '\0';
+       bucket->next = ino_dev_hashtable[i];
+       ino_dev_hashtable[i] = bucket;
+}
+
+/* Clear statbuf hash table */
+void reset_ino_dev_hashtable(void)
+{
+       int i;
+       ino_dev_hashtable_bucket_t *bucket;
+
+       for (i = 0; i < HASH_SIZE; i++) {
+               while (ino_dev_hashtable[i] != NULL) {
+                       bucket = ino_dev_hashtable[i]->next;
+                       free(ino_dev_hashtable[i]);
+                       ino_dev_hashtable[i] = bucket;
+               }
+       }
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/interface.c b/libbb/interface.c
new file mode 100644 (file)
index 0000000..5b1c418
--- /dev/null
@@ -0,0 +1,2172 @@
+/*
+ * ifconfig   This file contains an implementation of the command
+ *              that either displays or sets the characteristics of
+ *              one or more of the system's networking interfaces.
+ *
+ * Version:     $Id: interface.c,v 1.8 2003/07/28 06:37:04 andersen Exp $
+ *
+ * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *              and others.  Copyright 1993 MicroWalt Corporation
+ *
+ *              This program is free software; you can redistribute it
+ *              and/or  modify it under  the terms of  the GNU General
+ *              Public  License as  published  by  the  Free  Software
+ *              Foundation;  either  version 2 of the License, or  (at
+ *              your option) any later version.
+ *
+ * Patched to support 'add' and 'del' keywords for INET(4) addresses
+ * by Mrs. Brisby <mrs.brisby@nimh.org>
+ *
+ * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *                     - gettext instead of catgets for i18n
+ *          10/1998  - Andi Kleen. Use interface list primitives.       
+ *         20001008 - Bernd Eckenfels, Patch from RH for setting mtu 
+ *                     (default AF was wrong)
+ * stolen from net-tools-1.59 and stripped down for busybox by 
+ *                     Erik Andersen <andersee@debian.org>
+ */
+
+/*
+ * Heavily modified by Manuel Novoa III       Mar 12, 2001
+ *
+ * Pruned unused code using KEEP_UNUSED define.
+ * Added print_bytes_scaled function to reduce code size.
+ * Added some (potentially) missing defines.
+ * Improved display support for -a and for a named interface.
+ */
+
+/* #define KEEP_UNUSED */
+
+/* 
+ * 
+ * Protocol Families.
+ * 
+ */
+#define HAVE_AFINET 1
+#undef HAVE_AFINET6
+#undef HAVE_AFIPX
+#undef HAVE_AFATALK
+#undef HAVE_AFNETROM
+#undef HAVE_AFX25
+#undef HAVE_AFECONET
+#undef HAVE_AFASH
+
+/* 
+ * 
+ * Device Hardware types.
+ * 
+ */
+#define HAVE_HWETHER   1
+#define HAVE_HWPPP     1
+#undef HAVE_HWSLIP
+
+
+#include <features.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#if 0
+#include <arpa/nameser.h>
+#endif
+#include "libbb.h"
+
+#define _(x) x
+#define _PATH_PROCNET_DEV               "/proc/net/dev"
+#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
+#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
+
+static int procnetdev_vsn = 1;
+
+#ifdef DEBUG
+#include <resolv.h>
+#endif
+
+
+/* Ugh.  But libc5 doesn't provide POSIX types.  */
+#include <asm/types.h>
+
+
+#ifdef HAVE_HWSLIP
+#include <linux/if_slip.h>
+#endif
+
+#if HAVE_AFINET6
+
+#ifndef _LINUX_IN6_H
+/*
+ *    This is in linux/include/net/ipv6.h.
+ */
+
+struct in6_ifreq {
+    struct in6_addr ifr6_addr;
+    __u32 ifr6_prefixlen;
+    unsigned int ifr6_ifindex;
+};
+
+#endif
+
+#endif                         /* HAVE_AFINET6 */
+
+#if HAVE_AFIPX
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+#include <netipx/ipx.h>
+#else
+#include "ipx.h"
+#endif
+#endif
+#if 0
+#include "net-support.h"
+#include "pathnames.h"
+#include "version.h"
+#include "../intl.h"
+#include "interface.h"
+#include "sockets.h"
+#include "util.h"
+#endif
+
+/* Defines for glibc2.0 users. */
+#ifndef SIOCSIFTXQLEN
+#define SIOCSIFTXQLEN      0x8943
+#define SIOCGIFTXQLEN      0x8942
+#endif
+
+/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
+#ifndef ifr_qlen
+#define ifr_qlen        ifr_ifru.ifru_mtu
+#endif
+
+#ifndef HAVE_TXQUEUELEN
+#define HAVE_TXQUEUELEN 1
+#endif
+
+#ifndef IFF_DYNAMIC
+#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
+#endif
+
+/* This structure defines protocol families and their handlers. */
+struct aftype {
+    const char *name;
+    const char *title;
+    int af;
+    int alen;
+    char *(*print) (unsigned char *);
+    char *(*sprint) (struct sockaddr *, int numeric);
+    int (*input) (int type, char *bufp, struct sockaddr *);
+    void (*herror) (char *text);
+    int (*rprint) (int options);
+    int (*rinput) (int typ, int ext, char **argv);
+
+    /* may modify src */
+    int (*getmask) (char *src, struct sockaddr * mask, char *name);
+
+    int fd;
+    char *flag_file;
+};
+
+static struct aftype *aftypes[];
+
+#ifdef KEEP_UNUSED
+
+static int flag_unx;
+#ifdef HAVE_AFIPX
+static int flag_ipx;
+#endif
+#ifdef HAVE_AFX25
+static int flag_ax25;
+#endif
+#ifdef HAVE_AFATALK
+static int flag_ddp;
+#endif
+#ifdef HAVE_AFNETROM
+static int flag_netrom;
+#endif
+static int flag_inet;
+#ifdef HAVE_AFINET6
+static int flag_inet6;
+#endif
+#ifdef HAVE_AFECONET
+static int flag_econet;
+#endif
+#ifdef HAVE_AFX25
+static int flag_x25 = 0;
+#endif
+#ifdef HAVE_AFASH
+static int flag_ash;
+#endif
+
+
+static struct aftrans_t {
+    char *alias;
+    char *name;
+    int *flag;
+} aftrans[] = {
+
+#ifdef HAVE_AFX25
+    {
+       "ax25", "ax25", &flag_ax25
+    },
+#endif
+    {
+       "ip", "inet", &flag_inet
+    },
+#ifdef HAVE_AFINET6
+    {
+       "ip6", "inet6", &flag_inet6
+    },
+#endif
+#ifdef HAVE_AFIPX
+    {
+       "ipx", "ipx", &flag_ipx
+    },
+#endif
+#ifdef HAVE_AFATALK
+    {
+       "appletalk", "ddp", &flag_ddp
+    },
+#endif
+#ifdef HAVE_AFNETROM
+    {
+       "netrom", "netrom", &flag_netrom
+    },
+#endif
+    {
+       "inet", "inet", &flag_inet
+    },
+#ifdef HAVE_AFINET6
+    {
+       "inet6", "inet6", &flag_inet6
+    },
+#endif
+#ifdef HAVE_AFATALK
+    {
+       "ddp", "ddp", &flag_ddp
+    },
+#endif
+    {
+       "unix", "unix", &flag_unx
+    },
+    {
+       "tcpip", "inet", &flag_inet
+    },
+#ifdef HAVE_AFECONET
+    {
+       "econet", "ec", &flag_econet
+    },
+#endif
+#ifdef HAVE_AFX25
+    {
+       "x25", "x25", &flag_x25
+    },
+#endif
+#ifdef HAVE_AFASH
+    {
+        "ash", "ash", &flag_ash
+    },
+#endif
+    {
+       0, 0, 0
+    }
+};
+
+static char afname[256] = "";
+#endif /* KEEP_UNUSED */
+
+#if HAVE_AFUNIX
+
+/* Display a UNIX domain address. */
+static char *UNIX_print(unsigned char *ptr)
+{
+    return (ptr);
+}
+
+
+/* Display a UNIX domain address. */
+static char *UNIX_sprint(struct sockaddr *sap, int numeric)
+{
+    static char buf[64];
+
+    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+       return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
+    return (UNIX_print(sap->sa_data));
+}
+
+
+static struct aftype unix_aftype =
+{
+    "unix", "UNIX Domain", AF_UNIX, 0,
+    UNIX_print, UNIX_sprint, NULL, NULL,
+    NULL, NULL, NULL,
+    -1,
+    "/proc/net/unix"
+};
+#endif                         /* HAVE_AFUNIX */
+
+#if HAVE_AFINET
+
+#if 0
+extern int h_errno;             /* some netdb.h versions don't export this */
+#endif
+
+/* cache */
+struct addr {
+    struct sockaddr_in addr;
+    char *name;
+    int host;
+    struct addr *next;
+};
+
+static struct addr *INET_nn = NULL;    /* addr-to-name cache           */
+
+#ifdef KEEP_UNUSED
+static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
+{
+    struct hostent *hp;
+    struct netent *np;
+
+    /* Grmpf. -FvK */
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+
+    /* Default is special, meaning 0.0.0.0. */
+    if (!strcmp(name, "default")) {
+       sin->sin_addr.s_addr = INADDR_ANY;
+       return (1);
+    }
+    /* Look to see if it's a dotted quad. */
+    if (inet_aton(name, &sin->sin_addr)) {
+       return 0;
+    }
+    /* If we expect this to be a hostname, try hostname database first */
+#ifdef DEBUG
+    if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
+#endif
+    if (hostfirst && 
+       (hp = gethostbyname(name)) != (struct hostent *) NULL) {
+       memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
+               sizeof(struct in_addr));
+       return 0;
+    }
+    /* Try the NETWORKS database to see if this is a known network. */
+#ifdef DEBUG
+    fprintf (stderr, "getnetbyname (%s)\n", name);
+#endif
+    if ((np = getnetbyname(name)) != (struct netent *) NULL) {
+       sin->sin_addr.s_addr = htonl(np->n_net);
+       return 1;
+    }
+    if (hostfirst) {
+       /* Don't try again */
+       errno = h_errno;
+       return -1;
+    }
+#ifdef DEBUG
+    res_init();
+    _res.options |= RES_DEBUG;
+#endif
+
+#ifdef DEBUG
+    fprintf (stderr, "gethostbyname (%s)\n", name);
+#endif
+    if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
+       errno = h_errno;
+       return -1;
+    }
+    memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], 
+          sizeof(struct in_addr));
+
+    return 0;
+}
+#endif /* KEEP_UNUSED */
+
+/* numeric: & 0x8000: default instead of *, 
+ *         & 0x4000: host instead of net, 
+ *         & 0x0fff: don't resolve
+ */
+static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, 
+                        int numeric, unsigned int netmask)
+{
+    struct hostent *ent;
+    struct netent *np;
+    struct addr *pn;
+    unsigned long ad, host_ad;
+    int host = 0;
+
+    /* Grmpf. -FvK */
+    if (s_in->sin_family != AF_INET) {
+#ifdef DEBUG
+       fprintf(stderr, "rresolve: unsupport address family %d !\n", s_in->sin_family);
+#endif
+       errno = EAFNOSUPPORT;
+       return (-1);
+    }
+    ad = (unsigned long) s_in->sin_addr.s_addr;
+#ifdef DEBUG
+    fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
+#endif
+    if (ad == INADDR_ANY) {
+       if ((numeric & 0x0FFF) == 0) {
+           if (numeric & 0x8000)
+               safe_strncpy(name, "default", len);
+           else
+               safe_strncpy(name, "*", len);
+           return (0);
+       }
+    }
+    if (numeric & 0x0FFF) {
+        safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
+       return (0);
+    }
+
+    if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
+       host = 1;
+#if 0
+    INET_nn = NULL;
+#endif
+    pn = INET_nn;
+    while (pn != NULL) {
+       if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
+           safe_strncpy(name, pn->name, len);
+#ifdef DEBUG
+           fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
+#endif
+           return (0);
+       }
+       pn = pn->next;
+    }
+
+    host_ad = ntohl(ad);
+    np = NULL;
+    ent = NULL;
+    if (host) {
+#ifdef DEBUG
+       fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
+#endif
+       ent = gethostbyaddr((char *) &ad, 4, AF_INET);
+       if (ent != NULL)
+           safe_strncpy(name, ent->h_name, len);
+    } else {
+#ifdef DEBUG
+       fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
+#endif
+#if 0
+       np = getnetbyaddr(host_ad, AF_INET);
+       if (np != NULL)
+           safe_strncpy(name, np->n_name, len);
+#endif
+    }
+    if ((ent == NULL) && (np == NULL))
+       safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
+    pn = (struct addr *) xmalloc(sizeof(struct addr));
+    pn->addr = *s_in;
+    pn->next = INET_nn;
+    pn->host = host;
+    pn->name = (char *) xmalloc(strlen(name) + 1);
+    strcpy(pn->name, name);
+    INET_nn = pn;
+
+    return (0);
+}
+
+#ifdef KEEP_UNUSED
+static void INET_reserror(char *text)
+{
+    herror(text);
+}
+
+/* Display an Internet socket address. */
+static char *INET_print(unsigned char *ptr)
+{
+    return (inet_ntoa((*(struct in_addr *) ptr)));
+}
+#endif /* KEEP_UNUSED */
+
+/* Display an Internet socket address. */
+static char *INET_sprint(struct sockaddr *sap, int numeric)
+{
+    static char buff[128];
+
+    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+       return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
+
+    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
+                     numeric, 0xffffff00) != 0)
+       return (NULL);
+
+    return (buff);
+}
+
+#ifdef KEEP_UNUSED
+static char *INET_sprintmask(struct sockaddr *sap, int numeric, 
+                     unsigned int netmask)
+{
+    static char buff[128];
+
+    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+       return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
+    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 
+                     numeric, netmask) != 0)
+       return (NULL);
+    return (buff);
+}
+
+static int INET_getsock(char *bufp, struct sockaddr *sap)
+{
+    char *sp = bufp, *bp;
+    unsigned int i;
+    unsigned val;
+    struct sockaddr_in *sin;
+
+    sin = (struct sockaddr_in *) sap;
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+
+    val = 0;
+    bp = (char *) &val;
+    for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
+       *sp = toupper(*sp);
+
+       if ((*sp >= 'A') && (*sp <= 'F'))
+           bp[i] |= (int) (*sp - 'A') + 10;
+       else if ((*sp >= '0') && (*sp <= '9'))
+           bp[i] |= (int) (*sp - '0');
+       else
+           return (-1);
+
+       bp[i] <<= 4;
+       sp++;
+       *sp = toupper(*sp);
+
+       if ((*sp >= 'A') && (*sp <= 'F'))
+           bp[i] |= (int) (*sp - 'A') + 10;
+       else if ((*sp >= '0') && (*sp <= '9'))
+           bp[i] |= (int) (*sp - '0');
+       else
+           return (-1);
+
+       sp++;
+    }
+    sin->sin_addr.s_addr = htonl(val);
+
+    return (sp - bufp);
+}
+
+static int INET_input(int type, char *bufp, struct sockaddr *sap)
+{
+    switch (type) {
+    case 1:
+       return (INET_getsock(bufp, sap));
+    case 256:
+       return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
+    default:
+       return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
+    }
+}
+
+static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
+{
+    struct sockaddr_in *mask = (struct sockaddr_in *) m;
+    char *slash, *end;
+    int prefix;
+
+    if ((slash = strchr(adr, '/')) == NULL)
+       return 0;
+
+    *slash++ = '\0';
+    prefix = strtoul(slash, &end, 0);
+    if (*end != '\0')
+       return -1;
+
+    if (name) {
+       sprintf(name, "/%d", prefix);
+    }
+    mask->sin_family = AF_INET;
+    mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
+    return 1;
+}
+#endif /* KEEP_UNUSED */
+
+static struct aftype inet_aftype =
+{
+    "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
+    NULL /* UNUSED INET_print */, INET_sprint,
+       NULL /* UNUSED INET_input */, NULL /* UNUSED INET_reserror */,
+    NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
+    NULL /* UNUSED INET_getnetmask */,
+    -1,
+    NULL
+};
+
+#endif                         /* HAVE_AFINET */
+
+/* Display an UNSPEC address. */
+static char *UNSPEC_print(unsigned char *ptr)
+{
+    static char buff[sizeof(struct sockaddr)*3+1];
+    char *pos;
+    unsigned int i;
+
+    pos = buff;
+    for (i = 0; i < sizeof(struct sockaddr); i++) {
+       /* careful -- not every libc's sprintf returns # bytes written */
+       sprintf(pos, "%02X-", (*ptr++ & 0377));
+       pos += 3;
+    }
+    /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
+    *--pos = '\0';
+    return (buff);
+}
+
+/* Display an UNSPEC socket address. */
+static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
+{
+    static char buf[64];
+
+    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+       return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
+    return (UNSPEC_print(sap->sa_data));
+}
+
+static struct aftype unspec_aftype =
+{
+    "unspec", "UNSPEC", AF_UNSPEC, 0,
+    UNSPEC_print, UNSPEC_sprint, NULL, NULL,
+    NULL,
+};
+
+static struct aftype *aftypes[] =
+{
+#if HAVE_AFUNIX
+    &unix_aftype,
+#endif
+#if HAVE_AFINET
+    &inet_aftype,
+#endif
+#if HAVE_AFINET6
+    &inet6_aftype,
+#endif
+#if HAVE_AFAX25
+    &ax25_aftype,
+#endif
+#if HAVE_AFNETROM
+    &netrom_aftype,
+#endif
+#if HAVE_AFROSE
+    &rose_aftype,
+#endif
+#if HAVE_AFIPX
+    &ipx_aftype,
+#endif
+#if HAVE_AFATALK
+    &ddp_aftype,
+#endif
+#if HAVE_AFECONET
+    &ec_aftype,
+#endif
+#if HAVE_AFASH
+    &ash_aftype,
+#endif
+#if HAVE_AFX25
+    &x25_aftype,
+#endif
+    &unspec_aftype,
+    NULL
+};
+
+#ifdef KEEP_UNUSED
+static short sVafinit = 0;
+
+static void afinit()
+{
+    unspec_aftype.title = _("UNSPEC");
+#if HAVE_AFUNIX
+    unix_aftype.title = _("UNIX Domain");
+#endif
+#if HAVE_AFINET
+    inet_aftype.title = _("DARPA Internet");
+#endif
+#if HAVE_AFINET6
+    inet6_aftype.title = _("IPv6");
+#endif
+#if HAVE_AFAX25
+    ax25_aftype.title = _("AMPR AX.25");
+#endif
+#if HAVE_AFNETROM
+    netrom_aftype.title = _("AMPR NET/ROM");
+#endif
+#if HAVE_AFIPX
+    ipx_aftype.title = _("Novell IPX");
+#endif
+#if HAVE_AFATALK
+    ddp_aftype.title = _("Appletalk DDP");
+#endif
+#if HAVE_AFECONET
+    ec_aftype.title = _("Econet");
+#endif
+#if HAVE_AFX25
+    x25_aftype.title = _("CCITT X.25");
+#endif
+#if HAVE_AFROSE
+    rose_aftype.title = _("AMPR ROSE");
+#endif
+#if HAVE_AFASH
+    ash_aftype.title = _("Ash");
+#endif 
+    sVafinit = 1;
+}
+
+static int aftrans_opt(const char *arg)
+{
+    struct aftrans_t *paft;
+    char *tmp1, *tmp2;
+    char buf[256];
+
+    safe_strncpy(buf, arg, sizeof(buf));
+
+    tmp1 = buf;
+
+    while (tmp1) {
+
+       tmp2 = strchr(tmp1, ',');
+
+       if (tmp2)
+           *(tmp2++) = '\0';
+
+       paft = aftrans;
+       for (paft = aftrans; paft->alias; paft++) {
+           if (strcmp(tmp1, paft->alias))
+               continue;
+           if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
+               fprintf(stderr, _("Too much address family arguments.\n"));
+               return (0);
+           }
+           if (paft->flag)
+               (*paft->flag)++;
+           if (afname[0])
+               strcat(afname, ",");
+           strcat(afname, paft->name);
+           break;
+       }
+       if (!paft->alias) {
+           fprintf(stderr, _("Unknown address family `%s'.\n"), tmp1);
+           return (1);
+       }
+       tmp1 = tmp2;
+    }
+
+    return (0);
+}
+
+/* set the default AF list from the program name or a constant value    */
+static void aftrans_def(char *tool, char *argv0, char *dflt)
+{
+    char *tmp;
+    char *buf;
+
+    strcpy(afname, dflt);
+
+    if (!(tmp = strrchr(argv0, '/')))
+       tmp = argv0;            /* no slash?! */
+    else
+       tmp++;
+
+    if (!(buf = strdup(tmp)))
+       return;
+
+    if (strlen(tool) >= strlen(tmp)) {
+       free(buf);
+       return;
+    }
+    tmp = buf + (strlen(tmp) - strlen(tool));
+
+    if (strcmp(tmp, tool) != 0) {
+       free(buf);
+       return;
+    }
+    *tmp = '\0';
+    if ((tmp = strchr(buf, '_')))
+       *tmp = '\0';
+
+    afname[0] = '\0';
+    if (aftrans_opt(buf))
+       strcpy(afname, buf);
+
+    free(buf);
+}
+
+/* Check our protocol family table for this family. */
+static struct aftype *get_aftype(const char *name)
+{
+    struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+    if (!sVafinit)
+       afinit();
+#endif /* KEEP_UNUSED */
+
+    afp = aftypes;
+    while (*afp != NULL) {
+       if (!strcmp((*afp)->name, name))
+           return (*afp);
+       afp++;
+    }
+    if (strchr(name, ','))
+       fprintf(stderr, _("Please don't supply more than one address family.\n"));
+    return (NULL);
+}
+#endif /* KEEP_UNUSED */
+
+/* Check our protocol family table for this family. */
+static struct aftype *get_afntype(int af)
+{
+    struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+    if (!sVafinit)
+       afinit();
+#endif /* KEEP_UNUSED */
+
+    afp = aftypes;
+    while (*afp != NULL) {
+       if ((*afp)->af == af)
+           return (*afp);
+       afp++;
+    }
+    return (NULL);
+}
+
+/* Check our protocol family table for this family and return its socket */
+static int get_socket_for_af(int af)
+{
+    struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+    if (!sVafinit)
+       afinit();
+#endif /* KEEP_UNUSED */
+
+    afp = aftypes;
+    while (*afp != NULL) {
+       if ((*afp)->af == af)
+           return (*afp)->fd;
+       afp++;
+    }
+    return -1;
+}
+
+#ifdef KEEP_UNUSED
+/* type: 0=all, 1=getroute */
+static void print_aflist(int type) {
+    int count = 0;
+    char * txt;
+    struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+    if (!sVafinit)
+       afinit();
+#endif /* KEEP_UNUSED */
+
+    afp = aftypes;
+    while (*afp != NULL) {
+       if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
+               afp++; continue;
+       }
+       if ((count % 3) == 0) fprintf(stderr,count?"\n    ":"    "); 
+        txt = (*afp)->name; if (!txt) txt = "..";
+       fprintf(stderr,"%s (%s) ",txt,_((*afp)->title));
+       count++;
+       afp++;
+    }
+    fprintf(stderr,"\n");
+}
+#endif /* KEEP_UNUSED */
+
+struct user_net_device_stats {
+    unsigned long long rx_packets;     /* total packets received       */
+    unsigned long long tx_packets;     /* total packets transmitted    */
+    unsigned long long rx_bytes;       /* total bytes received         */
+    unsigned long long tx_bytes;       /* total bytes transmitted      */
+    unsigned long rx_errors;   /* bad packets received         */
+    unsigned long tx_errors;   /* packet transmit problems     */
+    unsigned long rx_dropped;  /* no space in linux buffers    */
+    unsigned long tx_dropped;  /* no space available in linux  */
+    unsigned long rx_multicast;        /* multicast packets received   */
+    unsigned long rx_compressed;
+    unsigned long tx_compressed;
+    unsigned long collisions;
+
+    /* detailed rx_errors: */
+    unsigned long rx_length_errors;
+    unsigned long rx_over_errors;      /* receiver ring buff overflow  */
+    unsigned long rx_crc_errors;       /* recved pkt with crc error    */
+    unsigned long rx_frame_errors;     /* recv'd frame alignment error */
+    unsigned long rx_fifo_errors;      /* recv'r fifo overrun          */
+    unsigned long rx_missed_errors;    /* receiver missed packet     */
+    /* detailed tx_errors */
+    unsigned long tx_aborted_errors;
+    unsigned long tx_carrier_errors;
+    unsigned long tx_fifo_errors;
+    unsigned long tx_heartbeat_errors;
+    unsigned long tx_window_errors;
+};
+
+struct interface {
+    struct interface *next, *prev; 
+    char name[IFNAMSIZ];       /* interface name        */
+    short type;                        /* if type               */
+    short flags;               /* various flags         */
+    int metric;                        /* routing metric        */
+    int mtu;                   /* MTU value             */
+    int tx_queue_len;          /* transmit queue length */
+    struct ifmap map;          /* hardware setup        */
+    struct sockaddr addr;      /* IP address            */
+    struct sockaddr dstaddr;   /* P-P IP address        */
+    struct sockaddr broadaddr; /* IP broadcast address  */
+    struct sockaddr netmask;   /* IP network mask       */
+    struct sockaddr ipxaddr_bb;        /* IPX network address   */
+    struct sockaddr ipxaddr_sn;        /* IPX network address   */
+    struct sockaddr ipxaddr_e3;        /* IPX network address   */
+    struct sockaddr ipxaddr_e2;        /* IPX network address   */
+    struct sockaddr ddpaddr;   /* Appletalk DDP address */
+    struct sockaddr ecaddr;    /* Econet address        */
+    int has_ip;
+    int has_ipx_bb;
+    int has_ipx_sn;
+    int has_ipx_e3;
+    int has_ipx_e2;
+    int has_ax25;
+    int has_ddp;
+    int has_econet;
+    char hwaddr[32];           /* HW address            */
+    int statistics_valid;
+    struct user_net_device_stats stats;                /* statistics            */
+    int keepalive;             /* keepalive value for SLIP */
+    int outfill;               /* outfill value for SLIP */
+};
+
+
+int interface_opt_a = 0;               /* show all interfaces          */
+
+#ifdef KEEP_UNUSED
+static int opt_i = 0;                  /* show the statistics          */
+static int opt_v = 0;                  /* debugging output flag        */
+
+static int addr_family = 0;            /* currently selected AF        */
+#endif /* KEEP_UNUSED */
+
+static struct interface *int_list, *int_last;
+static int skfd = -1;                  /* generic raw socket desc.     */
+
+
+static int sockets_open(int family)
+{
+    struct aftype **aft;
+    int sfd = -1;
+    static int force = -1;
+
+    if (force < 0) {
+       force = 0;
+       if (get_kernel_revision() < KRELEASE(2, 1, 0))
+           force = 1;
+       if (access("/proc/net", R_OK))
+           force = 1;
+    }
+    for (aft = aftypes; *aft; aft++) {
+       struct aftype *af = *aft;
+       int type = SOCK_DGRAM;
+       if (af->af == AF_UNSPEC)
+           continue;
+       if (family && family != af->af)
+           continue;
+       if (af->fd != -1) {
+           sfd = af->fd;
+           continue;
+       }
+       /* Check some /proc file first to not stress kmod */
+       if (!family && !force && af->flag_file) {
+           if (access(af->flag_file, R_OK))
+               continue;
+       }
+#if HAVE_AFNETROM
+       if (af->af == AF_NETROM)
+           type = SOCK_SEQPACKET;
+#endif
+#if HAVE_AFX25
+       if (af->af == AF_X25)
+           type = SOCK_SEQPACKET;
+#endif
+       af->fd = socket(af->af, type, 0);
+       if (af->fd >= 0)
+           sfd = af->fd;
+    }
+    if (sfd < 0)
+       fprintf(stderr, _("No usable address families found.\n"));
+    return sfd;
+}
+
+/* like strcmp(), but knows about numbers */
+static int nstrcmp(const char *astr, const char *b)
+{
+    const char *a = astr;
+
+    while (*a == *b) {
+       if (*a == '\0')
+           return 0;
+       a++;
+       b++;
+    }
+    if (isdigit(*a)) {
+       if (!isdigit(*b))
+           return -1;
+       while (a > astr) {
+           a--;
+           if (!isdigit(*a)) {
+               a++;
+               break;
+           }
+           if (!isdigit(*b))
+               return -1;
+           b--;
+       }
+       return atoi(a) > atoi(b) ? 1 : -1;
+    }
+    return *a - *b;
+}
+
+static struct interface *add_interface(char *name)
+{
+    struct interface *ife, **nextp, *new;
+
+    for (ife = int_last; ife; ife = ife->prev) {
+           int n = nstrcmp(ife->name, name); 
+           if (n == 0) 
+                   return ife; 
+           if (n < 0) 
+                   break; 
+    }
+    new(new); 
+    safe_strncpy(new->name, name, IFNAMSIZ); 
+    nextp = ife ? &ife->next : &int_list;
+    new->prev = ife;
+    new->next = *nextp; 
+    if (new->next) 
+           new->next->prev = new; 
+    else
+           int_last = new; 
+    *nextp = new; 
+    return new; 
+}
+
+
+static int if_readconf(void)
+{
+    int numreqs = 30;
+    struct ifconf ifc;
+    struct ifreq *ifr;
+    int n, err = -1;
+    int skfd2;
+
+    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
+       (as of 2.1.128) */ 
+    skfd2 = get_socket_for_af(AF_INET);
+    if (skfd2 < 0) {
+       fprintf(stderr, _("warning: no inet socket available: %s\n"),
+               strerror(errno));
+       /* Try to soldier on with whatever socket we can get hold of.  */
+       skfd2 = sockets_open(0);
+       if (skfd2 < 0)
+           return -1;
+    }
+
+    ifc.ifc_buf = NULL;
+    for (;;) {
+       ifc.ifc_len = sizeof(struct ifreq) * numreqs;
+       ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
+
+       if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
+           perror("SIOCGIFCONF");
+           goto out;
+       }
+       if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
+           /* assume it overflowed and try again */
+           numreqs += 10;
+           continue;
+       }
+       break;
+    }
+
+    ifr = ifc.ifc_req;
+    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
+       add_interface(ifr->ifr_name);
+       ifr++;
+    }
+    err = 0;
+
+out:
+    free(ifc.ifc_buf);
+    return err;
+}
+
+static char *get_name(char *name, char *p)
+{
+    while (isspace(*p))
+       p++;
+    while (*p) {
+       if (isspace(*p))
+           break;
+       if (*p == ':') {        /* could be an alias */
+           char *dot = p, *dotname = name;
+           *name++ = *p++;
+           while (isdigit(*p))
+               *name++ = *p++;
+           if (*p != ':') {    /* it wasn't, backup */
+               p = dot;
+               name = dotname;
+           }
+           if (*p == '\0')
+               return NULL;
+           p++;
+           break;
+       }
+       *name++ = *p++;
+    }
+    *name++ = '\0';
+    return p;
+}
+
+static int get_dev_fields(char *bp, struct interface *ife)
+{
+    switch (procnetdev_vsn) {
+    case 3:
+       sscanf(bp,
+       "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
+              &ife->stats.rx_bytes,
+              &ife->stats.rx_packets,
+              &ife->stats.rx_errors,
+              &ife->stats.rx_dropped,
+              &ife->stats.rx_fifo_errors,
+              &ife->stats.rx_frame_errors,
+              &ife->stats.rx_compressed,
+              &ife->stats.rx_multicast,
+
+              &ife->stats.tx_bytes,
+              &ife->stats.tx_packets,
+              &ife->stats.tx_errors,
+              &ife->stats.tx_dropped,
+              &ife->stats.tx_fifo_errors,
+              &ife->stats.collisions,
+              &ife->stats.tx_carrier_errors,
+              &ife->stats.tx_compressed);
+       break;
+    case 2:
+       sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
+              &ife->stats.rx_bytes,
+              &ife->stats.rx_packets,
+              &ife->stats.rx_errors,
+              &ife->stats.rx_dropped,
+              &ife->stats.rx_fifo_errors,
+              &ife->stats.rx_frame_errors,
+
+              &ife->stats.tx_bytes,
+              &ife->stats.tx_packets,
+              &ife->stats.tx_errors,
+              &ife->stats.tx_dropped,
+              &ife->stats.tx_fifo_errors,
+              &ife->stats.collisions,
+              &ife->stats.tx_carrier_errors);
+       ife->stats.rx_multicast = 0;
+       break;
+    case 1:
+       sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
+              &ife->stats.rx_packets,
+              &ife->stats.rx_errors,
+              &ife->stats.rx_dropped,
+              &ife->stats.rx_fifo_errors,
+              &ife->stats.rx_frame_errors,
+
+              &ife->stats.tx_packets,
+              &ife->stats.tx_errors,
+              &ife->stats.tx_dropped,
+              &ife->stats.tx_fifo_errors,
+              &ife->stats.collisions,
+              &ife->stats.tx_carrier_errors);
+       ife->stats.rx_bytes = 0;
+       ife->stats.tx_bytes = 0;
+       ife->stats.rx_multicast = 0;
+       break;
+    }
+    return 0;
+}
+
+static inline int procnetdev_version(char *buf)
+{
+    if (strstr(buf, "compressed"))
+       return 3;
+    if (strstr(buf, "bytes"))
+       return 2;
+    return 1;
+}
+
+static int if_readlist_proc(char *target)
+{
+    static int proc_read; 
+    FILE *fh;
+    char buf[512];
+    struct interface *ife;
+    int err;
+
+    if (proc_read) 
+           return 0; 
+    if (!target) 
+           proc_read = 1;
+
+    fh = fopen(_PATH_PROCNET_DEV, "r");
+    if (!fh) {
+               fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
+                       _PATH_PROCNET_DEV, strerror(errno)); 
+               return if_readconf();
+       }       
+    fgets(buf, sizeof buf, fh);        /* eat line */
+    fgets(buf, sizeof buf, fh);
+
+#if 0                          /* pretty, but can't cope with missing fields */
+    fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
+                      "face", "",      /* parsed separately */
+                      "bytes", "%lu",
+                      "packets", "%lu",
+                      "errs", "%lu",
+                      "drop", "%lu",
+                      "fifo", "%lu",
+                      "frame", "%lu",
+                      "compressed", "%lu",
+                      "multicast", "%lu",
+                      "bytes", "%lu",
+                      "packets", "%lu",
+                      "errs", "%lu",
+                      "drop", "%lu",
+                      "fifo", "%lu",
+                      "colls", "%lu",
+                      "carrier", "%lu",
+                      "compressed", "%lu",
+                      NULL);
+    if (!fmt)
+       return -1;
+#else
+    procnetdev_vsn = procnetdev_version(buf);
+#endif
+
+    err = 0;
+    while (fgets(buf, sizeof buf, fh)) {
+       char *s, name[128];
+       s = get_name(name, buf);    
+       ife = add_interface(name);
+       get_dev_fields(s, ife);
+       ife->statistics_valid = 1;
+       if (target && !strcmp(target,name))
+               break;
+    }
+    if (ferror(fh)) {
+       perror(_PATH_PROCNET_DEV);
+       err = -1;
+       proc_read = 0; 
+    }
+
+#if 0
+    free(fmt);
+#endif
+    fclose(fh);
+    return err;
+}
+
+static int if_readlist(void) 
+{ 
+    int err = if_readlist_proc(NULL); 
+    if (!err)
+           err = if_readconf();
+    return err;
+} 
+
+static int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
+{
+    struct interface *ife;
+
+    if (!int_list && (if_readlist() < 0))
+       return -1;
+    for (ife = int_list; ife; ife = ife->next) {
+       int err = doit(ife, cookie);
+       if (err)
+           return err;
+    }
+    return 0;
+}
+
+/* Support for fetching an IPX address */
+
+#if HAVE_AFIPX
+static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
+{
+    ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
+    return ioctl(sock, SIOCGIFADDR, ifr);
+}
+#endif
+
+
+/* Fetch the interface configuration from the kernel. */
+static int if_fetch(struct interface *ife)
+{
+    struct ifreq ifr;
+    int fd;
+    char *ifname = ife->name; 
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+       return (-1);
+    ife->flags = ifr.ifr_flags;
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
+       memset(ife->hwaddr, 0, 32);
+    else
+       memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
+
+    ife->type = ifr.ifr_hwaddr.sa_family;
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
+       ife->metric = 0;
+    else
+       ife->metric = ifr.ifr_metric;
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
+       ife->mtu = 0;
+    else
+       ife->mtu = ifr.ifr_mtu;
+
+#ifdef HAVE_HWSLIP
+    if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
+       ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
+       ife->type == ARPHRD_ADAPT) {
+#ifdef SIOCGOUTFILL
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
+           ife->outfill = 0;
+       else
+           ife->outfill = (unsigned int) ifr.ifr_data;
+#endif
+#ifdef SIOCGKEEPALIVE
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
+           ife->keepalive = 0;
+       else
+           ife->keepalive = (unsigned int) ifr.ifr_data;
+#endif
+    }
+#endif
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+       memset(&ife->map, 0, sizeof(struct ifmap));
+    else
+       memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+       memset(&ife->map, 0, sizeof(struct ifmap));
+    else
+       ife->map = ifr.ifr_map;
+
+#ifdef HAVE_TXQUEUELEN
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
+       ife->tx_queue_len = -1; /* unknown value */
+    else
+       ife->tx_queue_len = ifr.ifr_qlen;
+#else
+    ife->tx_queue_len = -1;    /* unknown value */
+#endif
+
+#if HAVE_AFINET
+    /* IPv4 address? */
+    fd = get_socket_for_af(AF_INET);
+    if (fd >= 0) {
+       strcpy(ifr.ifr_name, ifname);
+       ifr.ifr_addr.sa_family = AF_INET;
+       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+           ife->has_ip = 1;
+           ife->addr = ifr.ifr_addr;
+           strcpy(ifr.ifr_name, ifname);
+           if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
+               memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
+           else
+               ife->dstaddr = ifr.ifr_dstaddr;
+
+           strcpy(ifr.ifr_name, ifname);
+           if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
+               memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
+           else
+               ife->broadaddr = ifr.ifr_broadaddr;
+
+           strcpy(ifr.ifr_name, ifname);
+           if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
+               memset(&ife->netmask, 0, sizeof(struct sockaddr));
+           else
+               ife->netmask = ifr.ifr_netmask;
+       } else
+           memset(&ife->addr, 0, sizeof(struct sockaddr));
+    }
+#endif
+
+#if HAVE_AFATALK
+    /* DDP address maybe ? */
+    fd = get_socket_for_af(AF_APPLETALK);
+    if (fd >= 0) {
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+           ife->ddpaddr = ifr.ifr_addr;
+           ife->has_ddp = 1;
+       }
+    }
+#endif
+
+#if HAVE_AFIPX
+    /* Look for IPX addresses with all framing types */
+    fd = get_socket_for_af(AF_IPX);
+    if (fd >= 0) {
+       strcpy(ifr.ifr_name, ifname);
+       if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
+           ife->has_ipx_bb = 1;
+           ife->ipxaddr_bb = ifr.ifr_addr;
+       }
+       strcpy(ifr.ifr_name, ifname);
+       if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
+           ife->has_ipx_sn = 1;
+           ife->ipxaddr_sn = ifr.ifr_addr;
+       }
+       strcpy(ifr.ifr_name, ifname);
+       if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
+           ife->has_ipx_e3 = 1;
+           ife->ipxaddr_e3 = ifr.ifr_addr;
+       }
+       strcpy(ifr.ifr_name, ifname);
+       if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
+           ife->has_ipx_e2 = 1;
+           ife->ipxaddr_e2 = ifr.ifr_addr;
+       }
+    }
+#endif
+
+#if HAVE_AFECONET
+    /* Econet address maybe? */
+    fd = get_socket_for_af(AF_ECONET);
+    if (fd >= 0) {
+       strcpy(ifr.ifr_name, ifname);
+       if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+           ife->ecaddr = ifr.ifr_addr;
+           ife->has_econet = 1;
+       }
+    }
+#endif
+
+    return 0;
+}
+
+
+static int do_if_fetch(struct interface *ife)
+{ 
+    if (if_fetch(ife) < 0) {
+       char *errmsg; 
+       if (errno == ENODEV) { 
+           /* Give better error message for this case. */ 
+           errmsg = _("Device not found"); 
+       } else { 
+           errmsg = strerror(errno); 
+       }
+       fprintf(stderr, _("%s: error fetching interface information: %s\n"),
+               ife->name, errmsg);
+       return -1;
+    }
+    return 0; 
+}
+
+/* This structure defines hardware protocols and their handlers. */
+struct hwtype {
+    const char *name;
+    const char *title;
+    int type;
+    int alen;
+    char *(*print) (unsigned char *);
+    int (*input) (char *, struct sockaddr *);
+    int (*activate) (int fd);
+    int suppress_null_addr;
+};
+
+static struct hwtype unspec_hwtype =
+{
+    "unspec", "UNSPEC", -1, 0,
+    UNSPEC_print, NULL, NULL
+};
+
+static struct hwtype loop_hwtype =
+{
+    "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
+    NULL, NULL, NULL
+};
+
+#if HAVE_HWETHER
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+static struct hwtype ether_hwtype;
+
+/* Display an Ethernet address in readable format. */
+static char *pr_ether(unsigned char *ptr)
+{
+    static char buff[64];
+
+    snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
+            (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
+            (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
+       );
+    return (buff);
+}
+
+#ifdef KEEP_UNUSED
+/* Input an Ethernet address and convert to binary. */
+static int in_ether(char *bufp, struct sockaddr *sap)
+{
+    unsigned char *ptr;
+    char c, *orig;
+    int i;
+    unsigned val;
+
+    sap->sa_family = ether_hwtype.type;
+    ptr = sap->sa_data;
+
+    i = 0;
+    orig = bufp;
+    while ((*bufp != '\0') && (i < ETH_ALEN)) {
+       val = 0;
+       c = *bufp++;
+       if (isdigit(c))
+           val = c - '0';
+       else if (c >= 'a' && c <= 'f')
+           val = c - 'a' + 10;
+       else if (c >= 'A' && c <= 'F')
+           val = c - 'A' + 10;
+       else {
+#ifdef DEBUG
+           fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
+#endif
+           errno = EINVAL;
+           return (-1);
+       }
+       val <<= 4;
+       c = *bufp;
+       if (isdigit(c))
+           val |= c - '0';
+       else if (c >= 'a' && c <= 'f')
+           val |= c - 'a' + 10;
+       else if (c >= 'A' && c <= 'F')
+           val |= c - 'A' + 10;
+       else if (c == ':' || c == 0)
+           val >>= 4;
+       else {
+#ifdef DEBUG
+           fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig);
+#endif
+           errno = EINVAL;
+           return (-1);
+       }
+       if (c != 0)
+           bufp++;
+       *ptr++ = (unsigned char) (val & 0377);
+       i++;
+
+       /* We might get a semicolon here - not required. */
+       if (*bufp == ':') {
+           if (i == ETH_ALEN) {
+#ifdef DEBUG
+               fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"),
+                       orig)
+#endif
+                   ;           /* nothing */
+           }
+           bufp++;
+       }
+    }
+
+    /* That's it.  Any trailing junk? */
+    if ((i == ETH_ALEN) && (*bufp != '\0')) {
+#ifdef DEBUG
+       fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig);
+       errno = EINVAL;
+       return (-1);
+#endif
+    }
+#ifdef DEBUG
+    fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
+#endif
+
+    return (0);
+}
+#endif /* KEEP_UNUSED */
+
+
+static struct hwtype ether_hwtype =
+{
+    "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
+    pr_ether, NULL /* UNUSED in_ether */, NULL
+};
+
+
+#endif                         /* HAVE_HWETHER */
+
+
+#if HAVE_HWPPP
+
+#include <net/if_arp.h>
+
+#ifdef KEEP_UNUSED
+/* Start the PPP encapsulation on the file descriptor. */
+static int do_ppp(int fd)
+{
+    fprintf(stderr, _("You cannot start PPP with this program.\n"));
+    return -1;
+}
+#endif /* KEEP_UNUSED */
+
+static struct hwtype ppp_hwtype =
+{
+    "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
+    NULL, NULL, NULL /* UNUSED do_ppp */, 0
+};
+
+
+#endif                         /* HAVE_PPP */
+
+static struct hwtype *hwtypes[] =
+{
+
+    &loop_hwtype,
+
+#if HAVE_HWSLIP
+    &slip_hwtype,
+    &cslip_hwtype,
+    &slip6_hwtype,
+    &cslip6_hwtype,
+    &adaptive_hwtype,
+#endif
+#if HAVE_HWSTRIP
+    &strip_hwtype,
+#endif
+#if HAVE_HWASH
+    &ash_hwtype,
+#endif
+#if HAVE_HWETHER
+    &ether_hwtype,
+#endif
+#if HAVE_HWTR
+    &tr_hwtype,
+#ifdef ARPHRD_IEEE802_TR
+    &tr_hwtype1, 
+#endif
+#endif
+#if HAVE_HWAX25
+    &ax25_hwtype,
+#endif
+#if HAVE_HWNETROM
+    &netrom_hwtype,
+#endif
+#if HAVE_HWROSE
+    &rose_hwtype,
+#endif
+#if HAVE_HWTUNNEL
+    &tunnel_hwtype,
+#endif
+#if HAVE_HWPPP
+    &ppp_hwtype,
+#endif
+#if HAVE_HWHDLCLAPB
+    &hdlc_hwtype,
+    &lapb_hwtype,
+#endif
+#if HAVE_HWARC
+    &arcnet_hwtype,
+#endif
+#if HAVE_HWFR
+    &dlci_hwtype,
+    &frad_hwtype,
+#endif
+#if HAVE_HWSIT
+    &sit_hwtype,
+#endif
+#if HAVE_HWFDDI
+    &fddi_hwtype,
+#endif
+#if HAVE_HWHIPPI
+    &hippi_hwtype,
+#endif
+#if HAVE_HWIRDA
+    &irda_hwtype,
+#endif
+#if HAVE_HWEC
+    &ec_hwtype,
+#endif
+#if HAVE_HWX25
+    &x25_hwtype,
+#endif
+    &unspec_hwtype,
+    NULL
+};
+
+#ifdef KEEP_UNUSED
+static short sVhwinit = 0;
+
+static void hwinit()
+{
+    loop_hwtype.title = _("Local Loopback");
+    unspec_hwtype.title = _("UNSPEC");
+#if HAVE_HWSLIP
+    slip_hwtype.title = _("Serial Line IP");
+    cslip_hwtype.title = _("VJ Serial Line IP");
+    slip6_hwtype.title = _("6-bit Serial Line IP");
+    cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
+    adaptive_hwtype.title = _("Adaptive Serial Line IP");
+#endif
+#if HAVE_HWETHER
+    ether_hwtype.title = _("Ethernet");
+#endif
+#if HAVE_HWASH
+    ash_hwtype.title = _("Ash");
+#endif
+#if HAVE_HWFDDI
+    fddi_hwtype.title = _("Fiber Distributed Data Interface");
+#endif
+#if HAVE_HWHIPPI
+    hippi_hwtype.title = _("HIPPI");
+#endif
+#if HAVE_HWAX25
+    ax25_hwtype.title = _("AMPR AX.25");
+#endif
+#if HAVE_HWROSE
+    rose_hwtype.title = _("AMPR ROSE");
+#endif
+#if HAVE_HWNETROM
+    netrom_hwtype.title = _("AMPR NET/ROM");
+#endif
+#if HAVE_HWX25
+    x25_hwtype.title = _("generic X.25");
+#endif
+#if HAVE_HWTUNNEL
+    tunnel_hwtype.title = _("IPIP Tunnel");
+#endif
+#if HAVE_HWPPP
+    ppp_hwtype.title = _("Point-to-Point Protocol");
+#endif
+#if HAVE_HWHDLCLAPB
+    hdlc_hwtype.title = _("(Cisco)-HDLC");
+    lapb_hwtype.title = _("LAPB");
+#endif
+#if HAVE_HWARC
+    arcnet_hwtype.title = _("ARCnet");
+#endif
+#if HAVE_HWFR
+    dlci_hwtype.title = _("Frame Relay DLCI");
+    frad_hwtype.title = _("Frame Relay Access Device");
+#endif
+#if HAVE_HWSIT
+    sit_hwtype.title = _("IPv6-in-IPv4");
+#endif
+#if HAVE_HWIRDA
+    irda_hwtype.title = _("IrLAP");
+#endif
+#if HAVE_HWTR
+    tr_hwtype.title = _("16/4 Mbps Token Ring");
+#ifdef ARPHRD_IEEE802_TR
+    tr_hwtype1.title = _("16/4 Mbps Token Ring (New)") ; 
+#endif
+#endif
+#if HAVE_HWEC
+    ec_hwtype.title = _("Econet");
+#endif
+    sVhwinit = 1;
+}
+#endif /* KEEP_UNUSED */
+
+#ifdef IFF_PORTSEL
+static const char *if_port_text[][4] =
+{
+    /* Keep in step with <linux/netdevice.h> */
+    {"unknown", NULL, NULL, NULL},
+    {"10base2", "bnc", "coax", NULL},
+    {"10baseT", "utp", "tpe", NULL},
+    {"AUI", "thick", "db15", NULL},
+    {"100baseT", NULL, NULL, NULL},
+    {"100baseTX", NULL, NULL, NULL},
+    {"100baseFX", NULL, NULL, NULL},
+    {NULL, NULL, NULL, NULL},
+};
+#endif
+
+/* Check our hardware type table for this type. */
+static struct hwtype *get_hwntype(int type)
+{
+    struct hwtype **hwp;
+
+#ifdef KEEP_UNUSED
+    if (!sVhwinit)
+       hwinit();
+#endif /* KEEP_UNUSED */
+
+    hwp = hwtypes;
+    while (*hwp != NULL) {
+       if ((*hwp)->type == type)
+           return (*hwp);
+       hwp++;
+    }
+    return (NULL);
+}
+
+/* return 1 if address is all zeros */
+static int hw_null_address(struct hwtype *hw, void *ap)
+{
+    unsigned int i;
+    unsigned char *address = (unsigned char *)ap;
+    for (i = 0; i < hw->alen; i++)
+       if (address[i])
+           return 0;
+    return 1;
+}
+
+static const char TRext[] = "\0\0k\0M";
+
+static void print_bytes_scaled(unsigned long long ull, const char *end)
+{
+       unsigned long long int_part;
+       unsigned long frac_part;
+       const char *ext;
+       int i;
+
+       frac_part = 0;
+       ext = TRext;
+       int_part = ull;
+       for (i=0 ; i<2 ; i++) {
+               if (int_part >= 1024) {
+                       frac_part = ((int_part % 1024) * 10) / 1024;
+                       int_part /= 1024;
+                       ext += 2;                       /* Kb, Mb */
+               }
+       }
+
+       printf("X bytes:%Lu (%Lu.%lu %siB)%s", ull, int_part, frac_part, ext, end);
+}
+
+static void ife_print(struct interface *ptr)
+{
+    struct aftype *ap;
+    struct hwtype *hw;
+    int hf;
+    int can_compress = 0;
+
+#if HAVE_AFIPX
+    static struct aftype *ipxtype = NULL;
+#endif
+#if HAVE_AFECONET
+    static struct aftype *ectype = NULL;
+#endif
+#if HAVE_AFATALK
+    static struct aftype *ddptype = NULL;
+#endif
+#if HAVE_AFINET6
+    FILE *f;
+    char addr6[40], devname[20];
+    struct sockaddr_in6 sap;
+    int plen, scope, dad_status, if_idx;
+    extern struct aftype inet6_aftype;
+    char addr6p[8][5];
+#endif
+
+    ap = get_afntype(ptr->addr.sa_family);
+    if (ap == NULL)
+       ap = get_afntype(0);
+
+    hf = ptr->type;
+
+    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
+       can_compress = 1;
+
+    hw = get_hwntype(hf);
+    if (hw == NULL)
+       hw = get_hwntype(-1);
+
+    printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
+    /* For some hardware types (eg Ash, ATM) we don't print the 
+       hardware address if it's null.  */
+    if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
+                                 hw->suppress_null_addr)))
+       printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
+#ifdef IFF_PORTSEL
+    if (ptr->flags & IFF_PORTSEL) {
+       printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
+       if (ptr->flags & IFF_AUTOMEDIA)
+           printf(_("(auto)"));
+    }
+#endif
+    printf("\n");
+
+#if HAVE_AFINET
+    if (ptr->has_ip) {
+       printf(_("          %s addr:%s "), ap->name,
+              ap->sprint(&ptr->addr, 1));
+       if (ptr->flags & IFF_POINTOPOINT) {
+           printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
+       }
+       if (ptr->flags & IFF_BROADCAST) {
+           printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
+       }
+       printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
+    }
+#endif
+
+#if HAVE_AFINET6
+    /* FIXME: should be integrated into interface.c.   */
+
+    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
+       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
+                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
+                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
+                 &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
+           if (!strcmp(devname, ptr->name)) {
+               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
+                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
+               inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
+               printf(_("          inet6 addr: %s/%d"),
+                inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
+               printf(_(" Scope:"));
+               switch (scope) {
+               case 0:
+                   printf(_("Global"));
+                   break;
+               case IPV6_ADDR_LINKLOCAL:
+                   printf(_("Link"));
+                   break;
+               case IPV6_ADDR_SITELOCAL:
+                   printf(_("Site"));
+                   break;
+               case IPV6_ADDR_COMPATv4:
+                   printf(_("Compat"));
+                   break;
+               case IPV6_ADDR_LOOPBACK:
+                   printf(_("Host"));
+                   break;
+               default:
+                   printf(_("Unknown"));
+               }
+               printf("\n");
+           }
+       }
+       fclose(f);
+    }
+#endif
+
+#if HAVE_AFIPX
+    if (ipxtype == NULL)
+       ipxtype = get_afntype(AF_IPX);
+
+    if (ipxtype != NULL) {
+       if (ptr->has_ipx_bb)
+           printf(_("          IPX/Ethernet II addr:%s\n"),
+                  ipxtype->sprint(&ptr->ipxaddr_bb, 1));
+       if (ptr->has_ipx_sn)
+           printf(_("          IPX/Ethernet SNAP addr:%s\n"),
+                  ipxtype->sprint(&ptr->ipxaddr_sn, 1));
+       if (ptr->has_ipx_e2)
+           printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
+                  ipxtype->sprint(&ptr->ipxaddr_e2, 1));
+       if (ptr->has_ipx_e3)
+           printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
+                  ipxtype->sprint(&ptr->ipxaddr_e3, 1));
+    }
+#endif
+
+#if HAVE_AFATALK
+    if (ddptype == NULL)
+       ddptype = get_afntype(AF_APPLETALK);
+    if (ddptype != NULL) {
+       if (ptr->has_ddp)
+           printf(_("          EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1));
+    }
+#endif
+
+#if HAVE_AFECONET
+    if (ectype == NULL)
+       ectype = get_afntype(AF_ECONET);
+    if (ectype != NULL) {
+       if (ptr->has_econet)
+           printf(_("          econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1));
+    }
+#endif
+
+    printf("          ");
+    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
+    if (ptr->flags == 0)
+       printf(_("[NO FLAGS] "));
+    if (ptr->flags & IFF_UP)
+       printf(_("UP "));
+    if (ptr->flags & IFF_BROADCAST)
+       printf(_("BROADCAST "));
+    if (ptr->flags & IFF_DEBUG)
+       printf(_("DEBUG "));
+    if (ptr->flags & IFF_LOOPBACK)
+       printf(_("LOOPBACK "));
+    if (ptr->flags & IFF_POINTOPOINT)
+       printf(_("POINTOPOINT "));
+    if (ptr->flags & IFF_NOTRAILERS)
+       printf(_("NOTRAILERS "));
+    if (ptr->flags & IFF_RUNNING)
+       printf(_("RUNNING "));
+    if (ptr->flags & IFF_NOARP)
+       printf(_("NOARP "));
+    if (ptr->flags & IFF_PROMISC)
+       printf(_("PROMISC "));
+    if (ptr->flags & IFF_ALLMULTI)
+       printf(_("ALLMULTI "));
+    if (ptr->flags & IFF_SLAVE)
+       printf(_("SLAVE "));
+    if (ptr->flags & IFF_MASTER)
+       printf(_("MASTER "));
+    if (ptr->flags & IFF_MULTICAST)
+       printf(_("MULTICAST "));
+#ifdef HAVE_DYNAMIC
+    if (ptr->flags & IFF_DYNAMIC)
+       printf(_("DYNAMIC "));
+#endif
+    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
+    printf(_(" MTU:%d  Metric:%d"),
+          ptr->mtu, ptr->metric ? ptr->metric : 1);
+#ifdef SIOCSKEEPALIVE
+    if (ptr->outfill || ptr->keepalive)
+       printf(_("  Outfill:%d  Keepalive:%d"),
+              ptr->outfill, ptr->keepalive);
+#endif
+    printf("\n");
+
+    /* If needed, display the interface statistics. */
+
+    if (ptr->statistics_valid) {
+       /* XXX: statistics are currently only printed for the primary address,
+        *      not for the aliases, although strictly speaking they're shared
+        *      by all addresses.
+        */
+       printf("          ");
+
+       printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
+              ptr->stats.rx_packets, ptr->stats.rx_errors,
+              ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
+              ptr->stats.rx_frame_errors);
+       if (can_compress)
+           printf(_("             compressed:%lu\n"), ptr->stats.rx_compressed);
+       printf("          ");
+       printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
+              ptr->stats.tx_packets, ptr->stats.tx_errors,
+              ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
+              ptr->stats.tx_carrier_errors);
+       printf(_("          collisions:%lu "), ptr->stats.collisions);
+       if (can_compress)
+           printf(_("compressed:%lu "), ptr->stats.tx_compressed);
+       if (ptr->tx_queue_len != -1)
+           printf(_("txqueuelen:%d "), ptr->tx_queue_len);
+       printf("\n          R");
+       print_bytes_scaled(ptr->stats.rx_bytes, "  T");
+       print_bytes_scaled(ptr->stats.tx_bytes, "\n");
+
+    }
+
+    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
+        ptr->map.base_addr)) {
+       printf("          ");
+       if (ptr->map.irq)
+           printf(_("Interrupt:%d "), ptr->map.irq);
+       if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for 
+                                                  I/O maps */
+           printf(_("Base address:0x%lx "), (unsigned long)ptr->map.base_addr);
+       if (ptr->map.mem_start) {
+           printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
+       }
+       if (ptr->map.dma)
+           printf(_("DMA chan:%x "), ptr->map.dma);
+       printf("\n");
+    }
+    printf("\n");
+}
+
+
+static int do_if_print(struct interface *ife, void *cookie)
+{
+    int *opt_a = (int *) cookie;
+    int res; 
+
+    res = do_if_fetch(ife); 
+    if (res >= 0) {   
+       if ((ife->flags & IFF_UP) || *opt_a)
+           ife_print(ife);
+    }
+    return res;
+}
+
+static struct interface *lookup_interface(char *name)
+{
+    struct interface *ife = NULL;
+
+    if (if_readlist_proc(name) < 0) 
+           return NULL; 
+    ife = add_interface(name); 
+    return ife;
+}
+
+/* for ipv4 add/del modes */
+static int if_print(char *ifname)
+{
+    int res;
+
+    if (!ifname) {
+       res = for_all_interfaces(do_if_print, &interface_opt_a);
+    } else {
+       struct interface *ife;
+
+       ife = lookup_interface(ifname);
+       res = do_if_fetch(ife); 
+       if (res >= 0) 
+           ife_print(ife);
+    }
+    return res; 
+}
+
+int display_interfaces(char *ifname)
+{
+    int status;
+
+    /* Create a channel to the NET kernel. */
+    if ((skfd = sockets_open(0)) < 0) {
+               perror_msg_and_die("socket");
+    }
+
+    /* Do we have to show the current setup? */
+    status = if_print(ifname);
+    close(skfd);
+    exit(status < 0);
+}
diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c
new file mode 100644 (file)
index 0000000..3dfe105
--- /dev/null
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+/*
+ * Return TRUE if a fileName is a directory.
+ * Nonexistant files return FALSE.
+ */
+int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
+{
+       int status;
+       int didMalloc = 0;
+
+       if (statBuf == NULL) {
+           statBuf = (struct stat *)xmalloc(sizeof(struct stat));
+           ++didMalloc;
+       }
+
+       if (followLinks == TRUE)
+               status = stat(fileName, statBuf);
+       else
+               status = lstat(fileName, statBuf);
+
+       if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
+           status = FALSE;
+       }
+       else status = TRUE;
+
+       if (didMalloc) {
+           free(statBuf);
+           statBuf = NULL;
+       }
+       return status;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c
new file mode 100644 (file)
index 0000000..694af8e
--- /dev/null
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/utsname.h>               /* for uname(2) */
+
+#include "libbb.h"
+
+/* Returns kernel version encoded as major*65536 + minor*256 + patch,
+ * so, for example,  to check if the kernel is greater than 2.2.11:
+ *     if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
+ */
+extern int get_kernel_revision(void)
+{
+       struct utsname name;
+       char *s;
+       int i, r;
+
+       if (uname(&name) == -1) {
+               perror_msg("cannot get system information");
+               return (0);
+       }
+
+       s = name.release;
+       r = 0;
+       for (i=0 ; i<3 ; i++) {
+               r = r * 256 + atoi(strtok(s, "."));
+               s = NULL;
+       }
+       return r;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c
new file mode 100644 (file)
index 0000000..4e2ee92
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+/* Find out if the last character of a string matches the one given Don't
+ * underrun the buffer if the string length is 0.  Also avoids a possible
+ * space-hogging inline of strlen() per usage.
+ */
+char * last_char_is(const char *s, int c)
+{
+       char *sret;
+       if (!s)
+           return NULL;
+       sret  = (char *)s+strlen(s)-1;
+       if (sret>=s && *sret == c) { 
+               return sret;
+       } else {
+               return NULL;
+       }
+}
diff --git a/libbb/libbb.h b/libbb/libbb.h
new file mode 100644 (file)
index 0000000..c3b353f
--- /dev/null
@@ -0,0 +1,340 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef        __LIBBB_H__
+#define        __LIBBB_H__    1
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <netdb.h>
+
+#ifndef _BB_INTERNAL_H_
+#include "../busybox.h"
+#endif
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#include <features.h>
+
+#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
+/* libc5 doesn't define socklen_t */
+typedef unsigned int socklen_t;
+/* libc5 doesn't implement BSD 4.4 daemon() */
+extern int daemon (int nochdir, int noclose);
+/* libc5 doesn't implement strtok_r */
+char *strtok_r(char *s, const char *delim, char **ptrptr);
+#endif 
+
+/* Some useful definitions */
+#define FALSE   ((int) 0)
+#define TRUE    ((int) 1)
+#define SKIP   ((int) 2)
+
+/* for mtab.c */
+#define MTAB_GETMOUNTPT '1'
+#define MTAB_GETDEVICE  '2'
+
+#define BUF_SIZE        8192
+#define EXPAND_ALLOC    1024
+
+static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); }
+static inline int is_octal(int ch)   { return ((ch >= '0') && (ch <= '7')); }
+
+/* Macros for min/max.  */
+#ifndef MIN
+#define        MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define        MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+
+
+extern void show_usage(void) __attribute__ ((noreturn));
+extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
+extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+extern void perror_msg(const char *s, ...);
+extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
+extern void vherror_msg(const char *s, va_list p);
+extern void herror_msg(const char *s, ...);
+extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
+
+/* These two are used internally -- you shouldn't need to use them */
+extern void verror_msg(const char *s, va_list p);
+extern void vperror_msg(const char *s, va_list p);
+
+const char *mode_string(int mode);
+const char *time_string(time_t timeVal);
+int is_directory(const char *name, int followLinks, struct stat *statBuf);
+int isDevice(const char *name);
+
+int remove_file(const char *path, int flags);
+int copy_file(const char *source, const char *dest, int flags);
+int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
+char *buildName(const char *dirName, const char *fileName);
+int makeString(int argc, const char **argv, char *buf, int bufLen);
+char *getChunk(int size);
+char *chunkstrdup(const char *str);
+void freeChunks(void);
+ssize_t safe_read(int fd, void *buf, size_t count);
+ssize_t full_write(int fd, const void *buf, size_t len);
+ssize_t full_read(int fd, void *buf, size_t len);
+int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst,
+         int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
+         int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
+         void* userData);
+
+extern int parse_mode( const char* s, mode_t* theMode);
+
+extern int get_kernel_revision(void);
+
+extern int get_console_fd(void);
+extern struct mntent *find_mount_point(const char *name, const char *table);
+extern void write_mtab(char* blockDevice, char* directory, 
+       char* filesystemType, long flags, char* string_flags);
+extern void erase_mtab(const char * name);
+extern long atoi_w_units (const char *cp);
+extern long* find_pid_by_name( char* pidName);
+extern char *find_real_root_device_name(const char* name);
+extern char *get_line_from_file(FILE *file);
+extern char *get_chomped_line_from_file(FILE *file);
+extern void print_file(FILE *file);
+extern int copyfd(int fd1, int fd2);
+extern int print_file_by_name(char *filename);
+extern char process_escape_sequence(const char **ptr);
+extern char *get_last_path_component(char *path);
+extern FILE *wfopen(const char *path, const char *mode);
+extern FILE *xfopen(const char *path, const char *mode);
+extern void chomp(char *s);
+extern void trim(char *s);
+extern struct BB_applet *find_applet_by_name(const char *name);
+void run_applet_by_name(const char *name, int argc, char **argv);
+
+#ifndef DMALLOC
+extern void *xmalloc (size_t size);
+extern void *xrealloc(void *old, size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern char *xstrdup (const char *s);
+#endif
+extern char *xstrndup (const char *s, int n);
+extern char * safe_strncpy(char *dst, const char *src, size_t size);
+
+struct suffix_mult {
+       const char *suffix;
+       int mult;
+};
+
+extern unsigned long parse_number(const char *numstr,
+               const struct suffix_mult *suffixes);
+
+
+/* These parse entries in /etc/passwd and /etc/group.  This is desirable
+ * for BusyBox since we want to avoid using the glibc NSS stuff, which
+ * increases target size and is often not needed embedded systems.  */
+extern long my_getpwnam(const char *name);
+extern long my_getgrnam(const char *name);
+extern void my_getpwuid(char *name, long uid);
+extern void my_getgrgid(char *group, long gid);
+extern long my_getpwnamegid(const char *name);
+
+extern int device_open(char *device, int mode);
+
+extern int del_loop(const char *device);
+extern int set_loop(const char *device, const char *file, int offset, int *loopro);
+extern char *find_unused_loop_device (void);
+
+
+#if (__GLIBC__ < 2)
+extern int vdprintf(int d, const char *format, va_list ap);
+#endif
+
+int nfsmount(const char *spec, const char *node, int *flags,
+            char **extra_opts, char **mount_opts, int running_bg);
+
+void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg);
+void syslog_msg(int facility, int pri, const char *msg);
+
+/* Include our own copy of struct sysinfo to avoid binary compatability
+ * problems with Linux 2.4, which changed things.  Grumble, grumble. */
+struct sysinfo {
+       long uptime;                    /* Seconds since boot */
+       unsigned long loads[3];         /* 1, 5, and 15 minute load averages */
+       unsigned long totalram;         /* Total usable main memory size */
+       unsigned long freeram;          /* Available memory size */
+       unsigned long sharedram;        /* Amount of shared memory */
+       unsigned long bufferram;        /* Memory used by buffers */
+       unsigned long totalswap;        /* Total swap space size */
+       unsigned long freeswap;         /* swap space still available */
+       unsigned short procs;           /* Number of current processes */
+       unsigned short pad;                     /* Padding needed for m68k */
+       unsigned long totalhigh;        /* Total high memory size */
+       unsigned long freehigh;         /* Available high memory size */
+       unsigned int mem_unit;          /* Memory unit size in bytes */
+       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
+};
+extern int sysinfo (struct sysinfo* info);
+
+enum {
+       KILOBYTE = 1024,
+       MEGABYTE = (KILOBYTE*1024),
+       GIGABYTE = (MEGABYTE*1024)
+};
+const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit);
+
+int ask_confirmation(void);
+int klogctl(int type, char * b, int len);
+
+char *xgetcwd(char *cwd);
+char *xreadlink(const char *path);
+char *concat_path_file(const char *path, const char *filename);
+char *last_char_is(const char *s, int c);
+
+extern long arith (const char *startbuf, int *errcode);
+
+typedef struct file_headers_s {
+       char *name;
+       char *link_name;
+       off_t size;
+       uid_t uid;
+       gid_t gid;
+       mode_t mode;
+       time_t mtime;
+       dev_t device;
+} file_header_t;
+file_header_t *get_header_ar(FILE *in_file);
+file_header_t *get_header_cpio(FILE *src_stream);
+file_header_t *get_header_tar(FILE *tar_stream);
+
+enum extract_functions_e {
+       extract_verbose_list = 1,
+       extract_list = 2,
+       extract_one_to_buffer = 4,
+       extract_to_stdout = 8,
+       extract_all_to_fs = 16,
+       extract_preserve_date = 32,
+       extract_data_tar_gz = 64,
+       extract_control_tar_gz = 128,
+       extract_unzip_only = 256,
+       extract_unconditional = 512,
+       extract_create_leading_dirs = 1024,
+       extract_quiet = 2048,
+       extract_exclude_list = 4096
+};
+char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *),
+       const int extract_function, const char *prefix, char **extract_names);
+char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function,
+       const char *prefix, const char *filename);
+int read_package_field(const char *package_buffer, char **field_name, char **field_value);
+char *fgets_str(FILE *file, const char *terminating_string);
+
+extern int unzip(FILE *l_in_file, FILE *l_out_file);
+extern void gz_close(int gunzip_pid);
+extern FILE *gz_open(FILE *compressed_file, int *pid);
+
+extern struct hostent *xgethostbyname(const char *name);
+extern int create_icmp_socket(void);
+
+char *dirname (char *path);
+
+int make_directory (char *path, long mode, int flags);
+
+const char *u_signal_names(const char *str_sig, int *signo, int startnum);
+char *simplify_path(const char *path);
+
+#define CT_AUTO        0
+#define CT_UNIX2DOS    1
+#define CT_DOS2UNIX    2
+/* extern int convert(char *fn, int ConvType); */
+
+enum {
+       FILEUTILS_PRESERVE_STATUS = 1,
+       FILEUTILS_PRESERVE_SYMLINKS = 2,
+       FILEUTILS_RECUR = 4,
+       FILEUTILS_FORCE = 8,
+       FILEUTILS_INTERACTIVE = 16
+};
+
+extern const char *applet_name;
+extern const char * const full_version;
+extern const char * const name_too_long;
+extern const char * const omitting_directory;
+extern const char * const not_a_directory;
+extern const char * const memory_exhausted;
+extern const char * const invalid_date;
+extern const char * const invalid_option;
+extern const char * const io_error;
+extern const char * const dash_dash_help;
+extern const char * const write_error;
+extern const char * const too_few_args;
+extern const char * const name_longer_than_foo;
+extern const char * const unknown;
+extern const char * const can_not_create_raw_socket;
+
+#ifdef BB_FEATURE_DEVFS
+# define CURRENT_VC "/dev/vc/0"
+# define VC_1 "/dev/vc/1"
+# define VC_2 "/dev/vc/2"
+# define VC_3 "/dev/vc/3"
+# define VC_4 "/dev/vc/4"
+# define VC_5 "/dev/vc/5"
+# define SC_0 "/dev/tts/0"
+# define SC_1 "/dev/tts/1"
+# define VC_FORMAT "/dev/vc/%d"
+# define SC_FORMAT "/dev/tts/%d"
+# define LOOP_FORMAT "/dev/loop/%d"
+#else
+# define CURRENT_VC "/dev/tty0"
+# define VC_1 "/dev/tty1"
+# define VC_2 "/dev/tty2"
+# define VC_3 "/dev/tty3"
+# define VC_4 "/dev/tty4"
+# define VC_5 "/dev/tty5"
+# define SC_0 "/dev/ttyS0"
+# define SC_1 "/dev/ttyS1"
+# define VC_FORMAT "/dev/tty%d"
+# define SC_FORMAT "/dev/ttyS%d"
+# define LOOP_FORMAT "/dev/loop%d"
+#endif
+
+/* The following devices are the same on devfs and non-devfs systems.  */
+#define CURRENT_TTY "/dev/tty"
+#define CONSOLE_DEV "/dev/console"
+
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name);
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name);
+void reset_ino_dev_hashtable(void);
+
+
+/* Cope with mmu-less systems somewhat gracefully */
+#ifdef __uClinux__
+#undef fork
+#define fork   vfork
+#endif
+
+/* Stupid gcc always includes its own builtin strlen()... */
+extern size_t xstrlen(const char *string);
+#define strlen(x)      xstrlen(x)
+
+#endif /* __LIBBB_H__ */
diff --git a/libbb/libc5.c b/libbb/libc5.c
new file mode 100644 (file)
index 0000000..67ab161
--- /dev/null
@@ -0,0 +1,168 @@
+/* vi: set sw=4 ts=4: */
+
+
+#include <features.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+
+#if ! defined __dietlibc__ &&  __GNU_LIBRARY__ < 5
+
+
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+/*
+ * Modified by Manuel Novoa III     Mar 1, 2001
+ *
+ * Converted original strtok.c code of strtok to __strtok_r.
+ * Cleaned up logic and reduced code size.
+ */
+
+
+char *strtok_r(char *s, const char *delim, char **save_ptr)
+{
+       char *token;
+
+       token = 0;                                      /* Initialize to no token. */
+
+       if (s == 0) {                           /* If not first time called... */
+               s = *save_ptr;                  /* restart from where we left off. */
+       }
+       
+       if (s != 0) {                           /* If not finished... */
+               *save_ptr = 0;
+
+               s += strspn(s, delim);  /* Skip past any leading delimiters. */
+               if (*s != '\0') {               /* We have a token. */
+                       token = s;
+                       *save_ptr = strpbrk(token, delim); /* Find token's end. */
+                       if (*save_ptr != 0) {
+                               /* Terminate the token and make SAVE_PTR point past it.  */
+                               *(*save_ptr)++ = '\0';
+                       }
+               }
+       }
+
+       return token;
+}
+
+/* Basically getdelim() with the delimiter hard wired to '\n' */
+ssize_t getline(char **linebuf, size_t *n, FILE *file)
+{
+      return (getdelim (linebuf, n, '\n', file));
+}
+
+
+#ifndef __uClinux__
+/*
+ * daemon implementation for uClibc
+ *
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Modified for uClibc by Erik Andersen <andersee@debian.org>
+ *
+ * The uClibc Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * The GNU C 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
+ * Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU C Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+int daemon( int nochdir, int noclose )
+{
+    int fd;
+
+    switch (fork()) {
+       case -1:
+           return(-1);
+       case 0:
+           break;
+       default:
+           _exit(0);
+    }
+
+    if (setsid() == -1)
+       return(-1);
+
+    if (!nochdir)
+       chdir("/");
+
+    if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+       dup2(fd, STDIN_FILENO);
+       dup2(fd, STDOUT_FILENO);
+       dup2(fd, STDERR_FILENO);
+       if (fd > 2)
+           close(fd);
+    }
+    return(0);
+}
+#endif /* __uClinux__ */
+
+
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ */
+
+
+#endif 
+
diff --git a/libbb/loop.c b/libbb/loop.c
new file mode 100644 (file)
index 0000000..66e8921
--- /dev/null
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "libbb.h"
+#include "loop.h" /* Pull in loop device support */
+
+extern int del_loop(const char *device)
+{
+       int fd;
+
+       if ((fd = open(device, O_RDONLY)) < 0) {
+               perror_msg("%s", device);
+               return (FALSE);
+       }
+       if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+               close(fd);
+               perror_msg("ioctl: LOOP_CLR_FD");
+               return (FALSE);
+       }
+       close(fd);
+       return (TRUE);
+}
+
+extern int set_loop(const char *device, const char *file, int offset,
+                                       int *loopro)
+{
+       struct loop_info loopinfo;
+       int fd, ffd, mode;
+
+       mode = *loopro ? O_RDONLY : O_RDWR;
+       if ((ffd = open(file, mode)) < 0 && !*loopro
+               && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
+               perror_msg("%s", file);
+               return 1;
+       }
+       if ((fd = open(device, mode)) < 0) {
+               close(ffd);
+               perror_msg("%s", device);
+               return 1;
+       }
+       *loopro = (mode == O_RDONLY);
+
+       memset(&loopinfo, 0, sizeof(loopinfo));
+       safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
+
+       loopinfo.lo_offset = offset;
+
+       loopinfo.lo_encrypt_key_size = 0;
+       if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+               perror_msg("ioctl: LOOP_SET_FD");
+               close(fd);
+               close(ffd);
+               return 1;
+       }
+       if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+               (void) ioctl(fd, LOOP_CLR_FD, 0);
+               perror_msg("ioctl: LOOP_SET_STATUS");
+               close(fd);
+               close(ffd);
+               return 1;
+       }
+       close(fd);
+       close(ffd);
+       return 0;
+}
+
+extern char *find_unused_loop_device(void)
+{
+       char dev[20];
+       int i, fd;
+       struct stat statbuf;
+       struct loop_info loopinfo;
+
+       for (i = 0; i <= 7; i++) {
+               sprintf(dev, LOOP_FORMAT, i);
+               if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+                       if ((fd = open(dev, O_RDONLY)) >= 0) {
+                               if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) {
+                                       if (errno == ENXIO) {   /* probably free */
+                                               close(fd);
+                                               return strdup(dev);
+                                       }
+                               }
+                               close(fd);
+                       }
+               }
+       }
+       return NULL;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
new file mode 100644 (file)
index 0000000..a06a410
--- /dev/null
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini make_directory implementation for busybox
+ *
+ * Copyright (C) 2001  Matt Kraai.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+/* Create the directory PATH with mode MODE, or the default if MODE is -1.
+ * Also create parent directories as necessary if flags contains
+ * FILEUTILS_RECUR.  */
+
+int make_directory (char *path, long mode, int flags)
+{
+       if (!(flags & FILEUTILS_RECUR)) {
+               if (mkdir (path, 0777) < 0) {
+                       perror_msg ("Cannot create directory `%s'", path);
+                       return -1;
+               }
+
+               if (mode != -1 && chmod (path, mode) < 0) {
+                       perror_msg ("Cannot set permissions of directory `%s'", path);
+                       return -1;
+               }
+       } else {
+               struct stat st;
+
+               if (stat (path, &st) < 0 && errno == ENOENT) {
+                       int status;
+                       char *buf, *parent;
+                       mode_t mask;
+
+                       mask = umask (0);
+                       umask (mask);
+
+                       buf = xstrdup (path);
+                       parent = dirname (buf);
+                       status = make_directory (parent, (0777 & ~mask) | 0300,
+                                       FILEUTILS_RECUR);
+                       free (buf);
+
+                       if (status < 0 || make_directory (path, mode, 0) < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
diff --git a/libbb/messages.c b/libbb/messages.c
new file mode 100644 (file)
index 0000000..47b5526
--- /dev/null
@@ -0,0 +1,67 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "libbb.h"
+
+#ifdef L_full_version
+       const char * const full_version = BB_BANNER " multi-call binary";
+#endif
+#ifdef L_name_too_long
+       const char * const name_too_long = "file name too long";
+#endif
+
+#ifdef L_omitting_directory
+       const char * const omitting_directory = "%s: omitting directory";
+#endif
+#ifdef L_not_a_directory
+       const char * const not_a_directory = "%s: not a directory";
+#endif
+#ifdef L_memory_exhausted
+       const char * const memory_exhausted = "memory exhausted";
+#endif
+#ifdef L_invalid_date
+       const char * const invalid_date = "invalid date `%s'";
+#endif
+#ifdef L_invalid_option
+       const char * const invalid_option = "invalid option -- %c";
+#endif
+#ifdef L_io_error
+       const char * const io_error = "%s: input/output error -- %s";
+#endif
+#ifdef L_dash_dash_help
+       const char * const dash_dash_help = "--help";
+#endif
+#ifdef L_write_error
+       const char * const write_error = "Write Error";
+#endif
+#ifdef L_too_few_args
+       const char * const too_few_args = "too few arguments";
+#endif
+#ifdef L_name_longer_than_foo
+       const char * const name_longer_than_foo = "Names longer than %d chars not supported.";
+#endif
+#ifdef L_unknown
+       const char * const unknown = "(unknown)";
+#endif
+
+#ifdef L_can_not_create_raw_socket
+       const char * const can_not_create_raw_socket = "can`t create raw socket";
+#endif
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
new file mode 100644 (file)
index 0000000..12dc179
--- /dev/null
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+       0, 0, S_ISUID,
+       0, 0, S_ISGID,
+       0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+       S_IRUSR, S_IWUSR, S_IXUSR,
+       S_IRGRP, S_IWGRP, S_IXGRP,
+       S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[]  = "rwxrwxrwx";
+static const char MODE0[]  = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *mode_string(int mode)
+{
+       static char buf[12];
+
+       int i;
+
+       buf[0] = TYPECHAR(mode);
+       for (i = 0; i < 9; i++) {
+               if (mode & SBIT[i])
+                       buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+               else
+                       buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+       }
+       return buf;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/module_syscalls.c b/libbb/module_syscalls.c
new file mode 100644 (file)
index 0000000..1320a6a
--- /dev/null
@@ -0,0 +1,127 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * some system calls possibly missing from libc
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+   _syscall* defined.  */
+#define __LIBRARY__
+#include <sys/syscall.h>
+#if __GNU_LIBRARY__ < 5
+/* This is needed for libc5 */
+#include <asm/unistd.h>
+#endif
+#include "libbb.h"
+
+
+#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
+
+#if __GNU_LIBRARY__ < 5
+/* These syscalls are not included as part of libc5 */
+_syscall1(int, delete_module, const char *, name);
+_syscall1(int, get_kernel_syms, __ptr_t, ks);
+
+/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments
+ * (for 2.2 and 2.4 kernels).  Use the greatest common denominator,
+ * and let the kernel cope with whatever it gets.  Its good at that. */
+_syscall5(int, init_module, void *, first, void *, second, void *, third,
+               void *, fourth, void *, fifth);
+#else
+int delete_module(const char *name)
+{
+    return(syscall(__NR_delete_module, name));
+}
+int get_kernel_syms(__ptr_t ks)
+{
+    return(syscall(__NR_get_kernel_syms, ks));
+}
+
+/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments
+ * (for 2.2 and 2.4 kernels).  Use the greatest common denominator,
+ * and let the kernel cope with whatever it gets.  Its good at that. */
+int init_module(void *first, void *second, void *third, void *fourth, void *fifth)
+{
+    return(syscall(__NR_init_module, first, second, third, fourth, fifth));
+}
+#endif
+
+#ifndef __NR_query_module
+#warning This kernel does not support the query_module syscall
+#warning -> The query_module system call is being stubbed out...
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)
+{
+       fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
+       fprintf(stderr, "with a kernel supporting the query_module system call. -Erik\n\n");
+       errno=ENOSYS;
+       return -1;
+}
+#else
+# if __GNU_LIBRARY__ < 5
+_syscall5(int, query_module, const char *, name, int, which,
+               void *, buf, size_t, bufsize, size_t*, ret);
+# else
+    return(syscall(__NR_query_module, name, which, buf, bufsize, ret));
+# endif
+#endif
+
+# if __GNU_LIBRARY__ < 5
+/* Jump through hoops to fixup error return codes */
+#define __NR___create_module  __NR_create_module
+static inline _syscall2(long, __create_module, const char *, name, size_t, size)
+unsigned long create_module(const char *name, size_t size)
+{
+       long ret = __create_module(name, size);
+
+       if (ret == -1 && errno > 125) {
+               ret = -errno;
+               errno = 0;
+       }
+       return ret;
+}
+#else
+/* Jump through hoops to fixup error return codes */
+unsigned long create_module(const char *name, size_t size)
+{
+    long ret = syscall(__NR_create_module, name, size);
+
+    if (ret == -1 && errno > 125) {
+       ret = -errno;
+       errno = 0;
+    }
+    return ret;
+}
+#endif
+
+#endif /* __GNU_LIBRARY__ < 5 */
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
diff --git a/libbb/mtab.c b/libbb/mtab.c
new file mode 100644 (file)
index 0000000..c521b1e
--- /dev/null
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <mntent.h>
+#include "libbb.h"
+
+extern const char mtab_file[]; /* Defined in utility.c */
+static const int MS_RDONLY = 1;        /* Mount read-only.  */
+
+void erase_mtab(const char *name)
+{
+       struct mntent entries[20];
+       int count = 0;
+       FILE *mountTable = setmntent(mtab_file, "r");
+       struct mntent *m;
+
+       /* Check if reading the mtab file failed */
+       if (mountTable == 0
+                       /* Bummer.  fall back on trying the /proc filesystem */
+                       && (mountTable = setmntent("/proc/mounts", "r")) == 0) {
+               perror_msg("%s", mtab_file);
+               return;
+       }
+
+       while ((m = getmntent(mountTable)) != 0) {
+               entries[count].mnt_fsname = strdup(m->mnt_fsname);
+               entries[count].mnt_dir = strdup(m->mnt_dir);
+               entries[count].mnt_type = strdup(m->mnt_type);
+               entries[count].mnt_opts = strdup(m->mnt_opts);
+               entries[count].mnt_freq = m->mnt_freq;
+               entries[count].mnt_passno = m->mnt_passno;
+               count++;
+       }
+       endmntent(mountTable);
+       if ((mountTable = setmntent(mtab_file, "w"))) {
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       int result = (strcmp(entries[i].mnt_fsname, name) == 0
+                                                 || strcmp(entries[i].mnt_dir, name) == 0);
+
+                       if (result)
+                               continue;
+                       else
+                               addmntent(mountTable, &entries[i]);
+               }
+               endmntent(mountTable);
+       } else if (errno != EROFS)
+               perror_msg("%s", mtab_file);
+}
+
+void write_mtab(char *blockDevice, char *directory,
+                               char *filesystemType, long flags, char *string_flags)
+{
+       FILE *mountTable = setmntent(mtab_file, "a+");
+       struct mntent m;
+
+       if (mountTable == 0) {
+               perror_msg("%s", mtab_file);
+               return;
+       }
+       if (mountTable) {
+               int length = strlen(directory);
+
+               if (length > 1 && directory[length - 1] == '/')
+                       directory[length - 1] = '\0';
+
+               if (filesystemType == 0) {
+                       struct mntent *p = find_mount_point(blockDevice, "/proc/mounts");
+
+                       if (p && p->mnt_type)
+                               filesystemType = p->mnt_type;
+               }
+               m.mnt_fsname = blockDevice;
+               m.mnt_dir = directory;
+               m.mnt_type = filesystemType ? filesystemType : "default";
+
+               if (*string_flags) {
+                       m.mnt_opts = string_flags;
+               } else {
+                       if ((flags | MS_RDONLY) == flags)
+                               m.mnt_opts = "ro";
+                       else
+                               m.mnt_opts = "rw";
+               }
+
+               m.mnt_freq = 0;
+               m.mnt_passno = 0;
+               addmntent(mountTable, &m);
+               endmntent(mountTable);
+       }
+}
diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c
new file mode 100644 (file)
index 0000000..e6ccd09
--- /dev/null
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+/* Busybox mount uses either /proc/mounts or /dev/mtab to 
+ * get the list of currently mounted filesystems */ 
+#if defined BB_FEATURE_MTAB_SUPPORT
+const char mtab_file[] = "/etc/mtab";
+#else
+#  if defined BB_FEATURE_USE_DEVPS_PATCH
+      const char mtab_file[] = "/dev/mtab";
+#  else
+      const char mtab_file[] = "/proc/mounts";
+#  endif
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/my_getgrgid.c b/libbb/my_getgrgid.c
new file mode 100644 (file)
index 0000000..78f8001
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../pwd_grp/pwd.h"
+#include "../pwd_grp/grp.h"
+#include "libbb.h"
+
+
+/* gets a groupname given a gid */
+void my_getgrgid(char *group, long gid)
+{
+       struct group *mygroup;
+
+       mygroup  = getgrgid(gid);
+       if (mygroup==NULL)
+               sprintf(group, "%-8ld ", (long)gid);
+       else
+               strcpy(group, mygroup->gr_name);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/my_getgrnam.c b/libbb/my_getgrnam.c
new file mode 100644 (file)
index 0000000..bea4ce0
--- /dev/null
@@ -0,0 +1,50 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../pwd_grp/pwd.h"
+#include "../pwd_grp/grp.h"
+#include "libbb.h"
+
+
+
+/* returns a gid given a group name */
+long my_getgrnam(const char *name)
+{
+       struct group *mygroup;
+
+       mygroup  = getgrnam(name);
+       if (mygroup==NULL)
+               error_msg_and_die("unknown group name: %s", name);
+
+       return (mygroup->gr_gid);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/my_getpwnam.c b/libbb/my_getpwnam.c
new file mode 100644 (file)
index 0000000..2fc0101
--- /dev/null
@@ -0,0 +1,50 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../pwd_grp/pwd.h"
+#include "../pwd_grp/grp.h"
+#include "libbb.h"
+
+
+
+/* returns a uid given a username */
+long my_getpwnam(const char *name)
+{
+       struct passwd *myuser;
+
+       myuser  = getpwnam(name);
+       if (myuser==NULL)
+               error_msg_and_die("unknown user name: %s", name);
+
+       return myuser->pw_uid;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/my_getpwnamegid.c b/libbb/my_getpwnamegid.c
new file mode 100644 (file)
index 0000000..687c52c
--- /dev/null
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../pwd_grp/pwd.h"
+#include "../pwd_grp/grp.h"
+#include "libbb.h"
+
+
+
+/* gets a gid given a user name */
+long my_getpwnamegid(const char *name)
+{
+       struct group *mygroup;
+       struct passwd *myuser;
+
+       myuser=getpwnam(name);
+       if (myuser==NULL)
+               error_msg_and_die("unknown user name: %s", name);
+
+       mygroup  = getgrgid(myuser->pw_gid);
+       if (mygroup==NULL)
+               error_msg_and_die("unknown gid %ld", (long)myuser->pw_gid);
+
+       return mygroup->gr_gid;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/my_getpwuid.c b/libbb/my_getpwuid.c
new file mode 100644 (file)
index 0000000..8dd8288
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "../pwd_grp/pwd.h"
+#include "../pwd_grp/grp.h"
+#include "libbb.h"
+
+
+
+/* gets a username given a uid */
+void my_getpwuid(char *name, long uid)
+{
+       struct passwd *myuser;
+
+       myuser  = getpwuid(uid);
+       if (myuser==NULL)
+               sprintf(name, "%-8ld ", (long)uid);
+       else
+               strcpy(name, myuser->pw_name);
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c
new file mode 100644 (file)
index 0000000..ba34ea9
--- /dev/null
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+/* This function parses the sort of string you might pass
+ * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the
+ * correct mode described by the string. */
+extern int parse_mode(const char *s, mode_t * theMode)
+{
+       static const mode_t group_set[] = { 
+               S_ISUID | S_IRWXU,              /* u */
+               S_ISGID | S_IRWXG,              /* g */
+               S_IRWXO,                                /* o */
+               S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+       };
+
+       static const mode_t mode_set[] = {
+               S_IRUSR | S_IRGRP | S_IROTH, /* r */
+               S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+               S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+               S_ISUID | S_ISGID,              /* s */
+               S_ISVTX                                 /* t */
+       };
+
+       static const char group_chars[] = "ugoa";
+       static const char mode_chars[] = "rwxst";
+
+       const char *p;
+
+       mode_t andMode =
+               S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+       mode_t orMode = 0;
+       mode_t mode;
+       mode_t groups;
+       char type;
+       char c;
+
+       if (s==NULL) {
+               return (FALSE);
+       }
+
+       do {
+               mode = 0;
+               groups = 0;
+       NEXT_GROUP:
+               if ((c = *s++) == '\0') {
+                       return -1;
+               }
+               for (p=group_chars ; *p ; p++) {
+                       if (*p == c) {
+                               groups |= group_set[(int)(p-group_chars)];
+                               goto NEXT_GROUP;
+                       }
+               }
+               switch (c) {
+                       case '=':
+                       case '+':
+                       case '-':
+                               type = c;
+                               if (groups == 0) { /* The default is "all" */
+                                       groups |= S_ISUID | S_ISGID | S_ISVTX
+                                                       | S_IRWXU | S_IRWXG | S_IRWXO;
+                               }
+                               break;
+                       default:
+                               if ((c < '0') || (c > '7') || (mode | groups)) {
+                                       return (FALSE);
+                               } else {
+                                       *theMode = strtol(--s, NULL, 8);
+                                       return (TRUE);
+                               }
+               }
+
+       NEXT_MODE:
+               if (((c = *s++) != '\0') && (c != ',')) {
+                       for (p=mode_chars ; *p ; p++) {
+                               if (*p == c) {
+                                       mode |= mode_set[(int)(p-mode_chars)];
+                                       goto NEXT_MODE;
+                               }
+                       }
+                       break;                          /* We're done so break out of loop.*/
+               }
+               switch (type) {
+                       case '=':
+                               andMode &= ~(groups); /* Now fall through. */
+                       case '+':
+                               orMode |= mode & groups;
+                               break;
+                       case '-':
+                               andMode &= ~(mode & groups);
+                               orMode &= ~(mode & groups);
+                               break;
+               }
+       } while (c == ',');
+
+       *theMode &= andMode;
+       *theMode |= orMode;
+
+       return TRUE;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/parse_number.c b/libbb/parse_number.c
new file mode 100644 (file)
index 0000000..755a357
--- /dev/null
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+unsigned long parse_number(const char *numstr,
+               const struct suffix_mult *suffixes)
+{
+       const struct suffix_mult *sm;
+       unsigned long int ret;
+       int len;
+       char *end;
+       
+       ret = strtoul(numstr, &end, 10);
+       if (numstr == end)
+               error_msg_and_die("invalid number `%s'", numstr);
+       while (end[0] != '\0') {
+               sm = suffixes;
+               while ( sm != 0 ) {
+                       if(sm->suffix) {
+                               len = strlen(sm->suffix);
+                               if (strncmp(sm->suffix, end, len) == 0) {
+                                       ret *= sm->mult;
+                                       end += len;
+                                       break;
+                               }
+                       sm++;
+                       
+                       } else
+                               sm = 0;
+               }
+               if (sm == 0)
+                       error_msg_and_die("invalid number `%s'", numstr);
+       }
+       return ret;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c
new file mode 100644 (file)
index 0000000..8c57b0d
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void perror_msg(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       vperror_msg(s, p);
+       va_end(p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c
new file mode 100644 (file)
index 0000000..9004925
--- /dev/null
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void perror_msg_and_die(const char *s, ...)
+{
+       va_list p;
+
+       va_start(p, s);
+       vperror_msg(s, p);
+       va_end(p);
+       exit(EXIT_FAILURE);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/print_file.c b/libbb/print_file.c
new file mode 100644 (file)
index 0000000..bfedc5e
--- /dev/null
@@ -0,0 +1,61 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+
+extern void print_file(FILE *file)
+{
+       fflush(stdout);
+       copyfd(fileno(file), fileno(stdout));
+       fclose(file);
+}
+
+extern int print_file_by_name(char *filename)
+{
+       struct stat statBuf;
+       int status = TRUE;
+
+       if(is_directory(filename, TRUE, &statBuf)==TRUE) {
+               error_msg("%s: Is directory", filename);
+               status = FALSE;
+       } else {
+               FILE *f = wfopen(filename, "r");
+               if(f!=NULL)
+                       print_file(f);
+               else
+                       status = FALSE;
+       }
+
+       return status;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c
new file mode 100644 (file)
index 0000000..67b0490
--- /dev/null
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) Manuel Nova III <mnovoa3@bellsouth.net>
+ * and Vladimir Oleynik <vodz@usa.net> 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * 
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include "libbb.h"
+
+
+
+char process_escape_sequence(const char **ptr)
+{
+       static const char charmap[] = {
+               'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
+               '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
+
+       const char *p;
+       const char *q;
+       int num_digits;
+       unsigned int n;
+       
+       n = 0;
+       q = *ptr;
+
+       for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) {
+               if ((*q < '0') || (*q > '7')) { /* not a digit? */
+                       break;
+               }
+               n = n * 8 + (*q++ - '0');
+       }
+
+       if (num_digits == 0) {  /* mnemonic escape sequence? */
+               for (p=charmap ; *p ; p++) {
+                       if (*p == *q) {
+                               q++;
+                               break;
+                       }
+               }
+               n = *(p+(sizeof(charmap)/2));
+       }
+
+          /* doesn't hurt to fall through to here from mnemonic case */
+       if (n > UCHAR_MAX) {    /* is octal code too big for a char? */
+               n /= 8;                 /* adjust value and */
+               --q;                            /* back up one char */
+       }
+
+       *ptr = q;
+       return (char) n;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/read_package_field.c b/libbb/read_package_field.c
new file mode 100644 (file)
index 0000000..ac5f801
--- /dev/null
@@ -0,0 +1,114 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "libbb.h"
+
+/*
+ * Gets the next package field from package_buffer, seperated into the field name
+ * and field value, it returns the int offset to the first character of the next field
+ */
+int read_package_field(const char *package_buffer, char **field_name, char **field_value)
+{
+       int offset_name_start = 0;
+       int offset_name_end = 0;
+       int offset_value_start = 0;
+       int offset_value_end = 0;
+       int offset = 0;
+       int next_offset;
+       int name_length;
+       int value_length;
+       int exit_flag = FALSE;
+
+       if (package_buffer == NULL) {
+               *field_name = NULL;
+               *field_value = NULL;
+               return(-1);
+       }
+       while (1) {
+               next_offset = offset + 1;
+               switch (package_buffer[offset]) {
+                       case('\0'):
+                               exit_flag = TRUE;
+                               break;
+                       case(':'):
+                               if (offset_name_end == 0) {
+                                       offset_name_end = offset;
+                                       offset_value_start = next_offset;
+                               }
+                               /* TODO: Name might still have trailing spaces if ':' isnt
+                                * immediately after name */
+                               break;
+                       case('\n'):
+                               /* TODO: The char next_offset may be out of bounds */
+                               if (package_buffer[next_offset] != ' ') {
+                                       exit_flag = TRUE;
+                                       break;
+                               }
+                       case('\t'):
+                       case(' '):
+                               /* increment the value start point if its a just filler */
+                               if (offset_name_start == offset) {
+                                       offset_name_start++;
+                               }
+                               if (offset_value_start == offset) {
+                                       offset_value_start++;
+                               }
+                               break;
+               }
+               if (exit_flag == TRUE) {
+                       /* Check that the names are valid */
+                       offset_value_end = offset;
+                       name_length = offset_name_end - offset_name_start;
+                       value_length = offset_value_end - offset_value_start;
+                       if (name_length == 0) {
+                               break;
+                       }
+                       if ((name_length > 0) && (value_length > 0)) {
+                               break;
+                       }
+
+                       /* If not valid, start fresh with next field */
+                       exit_flag = FALSE;
+                       offset_name_start = offset + 1;
+                       offset_name_end = 0;
+                       offset_value_start = offset + 1;
+                       offset_value_end = offset + 1;
+                       offset++;
+               }
+               offset++;
+       }
+       if (name_length == 0) {
+               *field_name = NULL;
+       } else {
+               *field_name = xstrndup(&package_buffer[offset_name_start], name_length);
+       }
+       if (value_length > 0) {
+               *field_value = xstrndup(&package_buffer[offset_value_start], value_length);
+       } else {
+               *field_value = NULL;
+       }
+       return(next_offset);
+}
+
diff --git a/libbb/real_loop.h b/libbb/real_loop.h
new file mode 100644 (file)
index 0000000..1bd7fa8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
+ * permitted under the GNU Public License.
+ */
+
+#define LO_NAME_SIZE   64
+#define LO_KEY_SIZE    32
+       
+struct loop_info {
+       int             lo_number;      /* ioctl r/o */
+       dev_t           lo_device;      /* ioctl r/o */
+       unsigned long   lo_inode;       /* ioctl r/o */
+       dev_t           lo_rdevice;     /* ioctl r/o */
+       int             lo_offset;
+       int             lo_encrypt_type;
+       int             lo_encrypt_key_size;    /* ioctl w/o */
+       int             lo_flags;       /* ioctl r/o */
+       char            lo_name[LO_NAME_SIZE];
+       unsigned char   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+       unsigned long   lo_init[2];
+       char            reserved[4];
+};
+
+#define LO_CRYPT_NONE  0
+#define LO_CRYPT_XOR   1
+#define LO_CRYPT_DES   2
+#define LO_CRYPT_IDEA  3
+#define MAX_LO_CRYPT   4
+
+#define LOOP_SET_FD    0x4C00
+#define LOOP_CLR_FD    0x4C01
+#define LOOP_SET_STATUS        0x4C02
+#define LOOP_GET_STATUS        0x4C03
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
new file mode 100644 (file)
index 0000000..e87ab98
--- /dev/null
@@ -0,0 +1,144 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <stdlib.h>    /* free() */
+#include "libbb.h"
+
+#undef DEBUG_RECURS_ACTION
+
+
+/*
+ * Walk down all the directories under the specified 
+ * location, and do something (something specified
+ * by the fileAction and dirAction function pointers).
+ *
+ * Unfortunately, while nftw(3) could replace this and reduce 
+ * code size a bit, nftw() wasn't supported before GNU libc 2.1, 
+ * and so isn't sufficiently portable to take over since glibc2.1
+ * is so stinking huge.
+ */
+int recursive_action(const char *fileName,
+                                       int recurse, int followLinks, int depthFirst,
+                                       int (*fileAction) (const char *fileName,
+                                                                          struct stat * statbuf,
+                                                                          void* userData),
+                                       int (*dirAction) (const char *fileName,
+                                                                         struct stat * statbuf,
+                                                                         void* userData),
+                                       void* userData)
+{
+       int status;
+       struct stat statbuf;
+       struct dirent *next;
+
+       if (followLinks == TRUE)
+               status = stat(fileName, &statbuf);
+       else
+               status = lstat(fileName, &statbuf);
+
+       if (status < 0) {
+#ifdef DEBUG_RECURS_ACTION
+               fprintf(stderr,
+                               "status=%d followLinks=%d TRUE=%d\n",
+                               status, followLinks, TRUE);
+#endif
+               perror_msg("%s", fileName);
+               return FALSE;
+       }
+
+       if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
+               if (fileAction == NULL)
+                       return TRUE;
+               else
+                       return fileAction(fileName, &statbuf, userData);
+       }
+
+       if (recurse == FALSE) {
+               if (S_ISDIR(statbuf.st_mode)) {
+                       if (dirAction != NULL)
+                               return (dirAction(fileName, &statbuf, userData));
+                       else
+                               return TRUE;
+               }
+       }
+
+       if (S_ISDIR(statbuf.st_mode)) {
+               DIR *dir;
+
+               if (dirAction != NULL && depthFirst == FALSE) {
+                       status = dirAction(fileName, &statbuf, userData);
+                       if (status == FALSE) {
+                               perror_msg("%s", fileName);
+                               return FALSE;
+                       } else if (status == SKIP)
+                               return TRUE;
+               }
+               dir = opendir(fileName);
+               if (!dir) {
+                       perror_msg("%s", fileName);
+                       return FALSE;
+               }
+               status = TRUE;
+               while ((next = readdir(dir)) != NULL) {
+                       char *nextFile;
+
+                       if ((strcmp(next->d_name, "..") == 0)
+                                       || (strcmp(next->d_name, ".") == 0)) {
+                               continue;
+                       }
+                       nextFile = concat_path_file(fileName, next->d_name);
+                       if (recursive_action(nextFile, TRUE, followLinks, depthFirst,
+                                               fileAction, dirAction, userData) == FALSE) {
+                               status = FALSE;
+                       }
+                       free(nextFile);
+               }
+               closedir(dir);
+               if (dirAction != NULL && depthFirst == TRUE) {
+                       if (dirAction(fileName, &statbuf, userData) == FALSE) {
+                               perror_msg("%s", fileName);
+                               return FALSE;
+                       }
+               }
+               if (status == FALSE)
+                       return FALSE;
+       } else {
+               if (fileAction == NULL)
+                       return TRUE;
+               else
+                       return fileAction(fileName, &statbuf, userData);
+       }
+       return TRUE;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/remove_file.c b/libbb/remove_file.c
new file mode 100644 (file)
index 0000000..988b091
--- /dev/null
@@ -0,0 +1,126 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini remove_file implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include "libbb.h"
+
+extern int remove_file(const char *path, int flags)
+{
+       struct stat path_stat;
+       int path_exists = 1;
+
+       if (lstat(path, &path_stat) < 0) {
+               if (errno != ENOENT) {
+                       perror_msg("unable to stat `%s'", path);
+                       return -1;
+               }
+
+               path_exists = 0;
+       }
+
+       if (!path_exists) {
+               if (!(flags & FILEUTILS_FORCE)) {
+                       perror_msg("cannot remove `%s'", path);
+                       return -1;
+               }
+               return 0;
+       }
+
+       if (S_ISDIR(path_stat.st_mode)) {
+               DIR *dp;
+               struct dirent *d;
+               int status = 0;
+
+               if (!(flags & FILEUTILS_RECUR)) {
+                       error_msg("%s: is a directory", path);
+                       return -1;
+               }
+
+               if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
+                                       isatty(0)) ||
+                               (flags & FILEUTILS_INTERACTIVE)) {
+                       fprintf(stderr, "%s: descend into directory `%s'? ", applet_name,
+                                       path);
+                       if (!ask_confirmation())
+                               return 0;
+               }
+
+               if ((dp = opendir(path)) == NULL) {
+                       perror_msg("unable to open `%s'", path);
+                       return -1;
+               }
+
+               while ((d = readdir(dp)) != NULL) {
+                       char *new_path;
+
+                       if (strcmp(d->d_name, ".") == 0 ||
+                                       strcmp(d->d_name, "..") == 0)
+                               continue;
+
+                       new_path = concat_path_file(path, d->d_name);
+                       if (remove_file(new_path, flags) < 0)
+                               status = -1;
+                       free(new_path);
+               }
+
+               if (closedir(dp) < 0) {
+                       perror_msg("unable to close `%s'", path);
+                       return -1;
+               }
+
+               if (flags & FILEUTILS_INTERACTIVE) {
+                       fprintf(stderr, "%s: remove directory `%s'? ", applet_name, path);
+                       if (!ask_confirmation())
+                               return status;
+               }
+
+               if (rmdir(path) < 0) {
+                       perror_msg("unable to remove `%s'", path);
+                       return -1;
+               }
+
+               return status;
+       } else {
+               if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
+                                       !S_ISLNK(path_stat.st_mode) &&
+                                       isatty(0)) ||
+                               (flags & FILEUTILS_INTERACTIVE)) {
+                       fprintf(stderr, "%s: remove `%s'? ", applet_name, path);
+                       if (!ask_confirmation())
+                               return 0;
+               }
+
+               if (unlink(path) < 0) {
+                       perror_msg("unable to remove `%s'", path);
+                       return -1;
+               }
+
+               return 0;
+       }
+}
diff --git a/libbb/safe_read.c b/libbb/safe_read.c
new file mode 100644 (file)
index 0000000..67f3268
--- /dev/null
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+ssize_t safe_read(int fd, void *buf, size_t count)
+{
+       ssize_t n;
+
+       do {
+               n = read(fd, buf, count);
+       } while (n < 0 && errno == EINTR);
+
+       return n;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/safe_strncpy.c b/libbb/safe_strncpy.c
new file mode 100644 (file)
index 0000000..0c5cf12
--- /dev/null
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+
+
+/* Like strncpy but make sure the resulting string is always 0 terminated. */  
+extern char * safe_strncpy(char *dst, const char *src, size_t size)
+{   
+       dst[size-1] = '\0';
+       return strncpy(dst, src, size-1);   
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/safe_write.c b/libbb/safe_write.c
new file mode 100644 (file)
index 0000000..0ac6c2d
--- /dev/null
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+ssize_t safe_write(int fd, const void *buf, size_t count)
+{
+       ssize_t n;
+
+       do {
+               n = write(fd, buf, count);
+       } while (n < 0 && errno == EINTR);
+
+       return n;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c
new file mode 100644 (file)
index 0000000..7b2a1ca
--- /dev/null
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * simplify_path implementation for busybox
+ *
+ * Copyright (C) 2001  Manuel Novoa III  <mjn3@opensource.lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+
+#include "libbb.h"
+
+char *simplify_path(const char *path)
+{
+       char *s, *start, *p;
+
+       if (path[0] == '/')
+               start = xstrdup(path);
+       else {
+               s = xgetcwd(NULL);
+               start = concat_path_file(s, path);
+               free(s);
+       }
+       p = s = start;
+
+       do {
+               if (*p == '/') {
+                       if (*s == '/') {        /* skip duplicate (or initial) slash */
+                               continue;
+                       } else if (*s == '.') {
+                               if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
+                                       continue;
+                               } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
+                                       ++s;
+                                       if (p > start) {
+                                               while (*--p != '/');    /* omit previous dir */
+                                       }
+                                       continue;
+                               }
+                       }
+               }
+               *++p = *s;
+       } while (*++s);
+
+       if ((p == start) || (*p != '/')) {      /* not a trailing slash */
+               ++p;                                    /* so keep last character */
+       }
+       *p = 0;
+
+       return start;
+}
diff --git a/libbb/syscalls.c b/libbb/syscalls.c
new file mode 100644 (file)
index 0000000..7658688
--- /dev/null
@@ -0,0 +1,135 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * some system calls possibly missing from libc
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+   _syscall* defined.  */
+#define __LIBRARY__
+#include <sys/syscall.h>
+#if __GNU_LIBRARY__ < 5
+/* This is needed for libc5 */
+#include <asm/unistd.h>
+#endif
+#include "libbb.h"
+
+#if __GNU_LIBRARY__ < 5
+_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf);
+#else
+int sysfs( int option, unsigned int fs_index, char * buf)
+{
+       return(syscall(__NR_sysfs, option, fs_index, buf));
+}
+#endif
+
+#ifndef __NR_pivot_root
+#warning This kernel does not support the pivot_root syscall
+#warning -> The pivot_root system call is being stubbed out...
+int pivot_root(const char * new_root,const char * put_old)
+{
+       /* BusyBox was compiled against a kernel that did not support
+        *  the pivot_root system call.  To make this application work,
+        *  you will need to recompile with a kernel supporting the
+        *  pivot_root system call.
+        */
+       fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
+       fprintf(stderr, "with a kernel supporting the pivot_root system call. -Erik\n\n");
+       errno=ENOSYS;
+       return -1;
+}
+#else
+#  if __GNU_LIBRARY__ < 5
+    _syscall2(int,pivot_root,const char *,new_root,const char *,put_old);
+#  else
+       int pivot_root(const char * new_root,const char * put_old)
+       {
+               return(syscall(__NR_pivot_root, new_root, put_old));
+       }
+#  endif
+#endif
+
+
+
+/* These syscalls are not included in ancient glibc versions */
+#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
+
+
+#if __GNU_LIBRARY__ < 5
+/* These syscalls are not included as part of libc5 */
+_syscall2(int, bdflush, int, func, int, data);
+#else
+int bdflush(int func, int data)
+{
+    return(syscall(__NR_bdflush, func, data));
+}
+#endif
+
+#ifndef __alpha__
+#if __GNU_LIBRARY__ < 5
+# define __NR_klogctl __NR_syslog
+_syscall3(int, klogctl, int, type, char *, b, int, len);
+#else
+int klogctl(int type, char *b, int len)
+{
+    return(syscall(__NR_klogctl, type, b, len));
+}
+#endif
+#endif
+
+
+int umount2(const char * special_file, int flags)
+{
+#ifndef __NR_pivot_root
+#warning This kernel does not support the umount2 syscall
+#warning -> The umount2 system call is being stubbed out...
+    /* BusyBox was compiled against a kernel that did not support
+     *  the umount2 system call.  To make this application work,
+     *  you will need to recompile with a kernel supporting the
+     *  umount2 system call.
+     */
+    bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+           "BusyBox with a kernel supporting the umount2 system call.\n");
+    errno=ENOSYS;
+    return -1;
+#else
+#  if __GNU_LIBRARY__ < 5
+               _syscall2(int, umount2, const char *, special_file, int, flags);
+#  else
+               return(syscall(__NR_umount2, special_file, flags));
+#  endif
+#endif
+}
+
+
+#endif /* __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) */
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/syslog_msg_with_name.c b/libbb/syslog_msg_with_name.c
new file mode 100644 (file)
index 0000000..6474da4
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <sys/syslog.h>
+#include "libbb.h"
+
+void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg)
+{
+       openlog(name, 0, facility);
+       syslog(pri, "%s", msg);
+       closelog();
+}
+
+void syslog_msg(int facility, int pri, const char *msg)
+{
+       syslog_msg_with_name(applet_name, facility, pri, msg);
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/time_string.c b/libbb/time_string.c
new file mode 100644 (file)
index 0000000..d103a02
--- /dev/null
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+#include "libbb.h"
+
+
+/*
+ * Return the standard ls-like time string from a time_t
+ * This is static and so is overwritten on each call.
+ */
+const char *time_string(time_t timeVal)
+{
+       time_t now;
+       char *str;
+       static char buf[26];
+
+       time(&now);
+
+       str = ctime(&timeVal);
+
+       strcpy(buf, &str[4]);
+       buf[12] = '\0';
+
+       if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
+               strcpy(&buf[7], &str[20]);
+               buf[11] = '\0';
+       }
+
+       return buf;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/trim.c b/libbb/trim.c
new file mode 100644 (file)
index 0000000..cb673ca
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+void trim(char *s)
+{
+       int len = strlen(s);
+
+       /* trim trailing whitespace */
+       while ( len > 0 && isspace(s[len-1]))
+               s[--len]='\0';
+
+       /* trim leading whitespace */
+       memmove(s, &s[strspn(s, " \n\r\t\v")], len);
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
new file mode 100644 (file)
index 0000000..aee1db0
--- /dev/null
@@ -0,0 +1,189 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct signal_name {
+       const char *name;
+       int number;
+};
+
+static const struct signal_name signames[] = {
+       /* POSIX signals */
+       { "EXIT",       0 },            /* 0 */
+       { "HUP",        SIGHUP },       /* 1 */
+       { "INT",        SIGINT },       /* 2 */
+       { "QUIT",       SIGQUIT },      /* 3 */
+       { "ILL",        SIGILL },       /* 4 */
+       { "ABRT",       SIGABRT },      /* 6 */
+       { "FPE",        SIGFPE },       /* 8 */
+       { "KILL",       SIGKILL },      /* 9 */
+       { "SEGV",       SIGSEGV },      /* 11 */
+       { "PIPE",       SIGPIPE },      /* 13 */
+       { "ALRM",       SIGALRM },      /* 14 */
+       { "TERM",       SIGTERM },      /* 15 */
+       { "USR1",       SIGUSR1 },      /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
+       { "USR2",       SIGUSR2 },      /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
+       { "CHLD",       SIGCHLD },      /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
+       { "CONT",       SIGCONT },      /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
+       { "STOP",       SIGSTOP },      /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
+       { "TSTP",       SIGTSTP },      /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
+       { "TTIN",       SIGTTIN },      /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
+       { "TTOU",       SIGTTOU },      /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
+       /* Miscellaneous other signals */
+#ifdef SIGTRAP
+       { "TRAP",       SIGTRAP },      /* 5 */
+#endif
+#ifdef SIGIOT
+       { "IOT",        SIGIOT },       /* 6, same as SIGABRT */
+#endif
+#ifdef SIGEMT
+       { "EMT",        SIGEMT },       /* 7 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGBUS
+       { "BUS",        SIGBUS },       /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGSYS
+       { "SYS",        SIGSYS },       /* 12 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGSTKFLT
+       { "STKFLT",     SIGSTKFLT },    /* 16 (arm,i386,m68k,ppc) */
+#endif
+#ifdef SIGURG
+       { "URG",        SIGURG },       /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
+#endif
+#ifdef SIGIO
+       { "IO",         SIGIO },        /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
+#endif
+#ifdef SIGPOLL
+       { "POLL",       SIGPOLL },      /* same as SIGIO */
+#endif
+#ifdef SIGCLD
+       { "CLD",        SIGCLD },       /* same as SIGCHLD (mips) */
+#endif
+#ifdef SIGXCPU
+       { "XCPU",       SIGXCPU },      /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
+#endif
+#ifdef SIGXFSZ
+       { "XFSZ",       SIGXFSZ },      /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
+#endif
+#ifdef SIGVTALRM
+       { "VTALRM",     SIGVTALRM },    /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
+#endif
+#ifdef SIGPROF
+       { "PROF",       SIGPROF },      /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
+#endif
+#ifdef SIGPWR
+       { "PWR",        SIGPWR },       /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
+#endif
+#ifdef SIGINFO
+       { "INFO",       SIGINFO },      /* 29 (alpha) */
+#endif
+#ifdef SIGLOST
+       { "LOST",       SIGLOST },      /* 29 (arm,i386,m68k,ppc,sparc*) */
+#endif
+#ifdef SIGWINCH
+       { "WINCH",      SIGWINCH },     /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
+#endif
+#ifdef SIGUNUSED
+       { "UNUSED",     SIGUNUSED },    /* 31 (arm,i386,m68k,ppc) */
+#endif
+       {0, 0}
+};
+
+/*
+       if str_sig == NULL returned signal name [*signo],
+       if str_sig != NULL - set *signo from signal_name,
+               findings with digit number or with or without SIG-prefix name
+
+       if startnum=0 flag for support finding zero signal,
+               but str_sig="0" always found, (hmm - standart or realize?)
+       if startnum<0 returned reverse signal_number  <-> signal_name
+       if found error - returned NULL
+
+*/
+
+const char *
+u_signal_names(const char *str_sig, int *signo, int startnum)
+{
+       static char retstr[16];
+       const struct signal_name *s = signames;
+       static const char prefix[] = "SIG";
+       const char *sptr;
+
+       if(startnum)
+               s++;
+       if(str_sig==NULL) {
+               while (s->name != 0) {
+                       if(s->number == *signo)
+                               break;
+                       s++;
+               }
+       } else {
+               if (isdigit(((unsigned char)*str_sig))) {
+                       char *endp;
+                       long int sn = strtol(str_sig, &endp, 10);
+                       /* test correct and overflow */
+                       if(*endp == 0 && sn >= 0 && sn < NSIG) {
+                               *signo = (int)sn;
+                               /* test for unnamed */
+                               sptr = u_signal_names(0, signo, 0);
+                               if(sptr==NULL)
+                                       return NULL;
+                               if(sn!=0)
+                                       sptr += 3;
+                               return sptr;
+                       }
+               } else {
+                       sptr = str_sig;
+                       while (s->name != 0) {
+                               if (strcasecmp(s->name, sptr) == 0) {
+                                       *signo = s->number;
+                                       if(startnum<0) {
+                                               sprintf(retstr, "%d", *signo);
+                                               return retstr;
+                                       }
+                                       break;
+                               }
+                               if(s!=signames && sptr == str_sig &&
+                                               strncasecmp(sptr, prefix, 3) == 0) {
+                                       sptr += 3;      /* strlen(prefix) */
+                                       continue;
+                               }
+                               sptr = str_sig;
+                               s++;
+                       }
+               }
+       }
+       if(s->name==0)
+               return NULL;
+       if(s!=signames)
+               strcpy(retstr, prefix);
+        else
+               retstr[0] = 0;
+       return strcat(retstr, s->name);
+}
diff --git a/libbb/unarchive.c b/libbb/unarchive.c
new file mode 100644 (file)
index 0000000..cb35bc4
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ *  Copyright (C) 2000 by Glenn McGrath
+ *  Copyright (C) 2001 by Laurence Anderson
+ *     
+ *  Based on previous work by busybox developers and others.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include "libbb.h"
+
+extern void seek_sub_file(FILE *src_stream, const int count);
+extern char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
+ const int function, const char *prefix);
+
+
+#ifdef L_archive_offset
+off_t archive_offset;
+#else
+extern off_t archive_offset;
+#endif 
+
+#ifdef L_seek_sub_file
+void seek_sub_file(FILE *src_stream, const int count)
+{
+       int i;
+       /* Try to fseek as faster */
+       archive_offset += count;
+       if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) {
+       for (i = 0; i < count; i++) {
+               fgetc(src_stream);
+               }
+       }
+       return;
+}
+#endif 
+
+
+
+#ifdef L_extract_archive
+/* Extract the data postioned at src_stream to either filesystem, stdout or 
+ * buffer depending on the value of 'function' which is defined in libbb.h 
+ *
+ * prefix doesnt have to be just a directory, it may prefix the filename as well.
+ *
+ * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath 
+ * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have 
+ * 'dpkg.' as their prefix
+ *
+ * For this reason if prefix does point to a dir then it must end with a
+ * trailing '/' or else the last dir will be assumed to be the file prefix 
+ */
+char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
+ const int function, const char *prefix)
+{
+       FILE *dst_stream = NULL;
+       char *full_name = NULL;
+       char *buffer = NULL;
+       struct utimbuf t;
+
+       /* prefix doesnt have to be a proper path it may prepend 
+        * the filename as well */
+       if (prefix != NULL) {
+               /* strip leading '/' in filename to extract as prefix may not be dir */
+               /* Cant use concat_path_file here as prefix might not be a directory */
+               char *path = file_entry->name;
+               if (strncmp("./", path, 2) == 0) {
+                       path += 2;
+                       if (strlen(path) == 0) {
+                               return(NULL);
+                       }
+               }
+               full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
+               strcpy(full_name, prefix);
+               strcat(full_name, path);
+       } else {
+               full_name = file_entry->name;
+       }
+       if (function & extract_to_stdout) {
+               if (S_ISREG(file_entry->mode)) {
+                       copy_file_chunk(src_stream, out_stream, file_entry->size);                      
+                       archive_offset += file_entry->size;
+               }
+       }
+       else if (function & extract_one_to_buffer) { 
+               if (S_ISREG(file_entry->mode)) {
+                       buffer = (char *) xmalloc(file_entry->size + 1);
+                       fread(buffer, 1, file_entry->size, src_stream);
+                       buffer[file_entry->size] = '\0';
+                       archive_offset += file_entry->size;
+                       return(buffer);
+               }
+       }
+       else if (function & extract_all_to_fs) {
+               struct stat oldfile;
+               int stat_res;
+               stat_res = lstat (full_name, &oldfile);
+               if (stat_res == 0) { /* The file already exists */
+                       if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
+                               if (!S_ISDIR(oldfile.st_mode)) {
+                                       unlink(full_name); /* Directories might not be empty etc */
+                               }
+                       } else {
+                               if ((function & extract_quiet) != extract_quiet) {
+                                       error_msg("%s not created: newer or same age file exists", file_entry->name);
+                               }
+                               seek_sub_file(src_stream, file_entry->size);
+                               return (NULL);
+                       }
+               }
+               if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */
+                       char *buf, *parent;
+                       buf = xstrdup(full_name);
+                       parent = dirname(buf);
+                       if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) {
+                               if ((function & extract_quiet) != extract_quiet) {
+                                       error_msg("couldn't create leading directories");
+                               }
+                       }
+                       free (buf);
+               }
+               switch(file_entry->mode & S_IFMT) {
+                       case S_IFREG:
+                               if (file_entry->link_name) { /* Found a cpio hard link */
+                                       if (link(file_entry->link_name, full_name) != 0) {
+                                               if ((function & extract_quiet) != extract_quiet) {
+                                                       perror_msg("Cannot link from %s to '%s'",
+                                                               file_entry->name, file_entry->link_name);
+                                               }
+                                       }
+                               } else {
+                                       if ((dst_stream = wfopen(full_name, "w")) == NULL) {
+                                               seek_sub_file(src_stream, file_entry->size);
+                                               return NULL;
+                                       }
+                                       archive_offset += file_entry->size;
+                                       copy_file_chunk(src_stream, dst_stream, file_entry->size);                      
+                                       fclose(dst_stream);
+                               }
+                               break;
+                       case S_IFDIR:
+                               if (stat_res != 0) {
+                                       if (mkdir(full_name, file_entry->mode) < 0) {
+                                               if ((function & extract_quiet) != extract_quiet) {
+                                                       perror_msg("extract_archive: %s", full_name);
+                                               }
+                                       }
+                               }
+                               break;
+                       case S_IFLNK:
+                               if (symlink(file_entry->link_name, full_name) < 0) {
+                                       if ((function & extract_quiet) != extract_quiet) {
+                                               perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name);
+                                       }
+                                       return NULL;
+                               }
+                               break;
+                       case S_IFSOCK:
+                       case S_IFBLK:
+                       case S_IFCHR:
+                       case S_IFIFO:
+                               if (mknod(full_name, file_entry->mode, file_entry->device) == -1) {
+                                       if ((function & extract_quiet) != extract_quiet) {
+                                               perror_msg("Cannot create node %s", file_entry->name);
+                                       }
+                                       return NULL;
+                               }
+                               break;
+               }
+
+               /* Changing a symlink's properties normally changes the properties of the 
+                * file pointed to, so dont try and change the date or mode, lchown does
+                * does the right thing, but isnt available in older versions of libc */
+               if (S_ISLNK(file_entry->mode)) {
+#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1)
+                       lchown(full_name, file_entry->uid, file_entry->gid);
+#endif
+               } else {
+                       if (function & extract_preserve_date) {
+                               t.actime = file_entry->mtime;
+                               t.modtime = file_entry->mtime;
+                               utime(full_name, &t);
+                       }
+                       chmod(full_name, file_entry->mode);
+                       chown(full_name, file_entry->uid, file_entry->gid);
+               }
+       } else {
+               /* If we arent extracting data we have to skip it, 
+                * if data size is 0 then then just do it anyway
+                * (saves testing for it) */
+               seek_sub_file(src_stream, file_entry->size);
+       }
+
+       /* extract_list and extract_verbose_list can be used in conjunction
+        * with one of the above four extraction functions, so do this seperately */
+       if (function & extract_verbose_list) {
+               fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), 
+                       file_entry->uid, file_entry->gid,
+                       (int) file_entry->size, time_string(file_entry->mtime));
+       }
+       if ((function & extract_list) || (function & extract_verbose_list)){
+               /* fputs doesnt add a trailing \n, so use fprintf */
+               fprintf(out_stream, "%s\n", file_entry->name);
+       }
+
+       free(full_name);
+
+       return(NULL); /* Maybe we should say if failed */
+}
+#endif
+
+#ifdef L_unarchive
+char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *),
+       const int extract_function, const char *prefix, char **extract_names)
+{
+       file_header_t *file_entry;
+       int extract_flag;
+       int i;
+       char *buffer = NULL;
+
+       archive_offset = 0;
+       while ((file_entry = get_headers(src_stream)) != NULL) {
+               extract_flag = TRUE;
+               if (extract_names != NULL) {
+                       int found_flag = FALSE;
+                       for(i = 0; extract_names[i] != 0; i++) {
+                               if (strcmp(extract_names[i], file_entry->name) == 0) {
+                                       found_flag = TRUE;
+                                       break;
+                               }
+                       }
+                       if (extract_function & extract_exclude_list) {
+                               if (found_flag == TRUE) {
+                                       extract_flag = FALSE;
+                               }
+                       } else {
+                               /* If its not found in the include list dont extract it */
+                               if (found_flag == FALSE) {
+                                       extract_flag = FALSE;
+                               }
+                       }
+
+               }
+
+               if (extract_flag == TRUE) {
+                       buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix);
+               } else {
+                       /* seek past the data entry */
+                       seek_sub_file(src_stream, file_entry->size);
+               }
+               free(file_entry->name); /* may be null, but doesn't matter */
+               free(file_entry->link_name);
+               free(file_entry);
+       }
+       return(buffer);
+}
+#endif
+
+#ifdef L_get_header_ar
+file_header_t *get_header_ar(FILE *src_stream)
+{
+       file_header_t *typed;
+       union {
+               char raw[60];
+               struct {
+                       char name[16];
+                       char date[12];
+                       char uid[6];
+                       char gid[6];
+                       char mode[8];
+                       char size[10];
+                       char magic[2];
+               } formated;
+       } ar;
+       static char *ar_long_names;
+
+       if (fread(ar.raw, 1, 60, src_stream) != 60) {
+               return(NULL);
+       }
+       archive_offset += 60;
+       /* align the headers based on the header magic */
+       if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
+               /* some version of ar, have an extra '\n' after each data entry,
+                * this puts the next header out by 1 */
+               if (ar.formated.magic[1] != '`') {
+                       error_msg("Invalid magic");
+                       return(NULL);
+               }
+               /* read the next char out of what would be the data section,
+                * if its a '\n' then it is a valid header offset by 1*/
+               archive_offset++;
+               if (fgetc(src_stream) != '\n') {
+                       error_msg("Invalid magic");
+                       return(NULL);
+               }
+               /* fix up the header, we started reading 1 byte too early */
+               /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
+               memmove(ar.raw, &ar.raw[1], 59);
+       }
+               
+       typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
+
+       typed->size = (size_t) atoi(ar.formated.size);
+       /* long filenames have '/' as the first character */
+       if (ar.formated.name[0] == '/') {
+               if (ar.formated.name[1] == '/') {
+                       /* If the second char is a '/' then this entries data section
+                        * stores long filename for multiple entries, they are stored
+                        * in static variable long_names for use in future entries */
+                       ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
+                       fread(ar_long_names, 1, typed->size, src_stream);
+                       archive_offset += typed->size;
+                       /* This ar entries data section only contained filenames for other records
+                        * they are stored in the static ar_long_names for future reference */
+                       return (get_header_ar(src_stream)); /* Return next header */
+               } else if (ar.formated.name[1] == ' ') {
+                       /* This is the index of symbols in the file for compilers */
+                       seek_sub_file(src_stream, typed->size);
+                       return (get_header_ar(src_stream)); /* Return next header */
+               } else {
+                       /* The number after the '/' indicates the offset in the ar data section
+                       (saved in variable long_name) that conatains the real filename */
+                       if (!ar_long_names) {
+                               error_msg("Cannot resolve long file name");
+                               return (NULL);
+                       }
+                       typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
+               }
+       } else {
+               /* short filenames */
+               typed->name = xcalloc(1, 16);
+               strncpy(typed->name, ar.formated.name, 16);
+       }
+       typed->name[strcspn(typed->name, " /")]='\0';
+
+       /* convert the rest of the now valid char header to its typed struct */ 
+       parse_mode(ar.formated.mode, &typed->mode);
+       typed->mtime = atoi(ar.formated.date);
+       typed->uid = atoi(ar.formated.uid);
+       typed->gid = atoi(ar.formated.gid);
+
+       return(typed);
+}
+#endif
+
+#ifdef L_get_header_cpio
+struct hardlinks {
+       file_header_t *entry;
+       int inode;
+       struct hardlinks *next;
+};
+
+file_header_t *get_header_cpio(FILE *src_stream)
+{
+       file_header_t *cpio_entry = NULL;
+       char cpio_header[110];
+       int namesize;
+       char dummy[16];
+       int major, minor, nlink, inode;
+       static struct hardlinks *saved_hardlinks = NULL;
+       static int pending_hardlinks = 0;
+
+       if (pending_hardlinks) { /* Deal with any pending hardlinks */
+               struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
+               while (tmp) {
+                       if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
+                               cpio_entry = tmp->entry;
+                               if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */
+                               else saved_hardlinks = tmp->next;
+                               free(tmp);
+                               return (cpio_entry);
+                       }
+                       oldtmp = tmp;
+                       tmp = tmp->next;
+               }
+               pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
+       }
+  
+       /* There can be padding before archive header */
+       seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
+       if (fread(cpio_header, 1, 110, src_stream) == 110) {
+               archive_offset += 110;
+               if (strncmp(cpio_header, "07070", 5) != 0) {
+                       error_msg("Unsupported format or invalid magic");
+                       return(NULL);
+               }
+               switch (cpio_header[5]) {
+                       case '2': /* "crc" header format */
+                               /* Doesnt do the crc check yet */
+                       case '1': /* "newc" header format */
+                               cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t));
+                               sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
+                                       dummy, &inode, (unsigned int*)&cpio_entry->mode, 
+                                       (unsigned int*)&cpio_entry->uid, (unsigned int*)&cpio_entry->gid,
+                                       &nlink, &cpio_entry->mtime, (unsigned long*)&cpio_entry->size,
+                                       dummy, &major, &minor, &namesize, dummy);
+
+                               cpio_entry->name = (char *) xcalloc(1, namesize);
+                               fread(cpio_entry->name, 1, namesize, src_stream); /* Read in filename */
+                               archive_offset += namesize;
+                               /* Skip padding before file contents */
+                               seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
+                               if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) {
+                                       printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */
+                                       if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
+                                               struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
+                                               while (tmp) {
+                                                       error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
+                                                       oldtmp = tmp;
+                                                       tmp = tmp->next;
+                                                       free (oldtmp->entry->name);
+                                                       free (oldtmp->entry);
+                                                       free (oldtmp);
+                                               }
+                                               saved_hardlinks = NULL;
+                                               pending_hardlinks = 0;
+                                       }
+                                       return(NULL);
+                               }
+
+                               if (S_ISLNK(cpio_entry->mode)) {
+                                       cpio_entry->link_name = (char *) xcalloc(1, cpio_entry->size + 1);
+                                       fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream);
+                                       archive_offset += cpio_entry->size;
+                                       cpio_entry->size = 0; /* Stop possiable seeks in future */
+                               }
+                               if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) {
+                                       if (cpio_entry->size == 0) { /* Put file on a linked list for later */
+                                               struct hardlinks *new = xmalloc(sizeof(struct hardlinks));
+                                               new->next = saved_hardlinks;
+                                               new->inode = inode;
+                                               new->entry = cpio_entry;
+                                               saved_hardlinks = new;
+                                       return(get_header_cpio(src_stream)); /* Recurse to next file */
+                                       } else { /* Found the file with data in */
+                                               struct hardlinks *tmp = saved_hardlinks;
+                                               pending_hardlinks = 1;
+                                               while (tmp) {
+                                                       if (tmp->inode == inode) {
+                                                               tmp->entry->link_name = xstrdup(cpio_entry->name);
+                                                               nlink--;
+                                                       }
+                                                       tmp = tmp->next;
+                                               }
+                                               if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
+                                       }
+                               }
+                               cpio_entry->device = (major << 8) | minor;
+                               break;
+                       default:
+                               error_msg("Unsupported format");
+                               return(NULL);
+               }
+               if (ferror(src_stream) || feof(src_stream)) {
+                       perror_msg("Stream error");
+                       return(NULL);
+               }
+       }
+       return(cpio_entry);
+}
+#endif
+
+#ifdef L_get_header_tar
+file_header_t *get_header_tar(FILE *tar_stream)
+{
+       union {
+               unsigned char raw[512];
+               struct {
+                       char name[100];         /*   0-99 */
+                       char mode[8];           /* 100-107 */
+                       char uid[8];            /* 108-115 */
+                       char gid[8];            /* 116-123 */
+                       char size[12];          /* 124-135 */
+                       char mtime[12];         /* 136-147 */
+                       char chksum[8];         /* 148-155 */
+                       char typeflag;          /* 156-156 */
+                       char linkname[100];     /* 157-256 */
+                       char magic[6];          /* 257-262 */
+                       char version[2];        /* 263-264 */
+                       char uname[32];         /* 265-296 */
+                       char gname[32];         /* 297-328 */
+                       char devmajor[8];       /* 329-336 */
+                       char devminor[8];       /* 337-344 */
+                       char prefix[155];       /* 345-499 */
+                       char padding[12];       /* 500-512 */
+               } formated;
+       } tar;
+       file_header_t *tar_entry = NULL;
+       long i;
+       long sum = 0;
+
+       if (archive_offset % 512 != 0) {
+               seek_sub_file(tar_stream, 512 - (archive_offset % 512));
+       }
+
+       if (fread(tar.raw, 1, 512, tar_stream) != 512) {
+               /* Unfortunatly its common for tar files to have all sorts of
+                * trailing garbage, fail silently */
+//             error_msg("Couldnt read header");
+               return(NULL);
+       }
+       archive_offset += 512;
+
+       /* Check header has valid magic, unfortunately some tar files
+        * have empty (0'ed) tar entries at the end, which will
+        * cause this to fail, so fail silently for now
+        */
+       if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
+               return(NULL);
+       }
+
+       /* Do checksum on headers */
+       for (i =  0; i < 148 ; i++) {
+               sum += tar.raw[i];
+       }
+       sum += ' ' * 8;
+       for (i =  156; i < 512 ; i++) {
+               sum += tar.raw[i];
+       }
+       if (sum != strtol(tar.formated.chksum, NULL, 8)) {
+               error_msg("Invalid tar header checksum");
+               return(NULL);
+       }
+
+       /* convert to type'ed variables */
+       tar_entry = xcalloc(1, sizeof(file_header_t));
+       tar_entry->name = xstrdup(tar.formated.name);
+
+       parse_mode(tar.formated.mode, &tar_entry->mode);
+       tar_entry->uid   = strtol(tar.formated.uid, NULL, 8);
+       tar_entry->gid   = strtol(tar.formated.gid, NULL, 8);
+       tar_entry->size  = strtol(tar.formated.size, NULL, 8);
+       tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
+       tar_entry->link_name  = strlen(tar.formated.linkname) ? 
+           xstrdup(tar.formated.linkname) : NULL;
+       tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
+               strtol(tar.formated.devminor, NULL, 8);
+
+       return(tar_entry);
+}
+#endif
+
+#ifdef L_deb_extract
+char *deb_extract(const char *package_filename, FILE *out_stream, 
+       const int extract_function, const char *prefix, const char *filename)
+{
+       FILE *deb_stream;
+       FILE *uncompressed_stream = NULL;
+       file_header_t *ar_header = NULL;
+       char **file_list = NULL;
+       char *output_buffer = NULL;
+       char *ared_file = NULL;
+       char ar_magic[8];
+       int gunzip_pid;
+
+       if (filename != NULL) {
+               file_list = xmalloc(sizeof(char *) * 2);
+               file_list[0] = xstrdup(filename);
+               file_list[1] = NULL;
+       }
+       
+       if (extract_function & extract_control_tar_gz) {
+               ared_file = xstrdup("control.tar.gz");
+       }
+       else if (extract_function & extract_data_tar_gz) {              
+               ared_file = xstrdup("data.tar.gz");
+       }
+
+       /* open the debian package to be worked on */
+       deb_stream = wfopen(package_filename, "r");
+       if (deb_stream == NULL) {
+               return(NULL);
+       }
+       /* set the buffer size */
+       setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
+
+       /* check ar magic */
+       fread(ar_magic, 1, 8, deb_stream);
+       if (strncmp(ar_magic,"!<arch>",7) != 0) {
+               error_msg_and_die("invalid magic");
+       }
+       archive_offset = 8;
+
+       while ((ar_header = get_header_ar(deb_stream)) != NULL) {
+               if (strcmp(ared_file, ar_header->name) == 0) {
+                       /* open a stream of decompressed data */
+                       uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
+                       archive_offset = 0;
+                       output_buffer = unarchive(uncompressed_stream, out_stream, get_header_tar, extract_function, prefix, file_list);
+               }
+               seek_sub_file(deb_stream, ar_header->size);
+       }
+       gz_close(gunzip_pid);
+       fclose(deb_stream);
+       fclose(uncompressed_stream);
+       free(ared_file);
+       return(output_buffer);
+}
+#endif
diff --git a/libbb/unzip.c b/libbb/unzip.c
new file mode 100644 (file)
index 0000000..7462482
--- /dev/null
@@ -0,0 +1,1081 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersee@debian.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of
+ * standard busybox functions by Glenn McGrath <bug1@optushome.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#if 0
+static char *license_msg[] = {
+       "   Copyright (C) 1992-1993 Jean-loup Gailly",
+       "   This program is free software; you can redistribute it and/or modify",
+       "   it under the terms of the GNU General Public License as published by",
+       "   the Free Software Foundation; either version 2, or (at your option)",
+       "   any later version.",
+       "",
+       "   This program is distributed in the hope that it will be useful,",
+       "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
+       "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
+       "   GNU General Public License for more details.",
+       "",
+       "   You should have received a copy of the GNU General Public License",
+       "   along with this program; if not, write to the Free Software",
+       "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+       0
+};
+#endif
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libbb.h"
+
+static FILE *in_file, *out_file;
+
+/* these are freed by gz_close */
+static unsigned char *window;
+static unsigned long *crc_table;
+
+static unsigned long crc; /* shift register contents */
+
+/* Return codes from gzip */
+static const int ERROR = 1;
+
+/*
+ * window size--must be a power of two, and
+ *  at least 32K for zip's deflate method 
+ */
+static const int WSIZE = 0x8000;
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+static const int BMAX = 16;            /* maximum bit length of any code (16 for explode) */
+static const int N_MAX = 288;          /* maximum number of codes in any set */
+
+static long bytes_out;         /* number of output bytes */
+static unsigned long outcnt;   /* bytes in output buffer */
+
+static unsigned hufts;         /* track memory usage */
+static unsigned long bb;                       /* bit buffer */
+static unsigned bk;            /* bits in bit buffer */
+
+typedef struct huft_s {
+       unsigned char e;                /* number of extra bits or operation */
+       unsigned char b;                /* number of bits in this code or subcode */
+       union {
+               unsigned short n;               /* literal, length base, or distance base */
+               struct huft_s *t;       /* pointer to next level of table */
+       } v;
+} huft_t;
+
+static const unsigned short mask_bits[] = {
+       0x0000,
+       0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+       0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+//static int error_number = 0;
+/* ========================================================================
+ * Signal and error handler.
+ */
+static void abort_gzip()
+{
+       error_msg("gzip aborted\n");
+       exit(ERROR);
+}
+
+static void make_crc_table()
+{
+       unsigned long table_entry;      /* crc shift register */
+       unsigned long poly = 0;      /* polynomial exclusive-or pattern */
+       int i;                /* counter for all possible eight bit values */
+       int k;                /* byte being shifted into crc apparatus */
+
+       /* terms of polynomial defining this crc (except x^32): */
+       static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+       /* initial shift register value */
+       crc = 0xffffffffL;      
+       crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long));
+
+       /* Make exclusive-or pattern from polynomial (0xedb88320) */
+       for (i = 0; i < sizeof(p)/sizeof(int); i++)
+               poly |= 1L << (31 - p[i]);
+
+       /* Compute and print table of CRC's, five per line */
+       for (i = 0; i < 256; i++) {
+               table_entry = i;
+          /* The idea to initialize the register with the byte instead of
+            * zero was stolen from Haruhiko Okumura's ar002
+            */
+               for (k = 8; k; k--) {
+                       table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
+               }
+               crc_table[i]=table_entry;
+       }
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+       int n;
+
+       if (outcnt == 0)
+               return;
+
+       for (n = 0; n < outcnt; n++) {
+               crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
+       }
+
+       if (fwrite(window, 1, outcnt, out_file) != outcnt) {
+               error_msg_and_die("Couldnt write");
+       }
+       bytes_out += (unsigned long) outcnt;
+       outcnt = 0;
+}
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table. 
+ * t: table to free
+ */
+static int huft_free(huft_t *t)
+{
+       huft_t *p, *q;
+
+       /* Go through linked list, freeing from the malloced (t[-1]) address. */
+       p = t;
+       while (p != (huft_t *) NULL) {
+               q = (--p)->v.t;
+               free((char *) p);
+               p = q;
+       }
+       return 0;
+}
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes.  Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths), and three if not enough memory.
+ *
+ * b:  code lengths in bits (all assumed <= BMAX)
+ * n:  number of codes (assumed <= N_MAX)
+ * s:  number of simple-valued codes (0..s-1)
+ * d:  list of base values for non-simple codes
+ * e:  list of extra bits for non-simple codes
+ * t:  result: starting table
+ * m:  maximum lookup bits, returns actual
+ */
+static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, 
+       const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
+{
+       unsigned a;             /* counter for codes of length k */
+       unsigned c[BMAX + 1];   /* bit length count table */
+       unsigned f;             /* i repeats in table every f entries */
+       int g;                  /* maximum code length */
+       int h;                  /* table level */
+       register unsigned i;    /* counter, current code */
+       register unsigned j;    /* counter */
+       register int k;         /* number of bits in current code */
+       int l;                  /* bits per table (returned in m) */
+       register unsigned *p;           /* pointer into c[], b[], or v[] */
+       register huft_t *q;     /* points to current table */
+       huft_t r;               /* table entry for structure assignment */
+       huft_t *u[BMAX];        /* table stack */
+       unsigned v[N_MAX];      /* values in order of bit length */
+       register int w;         /* bits before this table == (l * h) */
+       unsigned x[BMAX + 1];   /* bit offsets, then code stack */
+       unsigned *xp;           /* pointer into x */
+       int y;                  /* number of dummy codes added */
+       unsigned z;             /* number of entries in current table */
+
+       /* Generate counts for each bit length */
+       memset ((void *)(c), 0, sizeof(c));
+       p = b;
+       i = n;
+       do {
+               c[*p]++;        /* assume all entries <= BMAX */
+               p++;            /* Can't combine with above line (Solaris bug) */
+       } while (--i);
+       if (c[0] == n) {        /* null input--all zero length codes */
+               *t = (huft_t *) NULL;
+               *m = 0;
+               return 0;
+       }
+
+       /* Find minimum and maximum length, bound *m by those */
+       l = *m;
+       for (j = 1; j <= BMAX; j++)
+               if (c[j])
+                       break;
+       k = j;                          /* minimum code length */
+       if ((unsigned) l < j)
+               l = j;
+       for (i = BMAX; i; i--)
+               if (c[i])
+                       break;
+       g = i;                          /* maximum code length */
+       if ((unsigned) l > i)
+               l = i;
+       *m = l;
+
+       /* Adjust last length count to fill out codes, if needed */
+       for (y = 1 << j; j < i; j++, y <<= 1)
+               if ((y -= c[j]) < 0)
+                       return 2;       /* bad input: more codes than bits */
+       if ((y -= c[i]) < 0)
+               return 2;
+       c[i] += y;
+
+       /* Generate starting offsets into the value table for each length */
+       x[1] = j = 0;
+       p = c + 1;
+       xp = x + 2;
+       while (--i) {                   /* note that i == g from above */
+               *xp++ = (j += *p++);
+       }
+
+       /* Make a table of values in order of bit lengths */
+       p = b;
+       i = 0;
+       do {
+               if ((j = *p++) != 0)
+                       v[x[j]++] = i;
+       } while (++i < n);
+
+       /* Generate the Huffman codes and for each, make the table entries */
+       x[0] = i = 0;                   /* first Huffman code is zero */
+       p = v;                          /* grab values in bit order */
+       h = -1;                         /* no tables yet--level -1 */
+       w = -l;                         /* bits decoded == (l * h) */
+       u[0] = (huft_t *) NULL; /* just to keep compilers happy */
+       q = (huft_t *) NULL;    /* ditto */
+       z = 0;                          /* ditto */
+
+       /* go through the bit lengths (k already is bits in shortest code) */
+       for (; k <= g; k++) {
+               a = c[k];
+               while (a--) {
+                       /* here i is the Huffman code of length k bits for value *p */
+                       /* make tables up to required level */
+                       while (k > w + l) {
+                               h++;
+                               w += l;         /* previous table always l bits */
+
+                               /* compute minimum size table less than or equal to l bits */
+                               z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
+                               if ((f = 1 << (j = k - w)) > a + 1) {   /* try a k-w bit table *//* too few codes for k-w bit table */
+                                       f -= a + 1;     /* deduct codes from patterns left */
+                                       xp = c + k;
+                                       while (++j < z) {       /* try smaller tables up to z bits */
+                                               if ((f <<= 1) <= *++xp)
+                                                       break;  /* enough codes to use up j bits */
+                                               f -= *xp;       /* else deduct codes from patterns */
+                                       }
+                               }
+                               z = 1 << j;             /* table entries for j-bit table */
+
+                               /* allocate and link in new table */
+                               if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
+                                       if (h) {
+                                               huft_free(u[0]);
+                                       }
+                                       return 3;       /* not enough memory */
+                               }
+                               hufts += z + 1; /* track memory usage */
+                               *t = q + 1;             /* link to list for huft_free() */
+                               *(t = &(q->v.t)) = NULL;
+                               u[h] = ++q;             /* table starts after link */
+
+                               /* connect to last table, if there is one */
+                               if (h) {
+                                       x[h] = i;       /* save pattern for backing up */
+                                       r.b = (unsigned char) l;        /* bits to dump before this table */
+                                       r.e = (unsigned char) (16 + j); /* bits in this table */
+                                       r.v.t = q;      /* pointer to this table */
+                                       j = i >> (w - l);       /* (get around Turbo C bug) */
+                                       u[h - 1][j] = r;        /* connect to last table */
+                               }
+                       }
+
+                       /* set up table entry in r */
+                       r.b = (unsigned char) (k - w);
+                       if (p >= v + n)
+                               r.e = 99;               /* out of values--invalid code */
+                       else if (*p < s) {
+                               r.e = (unsigned char) (*p < 256 ? 16 : 15);     /* 256 is end-of-block code */
+                               r.v.n = (unsigned short) (*p);  /* simple code is just the value */
+                               p++;                    /* one compiler does not like *p++ */
+                       } else {
+                               r.e = (unsigned char) e[*p - s];        /* non-simple--look up in lists */
+                               r.v.n = d[*p++ - s];
+                       }
+
+                       /* fill code-like entries with r */
+                       f = 1 << (k - w);
+                       for (j = i >> w; j < z; j += f)
+                               q[j] = r;
+
+                       /* backwards increment the k-bit code i */
+                       for (j = 1 << (k - 1); i & j; j >>= 1)
+                               i ^= j;
+                       i ^= j;
+
+                       /* backup over finished tables */
+                       while ((i & ((1 << w) - 1)) != x[h]) {
+                               h--;                    /* don't need to update q */
+                               w -= l;
+                       }
+               }
+       }
+       /* Return true (1) if we were given an incomplete table */
+       return y != 0 && g != 1;
+}
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
+{
+       register unsigned long e;               /* table entry flag/number of extra bits */
+       unsigned long n, d;                             /* length and index for copy */
+       unsigned long w;                                /* current window position */
+       huft_t *t;                              /* pointer to table entry */
+       unsigned ml, md;                        /* masks for bl and bd bits */
+       register unsigned long b;                               /* bit buffer */
+       register unsigned k;            /* number of bits in bit buffer */
+       register int input_char;
+
+       /* make local copies of globals */
+       b = bb;                                 /* initialize bit buffer */
+       k = bk;
+       w = outcnt;                             /* initialize window position */
+
+       /* inflate the coded data */
+       ml = mask_bits[bl];                     /* precompute masks for speed */
+       md = mask_bits[bd];
+       for (;;) {                              /* do until end of block */
+               while (k < (unsigned) bl) {
+                       input_char = fgetc(in_file);
+                       if (input_char == EOF) return 1;
+                       b |= ((unsigned long)input_char) << k;
+                       k += 8;
+               }
+               if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
+               do {
+                       if (e == 99) {
+                               return 1;
+                       }
+                       b >>= t->b;
+                       k -= t->b;
+                       e -= 16;
+                       while (k < e) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b |= ((unsigned long)input_char) << k;
+                               k += 8;
+                       }
+               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+               b >>= t->b;
+               k -= t->b;
+               if (e == 16) {          /* then it's a literal */
+                       window[w++] = (unsigned char) t->v.n;
+                       if (w == WSIZE) {
+                               outcnt=(w),
+                               flush_window();
+                               w = 0;
+                       }
+               } else {                                /* it's an EOB or a length */
+
+                       /* exit if end of block */
+                       if (e == 15) {
+                               break;
+                       }
+
+                       /* get length of block to copy */
+                       while (k < e) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b |= ((unsigned long)input_char) << k;
+                               k += 8;
+                       }
+                       n = t->v.n + ((unsigned) b & mask_bits[e]);
+                       b >>= e;
+                       k -= e;
+
+                       /* decode distance of block to copy */
+                       while (k < (unsigned) bd) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b |= ((unsigned long)input_char) << k;
+                               k += 8;
+                       }
+
+                       if ((e = (t = td + ((unsigned) b & md))->e) > 16)
+                               do {
+                                       if (e == 99)
+                                               return 1;
+                                       b >>= t->b;
+                                       k -= t->b;
+                                       e -= 16;
+                                       while (k < e) {
+                                               input_char = fgetc(in_file);
+                                               if (input_char == EOF) return 1;
+                                               b |= ((unsigned long)input_char) << k;
+                                               k += 8;
+                                       }
+                               } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+                       b >>= t->b;
+                       k -= t->b;
+                       while (k < e) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b |= ((unsigned long)input_char) << k;
+                               k += 8;
+                       }
+                       d = w - t->v.n - ((unsigned) b & mask_bits[e]);
+                       b >>= e;
+                       k -= e;
+
+                       /* do the copy */
+                       do {
+                               n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+                               if (w - d >= e) {       /* (this test assumes unsigned comparison) */
+                                       memcpy(window + w, window + d, e);
+                                       w += e;
+                                       d += e;
+                               } else                  /* do it slow to avoid memcpy() overlap */
+#endif                                                 /* !NOMEMCPY */
+                                       do {
+                                               window[w++] = window[d++];
+                                       } while (--e);
+                               if (w == WSIZE) {
+                                       outcnt=(w),
+                                       flush_window();
+                                       w = 0;
+                               }
+                       } while (n);
+               }
+       }
+
+       /* restore the globals from the locals */
+       outcnt = w;                     /* restore global window pointer */
+       bb = b;                         /* restore global bit buffer */
+       bk = k;
+
+       /* done */
+       return 0;
+}
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+static int inflate_block(int *e)
+{
+       unsigned t;                     /* block type */
+       register unsigned long b;                       /* bit buffer */
+       register unsigned k;            /* number of bits in bit buffer */
+       static unsigned short cplens[] = {              /* Copy lengths for literal codes 257..285 */
+               3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+               35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+       };
+       /* note: see note #13 above about the 258 in this list. */
+       static unsigned short cplext[] = {              /* Extra bits for literal codes 257..285 */
+               0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+               3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+       };                              /* 99==invalid */
+       static unsigned short cpdist[] = {              /* Copy offsets for distance codes 0..29 */
+               1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+               257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+               8193, 12289, 16385, 24577
+       };
+       static unsigned short cpdext[] = {              /* Extra bits for distance codes */
+               0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+               7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+               12, 12, 13, 13
+       };
+       int input_char;
+
+       /* make local bit buffer */
+       b = bb;
+       k = bk;
+
+       /* read in last block bit */
+       while (k < 1) {
+               input_char = fgetc(in_file);
+               if (input_char == EOF) return 1;
+               b |= ((unsigned long)input_char) << k;
+               k += 8;
+       }
+       *e = (int) b & 1;
+       b >>= 1;
+       k -= 1;
+
+       /* read in block type */
+       while (k < 2) {
+               input_char = fgetc(in_file);
+               if (input_char == EOF) return 1;
+               b |= ((unsigned long)input_char) << k;
+               k += 8;
+       }
+       t = (unsigned) b & 3;
+       b >>= 2;
+       k -= 2;
+
+       /* restore the global bit buffer */
+       bb = b;
+       bk = k;
+
+       /* inflate that block type */
+       switch (t) {
+       case 0: /* Inflate stored */
+               {
+                       unsigned long n;                        /* number of bytes in block */
+                       unsigned long w;                        /* current window position */
+                       register unsigned long b_stored;                        /* bit buffer */
+                       register unsigned long k_stored;                /* number of bits in bit buffer */
+
+                       /* make local copies of globals */
+                       b_stored = bb;                          /* initialize bit buffer */
+                       k_stored = bk;
+                       w = outcnt;                     /* initialize window position */
+
+                       /* go to byte boundary */
+                       n = k_stored & 7;
+                       b_stored >>= n;
+                       k_stored -= n;
+
+                       /* get the length and its complement */
+                       while (k_stored < 16) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b_stored |= ((unsigned long)input_char) << k_stored;
+                               k_stored += 8;
+                       }
+                       n = ((unsigned) b_stored & 0xffff);
+                       b_stored >>= 16;
+                       k_stored -= 16;
+                       while (k_stored < 16) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b_stored |= ((unsigned long)input_char) << k_stored;
+                               k_stored += 8;
+                       }
+                       if (n != (unsigned) ((~b_stored) & 0xffff)) {
+                               return 1;               /* error in compressed data */
+                       }
+                       b_stored >>= 16;
+                       k_stored -= 16;
+
+                       /* read and output the compressed data */
+                       while (n--) {
+                               while (k_stored < 8) {
+                                       input_char = fgetc(in_file);
+                                       if (input_char == EOF) return 1;
+                                       b_stored |= ((unsigned long)input_char) << k_stored;
+                                       k_stored += 8;
+                               }
+                               window[w++] = (unsigned char) b_stored;
+                               if (w == (unsigned long)WSIZE) {
+                                       outcnt=(w),
+                                       flush_window();
+                                       w = 0;
+                               }
+                               b_stored >>= 8;
+                               k_stored -= 8;
+                       }
+
+                       /* restore the globals from the locals */
+                       outcnt = w;                     /* restore global window pointer */
+                       bb = b_stored;                          /* restore global bit buffer */
+                       bk = k_stored;
+                       return 0;
+               }
+       case 1: /* Inflate fixed 
+                        * decompress an inflated type 1 (fixed Huffman codes) block.  We should
+                        * either replace this with a custom decoder, or at least precompute the
+                        * Huffman tables.
+                        */
+               {
+                       int i;                                  /* temporary variable */
+                       huft_t *tl;                             /* literal/length code table */
+                       huft_t *td;                             /* distance code table */
+                       int bl;                                 /* lookup bits for tl */
+                       int bd;                                 /* lookup bits for td */
+                       unsigned int l[288];    /* length list for huft_build */
+
+                       /* set up literal table */
+                       for (i = 0; i < 144; i++) {
+                               l[i] = 8;
+                       }
+                       for (; i < 256; i++) {
+                               l[i] = 9;
+                       }
+                       for (; i < 280; i++) {
+                               l[i] = 7;
+                       }
+                       for (; i < 288; i++) {  /* make a complete, but wrong code set */
+                               l[i] = 8;
+                       }
+                       bl = 7;
+                       if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+                               return i;
+                       }
+
+                       /* set up distance table */
+                       for (i = 0; i < 30; i++) {      /* make an incomplete code set */
+                               l[i] = 5;
+                       }
+                       bd = 5;
+                       if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
+                               huft_free(tl);
+                               return i;
+                       }
+
+                       /* decompress until an end-of-block code */
+                       if (inflate_codes(tl, td, bl, bd))
+                               return 1;
+
+                       /* free the decoding tables, return */
+                       huft_free(tl);
+                       huft_free(td);
+                       return 0;
+               }
+       case 2: /* Inflate dynamic */
+               {
+                       /* Tables for deflate from PKZIP's appnote.txt. */
+                       static unsigned border[] = {    /* Order of the bit length code lengths */
+                               16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+                       };
+                       int dbits = 6;                                  /* bits in base distance lookup table */
+                       int lbits = 9;                                  /* bits in base literal/length lookup table */
+
+                       int i;                                          /* temporary variables */
+                       unsigned j;
+                       unsigned l;                                     /* last length */
+                       unsigned m;                                     /* mask for bit lengths table */
+                       unsigned n;                                     /* number of lengths to get */
+                       huft_t *tl;                     /* literal/length code table */
+                       huft_t *td;                     /* distance code table */
+                       int bl;                                         /* lookup bits for tl */
+                       int bd;                                         /* lookup bits for td */
+                       unsigned nb;                            /* number of bit length codes */
+                       unsigned nl;                            /* number of literal/length codes */
+                       unsigned nd;                            /* number of distance codes */
+
+                       unsigned ll[286 + 30];          /* literal/length and distance code lengths */
+                       register unsigned long b_dynamic;       /* bit buffer */
+                       register unsigned k_dynamic;            /* number of bits in bit buffer */
+
+                       /* make local bit buffer */
+                       b_dynamic = bb;
+                       k_dynamic = bk;
+
+                       /* read in table lengths */
+                       while (k_dynamic < 5) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                               k_dynamic += 8;
+                       }
+                       nl = 257 + ((unsigned) b_dynamic & 0x1f);       /* number of literal/length codes */
+                       b_dynamic >>= 5;
+                       k_dynamic -= 5;
+                       while (k_dynamic < 5) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                               k_dynamic += 8;
+                       }
+                       nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
+                       b_dynamic >>= 5;
+                       k_dynamic -= 5;
+                       while (k_dynamic < 4) {
+                               input_char = fgetc(in_file);
+                               if (input_char == EOF) return 1;
+                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                               k_dynamic += 8;
+                       }
+                       nb = 4 + ((unsigned) b_dynamic & 0xf);  /* number of bit length codes */
+                       b_dynamic >>= 4;
+                       k_dynamic -= 4;
+                       if (nl > 286 || nd > 30) {
+                               return 1;       /* bad lengths */
+                       }
+
+                       /* read in bit-length-code lengths */
+                       for (j = 0; j < nb; j++) {
+                               while (k_dynamic < 3) {
+                                       input_char = fgetc(in_file);
+                                       if (input_char == EOF) return 1;
+                                       b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                                       k_dynamic += 8;
+                               }
+                               ll[border[j]] = (unsigned) b_dynamic & 7;
+                               b_dynamic >>= 3;
+                               k_dynamic -= 3;
+                       }
+                       for (; j < 19; j++) {
+                               ll[border[j]] = 0;
+                       }
+
+                       /* build decoding table for trees--single level, 7 bit lookup */
+                       bl = 7;
+                       if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
+                               if (i == 1) {
+                                       huft_free(tl);
+                               }
+                               return i;                       /* incomplete code set */
+                       }
+
+                       /* read in literal and distance code lengths */
+                       n = nl + nd;
+                       m = mask_bits[bl];
+                       i = l = 0;
+                       while ((unsigned) i < n) {
+                               while (k_dynamic < (unsigned) bl) {
+                                       input_char = fgetc(in_file);
+                                       if (input_char == EOF) return 1;
+                                       b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                                       k_dynamic += 8;
+                               }
+                               j = (td = tl + ((unsigned) b_dynamic & m))->b;
+                               b_dynamic >>= j;
+                               k_dynamic -= j;
+                               j = td->v.n;
+                               if (j < 16) {                   /* length of code in bits (0..15) */
+                                       ll[i++] = l = j;        /* save last length in l */
+                               }
+                               else if (j == 16) {             /* repeat last length 3 to 6 times */
+                                       while (k_dynamic < 2) {
+                                               input_char = fgetc(in_file);
+                                               if (input_char == EOF) return 1;
+                                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                                               k_dynamic += 8;
+                                       }
+                                       j = 3 + ((unsigned) b_dynamic & 3);
+                                       b_dynamic >>= 2;
+                                       k_dynamic -= 2;
+                                       if ((unsigned) i + j > n) {
+                                               return 1;
+                                       }
+                                       while (j--) {
+                                               ll[i++] = l;
+                                       }
+                               } else if (j == 17) {   /* 3 to 10 zero length codes */
+                                       while (k_dynamic < 3) {
+                                               input_char = fgetc(in_file);
+                                               if (input_char == EOF) return 1;
+                                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                                               k_dynamic += 8;
+                                       }
+                                       j = 3 + ((unsigned) b_dynamic & 7);
+                                       b_dynamic >>= 3;
+                                       k_dynamic -= 3;
+                                       if ((unsigned) i + j > n) {
+                                               return 1;
+                                       }
+                                       while (j--) {
+                                               ll[i++] = 0;
+                                       }
+                                       l = 0;
+                               } else {                /* j == 18: 11 to 138 zero length codes */
+                                       while (k_dynamic < 7) {
+                                               input_char = fgetc(in_file);
+                                               if (input_char == EOF) return 1;
+                                               b_dynamic |= ((unsigned long)input_char) << k_dynamic;
+                                               k_dynamic += 8;
+                                       }
+                                       j = 11 + ((unsigned) b_dynamic & 0x7f);
+                                       b_dynamic >>= 7;
+                                       k_dynamic -= 7;
+                                       if ((unsigned) i + j > n) {
+                                               return 1;
+                                       }
+                                       while (j--) {
+                                               ll[i++] = 0;
+                                       }
+                                       l = 0;
+                               }
+                       }
+
+                       /* free decoding table for trees */
+                       huft_free(tl);
+
+                       /* restore the global bit buffer */
+                       bb = b_dynamic;
+                       bk = k_dynamic;
+
+                       /* build the decoding tables for literal/length and distance codes */
+                       bl = lbits;
+                       if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
+                               if (i == 1) {
+                                       error_msg("Incomplete literal tree");
+                                       huft_free(tl);
+                               }
+                               return i;                       /* incomplete code set */
+                       }
+                       bd = dbits;
+                       if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
+                               if (i == 1) {
+                                       error_msg("incomplete distance tree");
+                                       huft_free(td);
+                               }
+                               huft_free(tl);
+                               return i;                       /* incomplete code set */
+                       }
+
+                       /* decompress until an end-of-block code */
+                       if (inflate_codes(tl, td, bl, bd))
+                               return 1;
+
+                       /* free the decoding tables, return */
+                       huft_free(tl);
+                       huft_free(td);
+                       return 0;
+               }
+       default:
+               /* bad block type */
+               return 2;
+       }
+}
+
+/*
+ * decompress an inflated entry
+ *
+ * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
+ */
+static int inflate()
+{
+       int e;                          /* last block flag */
+       int r;                          /* result code */
+       unsigned h = 0;         /* maximum struct huft's malloc'ed */
+
+       /* initialize window, bit buffer */
+       outcnt = 0;
+       bk = 0;
+       bb = 0;
+
+       /* decompress until the last block */
+       do {
+               hufts = 0;
+               if ((r = inflate_block(&e)) != 0) {
+                       return r;
+               }
+               if (hufts > h) {
+                       h = hufts;
+               }
+       } while (!e);
+
+       /* Undo too much lookahead.  The next read will be byte aligned so we
+        * can discard unused bits in the last meaningful byte.  */
+       while (bk >= 8) {
+               bk -= 8;
+               ungetc((bb << bk), in_file);
+       }
+
+       /* flush out window */
+       flush_window();
+
+       /* return success */
+       return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out.  This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets inptr to insize-1 included.
+ *   The magic header has already been checked. The output buffer is cleared.
+ * in, out: input and output file descriptors
+ */
+extern int unzip(FILE *l_in_file, FILE *l_out_file)
+{
+       const int extra_field = 0x04;   /* bit 2 set: extra field present */
+       const int orig_name = 0x08;     /* bit 3 set: original file name present */
+       const int comment = 0x10;       /* bit 4 set: file comment present */
+       unsigned char buf[8];   /* extended local header */
+       unsigned char flags;    /* compression flags */
+       char magic[2];                  /* magic header */
+       int method;
+       typedef void (*sig_type) (int);
+       int exit_code=0;        /* program exit code */
+       int i;
+
+       in_file = l_in_file;
+       out_file = l_out_file;
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+               (void) signal(SIGINT, (sig_type) abort_gzip);
+       }
+#ifdef SIGTERM
+//     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+//             (void) signal(SIGTERM, (sig_type) abort_gzip);
+//     }
+#endif
+#ifdef SIGHUP
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+               (void) signal(SIGHUP, (sig_type) abort_gzip);
+       }
+#endif
+
+       /* Allocate all global buffers (for DYN_ALLOC option) */
+       window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+       outcnt = 0;
+       bytes_out = 0L;
+
+       magic[0] = fgetc(in_file);
+       magic[1] = fgetc(in_file);
+
+       /* Magic header for gzip files, 1F 8B = \037\213 */
+       if (memcmp(magic, "\037\213", 2) != 0) {
+               error_msg("Invalid gzip magic");
+               return EXIT_FAILURE;
+       }
+
+       method = (int) fgetc(in_file);
+       if (method != 8) {                   /* also catches EOF */
+               error_msg("unknown method %d -- get newer version of gzip", method);
+               exit_code = 1;
+               return -1;
+       }
+
+       flags = (unsigned char) fgetc(in_file);
+
+       /* Ignore time stamp(4), extra flags(1), OS type(1) */
+       for (i = 0; i < 6; i++)
+               fgetc(in_file);
+
+       if ((flags & extra_field) != 0) {
+               size_t extra;
+               extra = fgetc(in_file);
+               extra += fgetc(in_file) << 8;
+               if (feof(in_file)) return 1;
+
+               for (i = 0; i < extra; i++)
+                       fgetc(in_file);
+       }
+
+       /* Discard original name if any */
+       if ((flags & orig_name) != 0) {
+               while (fgetc(in_file) != 0 && !feof(in_file));  /* null */
+       }
+
+       /* Discard file comment if any */
+       if ((flags & comment) != 0) {
+               while (fgetc(in_file) != 0 && !feof(in_file));  /* null */
+       }
+
+       if (method < 0) {
+               printf("it failed\n");
+               return(exit_code);              /* error message already emitted */
+       }
+
+       make_crc_table();
+
+       /* Decompress */
+       if (method == 8) {
+
+               int res = inflate();
+
+               if (res == 3) {
+                       error_msg(memory_exhausted);
+                       exit_code = 1;
+               } else if (res != 0) {
+                       error_msg("invalid compressed data--format violated");
+                       exit_code = 1;
+               }
+
+       } else {
+               error_msg("internal error, invalid method");
+               exit_code = 1;
+       }
+
+       /* Get the crc and original length
+        * crc32  (see algorithm.doc)
+        * uncompressed input size modulo 2^32
+        */
+       fread(buf, 1, 8, in_file);
+
+       /* Validate decompression - crc */
+       if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
+               error_msg("invalid compressed data--crc error");
+               exit_code = 1;
+       }
+       /* Validate decompression - size */
+       if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
+               error_msg("invalid compressed data--length error");
+               exit_code = 1;
+       }
+
+       free(window);
+       free(crc_table);
+
+       return exit_code;
+}
+
+/*
+ * This needs access to global variables wondow and crc_table, so its not in its own file.
+ */
+extern void gz_close(int gunzip_pid)
+{
+       if (kill(gunzip_pid, SIGTERM) == -1) {
+               error_msg_and_die("***  Couldnt kill old gunzip process *** aborting");
+       }
+
+       if (waitpid(gunzip_pid, NULL, 0) == -1) {
+               printf("Couldnt wait ?");
+       }
+               free(window);
+               free(crc_table);
+}
diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c
new file mode 100644 (file)
index 0000000..f3c1ed7
--- /dev/null
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+#if (__GLIBC__ < 2)
+extern int vdprintf(int d, const char *format, va_list ap)
+{
+       char buf[BUF_SIZE];
+       int len;
+
+       len = vsnprintf(buf, sizeof(buf), format, ap);
+       return write(d, buf, len);
+}
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
new file mode 100644 (file)
index 0000000..21cde20
--- /dev/null
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void verror_msg(const char *s, va_list p)
+{
+       fflush(stdout);
+       fprintf(stderr, "%s: ", applet_name);
+       vfprintf(stderr, s, p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/vherror_msg.c b/libbb/vherror_msg.c
new file mode 100644 (file)
index 0000000..8a7ada9
--- /dev/null
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <netdb.h>
+extern int h_errno;
+#include <stdio.h>
+
+#include "libbb.h"
+
+
+extern void vherror_msg(const char *s, va_list p)
+{
+       if(s == 0)
+               s = "";
+       verror_msg(s, p);
+       if (*s)
+               fputs(": ", stderr);
+       herror("");
+}
diff --git a/libbb/vperror_msg.c b/libbb/vperror_msg.c
new file mode 100644 (file)
index 0000000..7da5bae
--- /dev/null
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void vperror_msg(const char *s, va_list p)
+{
+       int err=errno;
+       if(s == 0) s = "";
+       verror_msg(s, p);
+       if (*s) s = ": ";
+       fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/wfopen.c b/libbb/wfopen.c
new file mode 100644 (file)
index 0000000..f58ec90
--- /dev/null
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "libbb.h"
+
+FILE *wfopen(const char *path, const char *mode)
+{
+       FILE *fp;
+       if ((fp = fopen(path, mode)) == NULL) {
+               perror_msg("%s", path);
+               errno = 0;
+       }
+       return fp;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
new file mode 100644 (file)
index 0000000..ee90e60
--- /dev/null
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+#ifndef DMALLOC
+extern void *xmalloc(size_t size)
+{
+       void *ptr = malloc(size);
+       if (ptr == NULL && size != 0)
+               error_msg_and_die(memory_exhausted);
+       return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+       ptr = realloc(ptr, size);
+       if (ptr == NULL && size != 0)
+               error_msg_and_die(memory_exhausted);
+       return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+       void *ptr = calloc(nmemb, size);
+       if (ptr == NULL && nmemb != 0 && size != 0)
+               error_msg_and_die(memory_exhausted);
+       return ptr;
+}
+
+extern char * xstrdup (const char *s) {
+       char *t;
+
+       if (s == NULL)
+               return NULL;
+
+       t = strdup (s);
+
+       if (t == NULL)
+               error_msg_and_die(memory_exhausted);
+
+       return t;
+}
+#endif
+
+extern char * xstrndup (const char *s, int n) {
+       char *t;
+
+       if (s == NULL)
+               error_msg_and_die("xstrndup bug");
+
+       t = xmalloc(++n);
+       
+       return safe_strncpy(t,s,n);
+}
+
+FILE *xfopen(const char *path, const char *mode)
+{
+       FILE *fp;
+       if ((fp = fopen(path, mode)) == NULL)
+               perror_msg_and_die("%s", path);
+       return fp;
+}
+
+/* Stupid gcc always includes its own builtin strlen()... */
+#undef strlen
+size_t xstrlen(const char *string)
+{
+       return(strlen(string));
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/libbb/xgetcwd.c b/libbb/xgetcwd.c
new file mode 100644 (file)
index 0000000..4f77481
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * xgetcwd.c -- return current directory with unlimited length
+ * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+ * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ *
+ * Special function for busybox written by Vladimir Oleynik <vodz@usa.net>
+*/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include "libbb.h"
+
+/* Amount to increase buffer size by in each try. */
+#define PATH_INCR 32
+
+/* Return the current directory, newly allocated, arbitrarily long.
+   Return NULL and set errno on error.
+   If argument is not NULL (previous usage allocate memory), call free()
+*/
+
+char *
+xgetcwd (char *cwd)
+{
+  char *ret;
+  unsigned path_max;
+
+  errno = 0;
+  path_max = (unsigned) PATH_MAX;
+  path_max += 2;                /* The getcwd docs say to do this. */
+
+  if(cwd==0)
+       cwd = xmalloc (path_max);
+
+  errno = 0;
+  while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
+      path_max += PATH_INCR;
+      cwd = xrealloc (cwd, path_max);
+      errno = 0;
+  }
+
+  if (ret == NULL) {
+      int save_errno = errno;
+      free (cwd);
+      errno = save_errno;
+      perror_msg("getcwd()");
+      return NULL;
+  }
+
+  return cwd;
+}
diff --git a/libbb/xgethostbyname.c b/libbb/xgethostbyname.c
new file mode 100644 (file)
index 0000000..f859a44
--- /dev/null
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xgethostbyname implementation.
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <netdb.h>
+extern int h_errno;
+#include "libbb.h"
+
+
+struct hostent *xgethostbyname(const char *name)
+{
+       struct hostent *retval;
+
+       if ((retval = gethostbyname(name)) == NULL)
+               herror_msg_and_die("%s", name);
+
+       return retval;
+}
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
new file mode 100644 (file)
index 0000000..932e487
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  xreadlink.c - safe implementation of readlink.
+ *  Returns a NULL on failure...
+ */
+
+#include <stdio.h>
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself. You have been warned.
+ */
+
+#include <unistd.h>
+#include "libbb.h"
+
+extern char *xreadlink(const char *path)
+{                       
+       static const int GROWBY = 80; /* how large we will grow strings by */
+
+       char *buf = NULL;   
+       int bufsize = 0, readsize = 0;
+
+       do {
+               buf = xrealloc(buf, bufsize += GROWBY);
+               readsize = readlink(path, buf, bufsize); /* 1st try */
+               if (readsize == -1) {
+                   perror_msg("%s:%s", applet_name, path);
+                   return NULL;
+               }
+       }           
+       while (bufsize < readsize + 1);
+
+       buf[readsize] = '\0';
+
+       return buf;
+}       
+
diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c
new file mode 100644 (file)
index 0000000..07cf779
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.  If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+#include <regex.h>
+
+
+
+void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+       int ret;
+       if ((ret = regcomp(preg, regex, cflags)) != 0) {
+               int errmsgsz = regerror(ret, preg, NULL, 0);
+               char *errmsg = xmalloc(errmsgsz);
+               regerror(ret, preg, errmsg, errmsgsz);
+               error_msg_and_die("xregcomp: %s", errmsg);
+       }
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/ln.c b/ln.c
new file mode 100644 (file)
index 0000000..213db9b
--- /dev/null
+++ b/ln.c
@@ -0,0 +1,131 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ln implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "busybox.h"
+
+
+static const int LN_SYMLINK = 1;
+static const int LN_FORCE = 2;
+static const int LN_NODEREFERENCE = 4;
+
+/*
+ * linkDestName is where the link points to,
+ * linkSrcName is the name of the link to be created.
+ */
+static int fs_link(const char *link_destname, const char *link_srcname, 
+               const int flag)
+{
+       int status;
+       int src_is_dir;
+       char *src_name;
+
+       if (link_destname==NULL)
+               return(FALSE);
+
+       src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1);
+
+       if (link_srcname==NULL)
+               strcpy(src_name, link_destname);
+       else
+               strcpy(src_name, link_srcname);
+
+       if (flag&LN_NODEREFERENCE)
+               src_is_dir = is_directory(src_name, TRUE, NULL);
+       else
+               src_is_dir = is_directory(src_name, FALSE, NULL);       
+       
+       if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) {
+               char* srcdir_name;
+
+               srcdir_name = xstrdup(link_destname);
+               strcat(src_name, "/");
+               strcat(src_name, get_last_path_component(srcdir_name));
+               free(srcdir_name);
+       }
+       
+       if (flag&LN_FORCE)
+               unlink(src_name);
+               
+       if (flag&LN_SYMLINK)
+               status = symlink(link_destname, src_name);
+       else
+               status = link(link_destname, src_name);
+
+       if (status != 0) {
+               perror_msg(src_name);
+               return(FALSE);
+       }
+       return(TRUE);
+}
+
+extern int ln_main(int argc, char **argv)
+{
+       int status = EXIT_SUCCESS;
+       int flag = 0;
+       int opt;
+       
+       /* Parse any options */
+       while ((opt=getopt(argc, argv, "sfn")) != -1) {
+               switch(opt) {
+                       case 's':
+                               flag |= LN_SYMLINK;
+                               break;
+                       case 'f':
+                               flag |= LN_FORCE;
+                               break;
+                       case 'n':
+                               flag |= LN_NODEREFERENCE;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+       if (optind > (argc-1)) {
+               show_usage();
+       } 
+       if (optind == (argc-1)) {
+               if (fs_link(argv[optind], 
+                                       get_last_path_component(argv[optind]), flag)==FALSE)
+                       status = EXIT_FAILURE;
+       }
+       while(optind<(argc-1)) {
+               if (fs_link(argv[optind], argv[argc-1], flag)==FALSE)
+                       status = EXIT_FAILURE;
+               optind++;
+       }
+       exit(status);
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/loadacm.c b/loadacm.c
new file mode 100644 (file)
index 0000000..3fb4e76
--- /dev/null
+++ b/loadacm.c
@@ -0,0 +1,357 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Derived from
+ * mapscrn.c - version 0.92
+ *
+ * Was taken from console-tools and adapted by 
+ * Peter Novodvorsky <petya@logic.ru>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/kd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+typedef unsigned short unicode;
+
+static long int ctoi(unsigned char *s, int *is_unicode);
+static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]);
+static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode);
+static unicode utf8_to_ucs2(char *buf);
+static int screen_map_load(int fd, FILE * fp);
+
+int loadacm_main(int argc, char **argv)
+{
+       int fd;
+
+       if (argc>=2 && *argv[1]=='-') {
+               show_usage();
+       }
+
+       fd = open(CURRENT_VC, O_RDWR);
+       if (fd < 0) {
+               perror_msg_and_die("Error opening " CURRENT_VC);
+       }
+
+       if (screen_map_load(fd, stdin)) {
+               perror_msg_and_die("Error loading acm");
+       }
+
+       write(fd, "\033(K", 3);
+
+       return EXIT_SUCCESS;
+}
+
+static int screen_map_load(int fd, FILE * fp)
+{
+       struct stat stbuf;
+       unicode wbuf[E_TABSZ];
+       unsigned char buf[E_TABSZ];
+       int parse_failed = 0;
+       int is_unicode;
+
+       if (fstat(fileno(fp), &stbuf))
+               perror_msg_and_die("Cannot stat map file");
+
+       /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */
+       if (!
+               (parse_failed =
+                (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode)))
+|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) {       /* test for binary UTF map by size */
+               if (parse_failed) {
+                       if (-1 == fseek(fp, 0, SEEK_SET)) {
+                               if (errno == ESPIPE)
+                                       error_msg_and_die("16bit screen-map MUST be a regular file.");
+                               else
+                                       perror_msg_and_die("fseek failed reading binary 16bit screen-map");
+                       }
+
+                       if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1)
+                               perror_msg_and_die("Cannot read [new] map from file");
+#if 0
+                       else
+                               error_msg("Input screen-map is binary.");
+#endif
+               }
+
+               /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */
+               /* same if it was binary, ie. if parse_failed */
+               if (parse_failed || is_unicode) {
+                       if (ioctl(fd, PIO_UNISCRNMAP, wbuf))
+                               perror_msg_and_die("PIO_UNISCRNMAP ioctl");
+                       else
+                               return 0;
+               }
+       }
+
+       /* rewind... */
+       if (-1 == fseek(fp, 0, SEEK_SET)) {
+               if (errno == ESPIPE)
+                       error_msg("Assuming 8bit screen-map - MUST be a regular file."),
+                               exit(1);
+               else
+                       perror_msg_and_die("fseek failed assuming 8bit screen-map");
+       }
+
+       /* ... and try an old 8-bit screen-map */
+       if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) ||
+               (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) {       /* test for binary old 8-bit map by size */
+               if (parse_failed) {
+                       if (-1 == fseek(fp, 0, SEEK_SET)) {
+                               if (errno == ESPIPE)
+                                       /* should not - it succedeed above */
+                                       error_msg_and_die("fseek() returned ESPIPE !");
+                               else
+                                       perror_msg_and_die("fseek for binary 8bit screen-map");
+                       }
+
+                       if (fread(buf, E_TABSZ, 1, fp) != 1)
+                               perror_msg_and_die("Cannot read [old] map from file");
+#if 0
+                       else
+                               error_msg("Input screen-map is binary.");
+#endif
+               }
+
+               if (ioctl(fd, PIO_SCRNMAP, buf))
+                       perror_msg_and_die("PIO_SCRNMAP ioctl");
+               else
+                       return 0;
+       }
+       error_msg("Error parsing symbolic map");
+       return(1);
+}
+
+
+/*
+ * - reads `fp' as a 16-bit ASCII SFM file.
+ * - returns -1 on error.
+ * - returns it in `unicode' in an E_TABSZ-elements array.
+ * - sets `*is_unicode' flagiff there were any non-8-bit
+ *   (ie. real 16-bit) mapping.
+ *
+ * FIXME: ignores everything after second word
+ */
+static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode)
+{
+       char buffer[256];                       /* line buffer reading file */
+       char *p, *q;                            /* 1st + 2nd words in line */
+       int in, on;                                     /* the same, as numbers */
+       int tmp_is_unicode;                     /* tmp for is_unicode calculation */
+       int i;                                          /* loop index - result holder */
+       int ret_code = 0;                       /* return code */
+       sigset_t acmsigset, old_sigset;
+
+       assert(is_unicode);
+
+       *is_unicode = 0;
+
+       /* first 128 codes defaults to ASCII */
+       for (i = 0; i < 128; i++)
+               buf[i] = i;
+       /* remaining defaults to replacement char (usually E_TABSZ = 256) */
+       for (; i < E_TABSZ; i++)
+               buf[i] = 0xfffd;
+
+       /* block SIGCHLD */
+       sigemptyset(&acmsigset);
+       sigaddset(&acmsigset, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset);
+
+       do {
+               if (NULL == fgets(buffer, sizeof(buffer), fp)) {
+                       if (feof(fp))
+                               break;
+                       else
+                               perror_msg_and_die("uni_screen_map_read_ascii() can't read line");
+               }
+
+               /* get "charset-relative charcode", stripping leading spaces */
+               p = strtok(buffer, " \t\n");
+
+               /* skip empty lines and comments */
+               if (!p || *p == '#')
+                       continue;
+
+               /* get unicode mapping */
+               q = strtok(NULL, " \t\n");
+               if (q) {
+                       in = ctoi(p, NULL);
+                       if (in < 0 || in > 255) {
+                               ret_code = -1;
+                               break;
+                       }
+
+                       on = ctoi(q, &tmp_is_unicode);
+                       if (in < 0 && on > 65535) {
+                               ret_code = -1;
+                               break;
+                       }
+
+                       *is_unicode |= tmp_is_unicode;
+                       buf[in] = on;
+               } else {
+                       ret_code = -1;
+                       break;
+               }
+       }
+       while (1);                                      /* terminated by break on feof() */
+
+       /* restore sig mask */
+       sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+
+       return ret_code;
+}
+
+
+static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[])
+{
+       char buffer[256];
+       int in, on;
+       char *p, *q;
+
+       for (in = 0; in < 256; in++)
+               buf[in] = in;
+
+       while (fgets(buffer, sizeof(buffer) - 1, fp)) {
+               p = strtok(buffer, " \t\n");
+
+               if (!p || *p == '#')
+                       continue;
+
+               q = strtok(NULL, " \t\n#");
+               if (q) {
+                       in = ctoi(p, NULL);
+                       if (in < 0 || in > 255)
+                               return -1;
+
+                       on = ctoi(q, NULL);
+                       if (in < 0 && on > 255)
+                               return -1;
+
+                       buf[in] = on;
+               } else
+                       return -1;
+       }
+
+       return (0);
+}
+
+
+/*
+ * - converts a string into an int.
+ * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars.
+ * - returns the converted value
+ * - if `is_unicode != NULL', use it to tell whether it was unicode
+ *
+ * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones.
+ */
+static long int ctoi(unsigned char *s, int *is_unicode)
+{
+       int i;
+       size_t ls;
+
+       ls = strlen(s);
+       if (is_unicode)
+               *is_unicode = 0;
+
+       /* hex-specified UCS2 */
+       if ((strncmp(s, "U+", 2) == 0) &&
+               (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) {
+               sscanf(s + 2, "%x", &i);
+               if (is_unicode)
+                       *is_unicode = 1;
+       }
+
+       /* hex-specified byte */
+       else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) &&
+                        (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2))
+               sscanf(s + 2, "%x", &i);
+
+       /* oct-specified number (byte) */
+       else if ((*s == '0') && (strspn(s, "01234567") == ls))
+               sscanf(s, "%o", &i);
+
+       /* dec-specified number (byte) */
+       else if (strspn(s, "0123456789") == ls)
+               sscanf(s, "%d", &i);
+
+       /* single-byte quoted char */
+       else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
+               i = s[1];
+
+       /* multi-byte UTF8 quoted char */
+       else if ((s[0] == '\'') && (s[ls - 1] == '\'')) {
+               s[ls - 1] = 0;                  /* ensure we'll not "parse UTF too far" */
+               i = utf8_to_ucs2(s + 1);
+               if (is_unicode)
+                       *is_unicode = 1;
+       } else
+               return (-1);
+
+       return (i);
+}
+
+
+static unicode utf8_to_ucs2(char *buf)
+{
+       int utf_count = 0;
+       long utf_char = 0;
+       unicode tc = 0;
+       unsigned char c;
+
+       do {
+               c = *buf;
+               buf++;
+
+               /* if byte should be part of multi-byte sequence */
+               if (c & 0x80) {
+                       /* if we have already started to parse a UTF8 sequence */
+                       if (utf_count > 0 && (c & 0xc0) == 0x80) {
+                               utf_char = (utf_char << 6) | (c & 0x3f);
+                               utf_count--;
+                               if (utf_count == 0)
+                                       tc = utf_char;
+                               else
+                                       continue;
+                       } else {                        /* Possibly 1st char of a UTF8 sequence */
+
+                               if ((c & 0xe0) == 0xc0) {
+                                       utf_count = 1;
+                                       utf_char = (c & 0x1f);
+                               } else if ((c & 0xf0) == 0xe0) {
+                                       utf_count = 2;
+                                       utf_char = (c & 0x0f);
+                               } else if ((c & 0xf8) == 0xf0) {
+                                       utf_count = 3;
+                                       utf_char = (c & 0x07);
+                               } else if ((c & 0xfc) == 0xf8) {
+                                       utf_count = 4;
+                                       utf_char = (c & 0x03);
+                               } else if ((c & 0xfe) == 0xfc) {
+                                       utf_count = 5;
+                                       utf_char = (c & 0x01);
+                               } else
+                                       utf_count = 0;
+                               continue;
+                       }
+               } else {                                /* not part of multi-byte sequence - treat as ASCII
+                                                                  * this makes incomplete sequences to be ignored
+                                                                */
+                       tc = c;
+                       utf_count = 0;
+               }
+       }
+       while (utf_count);
+
+       return tc;
+}
diff --git a/loadfont.c b/loadfont.c
new file mode 100644 (file)
index 0000000..d665001
--- /dev/null
@@ -0,0 +1,209 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * loadfont.c - Eugene Crosser & Andries Brouwer
+ *
+ * Version 0.96bb
+ *
+ * Loads the console font, and possibly the corresponding screen map(s).
+ * (Adapted for busybox by Matej Vela.)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/kd.h>
+#include <endian.h>
+#include "busybox.h"
+
+static const int PSF_MAGIC1 = 0x36;
+static const int PSF_MAGIC2 = 0x04;
+
+static const int PSF_MODE512 = 0x01;
+static const int PSF_MODEHASTAB = 0x02;
+static const int PSF_MAXMODE = 0x03;
+static const int PSF_SEPARATOR = 0xFFFF;
+
+struct psf_header {
+       unsigned char magic1, magic2;   /* Magic number */
+       unsigned char mode;                     /* PSF font mode */
+       unsigned char charsize;         /* Character size */
+};
+
+#define PSF_MAGIC_OK(x)        ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2)
+
+static void loadnewfont(int fd);
+
+extern int loadfont_main(int argc, char **argv)
+{
+       int fd;
+
+       if (argc != 1)
+               show_usage();
+
+       fd = open(CURRENT_VC, O_RDWR);
+       if (fd < 0)
+               perror_msg_and_die("Error opening " CURRENT_VC);
+       loadnewfont(fd);
+
+       return EXIT_SUCCESS;
+}
+
+static void do_loadfont(int fd, char *inbuf, int unit, int fontsize)
+{
+       char buf[16384];
+       int i;
+
+       memset(buf, 0, sizeof(buf));
+
+       if (unit < 1 || unit > 32)
+               error_msg_and_die("Bad character size %d", unit);
+
+       for (i = 0; i < fontsize; i++)
+               memcpy(buf + (32 * i), inbuf + (unit * i), unit);
+
+#if defined( PIO_FONTX ) && !defined( __sparc__ )
+       {
+               struct consolefontdesc cfd;
+
+               cfd.charcount = fontsize;
+               cfd.charheight = unit;
+               cfd.chardata = buf;
+
+               if (ioctl(fd, PIO_FONTX, &cfd) == 0)
+                       return;                         /* success */
+               perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)");
+       }
+#endif
+       if (ioctl(fd, PIO_FONT, buf))
+               perror_msg_and_die("PIO_FONT ioctl error");
+}
+
+static void
+do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
+{
+       struct unimapinit advice;
+       struct unimapdesc ud;
+       struct unipair *up;
+       int ct = 0, maxct;
+       int glyph;
+       u_short unicode;
+
+       maxct = tailsz;                         /* more than enough */
+       up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair));
+
+       for (glyph = 0; glyph < fontsize; glyph++) {
+               while (tailsz >= 2) {
+                       unicode = (((u_short) inbuf[1]) << 8) + inbuf[0];
+                       tailsz -= 2;
+                       inbuf += 2;
+                       if (unicode == PSF_SEPARATOR)
+                               break;
+                       up[ct].unicode = unicode;
+                       up[ct].fontpos = glyph;
+                       ct++;
+               }
+       }
+
+       /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP
+          this printf did not work on many kernels */
+
+       advice.advised_hashsize = 0;
+       advice.advised_hashstep = 0;
+       advice.advised_hashlevel = 0;
+       if (ioctl(fd, PIO_UNIMAPCLR, &advice)) {
+#ifdef ENOIOCTLCMD
+               if (errno == ENOIOCTLCMD) {
+                       error_msg("It seems this kernel is older than 1.1.92");
+                       error_msg_and_die("No Unicode mapping table loaded.");
+               } else
+#endif
+                       perror_msg_and_die("PIO_UNIMAPCLR");
+       }
+       ud.entry_ct = ct;
+       ud.entries = up;
+       if (ioctl(fd, PIO_UNIMAP, &ud)) {
+#if 0
+               if (errno == ENOMEM) {
+                       /* change advice parameters */
+               }
+#endif
+               perror_msg_and_die("PIO_UNIMAP");
+       }
+}
+
+static void loadnewfont(int fd)
+{
+       int unit;
+       char inbuf[32768];                      /* primitive */
+       unsigned int inputlth, offset;
+
+       /*
+        * We used to look at the length of the input file
+        * with stat(); now that we accept compressed files,
+        * just read the entire file.
+        */
+       inputlth = fread(inbuf, 1, sizeof(inbuf), stdin);
+       if (ferror(stdin))
+               perror_msg_and_die("Error reading input font");
+       /* use malloc/realloc in case of giant files;
+          maybe these do not occur: 16kB for the font,
+          and 16kB for the map leaves 32 unicode values
+          for each font position */
+       if (!feof(stdin))
+               perror_msg_and_die("Font too large");
+
+       /* test for psf first */
+       {
+               struct psf_header psfhdr;
+               int fontsize;
+               int hastable;
+               unsigned int head0, head;
+
+               if (inputlth < sizeof(struct psf_header))
+                       goto no_psf;
+
+               psfhdr = *(struct psf_header *) &inbuf[0];
+
+               if (!PSF_MAGIC_OK(psfhdr))
+                       goto no_psf;
+
+               if (psfhdr.mode > PSF_MAXMODE)
+                       error_msg_and_die("Unsupported psf file mode");
+               fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256);
+#if !defined( PIO_FONTX ) || defined( __sparc__ )
+               if (fontsize != 256)
+                       error_msg_and_die("Only fontsize 256 supported");
+#endif
+               hastable = (psfhdr.mode & PSF_MODEHASTAB);
+               unit = psfhdr.charsize;
+               head0 = sizeof(struct psf_header);
+
+               head = head0 + fontsize * unit;
+               if (head > inputlth || (!hastable && head != inputlth))
+                       error_msg_and_die("Input file: bad length");
+               do_loadfont(fd, inbuf + head0, unit, fontsize);
+               if (hastable)
+                       do_loadtable(fd, inbuf + head, inputlth - head, fontsize);
+               return;
+       }
+  no_psf:
+
+       /* file with three code pages? */
+       if (inputlth == 9780) {
+               offset = 40;
+               unit = 16;
+       } else {
+               /* bare font */
+               if (inputlth & 0377)
+                       error_msg_and_die("Bad input file size");
+               offset = 0;
+               unit = inputlth / 256;
+       }
+       do_loadfont(fd, inbuf + offset, unit, 256);
+}
diff --git a/loadkmap.c b/loadkmap.c
new file mode 100644 (file)
index 0000000..4f217d6
--- /dev/null
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini loadkmap implementation for busybox
+ *
+ * Copyright (C) 1998 Enrique Zanardi <ezanardi@ull.es>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+#define BINARY_KEYMAP_MAGIC "bkeymap"
+
+/* From <linux/kd.h> */
+struct kbentry {
+       unsigned char kb_table;
+       unsigned char kb_index;
+       unsigned short kb_value;
+};
+static const int KDSKBENT = 0x4B47;  /* sets one entry in translation table */
+
+/* From <linux/keyboard.h> */
+static const int NR_KEYS = 128;
+static const int MAX_NR_KEYMAPS = 256;
+
+int loadkmap_main(int argc, char **argv)
+{
+       struct kbentry ke;
+       u_short *ibuff;
+       int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short);
+       char flags[MAX_NR_KEYMAPS], buff[7];
+
+       if (argc != 1)
+               show_usage();
+
+       fd = open(CURRENT_VC, O_RDWR);
+       if (fd < 0)
+               perror_msg_and_die("Error opening " CURRENT_VC);
+
+       read(0, buff, 7);
+       if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7))
+               error_msg_and_die("This is not a valid binary keymap.");
+
+       if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS))
+               perror_msg_and_die("Error reading keymap flags");
+
+       ibuff = (u_short *) xmalloc(ibuffsz);
+
+       for (i = 0; i < MAX_NR_KEYMAPS; i++) {
+               if (flags[i] == 1) {
+                       pos = 0;
+                       while (pos < ibuffsz) {
+                               if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0)
+                                       perror_msg_and_die("Error reading keymap");
+                               pos += readsz;
+                       }
+                       for (j = 0; j < NR_KEYS; j++) {
+                               ke.kb_index = j;
+                               ke.kb_table = i;
+                               ke.kb_value = ibuff[j];
+                               ioctl(fd, KDSKBENT, &ke);
+                       }
+               }
+       }
+       /* Don't bother to close files.  Exit does that 
+        * automagically, so we can save a few bytes */
+       /* close(fd); */
+       return EXIT_SUCCESS;
+}
diff --git a/logger.c b/logger.c
new file mode 100644 (file)
index 0000000..37155c9
--- /dev/null
+++ b/logger.c
@@ -0,0 +1,200 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini logger implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+#if !defined BB_SYSLOGD
+
+#define SYSLOG_NAMES
+#include <sys/syslog.h>
+
+#else
+#include <sys/syslog.h>
+#  ifndef __dietlibc__
+       /* We have to do this since the header file defines static
+        * structures.  Argh.... bad libc, bad, bad...
+        */
+       typedef struct _code {
+               char *c_name;
+               int c_val;
+       } CODE;
+       extern CODE prioritynames[];
+       extern CODE facilitynames[];
+#  endif
+#endif
+
+/* Decode a symbolic name to a numeric value 
+ * this function is based on code
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California.  All rights reserved.
+ *  
+ * Original copyright notice is retained at the end of this file.
+ */
+static int decode(char *name, CODE * codetab)
+{
+       CODE *c;
+
+       if (isdigit(*name))
+               return (atoi(name));
+       for (c = codetab; c->c_name; c++) {
+               if (!strcasecmp(name, c->c_name)) {
+                       return (c->c_val);
+               }
+       }
+
+       return (-1);
+}
+
+/* Decode a symbolic name to a numeric value 
+ * this function is based on code
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+static int pencode(char *s)
+{
+       char *save;
+       int lev, fac = LOG_USER;
+
+       for (save = s; *s && *s != '.'; ++s);
+       if (*s) {
+               *s = '\0';
+               fac = decode(save, facilitynames);
+               if (fac < 0)
+                       error_msg_and_die("unknown facility name: %s", save);
+               *s++ = '.';
+       } else {
+               s = save;
+       }
+       lev = decode(s, prioritynames);
+       if (lev < 0)
+               error_msg_and_die("unknown priority name: %s", save);
+       return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+}
+
+
+extern int logger_main(int argc, char **argv)
+{
+       int pri = LOG_USER | LOG_NOTICE;
+       int option = 0;
+       int c, i, len, opt;
+       char *message=NULL, buf[1024], name[128];
+
+       /* Fill out the name string early (may be overwritten later) */
+       my_getpwuid(name, geteuid());
+
+       /* Parse any options */
+       while ((opt = getopt(argc, argv, "p:st:")) > 0) {
+               switch (opt) {
+                       case 's':
+                               option |= LOG_PERROR;
+                               break;
+                       case 'p':
+                               pri = pencode(optarg);
+                               break;
+                       case 't':
+                               strncpy(name, optarg, sizeof(name));
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       openlog(name, option, (pri | LOG_FACMASK));
+       if (optind == argc) {
+               do {
+                       /* read from stdin */
+                       i = 0;
+                       while ((c = getc(stdin)) != EOF && c != '\n' && 
+                                       i < (sizeof(buf)-1)) {
+                               buf[i++] = c;
+                       }
+                       if (i > 0) {
+                               buf[i++] = '\0';
+                               syslog(pri, "%s", buf);
+                       }
+               } while (c != EOF);
+       } else {
+               len = 1; /* for the '\0' */
+               message=xcalloc(1, 1);
+               for (i = optind; i < argc; i++) {
+                       len += strlen(argv[i]);
+                       len += 1;  /* for the space between the args */
+                       message = xrealloc(message, len);
+                       strcat(message, argv[i]);
+                       strcat(message, " ");
+               }
+               message[strlen(message)-1] = '\0';
+               syslog(pri, "%s", message);
+       }
+
+       closelog();
+       return EXIT_SUCCESS;
+}
+
+
+/*-
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This is the original license statement for the decode and pencode functions.
+ *
+ * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ */
+
+
+
diff --git a/logname.c b/logname.c
new file mode 100644 (file)
index 0000000..0924b24
--- /dev/null
+++ b/logname.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini logname implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int logname_main(int argc, char **argv)
+{
+       char user[9];
+
+       if (argc > 1)
+               show_usage();
+
+       my_getpwuid(user, geteuid());
+       if (*user) {
+               puts(user);
+               return EXIT_SUCCESS;
+       }
+       error_msg_and_die("no login name");
+}
diff --git a/logread.c b/logread.c
new file mode 100644 (file)
index 0000000..d334962
--- /dev/null
+++ b/logread.c
@@ -0,0 +1,144 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * circular buffer syslog implementation for busybox
+ *
+ * Copyright (C) 2000 by Gennady Feldman <gfeldman@cachier.com>
+ *
+ * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/types.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <signal.h>
+#include <setjmp.h>
+#include "busybox.h"
+
+#if __GNU_LIBRARY__ < 5
+#error Sorry.  Looks like you are using libc5.  
+#error libc5 shm support isnt good enough.
+#error Please disable BB_FEATURE_IPC_SYSLOG 
+#endif 
+
+
+static const long KEY_ID = 0x414e4547; /*"GENA"*/
+
+static struct shbuf_ds {
+       int size;               // size of data written
+       int head;               // start of message list
+       int tail;               // end of message list
+       char data[1];           // data/messages
+} *buf = NULL;                 // shared memory pointer
+
+
+// Semaphore operation structures
+static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup
+static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn
+
+static int     log_shmid = -1; // ipc shared memory id
+static int     log_semid = -1; // ipc semaphore id
+static jmp_buf jmp_env;
+
+static void error_exit(const char *str);
+static void interrupted(int sig);
+
+/*
+ * sem_up - up()'s a semaphore.
+ */
+static inline void sem_up(int semid)
+{
+       if ( semop(semid, SMrup, 1) == -1 ) 
+               error_exit("semop[SMrup]");
+}
+
+/*
+ * sem_down - down()'s a semaphore
+ */                            
+static inline void sem_down(int semid)
+{
+       if ( semop(semid, SMrdn, 2) == -1 )
+               error_exit("semop[SMrdn]");
+}
+
+extern int logread_main(int argc, char **argv)
+{
+       int i;
+       
+       /* no options, no getopt */
+       if (argc > 1)
+               show_usage();
+       
+       // handle intrrupt signal
+       if (setjmp(jmp_env)) goto output_end;
+       
+       // attempt to redefine ^C signal
+       signal(SIGINT, interrupted);
+       
+       if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1)
+               error_exit("Can't find circular buffer");
+       
+       // Attach shared memory to our char*
+       if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL)
+               error_exit("Can't get access to circular buffer from syslogd");
+
+       if ( (log_semid = semget(KEY_ID, 0, 0)) == -1)
+               error_exit("Can't get access to semaphone(s) for circular buffer from syslogd");
+
+       sem_down(log_semid);    
+       // Read Memory 
+       i=buf->head;
+
+       //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size);
+       if (buf->head == buf->tail) {
+               printf("<empty syslog>\n");
+       }
+       
+       while ( i != buf->tail) {
+               printf("%s", buf->data+i);
+               i+= strlen(buf->data+i) + 1;
+               if (i >= buf->size )
+                       i=0;
+       }
+       sem_up(log_semid);
+
+output_end:
+       if (log_shmid != -1) 
+               shmdt(buf);
+               
+       return EXIT_SUCCESS;            
+}
+
+static void interrupted(int sig){
+       signal(SIGINT, SIG_IGN);
+       longjmp(jmp_env, 1);
+}
+
+static void error_exit(const char *str){
+       perror(str);
+       //release all acquired resources
+       if (log_shmid != -1) 
+               shmdt(buf);
+
+       exit(1);
+}
diff --git a/losetup.c b/losetup.c
new file mode 100644 (file)
index 0000000..bfeb6b2
--- /dev/null
+++ b/losetup.c
@@ -0,0 +1,58 @@
+/*
+ * Mini losetup implementation for busybox
+ *
+ * Copyright (C) 2002  Matt Kraai.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+int
+losetup_main (int argc, char **argv)
+{
+  int delete = 0;
+  int offset = 0;
+  int opt;
+
+  while ((opt = getopt (argc, argv, "do:")) != -1)
+    switch (opt)
+      {
+      case 'd':
+       delete = 1;
+       break;
+
+      case 'o':
+       offset = parse_number (optarg, NULL);
+       break;
+
+      default:
+       show_usage ();
+      }
+
+  if ((delete && (offset || optind + 1 != argc))
+      || (!delete && optind + 2 != argc))
+    show_usage ();
+
+  if (delete)
+    return del_loop (argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE;
+  else
+    return set_loop (argv[optind], argv[optind + 1], offset, &opt)
+      ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/ls.c b/ls.c
new file mode 100644 (file)
index 0000000..360b95c
--- /dev/null
+++ b/ls.c
@@ -0,0 +1,1001 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tiny-ls.c version 0.1.0: A minimalist 'ls'
+ * Copyright (C) 1996 Brian Candler <B.Candler@pobox.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * To achieve a small memory footprint, this version of 'ls' doesn't do any
+ * file sorting, and only has the most essential command line switches
+ * (i.e., the ones I couldn't live without :-) All features which involve
+ * linking in substantial chunks of libc can be disabled.
+ *
+ * Although I don't really want to add new features to this program to
+ * keep it small, I *am* interested to receive bug fixes and ways to make
+ * it more portable.
+ *
+ * KNOWN BUGS:
+ * 1. ls -l of a directory doesn't give "total <blocks>" header
+ * 2. ls of a symlink to a directory doesn't list directory contents
+ * 3. hidden files can make column width too large
+ *
+ * NON-OPTIMAL BEHAVIOUR:
+ * 1. autowidth reads directories twice
+ * 2. if you do a short directory listing without filetype characters
+ *    appended, there's no need to stat each one
+ * PORTABILITY:
+ * 1. requires lstat (BSD) - how do you do it without?
+ */
+
+enum {
+       TERMINAL_WIDTH = 80,            /* use 79 if terminal has linefold bug */
+       COLUMN_WIDTH = 14,                      /* default if AUTOWIDTH not defined */
+       COLUMN_GAP = 2,                         /* includes the file type char */
+};
+
+
+/************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+#include <time.h>
+#endif
+
+#ifndef MAJOR
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
+
+/* what is the overall style of the listing */
+enum {
+STYLE_AUTO = 0,
+STYLE_LONG = 1,                /* one record per line, extended info */
+STYLE_SINGLE = 2,              /* one record per line */
+STYLE_COLUMNS = 3              /* fill columns */
+};
+
+/* 51306 lrwxrwxrwx  1 root     root         2 May 11 01:43 /bin/view -> vi* */
+/* what file information will be listed */
+#define LIST_INO               (1<<0)
+#define LIST_BLOCKS            (1<<1)
+#define LIST_MODEBITS  (1<<2)
+#define LIST_NLINKS            (1<<3)
+#define LIST_ID_NAME   (1<<4)
+#define LIST_ID_NUMERIC        (1<<5)
+#define LIST_SIZE              (1<<6)
+#define LIST_DEV               (1<<7)
+#define LIST_DATE_TIME (1<<8)
+#define LIST_FULLTIME  (1<<9)
+#define LIST_FILENAME  (1<<10)
+#define LIST_SYMLINK   (1<<11)
+#define LIST_FILETYPE  (1<<12)
+#define LIST_EXEC              (1<<13)
+
+/* what files will be displayed */
+#define DISP_NORMAL            (0)             /* show normal filenames */
+#define DISP_DIRNAME   (1<<0)  /* 2 or more items? label directories */
+#define DISP_HIDDEN            (1<<1)  /* show filenames starting with .  */
+#define DISP_DOT               (1<<2)  /* show . and .. */
+#define DISP_NOLIST            (1<<3)  /* show directory as itself, not contents */
+#define DISP_RECURSIVE (1<<4)  /* show directory and everything below it */
+#define DISP_ROWS              (1<<5)  /* print across rows */
+
+#ifdef BB_FEATURE_LS_SORTFILES
+/* how will the files be sorted */
+static const int SORT_FORWARD = 0;             /* sort in reverse order */
+static const int SORT_REVERSE = 1;             /* sort in reverse order */
+static const int SORT_NAME = 2;                /* sort by file name */
+static const int SORT_SIZE = 3;                /* sort by file size */
+static const int SORT_ATIME = 4;               /* sort by last access time */
+static const int SORT_CTIME = 5;               /* sort by last change time */
+static const int SORT_MTIME = 6;               /* sort by last modification time */
+static const int SORT_VERSION = 7;             /* sort by version */
+static const int SORT_EXT = 8;         /* sort by file name extension */
+static const int SORT_DIR = 9;         /* sort by file or directory */
+#endif
+
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+/* which of the three times will be used */
+static const int TIME_MOD = 0;
+static const int TIME_CHANGE = 1;
+static const int TIME_ACCESS = 2;
+#endif
+
+#define LIST_SHORT             (LIST_FILENAME)
+#define LIST_ISHORT            (LIST_INO | LIST_FILENAME)
+#define LIST_LONG              (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | \
+                                               LIST_SIZE | LIST_DATE_TIME | LIST_FILENAME | \
+                                               LIST_SYMLINK)
+#define LIST_ILONG             (LIST_INO | LIST_LONG)
+
+static const int SPLIT_DIR = 0;
+static const int SPLIT_FILE = 1;
+static const int SPLIT_SUBDIR = 2;
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR)
+#define APPCHAR(mode)   ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
+#endif
+/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
+#ifdef BB_FEATURE_LS_COLOR
+static int show_color = 0;
+#define COLOR(mode)   ("\000\043\043\043\042\000\043\043"\
+                                          "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
+#define ATTR(mode)   ("\00\00\01\00\01\00\01\00"\
+                                         "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
+#endif
+
+/*
+ * a directory entry and its stat info are stored here
+ */
+struct dnode {                         /* the basic node */
+    char *name;                                /* the dir entry name */
+    char *fullname;                    /* the dir entry name */
+    struct stat dstat;         /* the file stat info */
+    struct dnode *next;                /* point at the next node */
+};
+typedef struct dnode dnode_t;
+
+static struct dnode **list_dir(char *);
+static struct dnode **dnalloc(int);
+static int list_single(struct dnode *);
+
+static unsigned int disp_opts;
+static unsigned int style_fmt;
+static unsigned int list_fmt;
+#ifdef BB_FEATURE_LS_SORTFILES
+static unsigned int sort_opts;
+static unsigned int sort_order;
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+static unsigned int time_fmt;
+#endif
+#ifdef BB_FEATURE_LS_FOLLOWLINKS
+static unsigned int follow_links=FALSE;
+#endif
+
+static unsigned short column = 0;
+#ifdef BB_FEATURE_AUTOWIDTH
+static unsigned short terminal_width = TERMINAL_WIDTH;
+static unsigned short column_width = COLUMN_WIDTH;
+static unsigned short tabstops = COLUMN_GAP;
+#else
+static unsigned short column_width = COLUMN_WIDTH;
+#endif
+
+static int status = EXIT_SUCCESS;
+
+#ifdef BB_FEATURE_HUMAN_READABLE
+static unsigned long ls_disp_hr = 0;
+#endif
+
+static int my_stat(struct dnode *cur)
+{
+#ifdef BB_FEATURE_LS_FOLLOWLINKS
+       if (follow_links == TRUE) {
+               if (stat(cur->fullname, &cur->dstat)) {
+                       perror_msg("%s", cur->fullname);
+                       status = EXIT_FAILURE;
+                       free(cur->fullname);
+                       free(cur);
+                       return -1;
+               }
+       } else
+#endif
+       if (lstat(cur->fullname, &cur->dstat)) {
+               perror_msg("%s", cur->fullname);
+               status = EXIT_FAILURE;
+               free(cur->fullname);
+               free(cur);
+               return -1;
+       }
+       return 0;
+}
+
+static void newline(void)
+{
+    if (column > 0) {
+        putchar('\n');
+        column = 0;
+    }
+}
+
+/*----------------------------------------------------------------------*/
+#ifdef BB_FEATURE_LS_COLOR
+static char fgcolor(mode_t mode)
+{
+       /* Check if the file is missing */
+       if ( errno == ENOENT ) {
+               errno = 0;
+               /* Color it red! */
+           return '\037';
+       }
+       if ( LIST_EXEC && S_ISREG( mode )
+           && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) ) 
+               return COLOR(0xF000);   /* File is executable ... */
+       return COLOR(mode);
+}
+
+/*----------------------------------------------------------------------*/
+static char bgcolor(mode_t mode)
+{
+       if ( LIST_EXEC && S_ISREG( mode )
+           && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) ) 
+               return ATTR(0xF000);    /* File is executable ... */
+       return ATTR(mode);
+}
+#endif
+
+/*----------------------------------------------------------------------*/
+#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR)
+static char append_char(mode_t mode)
+{
+       if ( !(list_fmt & LIST_FILETYPE))
+               return '\0';
+       if ((list_fmt & LIST_EXEC) && S_ISREG(mode)
+           && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*';
+               return APPCHAR(mode);
+}
+#endif
+
+/*----------------------------------------------------------------------*/
+static void nexttabstop( void )
+{
+       static short nexttab= 0;
+       int n=0;
+
+       if (column > 0) {
+               n= nexttab - column;
+               if (n < 1) n= 1;
+               while (n--) {
+                       putchar(' ');
+                       column++;
+               }
+       }
+       nexttab= column + column_width + COLUMN_GAP; 
+}
+
+/*----------------------------------------------------------------------*/
+static int is_subdir(struct dnode *dn)
+{
+       return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 &&
+                       strcmp(dn->name, "..") != 0);
+}
+
+static int countdirs(struct dnode **dn, int nfiles)
+{
+       int i, dirs;
+
+       if (dn==NULL || nfiles < 1) return(0);
+       dirs= 0;
+       for (i=0; i<nfiles; i++) {
+               if (S_ISDIR(dn[i]->dstat.st_mode)) dirs++;
+       }
+       return(dirs);
+}
+
+static int countsubdirs(struct dnode **dn, int nfiles)
+{
+       int i, subdirs;
+
+       if (dn == NULL || nfiles < 1) return 0;
+       subdirs = 0;
+       for (i = 0; i < nfiles; i++)
+               if (is_subdir(dn[i]))
+                       subdirs++;
+       return subdirs;
+}
+
+static int countfiles(struct dnode **dnp)
+{
+       int nfiles;
+       struct dnode *cur;
+
+       if (dnp == NULL) return(0);
+       nfiles= 0;
+       for (cur= dnp[0];  cur->next != NULL ; cur= cur->next) nfiles++;
+       nfiles++;
+       return(nfiles);
+}
+
+/* get memory to hold an array of pointers */
+static struct dnode **dnalloc(int num)
+{
+       struct dnode **p;
+
+       if (num < 1) return(NULL);
+
+       p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *)));
+       return(p);
+}
+
+#ifdef BB_FEATURE_LS_RECURSIVE
+static void dfree(struct dnode **dnp)
+{
+       struct dnode *cur, *next;
+
+       if(dnp == NULL) return;
+
+       cur=dnp[0];
+       while (cur != NULL) {
+               if (cur->fullname != NULL) free(cur->fullname); /* free the filename */
+               next= cur->next;
+               free(cur);                              /* free the dnode */
+               cur= next;
+       }
+       free(dnp);      /* free the array holding the dnode pointers */
+}
+#endif
+
+static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
+{
+       int dncnt, i, d;
+       struct dnode **dnp;
+
+       if (dn==NULL || nfiles < 1) return(NULL);
+
+       /* count how many dirs and regular files there are */
+       if (which == SPLIT_SUBDIR)
+               dncnt = countsubdirs(dn, nfiles);
+       else {
+               dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */
+               if (which == SPLIT_FILE)
+                       dncnt= nfiles - dncnt;  /* looking for files */
+       }
+
+       /* allocate a file array and a dir array */
+       dnp= dnalloc(dncnt);
+
+       /* copy the entrys into the file or dir array */
+       for (d= i=0; i<nfiles; i++) {
+               if (which == SPLIT_DIR) {
+                       if (S_ISDIR(dn[i]->dstat.st_mode)) {
+                               dnp[d++]= dn[i];
+                       }  /* else skip the file */
+               } else if (which == SPLIT_SUBDIR) {
+                       if (is_subdir(dn[i])) {
+                               dnp[d++]= dn[i];
+                       }  /* else skip the file or dir */
+               } else {
+                       if (!(S_ISDIR(dn[i]->dstat.st_mode))) {
+                               dnp[d++]= dn[i];
+                       }  /* else skip the dir */
+               }
+       }
+       return(dnp);
+}
+
+/*----------------------------------------------------------------------*/
+#ifdef BB_FEATURE_LS_SORTFILES
+static int sortcmp(struct dnode *d1, struct dnode *d2)
+{
+       int cmp, dif;
+
+       cmp= 0;
+       if (sort_opts == SORT_SIZE) {
+               dif= (int)(d1->dstat.st_size - d2->dstat.st_size);
+       } else if (sort_opts == SORT_ATIME) {
+               dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime);
+       } else if (sort_opts == SORT_CTIME) {
+               dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime);
+       } else if (sort_opts == SORT_MTIME) {
+               dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime);
+       } else if (sort_opts == SORT_DIR) {
+               dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode);
+       /* } else if (sort_opts == SORT_VERSION) { */
+       /* } else if (sort_opts == SORT_EXT) { */
+       } else {    /* assume SORT_NAME */
+               dif= 0;
+       }
+
+       if (dif > 0) cmp= -1;
+       if (dif < 0) cmp=  1;
+       if (dif == 0) {
+               /* sort by name- may be a tie_breaker for time or size cmp */
+               dif= strcmp(d1->name, d2->name);
+               if (dif > 0) cmp=  1;
+               if (dif < 0) cmp= -1;
+       }
+
+       if (sort_order == SORT_REVERSE) {
+               cmp=  -1 * cmp;
+       }
+       return(cmp);
+}
+
+/*----------------------------------------------------------------------*/
+static void shellsort(struct dnode **dn, int size)
+{
+       struct dnode *temp;
+       int gap, i, j;
+
+       /* shell short the array */
+       if(dn==NULL || size < 2) return;
+
+       for (gap= size/2; gap>0; gap /=2) {
+               for (i=gap; i<size; i++) {
+                       for (j= i-gap; j>=0; j-=gap) {
+                               if (sortcmp(dn[j], dn[j+gap]) <= 0)
+                                       break;
+                               /* they are out of order, swap them */
+                               temp= dn[j];
+                               dn[j]= dn[j+gap];
+                               dn[j+gap]= temp;
+                       }
+               }
+       }
+}
+#endif
+
+/*----------------------------------------------------------------------*/
+static void showfiles(struct dnode **dn, int nfiles)
+{
+       int i, ncols, nrows, row, nc;
+#ifdef BB_FEATURE_AUTOWIDTH
+       int len;
+#endif
+
+       if(dn==NULL || nfiles < 1) return;
+
+#ifdef BB_FEATURE_AUTOWIDTH
+       /* find the longest file name-  use that as the column width */
+       column_width= 0;
+       for (i=0; i<nfiles; i++) {
+               len= strlen(dn[i]->name) +
+                       ((list_fmt & LIST_INO) ? 8 : 0) +
+                       ((list_fmt & LIST_BLOCKS) ? 5 : 0)
+                       ;
+               if (column_width < len) 
+                       column_width= len;
+       }
+       if (column_width >= 1)
+               ncols = (int)(terminal_width / (column_width + COLUMN_GAP));
+       else {
+               ncols = 1;
+               column_width = COLUMN_WIDTH;
+       }
+#else
+       ncols= TERMINAL_WIDTH;
+#endif
+       switch (style_fmt) {
+               case STYLE_LONG:        /* one record per line, extended info */
+               case STYLE_SINGLE:      /* one record per line */
+                       ncols= 1;
+                       break;
+       }
+
+       if (ncols > 1) {
+               nrows = nfiles / ncols;
+       } else {
+               nrows = nfiles;
+               ncols = 1;
+       }
+       if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */
+
+       if (nrows > nfiles) nrows= nfiles;
+       for (row=0; row<nrows; row++) {
+               for (nc=0; nc<ncols; nc++) {
+                       /* reach into the array based on the column and row */
+                       i= (nc * nrows) + row;          /* assume display by column */
+                       if (disp_opts & DISP_ROWS)
+                               i= (row * ncols) + nc;  /* display across row */
+                       if (i < nfiles) {
+                               nexttabstop();
+                               list_single(dn[i]);
+                       }
+               }
+               newline();
+       }
+}
+
+/*----------------------------------------------------------------------*/
+static void showdirs(struct dnode **dn, int ndirs)
+{
+       int i, nfiles;
+       struct dnode **subdnp;
+#ifdef BB_FEATURE_LS_RECURSIVE
+       int dndirs;
+       struct dnode **dnd;
+#endif
+
+       if (dn==NULL || ndirs < 1) return;
+
+       for (i=0; i<ndirs; i++) {
+               if (disp_opts & (DISP_DIRNAME | DISP_RECURSIVE)) {
+                       printf("\n%s:\n", dn[i]->fullname);
+               }
+               subdnp= list_dir(dn[i]->fullname);
+               nfiles= countfiles(subdnp);
+               if (nfiles > 0) {
+                       /* list all files at this level */
+#ifdef BB_FEATURE_LS_SORTFILES
+                       shellsort(subdnp, nfiles);
+#endif
+                       showfiles(subdnp, nfiles);
+#ifdef BB_FEATURE_LS_RECURSIVE
+                       if (disp_opts & DISP_RECURSIVE) {
+                               /* recursive- list the sub-dirs */
+                               dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
+                               dndirs= countsubdirs(subdnp, nfiles);
+                               if (dndirs > 0) {
+#ifdef BB_FEATURE_LS_SORTFILES
+                                       shellsort(dnd, dndirs);
+#endif
+                                       showdirs(dnd, dndirs);
+                                       free(dnd);  /* free the array of dnode pointers to the dirs */
+                               }
+                       }
+                       dfree(subdnp);  /* free the dnodes and the fullname mem */
+#endif
+               }
+       }
+}
+
+/*----------------------------------------------------------------------*/
+static struct dnode **list_dir(char *path)
+{
+       struct dnode *dn, *cur, **dnp;
+       struct dirent *entry;
+       DIR *dir;
+       int i, nfiles;
+
+       if (path==NULL) return(NULL);
+
+       dn= NULL;
+       nfiles= 0;
+       dir = opendir(path);
+       if (dir == NULL) {
+               perror_msg("%s", path);
+               status = EXIT_FAILURE;
+               return(NULL);   /* could not open the dir */
+       }
+       while ((entry = readdir(dir)) != NULL) {
+               /* are we going to list the file- it may be . or .. or a hidden file */
+               if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT))
+                       continue;
+               if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT))
+                       continue;
+               if ((entry->d_name[0] ==  '.') && !(disp_opts & DISP_HIDDEN))
+                       continue;
+               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
+               cur->fullname = concat_path_file(path, entry->d_name);
+               cur->name = cur->fullname +
+                               (strlen(cur->fullname) - strlen(entry->d_name));
+               if (my_stat(cur))
+                       continue;
+               cur->next= dn;
+               dn= cur;
+               nfiles++;
+       }
+       closedir(dir);
+
+       /* now that we know how many files there are
+       ** allocate memory for an array to hold dnode pointers
+       */
+       if (nfiles < 1) return(NULL);
+       dnp= dnalloc(nfiles);
+       for (i=0, cur=dn; i<nfiles; i++) {
+               dnp[i]= cur;   /* save pointer to node in array */
+               cur= cur->next;
+       }
+
+       return(dnp);
+}
+
+/*----------------------------------------------------------------------*/
+static int list_single(struct dnode *dn)
+{
+       int i;
+#ifdef BB_FEATURE_LS_USERNAME
+       char scratch[BUFSIZ + 1];
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       char *filetime;
+       time_t ttime, age;
+#endif
+#if defined (BB_FEATURE_LS_FILETYPES) || defined (BB_FEATURE_LS_COLOR)
+       struct stat info;
+       char append;
+#endif
+
+       if (dn==NULL || dn->fullname==NULL) return(0);
+
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       ttime= dn->dstat.st_mtime;      /* the default time */
+       if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime;
+       if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime;
+       filetime= ctime(&ttime);
+#endif
+#ifdef BB_FEATURE_LS_FILETYPES
+       append = append_char(dn->dstat.st_mode);
+#endif
+
+       for (i=0; i<=31; i++) {
+               switch (list_fmt & (1<<i)) {
+                       case LIST_INO:
+                               printf("%7ld ", (long int)dn->dstat.st_ino);
+                               column += 8;
+                               break;
+                       case LIST_BLOCKS:
+#ifdef BB_FEATURE_HUMAN_READABLE
+                               fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, 
+                                                       KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE));
+#else
+#if _FILE_OFFSET_BITS == 64
+                               printf("%4lld ", dn->dstat.st_blocks>>1);
+#else
+                               printf("%4ld ", dn->dstat.st_blocks>>1);
+#endif
+#endif
+                               column += 5;
+                               break;
+                       case LIST_MODEBITS:
+                               printf("%-10s ", (char *)mode_string(dn->dstat.st_mode));
+                               column += 10;
+                               break;
+                       case LIST_NLINKS:
+                               printf("%4ld ", (long)dn->dstat.st_nlink);
+                               column += 10;
+                               break;
+                       case LIST_ID_NAME:
+#ifdef BB_FEATURE_LS_USERNAME
+                               my_getpwuid(scratch, dn->dstat.st_uid);
+                               printf("%-8.8s ", scratch);
+                               my_getgrgid(scratch, dn->dstat.st_gid);
+                               printf("%-8.8s", scratch);
+                               column += 17;
+                               break;
+#endif
+                       case LIST_ID_NUMERIC:
+                               printf("%-8ld %-8ld", (long)dn->dstat.st_uid, (long)dn->dstat.st_gid);
+                               column += 17;
+                               break;
+                       case LIST_SIZE:
+                       case LIST_DEV:
+                               if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
+                                       printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev));
+                               } else {
+#ifdef BB_FEATURE_HUMAN_READABLE
+                                       if (ls_disp_hr==TRUE) {
+                                               fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0));
+                                       } else 
+#endif 
+                                       {
+#if _FILE_OFFSET_BITS == 64
+                                               printf("%9lld ", (long long)dn->dstat.st_size);
+#else
+                                               printf("%9ld ", dn->dstat.st_size);
+#endif
+                                       }
+                               }
+                               column += 10;
+                               break;
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+                       case LIST_FULLTIME:
+                       case LIST_DATE_TIME:
+                               if (list_fmt & LIST_FULLTIME) {
+                                       printf("%24.24s ", filetime);
+                                       column += 25;
+                                       break;
+                               }
+                               age = time(NULL) - ttime;
+                               printf("%6.6s ", filetime+4);
+                               if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
+                                       /* hh:mm if less than 6 months old */
+                                       printf("%5.5s ", filetime+11);
+                               } else {
+                                       printf(" %4.4s ", filetime+20);
+                               }
+                               column += 13;
+                               break;
+#endif
+                       case LIST_FILENAME:
+#ifdef BB_FEATURE_LS_COLOR
+                               errno = 0;
+                               if (show_color && !lstat(dn->fullname, &info)) {
+                                   printf( "\033[%d;%dm", bgcolor(info.st_mode), 
+                                                               fgcolor(info.st_mode) );
+                               }
+#endif
+                               printf("%s", dn->name);
+#ifdef BB_FEATURE_LS_COLOR
+                               if (show_color) {
+                                       printf( "\033[0m" );
+                               }
+#endif
+                               column += strlen(dn->name);
+                               break;
+                       case LIST_SYMLINK:
+                               if (S_ISLNK(dn->dstat.st_mode)) {
+                                       char *lpath = xreadlink(dn->fullname);
+                                       if (lpath) {
+                                               printf(" -> ");
+#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR)
+                                               if (!stat(dn->fullname, &info)) {
+                                                       append = append_char(info.st_mode);
+                                               }
+#endif
+#ifdef BB_FEATURE_LS_COLOR
+                                               if (show_color) {
+                                                       errno = 0;
+                                                       printf( "\033[%d;%dm", bgcolor(info.st_mode), 
+                                                                       fgcolor(info.st_mode) );
+                                               }
+#endif
+                                               printf("%s", lpath);
+#ifdef BB_FEATURE_LS_COLOR
+                                               if (show_color) {
+                                                       printf( "\033[0m" );
+                                               }
+#endif
+                                               column += strlen(lpath) + 4;
+                                               free(lpath);
+                                       }
+                               }
+                               break;
+#ifdef BB_FEATURE_LS_FILETYPES
+                       case LIST_FILETYPE:
+                               if (append != '\0') {
+                                       printf("%1c", append);
+                                       column++;
+                               }
+                               break;
+#endif
+               }
+       }
+
+       return(0);
+}
+
+/*----------------------------------------------------------------------*/
+extern int ls_main(int argc, char **argv)
+{
+       struct dnode **dnf, **dnd;
+       int dnfiles, dndirs;
+       struct dnode *dn, *cur, **dnp;
+       int i, nfiles;
+       int opt;
+       int oi, ac;
+       char **av;
+#ifdef BB_FEATURE_AUTOWIDTH
+       struct winsize win = { 0, 0, 0, 0 };
+#endif
+
+       disp_opts= DISP_NORMAL;
+       style_fmt= STYLE_AUTO;
+       list_fmt=  LIST_SHORT;
+#ifdef BB_FEATURE_LS_SORTFILES
+       sort_opts= SORT_NAME;
+       sort_order=     SORT_FORWARD;
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       time_fmt= TIME_MOD;
+#endif
+#ifdef BB_FEATURE_AUTOWIDTH
+       ioctl(fileno(stdout), TIOCGWINSZ, &win);
+       if (win.ws_row > 4)
+               column_width = win.ws_row - 2;
+       if (win.ws_col > 0)
+               terminal_width = win.ws_col - 1;
+#endif
+       nfiles=0;
+
+#ifdef BB_FEATURE_LS_COLOR
+       if (isatty(fileno(stdout)))
+               show_color = 1;
+#endif
+
+       /* process options */
+       while ((opt = getopt(argc, argv, "1AaCdgilnsx"
+#ifdef BB_FEATURE_AUTOWIDTH
+"T:w:"
+#endif
+#ifdef BB_FEATURE_LS_FILETYPES
+"Fp"
+#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+"R"
+#endif
+#ifdef BB_FEATURE_LS_SORTFILES
+"rSvX"
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+"cetu"
+#endif
+#ifdef BB_FEATURE_LS_FOLLOWLINKS
+"L"
+#endif
+#ifdef BB_FEATURE_HUMAN_READABLE
+"h"
+#endif
+"k")) > 0) {
+               switch (opt) {
+                       case '1': style_fmt = STYLE_SINGLE; break;
+                       case 'A': disp_opts |= DISP_HIDDEN; break;
+                       case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break;
+                       case 'C': style_fmt = STYLE_COLUMNS; break;
+                       case 'd': disp_opts |= DISP_NOLIST; break;
+                       case 'g': /* ignore -- for ftp servers */ break;
+                       case 'i': list_fmt |= LIST_INO; break;
+                       case 'l':
+                               style_fmt = STYLE_LONG;
+                               list_fmt |= LIST_LONG;
+#ifdef BB_FEATURE_HUMAN_READABLE
+                               ls_disp_hr = FALSE;
+#endif
+                       break;
+                       case 'n': list_fmt |= LIST_ID_NUMERIC; break;
+                       case 's': list_fmt |= LIST_BLOCKS; break;
+                       case 'x': disp_opts = DISP_ROWS; break;
+#ifdef BB_FEATURE_LS_FILETYPES
+                       case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break;
+                       case 'p': list_fmt |= LIST_FILETYPE; break;
+#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+                       case 'R': disp_opts |= DISP_RECURSIVE; break;
+#endif
+#ifdef BB_FEATURE_LS_SORTFILES
+                       case 'r': sort_order |= SORT_REVERSE; break;
+                       case 'S': sort_opts= SORT_SIZE; break;
+                       case 'v': sort_opts= SORT_VERSION; break;
+                       case 'X': sort_opts= SORT_EXT; break;
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+                       case 'e': list_fmt |= LIST_FULLTIME; break;
+                       case 'c':
+                               time_fmt = TIME_CHANGE;
+#ifdef BB_FEATURE_LS_SORTFILES
+                               sort_opts= SORT_CTIME;
+#endif
+                               break;
+                       case 'u':
+                               time_fmt = TIME_ACCESS;
+#ifdef BB_FEATURE_LS_SORTFILES
+                               sort_opts= SORT_ATIME;
+#endif
+                               break;
+                       case 't':
+#ifdef BB_FEATURE_LS_SORTFILES
+                               sort_opts= SORT_MTIME;
+#endif
+                               break;
+#endif
+#ifdef BB_FEATURE_LS_FOLLOWLINKS
+                       case 'L': follow_links= TRUE; break;
+#endif
+#ifdef BB_FEATURE_AUTOWIDTH
+                       case 'T': tabstops= atoi(optarg); break;
+                       case 'w': terminal_width= atoi(optarg); break;
+#endif
+#ifdef BB_FEATURE_HUMAN_READABLE
+                       case 'h': ls_disp_hr = TRUE; break;
+#endif
+                       case 'k': break;
+                       default:
+                               goto print_usage_message;
+               }
+       }
+
+       /* sort out which command line options take precedence */
+#ifdef BB_FEATURE_LS_RECURSIVE
+       if (disp_opts & DISP_NOLIST)
+               disp_opts &= ~DISP_RECURSIVE;   /* no recurse if listing only dir */
+#endif
+#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES)
+       if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME;
+       if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME;
+#endif
+       if (style_fmt != STYLE_LONG)
+                       list_fmt &= ~LIST_ID_NUMERIC;  /* numeric uid only for long list */
+#ifdef BB_FEATURE_LS_USERNAME
+       if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC))
+                       list_fmt &= ~LIST_ID_NAME;  /* don't list names if numeric uid */
+#endif
+
+       /* choose a display format */
+       if (style_fmt == STYLE_AUTO)
+               style_fmt = isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE;
+
+       /*
+        * when there are no cmd line args we have to supply a default "." arg.
+        * we will create a second argv array, "av" that will hold either
+        * our created "." arg, or the real cmd line args.  The av array
+        * just holds the pointers- we don't move the date the pointers
+        * point to.
+        */
+       ac= argc - optind;   /* how many cmd line args are left */
+       if (ac < 1) {
+               av= (char **)xcalloc((size_t)1, (size_t)(sizeof(char *)));
+               av[0]= xstrdup(".");
+               ac=1;
+       } else {
+               av= (char **)xcalloc((size_t)ac, (size_t)(sizeof(char *)));
+               for (oi=0 ; oi < ac; oi++) {
+                       av[oi]= argv[optind++];  /* copy pointer to real cmd line arg */
+               }
+       }
+
+       /* now, everything is in the av array */
+       if (ac > 1)
+               disp_opts |= DISP_DIRNAME;   /* 2 or more items? label directories */
+
+       /* stuff the command line file names into an dnode array */
+       dn=NULL;
+       for (oi=0 ; oi < ac; oi++) {
+               cur= (struct dnode *)xmalloc(sizeof(struct dnode));
+               cur->fullname= xstrdup(av[oi]);
+               cur->name= cur->fullname;
+               if (my_stat(cur))
+                       continue;
+               cur->next= dn;
+               dn= cur;
+               nfiles++;
+       }
+
+       /* now that we know how many files there are
+       ** allocate memory for an array to hold dnode pointers
+       */
+       dnp= dnalloc(nfiles);
+       for (i=0, cur=dn; i<nfiles; i++) {
+               dnp[i]= cur;   /* save pointer to node in array */
+               cur= cur->next;
+       }
+
+
+       if (disp_opts & DISP_NOLIST) {
+#ifdef BB_FEATURE_LS_SORTFILES
+               shellsort(dnp, nfiles);
+#endif
+               if (nfiles > 0) showfiles(dnp, nfiles);
+       } else {
+               dnd= splitdnarray(dnp, nfiles, SPLIT_DIR);
+               dnf= splitdnarray(dnp, nfiles, SPLIT_FILE);
+               dndirs= countdirs(dnp, nfiles);
+               dnfiles= nfiles - dndirs;
+               if (dnfiles > 0) {
+#ifdef BB_FEATURE_LS_SORTFILES
+                       shellsort(dnf, dnfiles);
+#endif
+                       showfiles(dnf, dnfiles);
+               }
+               if (dndirs > 0) {
+#ifdef BB_FEATURE_LS_SORTFILES
+                       shellsort(dnd, dndirs);
+#endif
+                       showdirs(dnd, dndirs);
+               }
+       }
+       return(status);
+
+  print_usage_message:
+       show_usage();
+}
diff --git a/lsmod.c b/lsmod.c
new file mode 100644 (file)
index 0000000..a7da1c9
--- /dev/null
+++ b/lsmod.c
@@ -0,0 +1,195 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini lsmod implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+ * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
+ * (which lack the query_module() interface).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <assert.h>
+#include <getopt.h>
+#include <sys/utsname.h>
+#include <sys/file.h>
+#include "busybox.h"
+
+
+#define TAINT_FILENAME                  "/proc/sys/kernel/tainted"
+#define TAINT_PROPRIETORY_MODULE        (1<<0)
+#define TAINT_FORCED_MODULE             (1<<1)
+#define TAINT_UNSAFE_SMP                (1<<2)
+
+void check_tainted(void) 
+{
+       int tainted;
+       FILE *f;
+
+       tainted = 0;
+       if ((f = fopen(TAINT_FILENAME, "r"))) {
+               fscanf(f, "%d", &tainted);
+               fclose(f);
+       }
+       if (f && tainted) {
+               printf("    Tainted: %c%c%c\n",
+                               tainted & TAINT_PROPRIETORY_MODULE      ? 'P' : 'G',
+                               tainted & TAINT_FORCED_MODULE           ? 'F' : ' ',
+                               tainted & TAINT_UNSAFE_SMP              ? 'S' : ' ');
+       }
+       else {
+               printf("    Not tainted\n");
+       }
+}
+
+
+#ifdef BB_FEATURE_NEW_MODULE_INTERFACE
+
+struct module_info
+{
+       unsigned long addr;
+       unsigned long size;
+       unsigned long flags;
+       long usecount;
+};
+
+
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
+
+/* Values for query_module's which.  */
+static const int QM_MODULES = 1;
+static const int QM_DEPS = 2;
+static const int QM_REFS = 3;
+static const int QM_SYMBOLS = 4;
+static const int QM_INFO = 5;
+
+/* Bits of module.flags.  */
+static const int NEW_MOD_RUNNING = 1;
+static const int NEW_MOD_DELETED = 2;
+static const int NEW_MOD_AUTOCLEAN = 4;
+static const int NEW_MOD_VISITED = 8;
+static const int NEW_MOD_USED_ONCE = 16;
+static const int NEW_MOD_INITIALIZING = 64;
+
+static int my_query_module(const char *name, int which, void **buf,
+               size_t *bufsize, size_t *ret)
+{
+       int my_ret;
+
+       my_ret = query_module(name, which, *buf, *bufsize, ret);
+
+       if (my_ret == -1 && errno == ENOSPC) {
+               *buf = xrealloc(*buf, *ret);
+               *bufsize = *ret;
+
+               my_ret = query_module(name, which, *buf, *bufsize, ret);
+       }
+
+       return my_ret;
+}
+
+extern int lsmod_main(int argc, char **argv)
+{
+       struct module_info info;
+       char *module_names, *mn, *deps, *dn;
+       size_t bufsize, depsize, nmod, count, i, j;
+
+       module_names = xmalloc(bufsize = 256);
+       if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize,
+                               &nmod)) {
+               perror_msg_and_die("QM_MODULES");
+       }
+
+       deps = xmalloc(depsize = 256);
+       printf("Module                  Size  Used by");
+       check_tainted();
+
+       for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
+               if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
+                       if (errno == ENOENT) {
+                               /* The module was removed out from underneath us. */
+                               continue;
+                       }
+                       /* else choke */
+                       perror_msg_and_die("module %s: QM_INFO", mn);
+               }
+               if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) {
+                       if (errno == ENOENT) {
+                               /* The module was removed out from underneath us. */
+                               continue;
+                       }
+                       perror_msg_and_die("module %s: QM_REFS", mn);
+               }
+               printf("%-20s%8lu%4ld", mn, info.size, info.usecount);
+               if (info.flags & NEW_MOD_DELETED)
+                       printf(" (deleted)");
+               else if (info.flags & NEW_MOD_INITIALIZING)
+                       printf(" (initializing)");
+               else if (!(info.flags & NEW_MOD_RUNNING))
+                       printf(" (uninitialized)");
+               else {
+                       if (info.flags & NEW_MOD_AUTOCLEAN)
+                               printf(" (autoclean) ");
+                       if (!(info.flags & NEW_MOD_USED_ONCE))
+                               printf(" (unused)");
+               }
+               if (count) printf(" [");
+               for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
+                       printf("%s%s", dn, (j==count-1)? "":" ");
+               }
+               if (count) printf("]");
+
+               printf("\n");
+       }
+
+
+       return( 0);
+}
+
+#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/
+
+extern int lsmod_main(int argc, char **argv)
+{
+       int fd, i;
+       char line[128];
+
+       printf("Module                  Size  Used by");
+       check_tainted();
+       fflush(stdout);
+
+       if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
+               while ((i = read(fd, line, sizeof(line))) > 0) {
+                       write(fileno(stdout), line, i);
+               }
+               close(fd);
+               return 0;
+       }
+       perror_msg_and_die("/proc/modules");
+       return 1;
+}
+
+#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/
diff --git a/makedevs.c b/makedevs.c
new file mode 100644 (file)
index 0000000..67b28b5
--- /dev/null
@@ -0,0 +1,92 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+ * 
+ * makedevs
+ * Make ranges of device files quickly. 
+ * known bugs: can't deal with alpha ranges
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+int makedevs_main(int argc, char **argv)
+{
+       mode_t mode;
+       char *basedev, *type, *nodname, buf[255];
+       int major, Sminor, S, E;
+
+       if (argc < 7 || *argv[1]=='-')
+               show_usage();
+
+       basedev = argv[1];
+       type = argv[2];
+       major = atoi(argv[3]) << 8;  /* correcting param to mknod() */
+       Sminor = atoi(argv[4]);
+       S = atoi(argv[5]);
+       E = atoi(argv[6]);
+       nodname = argc == 8 ? basedev : buf;
+
+       mode = 0660;
+
+       switch (type[0]) {
+       case 'c':
+               mode |= S_IFCHR;
+               break;
+       case 'b':
+               mode |= S_IFBLK;
+               break;
+       case 'f':
+               mode |= S_IFIFO;
+               break;
+       default:
+               show_usage();
+       }
+
+       while (S <= E) {
+               int sz;
+
+               sz = snprintf(buf, sizeof(buf), "%s%d", basedev, S);
+               if(sz<0 || sz>=sizeof(buf))  /* libc different */
+                       error_msg_and_die("%s too large", basedev);
+
+       /* if mode != S_IFCHR and != S_IFBLK third param in mknod() ignored */
+
+               if (mknod(nodname, mode, major | Sminor))
+                       error_msg("Failed to create: %s", nodname);
+
+               if (nodname == basedev) /* ex. /dev/hda - to /dev/hda1 ... */
+                       nodname = buf;
+               S++;
+               Sminor++;
+       }
+
+       return 0;
+}
+
+/*
+And this is what this program replaces. The shell is too slow!
+
+makedev () {
+local basedev=$1; local S=$2; local E=$3
+local major=$4; local Sminor=$5; local type=$6
+local sbase=$7
+
+       if [ ! "$sbase" = "" ]; then
+               mknod "$basedev" $type $major $Sminor
+               S=`expr $S + 1`
+               Sminor=`expr $Sminor + 1`
+       fi
+
+       while [ $S -le $E ]; do
+               mknod "$basedev$S" $type $major $Sminor
+               S=`expr $S + 1`
+               Sminor=`expr $Sminor + 1`
+       done
+}
+*/
diff --git a/md5sum.c b/md5sum.c
new file mode 100644 (file)
index 0000000..da79f83
--- /dev/null
+++ b/md5sum.c
@@ -0,0 +1,1074 @@
+/* md5sum.c - Compute MD5 checksum of files or strings according to the
+ *            definition of MD5 in RFC 1321 from April 1992.
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
+/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
+
+/*
+ * June 29, 2001        Manuel Novoa III
+ *
+ * Added MD5SUM_SIZE_VS_SPEED configuration option.
+ *
+ * Current valid values, with data from my system for comparison, are:
+ *   (using uClibc and running on linux-2.4.4.tar.bz2)
+ *                     user times (sec)  text size (386)
+ *     0 (fastest)         1.1                6144
+ *     1                   1.4                5392
+ *     2                   3.0                5088
+ *     3 (smallest)        5.1                4912
+ */
+
+#define MD5SUM_SIZE_VS_SPEED 2
+
+/**********************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <sys/types.h>
+#if defined HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#include "busybox.h"
+
+/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
+#undef TRUE
+#undef FALSE
+#define FALSE   ((int) 1)
+#define TRUE    ((int) 0)
+    
+/* It is unfortunate that C does not provide an operator for
+   cyclic rotation.  Hope the C compiler is smart enough.
+   gcc 2.95.4 seems to be --aaronl */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+
+//----------------------------------------------------------------------------
+//--------md5.c
+//----------------------------------------------------------------------------
+
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ *         according to the definition of MD5 in RFC 1321 from April 1992.
+ */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+
+//----------------------------------------------------------------------------
+//--------md5.h
+//----------------------------------------------------------------------------
+
+/* md5.h - Declaration of functions and data types used for MD5 sum
+   computing library functions. */
+
+typedef u_int32_t md5_uint32;
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+static void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+static void md5_process_block __P ((const void *buffer, size_t len,
+                                   struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+static void md5_process_bytes __P ((const void *buffer, size_t len,
+                                   struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+static void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+static int md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+static void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+
+//----------------------------------------------------------------------------
+//--------end of md5.h
+//----------------------------------------------------------------------------
+
+/* Handle endian-ness */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       #define SWAP(n) (n)
+#else
+       #define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
+#endif
+
+
+
+#if MD5SUM_SIZE_VS_SPEED == 0
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */  };
+#endif
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+void md5_init_ctx(struct md5_ctx *ctx)
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
+{
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+#if MD5SUM_SIZE_VS_SPEED > 0
+  memset(&ctx->buffer[bytes], 0, pad);
+  ctx->buffer[bytes] = 0x80;
+#else
+  memcpy(&ctx->buffer[bytes], fillbuf, pad);
+#endif
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
+  *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
+    SWAP( ((ctx->total[1] << 3) | (ctx->total[0] >> 29)) );
+
+  /* Process last bytes.  */
+  md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+  ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
+
+  return resbuf;
+}
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+static int md5_stream(FILE *stream, void *resblock)
+{
+  /* Important: BLOCKSIZE must be a multiple of 64.  */
+static const int BLOCKSIZE = 4096;
+  struct md5_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx(&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1) {
+    /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+       computation function processes the whole buffer so that with the
+       next round of the loop another block can be read.  */
+    size_t n;
+    sum = 0;
+
+    /* Read block.  Take care for partial reads.  */
+    do {
+      n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+      sum += n;
+    }
+    while (sum < BLOCKSIZE && n != 0);
+    if (n == 0 && ferror(stream))
+      return 1;
+
+    /* If end of file is reached, end the loop.  */
+    if (n == 0)
+      break;
+
+    /* Process buffer with BLOCKSIZE bytes.  Note that
+       BLOCKSIZE % 64 == 0
+    */
+    md5_process_block(buffer, BLOCKSIZE, &ctx);
+  }
+
+  /* Add the last bytes if necessary.  */
+  if (sum > 0)
+    md5_process_bytes(buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx(&ctx, resblock);
+  return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+static void *md5_buffer(const char *buffer, size_t len, void *resblock)
+{
+  struct md5_ctx ctx;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx(&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  md5_process_bytes(buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return md5_finish_ctx(&ctx, resblock);
+}
+
+static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0) {
+    size_t left_over = ctx->buflen;
+    size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+    memcpy(&ctx->buffer[left_over], buffer, add);
+    ctx->buflen += add;
+
+    if (left_over + add > 64) {
+      md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
+      /* The regions in the following copy operation cannot overlap.  */
+      memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+            (left_over + add) & 63);
+      ctx->buflen = (left_over + add) & 63;
+    }
+
+    buffer = (const char *) buffer + add;
+    len -= add;
+  }
+
+  /* Process available complete blocks.  */
+  if (len > 64) {
+    md5_process_block(buffer, len & ~63, ctx);
+    buffer = (const char *) buffer + (len & ~63);
+    len &= 63;
+  }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0) {
+    memcpy(ctx->buffer, buffer, len);
+    ctx->buflen = len;
+  }
+}
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+   and defined in the RFC 1321.  The first function is a little bit optimized
+   (as found in Colin Plumbs public domain implementation).  */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.  */
+static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+  md5_uint32 correct_words[16];
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof(md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+#if MD5SUM_SIZE_VS_SPEED > 0
+  static const md5_uint32 C_array[] = {
+      /* round 1 */
+      0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+      0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+      0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+      /* round 2 */
+      0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+      0xd62f105d, 0x2441453,  0xd8a1e681, 0xe7d3fbc8,
+      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+      0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+      /* round 3 */
+      0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+      0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+      0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+      /* round 4 */
+      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+      0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+      0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+  };
+
+  static const char P_array[] = {
+#if MD5SUM_SIZE_VS_SPEED > 1
+      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+#endif
+      1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
+      5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
+      0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
+  };
+
+#if MD5SUM_SIZE_VS_SPEED > 1
+  static const char S_array[] = {
+      7, 12, 17, 22,
+      5, 9, 14, 20,
+      4, 11, 16, 23,
+      6, 10, 15, 21
+  };
+#endif
+#endif
+
+  md5_uint32 A = ctx->A;
+  md5_uint32 B = ctx->B;
+  md5_uint32 C = ctx->C;
+  md5_uint32 D = ctx->D;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+  /* Process all bytes in the buffer with 64 bytes in each round of
+     the loop.  */
+  while (words < endp) {
+    md5_uint32 *cwp = correct_words;
+    md5_uint32 A_save = A;
+    md5_uint32 B_save = B;
+    md5_uint32 C_save = C;
+    md5_uint32 D_save = D;
+
+#if MD5SUM_SIZE_VS_SPEED > 1
+
+    const md5_uint32 *pc;
+    const char *pp;
+    const char *ps;
+    int i;
+    md5_uint32 temp;
+
+    for ( i=0 ; i < 16 ; i++ ) {
+       cwp[i] = SWAP(words[i]);
+    }
+    words += 16;
+
+#if MD5SUM_SIZE_VS_SPEED > 2
+    pc = C_array; pp = P_array; ps = S_array - 4;
+
+    for ( i = 0 ; i < 64 ; i++ ) {
+       if ((i&0x0f) == 0) ps += 4;
+       temp = A;
+       switch (i>>4) {
+           case 0:
+               temp += FF(B,C,D);
+               break;
+           case 1:
+               temp += FG(B,C,D);
+               break;
+           case 2:
+               temp += FH(B,C,D);
+               break;
+           case 3:
+               temp += FI(B,C,D);
+       }
+       temp += cwp[(int)(*pp++)] + *pc++;
+       CYCLIC (temp, ps[i&3]);
+       temp += B;
+       A = D; D = C; C = B; B = temp;
+    }
+#else
+    pc = C_array; pp = P_array; ps = S_array;
+
+    for ( i = 0 ; i < 16 ; i++ ) {
+       temp = A + FF(B,C,D) + cwp[(int)(*pp++)] + *pc++;
+       CYCLIC (temp, ps[i&3]);
+       temp += B;
+       A = D; D = C; C = B; B = temp;
+    }
+
+    ps += 4;
+    for ( i = 0 ; i < 16 ; i++ ) {
+       temp = A + FG(B,C,D) + cwp[(int)(*pp++)] + *pc++;
+       CYCLIC (temp, ps[i&3]);
+       temp += B;
+       A = D; D = C; C = B; B = temp;
+    }
+    ps += 4;
+    for ( i = 0 ; i < 16 ; i++ ) {
+       temp = A + FH(B,C,D) + cwp[(int)(*pp++)] + *pc++;
+       CYCLIC (temp, ps[i&3]);
+       temp += B;
+       A = D; D = C; C = B; B = temp;
+    }
+    ps += 4;
+    for ( i = 0 ; i < 16 ; i++ ) {
+       temp = A + FI(B,C,D) + cwp[(int)(*pp++)] + *pc++;
+       CYCLIC (temp, ps[i&3]);
+       temp += B;
+       A = D; D = C; C = B; B = temp;
+    }
+
+#endif
+#else
+    /* First round: using the given function, the context and a constant
+       the next context is computed.  Because the algorithms processing
+       unit is a 32-bit word and it is determined to work on words in
+       little endian byte order we perhaps have to change the byte order
+       before the computation.  To reduce the work for the next steps
+       we store the swapped words in the array CORRECT_WORDS.  */
+
+#define OP(a, b, c, d, s, T)                                           \
+      do                                                               \
+        {                                                              \
+         a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;             \
+         ++words;                                                      \
+         CYCLIC (a, s);                                                \
+         a += b;                                                       \
+        }                                                              \
+      while (0)
+
+    /* Before we start, one word to the strange constants.
+       They are defined in RFC 1321 as
+
+       T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+    */
+
+#if MD5SUM_SIZE_VS_SPEED == 1
+    const md5_uint32 *pc;
+    const char *pp;
+    int i;
+#endif
+
+    /* Round 1.  */
+#if MD5SUM_SIZE_VS_SPEED == 1
+    pc = C_array;
+    for ( i=0 ; i < 4 ; i++ ) {
+       OP(A, B, C, D, 7, *pc++);
+       OP(D, A, B, C, 12, *pc++);
+       OP(C, D, A, B, 17, *pc++);
+       OP(B, C, D, A, 22, *pc++);
+    }
+#else
+    OP(A, B, C, D, 7, 0xd76aa478);
+    OP(D, A, B, C, 12, 0xe8c7b756);
+    OP(C, D, A, B, 17, 0x242070db);
+    OP(B, C, D, A, 22, 0xc1bdceee);
+    OP(A, B, C, D, 7, 0xf57c0faf);
+    OP(D, A, B, C, 12, 0x4787c62a);
+    OP(C, D, A, B, 17, 0xa8304613);
+    OP(B, C, D, A, 22, 0xfd469501);
+    OP(A, B, C, D, 7, 0x698098d8);
+    OP(D, A, B, C, 12, 0x8b44f7af);
+    OP(C, D, A, B, 17, 0xffff5bb1);
+    OP(B, C, D, A, 22, 0x895cd7be);
+    OP(A, B, C, D, 7, 0x6b901122);
+    OP(D, A, B, C, 12, 0xfd987193);
+    OP(C, D, A, B, 17, 0xa679438e);
+    OP(B, C, D, A, 22, 0x49b40821);
+#endif
+
+    /* For the second to fourth round we have the possibly swapped words
+       in CORRECT_WORDS.  Redefine the macro to take an additional first
+       argument specifying the function to use.  */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T)                                     \
+      do                                                               \
+       {                                                               \
+         a += f (b, c, d) + correct_words[k] + T;                      \
+         CYCLIC (a, s);                                                \
+         a += b;                                                       \
+       }                                                               \
+      while (0)
+
+    /* Round 2.  */
+#if MD5SUM_SIZE_VS_SPEED == 1
+    pp = P_array;
+    for ( i=0 ; i < 4 ; i++ ) {
+       OP(FG, A, B, C, D, (int)(*pp++), 5, *pc++);
+       OP(FG, D, A, B, C, (int)(*pp++), 9, *pc++);
+       OP(FG, C, D, A, B, (int)(*pp++), 14, *pc++);
+       OP(FG, B, C, D, A, (int)(*pp++), 20, *pc++);
+    }
+#else
+    OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
+    OP(FG, D, A, B, C, 6, 9, 0xc040b340);
+    OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
+    OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+    OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
+    OP(FG, D, A, B, C, 10, 9, 0x02441453);
+    OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
+    OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+    OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
+    OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
+    OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
+    OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
+    OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
+    OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+    OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
+    OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+#endif
+
+    /* Round 3.  */
+#if MD5SUM_SIZE_VS_SPEED == 1
+    for ( i=0 ; i < 4 ; i++ ) {
+       OP(FH, A, B, C, D, (int)(*pp++), 4, *pc++);
+       OP(FH, D, A, B, C, (int)(*pp++), 11, *pc++);
+       OP(FH, C, D, A, B, (int)(*pp++), 16, *pc++);
+       OP(FH, B, C, D, A, (int)(*pp++), 23, *pc++);
+    }
+#else
+    OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
+    OP(FH, D, A, B, C, 8, 11, 0x8771f681);
+    OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
+    OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
+    OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
+    OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+    OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+    OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
+    OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
+    OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
+    OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
+    OP(FH, B, C, D, A, 6, 23, 0x04881d05);
+    OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
+    OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
+    OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+    OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
+#endif
+
+    /* Round 4.  */
+#if MD5SUM_SIZE_VS_SPEED == 1
+    for ( i=0 ; i < 4 ; i++ ) {
+       OP(FI, A, B, C, D, (int)(*pp++), 6, *pc++);
+       OP(FI, D, A, B, C, (int)(*pp++), 10, *pc++);
+       OP(FI, C, D, A, B, (int)(*pp++), 15, *pc++);
+       OP(FI, B, C, D, A, (int)(*pp++), 21, *pc++);
+    }
+#else
+    OP(FI, A, B, C, D, 0, 6, 0xf4292244);
+    OP(FI, D, A, B, C, 7, 10, 0x432aff97);
+    OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
+    OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
+    OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
+    OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+    OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
+    OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
+    OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+    OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+    OP(FI, C, D, A, B, 6, 15, 0xa3014314);
+    OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
+    OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
+    OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
+    OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+    OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
+#endif
+#endif
+
+    /* Add the starting values of the context.  */
+    A += A_save;
+    B += B_save;
+    C += C_save;
+    D += D_save;
+  }
+
+  /* Put checksum in context given as argument.  */
+  ctx->A = A;
+  ctx->B = B;
+  ctx->C = C;
+  ctx->D = D;
+}
+
+//----------------------------------------------------------------------------
+//--------end of md5.c
+//----------------------------------------------------------------------------
+
+#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
+#define ISXDIGIT(c) (isxdigit (c))
+
+/* The minimum length of a valid digest line in a file produced
+   by `md5sum FILE' and read by `md5sum -c'.  This length does
+   not include any newline character at the end of a line.  */
+static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
+                                      2 - blank and binary indicator
+                                      1 - minimum filename length */
+
+static int have_read_stdin; /* Nonzero if any of the files read were
+                               the standard input. */
+
+static int status_only = 0; /* With -c, don't generate any output.
+                               The exit code indicates success or failure */
+static int warn = 0; /* With -w, print a message to standard error warning
+                        about each improperly formatted MD5 checksum line */
+
+static int split_3(char *s,
+                   size_t s_len,
+                   unsigned char **u,
+                   char **w)
+{
+  size_t i = 0;
+  int escaped_filename = 0;
+
+  while (ISWHITE(s[i]))
+    ++i;
+
+  /* The line must have at least 35 (36 if the first is a backslash)
+     more characters to contain correct message digest information.
+     Ignore this line if it is too short.  */
+  if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
+        || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
+    return FALSE;
+
+  if (s[i] == '\\') {
+    ++i;
+    escaped_filename = 1;
+  }
+  *u = (unsigned char *) &s[i];
+
+  /* The first field has to be the 32-character hexadecimal
+     representation of the message digest.  If it is not followed
+     immediately by a white space it's an error.  */
+  i += 32;
+  if (!ISWHITE(s[i]))
+    return FALSE;
+
+  s[i++] = '\0';
+
+  if (s[i] != ' ' && s[i] != '*')
+    return FALSE;
+
+  /* All characters between the type indicator and end of line are
+     significant -- that includes leading and trailing white space.  */
+  *w = &s[++i];
+
+  if (escaped_filename) {
+    /* Translate each `\n' string in the file name to a NEWLINE,
+       and each `\\' string to a backslash.  */
+
+    char *dst = &s[i];
+
+    while (i < s_len) {
+      switch (s[i]) {
+       case '\\':
+        if (i == s_len - 1) {
+          /* A valid line does not end with a backslash.  */
+          return FALSE;
+        }
+        ++i;
+        switch (s[i++]) {
+         case 'n':
+          *dst++ = '\n';
+          break;
+         case '\\':
+          *dst++ = '\\';
+          break;
+         default:
+          /* Only `\' or `n' may follow a backslash.  */
+          return FALSE;
+        }
+        break;
+
+       case '\0':
+        /* The file name may not contain a NUL.  */
+        return FALSE;
+        break;
+
+       default:
+        *dst++ = s[i++];
+        break;
+      }
+    }
+    *dst = '\0';
+  }
+  return TRUE;
+}
+
+static inline int hex_digits(unsigned char const *s)
+{
+  while (*s) {
+    if (!ISXDIGIT(*s))
+      return TRUE;
+    ++s;
+  }
+  return FALSE;
+}
+
+/* An interface to md5_stream.  Operate on FILENAME (it may be "-") and
+   put the result in *MD5_RESULT.  Return non-zero upon failure, zero
+   to indicate success.  */
+static int md5_file(const char *filename,
+                    unsigned char *md5_result)
+{
+  FILE *fp;
+
+  if (filename[0] == '-' && filename[1] == '\0') {
+    have_read_stdin = 1;
+    fp = stdin;
+  } else {
+    fp = wfopen(filename, "r");
+    if (fp == NULL)
+      return FALSE;
+    }
+
+  if (md5_stream(fp, md5_result)) {
+    perror_msg("%s", filename);
+
+    if (fp != stdin)
+      fclose(fp);
+    return FALSE;
+  }
+
+  if (fp != stdin && fclose(fp) == EOF) {
+    perror_msg("%s", filename);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static int md5_check(const char *checkfile_name)
+{
+  FILE *checkfile_stream;
+  int n_properly_formated_lines = 0;
+  int n_mismatched_checksums = 0;
+  int n_open_or_read_failures = 0;
+  unsigned char md5buffer[16];
+  size_t line_number;
+  char line[BUFSIZ];
+
+  if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
+    have_read_stdin = 1;
+    checkfile_stream = stdin;
+  } else {
+    checkfile_stream = wfopen(checkfile_name, "r");
+    if (checkfile_stream == NULL)
+      return FALSE;
+    }
+
+  line_number = 0;
+
+  do {
+    char *filename;
+    unsigned char *md5num;
+    int line_length;
+
+    ++line_number;
+
+    fgets(line, BUFSIZ-1, checkfile_stream);
+    line_length = strlen(line);
+
+    if (line_length <= 0 || line==NULL)
+      break;
+
+    /* Ignore comment lines, which begin with a '#' character.  */
+    if (line[0] == '#')
+      continue;
+
+    /* Remove any trailing newline.  */
+    if (line[line_length - 1] == '\n')
+      line[--line_length] = '\0';
+
+    if (split_3(line, line_length, &md5num, &filename)
+        || !hex_digits(md5num)) {
+      if (warn) {
+        error_msg("%s: %lu: improperly formatted MD5 checksum line",
+                 checkfile_name, (unsigned long) line_number);
+      }
+    } else {
+      static const char bin2hex[] = {
+        '0', '1', '2', '3',
+        '4', '5', '6', '7',
+        '8', '9', 'a', 'b',
+        'c', 'd', 'e', 'f'
+      };
+
+      ++n_properly_formated_lines;
+
+      if (md5_file(filename, md5buffer)) {
+        ++n_open_or_read_failures;
+        if (!status_only) {
+          printf("%s: FAILED open or read\n", filename);
+          fflush(stdout);
+        }
+      } else {
+        size_t cnt;
+        /* Compare generated binary number with text representation
+           in check file.  Ignore case of hex digits.  */
+        for (cnt = 0; cnt < 16; ++cnt) {
+          if (tolower(md5num[2 * cnt])
+              != bin2hex[md5buffer[cnt] >> 4]
+              || (tolower(md5num[2 * cnt + 1])
+                  != (bin2hex[md5buffer[cnt] & 0xf])))
+            break;
+        }
+        if (cnt != 16)
+          ++n_mismatched_checksums;
+
+        if (!status_only) {
+          printf("%s: %s\n", filename,
+                 (cnt != 16 ? "FAILED" : "OK"));
+          fflush(stdout);
+        }
+      }
+    }
+  }
+
+  while (!feof(checkfile_stream) && !ferror(checkfile_stream));
+
+  if (ferror(checkfile_stream)) {
+    error_msg("%s: read error", checkfile_name);
+    return FALSE;
+  }
+
+  if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
+    perror_msg("md5sum: %s", checkfile_name);
+    return FALSE;
+  }
+
+  if (n_properly_formated_lines == 0) {
+    /* Warn if no tests are found.  */
+    error_msg("%s: no properly formatted MD5 checksum lines found",
+             checkfile_name);
+    return FALSE;
+  } else {
+    if (!status_only) {
+      int n_computed_checkums = (n_properly_formated_lines
+                                 - n_open_or_read_failures);
+
+      if (n_open_or_read_failures > 0) {
+        error_msg("WARNING: %d of %d listed files could not be read",
+                 n_open_or_read_failures, n_properly_formated_lines);
+        return FALSE;
+      }
+
+      if (n_mismatched_checksums > 0) {
+        error_msg("WARNING: %d of %d computed checksums did NOT match",
+                 n_mismatched_checksums, n_computed_checkums);
+        return FALSE;
+      }
+    }
+  }
+
+  return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
+           && n_open_or_read_failures == 0) ? 0 : 1);
+}
+
+int md5sum_main(int argc,
+                char **argv)
+{
+  unsigned char md5buffer[16];
+  int do_check = 0;
+  int opt;
+  char **string = NULL;
+  size_t n_strings = 0;
+  size_t err = 0;
+  char file_type_specified = 0;
+  char binary = 0;
+
+  while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
+    switch (opt) {
+     case 'g': { /* read a string */
+       if (string == NULL)
+         string = (char **) xmalloc ((argc - 1) * sizeof (char *));
+
+       string[n_strings++] = optarg;
+       break;
+     }
+
+     case 'b': /* read files in binary mode */
+      file_type_specified = 1;
+      binary = 1;
+      break;
+
+     case 'c': /* check MD5 sums against given list */
+      do_check = 1;
+      break;
+
+     case 's':  /* don't output anything, status code shows success */
+      status_only = 1;
+      warn = 0;
+      break;
+
+     case 't': /* read files in text mode (default) */
+      file_type_specified = 1;
+      binary = 0;
+      break;
+
+     case 'w': /* warn about improperly formated MD5 checksum lines */
+      status_only = 0;
+      warn = 1;
+      break;
+
+     default:
+      show_usage();
+    }
+  }
+
+  if (file_type_specified && do_check) {
+    error_msg_and_die("the -b and -t options are meaningless when verifying checksums");
+  }
+
+  if (n_strings > 0 && do_check) {
+    error_msg_and_die("the -g and -c options are mutually exclusive");
+  }
+
+  if (status_only && !do_check) {
+    error_msg_and_die("the -s option is meaningful only when verifying checksums");
+  }
+
+  if (warn && !do_check) {
+    error_msg_and_die("the -w option is meaningful only when verifying checksums");
+  }
+
+  if (n_strings > 0) {
+    size_t i;
+
+    if (optind < argc) {
+      error_msg_and_die("no files may be specified when using -g");
+    }
+    for (i = 0; i < n_strings; ++i) {
+      size_t cnt;
+      md5_buffer (string[i], strlen (string[i]), md5buffer);
+
+      for (cnt = 0; cnt < 16; ++cnt)
+        printf ("%02x", md5buffer[cnt]);
+
+      printf ("  \"%s\"\n", string[i]);
+    }
+  } else if (do_check) {
+    if (optind + 1 < argc) {
+      error_msg("only one argument may be specified when using -c");
+    }
+
+    err = md5_check ((optind == argc) ? "-" : argv[optind]);
+  } else {
+    if (optind == argc)
+      argv[argc++] = "-";
+
+    for (; optind < argc; ++optind) {
+      int fail;
+      char *file = argv[optind];
+
+      fail = md5_file (file, md5buffer);
+      err |= fail;
+      if (!fail && file[0]=='-' && file[1] == '\0') {
+         size_t i;
+         for (i = 0; i < 16; ++i)
+             printf ("%02x", md5buffer[i]);
+         putchar ('\n');
+      } else if (!fail) {
+        size_t i;
+        /* Output a leading backslash if the file name contains
+           a newline or backslash.  */
+        if (strchr (file, '\n') || strchr (file, '\\'))
+          putchar ('\\');
+
+        for (i = 0; i < 16; ++i)
+          printf ("%02x", md5buffer[i]);
+
+        putchar (' ');
+        if (binary)
+          putchar ('*');
+        else
+          putchar (' ');
+
+        /* Translate each NEWLINE byte to the string, "\\n",
+           and each backslash to "\\\\".  */
+        for (i = 0; i < strlen (file); ++i) {
+          switch (file[i]) {
+           case '\n':
+            fputs ("\\n", stdout);
+            break;
+
+           case '\\':
+            fputs ("\\\\", stdout);
+            break;
+
+           default:
+            putchar (file[i]);
+            break;
+          }
+        }
+        putchar ('\n');
+      }
+    }
+  }
+
+  if (fclose (stdout) == EOF) {
+    error_msg_and_die("write error");
+  }
+
+  if (have_read_stdin && fclose (stdin) == EOF) {
+    error_msg_and_die("standard input");
+  }
+
+  if (err == 0)
+         return EXIT_SUCCESS;
+  else
+         return EXIT_FAILURE;
+}
diff --git a/mk_loop_h.sh b/mk_loop_h.sh
new file mode 100755 (executable)
index 0000000..5adfbd5
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Figure out (i) the type of dev_t (ii) the defines for loop stuff
+#
+# Output of this script is normally redirected to "loop.h".
+
+# Since 1.3.79 there is an include file <asm/posix_types.h>
+# that defines __kernel_dev_t.
+# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
+# If it exists, we use it, or, rather, <linux/posix_types.h> which
+# avoids namespace pollution.  Otherwise we guess that __kernel_dev_t
+# is an unsigned short (which is true on i386, but false on alpha).
+
+# BUG: This test is actually broken if your gcc is not configured to
+# search /usr/include, as may well happen with cross-compilers.
+# It would be better to ask $(CC) if these files can be found.
+
+if [ -f ${LINUXDIR:-/usr}/include/linux/posix_types.h ]; then
+   echo '#include <linux/posix_types.h>'
+   echo '#undef dev_t'
+   echo '#define dev_t __kernel_dev_t'
+else
+   echo '#undef dev_t'
+   echo '#define dev_t unsigned short'
+fi
+
+# Next we have to find the loop stuff itself.
+# First try kernel source, then a private version.
+
+if [ -f ${LINUXDIR:-/usr}/include/linux/loop.h ]; then
+   echo '#include <linux/loop.h>'
+else
+   echo '#include "real_loop.h"'
+fi
+
+echo '#undef dev_t'
+
diff --git a/mkdir.c b/mkdir.c
new file mode 100644 (file)
index 0000000..03c49f0
--- /dev/null
+++ b/mkdir.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mkdir implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "busybox.h"
+
+extern int mkdir_main (int argc, char **argv)
+{
+       mode_t mode = -1;
+       int flags = 0;
+       int status = 0;
+       int i, opt;
+
+       while ((opt = getopt (argc, argv, "m:p")) != -1) {
+               switch (opt) {
+               case 'm':
+                       mode = 0777;
+                       if (!parse_mode (optarg, &mode))
+                               error_msg_and_die ("invalid mode `%s'", optarg);
+                       break;
+               case 'p':
+                       flags |= FILEUTILS_RECUR;
+                       break;
+               default:
+                       show_usage ();
+               }
+       }
+
+       if (optind == argc)
+               show_usage ();
+
+       for (i = optind; i < argc; i++)
+               if (make_directory (argv[i], mode, flags) < 0)
+                       status = 1;
+
+       return status;
+}
diff --git a/mkfifo.c b/mkfifo.c
new file mode 100644 (file)
index 0000000..ca217fa
--- /dev/null
+++ b/mkfifo.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mkfifo implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int mkfifo_main(int argc, char **argv)
+{
+       char *thisarg;
+       mode_t mode = 0666;
+
+       argc--;
+       argv++;
+
+       /* Parse any options */
+       while (argc > 1) {
+               if (**argv != '-')
+                       show_usage();
+               thisarg = *argv;
+               thisarg++;
+               switch (*thisarg) {
+               case 'm':
+                       argc--;
+                       argv++;
+                       parse_mode(*argv, &mode);
+                       break;
+               default:
+                       show_usage();
+               }
+               argc--;
+               argv++;
+       }
+       if (argc < 1 || *argv[0] == '-')
+               show_usage();
+       if (mkfifo(*argv, mode) < 0)
+               perror_msg_and_die("mkfifo");
+       return EXIT_SUCCESS;
+}
diff --git a/mkfs_minix.c b/mkfs_minix.c
new file mode 100644 (file)
index 0000000..ccc0e85
--- /dev/null
@@ -0,0 +1,847 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs.c - make a linux (minix) file-system.
+ *
+ * (C) 1991 Linus Torvalds. This file may be redistributed as per
+ * the Linux copyright.
+ */
+
+/*
+ * DD.MM.YY
+ *
+ * 24.11.91  - Time began. Used the fsck sources to get started.
+ *
+ * 25.11.91  - Corrected some bugs. Added support for ".badblocks"
+ *             The algorithm for ".badblocks" is a bit weird, but
+ *             it should work. Oh, well.
+ *
+ * 25.01.92  - Added the -l option for getting the list of bad blocks
+ *             out of a named file. (Dave Rivers, rivers@ponds.uucp)
+ *
+ * 28.02.92  - Added %-information when using -c.
+ *
+ * 28.02.93  - Added support for other namelengths than the original
+ *             14 characters so that I can test the new kernel routines..
+ *
+ * 09.10.93  - Make exit status conform to that required by fsutil
+ *             (Rik Faith, faith@cs.unc.edu)
+ *
+ * 31.10.93  - Added inode request feature, for backup floppies: use
+ *             32 inodes, for a news partition use more.
+ *             (Scott Heavner, sdh@po.cwru.edu)
+ *
+ * 03.01.94  - Added support for file system valid flag.
+ *             (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
+ *
+ * 30.10.94 - added support for v2 filesystem
+ *           (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ * 
+ * 09.11.94  - Added test to prevent overwrite of mounted fs adapted
+ *             from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
+ *             program.  (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 03.20.95  - Clear first 512 bytes of filesystem to make certain that
+ *             the filesystem is not misidentified as a MS-DOS FAT filesystem.
+ *             (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 02.07.96  -  Added small patch from Russell King to make the program a
+ *             good deal more portable (janl@math.uio.no)
+ *
+ * Usage:  mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
+ *
+ *     -c for readablility checking (SLOW!)
+ *      -l for getting a list of bad blocks from a file.
+ *     -n for namelength (currently the kernel only uses 14 or 30)
+ *     -i for number of inodes
+ *     -v for v2 filesystem
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-). 
+ *
+ * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
+ *     removed getopt based parser and added a hand rolled one.
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <mntent.h>
+#include "busybox.h"
+
+#define MINIX_ROOT_INO 1
+#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX        65530
+
+#define MINIX_I_MAP_SLOTS      8
+#define MINIX_Z_MAP_SLOTS      64
+#define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
+#define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC     0x2468          /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2    0x2478          /* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS         0x0001          /* Clean fs. */
+#define MINIX_ERROR_FS         0x0002          /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+#define MINIX_V1               0x0001          /* original minix fs */
+#define MINIX_V2               0x0002          /* minix V2 fs */
+
+#define INODE_VERSION(inode)   inode->i_sb->u.minix_sb.s_version
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+       u_int16_t i_mode;
+       u_int16_t i_uid;
+       u_int32_t i_size;
+       u_int32_t i_time;
+       u_int8_t  i_gid;
+       u_int8_t  i_nlinks;
+       u_int16_t i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+       u_int16_t i_mode;
+       u_int16_t i_nlinks;
+       u_int16_t i_uid;
+       u_int16_t i_gid;
+       u_int32_t i_size;
+       u_int32_t i_atime;
+       u_int32_t i_mtime;
+       u_int32_t i_ctime;
+       u_int32_t i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+       u_int16_t s_ninodes;
+       u_int16_t s_nzones;
+       u_int16_t s_imap_blocks;
+       u_int16_t s_zmap_blocks;
+       u_int16_t s_firstdatazone;
+       u_int16_t s_log_zone_size;
+       u_int32_t s_max_size;
+       u_int16_t s_magic;
+       u_int16_t s_state;
+       u_int32_t s_zones;
+};
+
+struct minix_dir_entry {
+       u_int16_t inode;
+       char name[0];
+};
+
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+#define NAME_MAX         255   /* # chars in a file name */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+
+#define MINIX_VALID_FS               0x0001          /* Clean fs. */
+#define MINIX_ERROR_FS               0x0002          /* fs has errors. */
+
+#define MINIX_SUPER_MAGIC    0x137F          /* original minix fs */
+#define MINIX_SUPER_MAGIC2   0x138F          /* minix fs, 30 char names */
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96)    /* return device size */
+#endif
+
+
+#ifndef __linux__
+#define volatile
+#endif
+
+#define MINIX_ROOT_INO 1
+#define MINIX_BAD_INO 2
+
+#define TEST_BUFFER_BLOCKS 16
+#define MAX_GOOD_BLOCKS 512
+
+#define UPPER(size,n) (((size)+((n)-1))/(n))
+#define INODE_SIZE (sizeof(struct minix_inode))
+#ifdef BB_FEATURE_MINIX2
+#define INODE_SIZE2 (sizeof(struct minix2_inode))
+#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
+                                   : MINIX_INODES_PER_BLOCK))
+#else
+#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
+#endif
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+
+#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
+
+static char *device_name = NULL;
+static int DEV = -1;
+static long BLOCKS = 0;
+static int check = 0;
+static int badblocks = 0;
+static int namelen = 30;               /* default (changed to 30, per Linus's
+
+                                                                  suggestion, Sun Nov 21 08:05:07 1993) */
+static int dirsize = 32;
+static int magic = MINIX_SUPER_MAGIC2;
+static int version2 = 0;
+
+static char root_block[BLOCK_SIZE] = "\0";
+
+static char *inode_buffer = NULL;
+
+#define Inode (((struct minix_inode *) inode_buffer)-1)
+#ifdef BB_FEATURE_MINIX2
+#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
+#endif
+static char super_block_buffer[BLOCK_SIZE];
+static char boot_block_buffer[512];
+
+#define Super (*(struct minix_super_block *)super_block_buffer)
+#define INODES ((unsigned long)Super.s_ninodes)
+#ifdef BB_FEATURE_MINIX2
+#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
+#else
+#define ZONES ((unsigned long)(Super.s_nzones))
+#endif
+#define IMAPS ((unsigned long)Super.s_imap_blocks)
+#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
+#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
+#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
+#define MAXSIZE ((unsigned long)Super.s_max_size)
+#define MAGIC (Super.s_magic)
+#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
+
+static char *inode_map;
+static char *zone_map;
+
+static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
+static int used_good_blocks = 0;
+static unsigned long req_nr_inodes = 0;
+
+static inline int bit(char * a,unsigned int i)
+{
+         return (a[i >> 3] & (1<<(i & 7))) != 0;
+}
+#define inode_in_use(x) (bit(inode_map,(x)))
+#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
+
+#define mark_inode(x) (setbit(inode_map,(x)))
+#define unmark_inode(x) (clrbit(inode_map,(x)))
+
+#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
+#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
+
+/*
+ * Check to make certain that our new filesystem won't be created on
+ * an already mounted partition.  Code adapted from mke2fs, Copyright
+ * (C) 1994 Theodore Ts'o.  Also licensed under GPL.
+ */
+static void check_mount(void)
+{
+       FILE *f;
+       struct mntent *mnt;
+
+       if ((f = setmntent(MOUNTED, "r")) == NULL)
+               return;
+       while ((mnt = getmntent(f)) != NULL)
+               if (strcmp(device_name, mnt->mnt_fsname) == 0)
+                       break;
+       endmntent(f);
+       if (!mnt)
+               return;
+
+       error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
+}
+
+static long valid_offset(int fd, int offset)
+{
+       char ch;
+
+       if (lseek(fd, offset, 0) < 0)
+               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;
+
+       if ((fd = open(file, O_RDWR)) < 0)
+               perror_msg_and_die("%s", file);
+       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+               close(fd);
+               return (size * 512);
+       }
+
+       size = count_blocks(fd);
+       close(fd);
+       return size;
+}
+
+static void write_tables(void)
+{
+       /* Mark the super block valid. */
+       Super.s_state |= MINIX_VALID_FS;
+       Super.s_state &= ~MINIX_ERROR_FS;
+
+       if (lseek(DEV, 0, SEEK_SET))
+               error_msg_and_die("seek to boot block failed in write_tables");
+       if (512 != write(DEV, boot_block_buffer, 512))
+               error_msg_and_die("unable to clear boot sector");
+       if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
+               error_msg_and_die("seek failed in write_tables");
+       if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
+               error_msg_and_die("unable to write super-block");
+       if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
+               error_msg_and_die("unable to write inode map");
+       if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
+               error_msg_and_die("unable to write zone map");
+       if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
+               error_msg_and_die("unable to write inodes");
+
+}
+
+static void write_block(int blk, char *buffer)
+{
+       if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
+               error_msg_and_die("seek failed in write_block");
+       if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
+               error_msg_and_die("write failed in write_block");
+}
+
+static int get_free_block(void)
+{
+       int blk;
+
+       if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
+               error_msg_and_die("too many bad blocks");
+       if (used_good_blocks)
+               blk = good_blocks_table[used_good_blocks - 1] + 1;
+       else
+               blk = FIRSTZONE;
+       while (blk < ZONES && zone_in_use(blk))
+               blk++;
+       if (blk >= ZONES)
+               error_msg_and_die("not enough good blocks");
+       good_blocks_table[used_good_blocks] = blk;
+       used_good_blocks++;
+       return blk;
+}
+
+static void mark_good_blocks(void)
+{
+       int blk;
+
+       for (blk = 0; blk < used_good_blocks; blk++)
+               mark_zone(good_blocks_table[blk]);
+}
+
+static int next(int zone)
+{
+       if (!zone)
+               zone = FIRSTZONE - 1;
+       while (++zone < ZONES)
+               if (zone_in_use(zone))
+                       return zone;
+       return 0;
+}
+
+static void make_bad_inode(void)
+{
+       struct minix_inode *inode = &Inode[MINIX_BAD_INO];
+       int i, j, zone;
+       int ind = 0, dind = 0;
+       unsigned short ind_block[BLOCK_SIZE >> 1];
+       unsigned short dind_block[BLOCK_SIZE >> 1];
+
+#define NEXT_BAD (zone = next(zone))
+
+       if (!badblocks)
+               return;
+       mark_inode(MINIX_BAD_INO);
+       inode->i_nlinks = 1;
+       inode->i_time = time(NULL);
+       inode->i_mode = S_IFREG + 0000;
+       inode->i_size = 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;
+               }
+       }
+       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);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void make_bad_inode2(void)
+{
+       struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
+       int i, j, zone;
+       int ind = 0, dind = 0;
+       unsigned long ind_block[BLOCK_SIZE >> 2];
+       unsigned long dind_block[BLOCK_SIZE >> 2];
+
+       if (!badblocks)
+               return;
+       mark_inode(MINIX_BAD_INO);
+       inode->i_nlinks = 1;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
+       inode->i_mode = S_IFREG + 0000;
+       inode->i_size = 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 */
+       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);
+}
+#endif
+
+static void make_root_inode(void)
+{
+       struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
+
+       mark_inode(MINIX_ROOT_INO);
+       inode->i_zone[0] = get_free_block();
+       inode->i_nlinks = 2;
+       inode->i_time = time(NULL);
+       if (badblocks)
+               inode->i_size = 3 * dirsize;
+       else {
+               root_block[2 * dirsize] = '\0';
+               root_block[2 * dirsize + 1] = '\0';
+               inode->i_size = 2 * 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], root_block);
+}
+
+#ifdef BB_FEATURE_MINIX2
+static void make_root_inode2(void)
+{
+       struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
+
+       mark_inode(MINIX_ROOT_INO);
+       inode->i_zone[0] = get_free_block();
+       inode->i_nlinks = 2;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
+       if (badblocks)
+               inode->i_size = 3 * dirsize;
+       else {
+               root_block[2 * dirsize] = '\0';
+               root_block[2 * dirsize + 1] = '\0';
+               inode->i_size = 2 * 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], root_block);
+}
+#endif
+
+static void setup_tables(void)
+{
+       int i;
+       unsigned long inodes;
+
+       memset(super_block_buffer, 0, BLOCK_SIZE);
+       memset(boot_block_buffer, 0, 512);
+       MAGIC = magic;
+       ZONESIZE = 0;
+       MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
+       ZONES = BLOCKS;
+/* some magic nrs: 1 inode / 3 blocks */
+       if (req_nr_inodes == 0)
+               inodes = BLOCKS / 3;
+       else
+               inodes = req_nr_inodes;
+       /* Round up inode count to fill block size */
+#ifdef BB_FEATURE_MINIX2
+       if (version2)
+               inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
+                                 ~(MINIX2_INODES_PER_BLOCK - 1));
+       else
+#endif
+               inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
+                                 ~(MINIX_INODES_PER_BLOCK - 1));
+       if (inodes > 65535)
+               inodes = 65535;
+       INODES = inodes;
+       IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
+       ZMAPS = 0;
+       i = 0;
+       while (ZMAPS !=
+                  UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
+                                BITS_PER_BLOCK) && i < 1000) {
+               ZMAPS =
+                       UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
+                                 BITS_PER_BLOCK);
+               i++;
+       }
+       /* Real bad hack but overwise mkfs.minix can be thrown
+        * in infinite loop...
+        * try:
+        * dd if=/dev/zero of=test.fs count=10 bs=1024
+        * /sbin/mkfs.minix -i 200 test.fs
+        * */
+       if (i >= 999) {
+               error_msg_and_die("unable to allocate buffers for maps");
+       }
+       FIRSTZONE = NORM_FIRSTZONE;
+       inode_map = xmalloc(IMAPS * BLOCK_SIZE);
+       zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
+       memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
+       memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
+       for (i = FIRSTZONE; i < ZONES; i++)
+               unmark_zone(i);
+       for (i = MINIX_ROOT_INO; i <= INODES; i++)
+               unmark_inode(i);
+       inode_buffer = xmalloc(INODE_BUFFER_SIZE);
+       memset(inode_buffer, 0, INODE_BUFFER_SIZE);
+       printf("%ld inodes\n", INODES);
+       printf("%ld blocks\n", ZONES);
+       printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
+       printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
+       printf("Maxsize=%ld\n\n", MAXSIZE);
+}
+
+/*
+ * Perform a test of a block; return the number of
+ * blocks readable/writeable.
+ */
+static long do_check(char *buffer, int try, unsigned int current_block)
+{
+       long got;
+
+       /* Seek to the correct loc. */
+       if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
+               current_block * BLOCK_SIZE) {
+               error_msg_and_die("seek failed during testing of blocks");
+       }
+
+
+       /* Try the read */
+       got = read(DEV, buffer, try * BLOCK_SIZE);
+       if (got < 0)
+               got = 0;
+       if (got & (BLOCK_SIZE - 1)) {
+               printf("Weird values in do_check: probably bugs\n");
+       }
+       got /= BLOCK_SIZE;
+       return got;
+}
+
+static unsigned int currently_testing = 0;
+
+static void alarm_intr(int alnum)
+{
+       if (currently_testing >= ZONES)
+               return;
+       signal(SIGALRM, alarm_intr);
+       alarm(5);
+       if (!currently_testing)
+               return;
+       printf("%d ...", currently_testing);
+       fflush(stdout);
+}
+
+static void check_blocks(void)
+{
+       int try, got;
+       static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
+
+       currently_testing = 0;
+       signal(SIGALRM, alarm_intr);
+       alarm(5);
+       while (currently_testing < ZONES) {
+               if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
+                       currently_testing * BLOCK_SIZE)
+                       error_msg_and_die("seek failed in check_blocks");
+               try = TEST_BUFFER_BLOCKS;
+               if (currently_testing + try > ZONES)
+                       try = ZONES - currently_testing;
+               got = do_check(buffer, try, currently_testing);
+               currently_testing += got;
+               if (got == try)
+                       continue;
+               if (currently_testing < FIRSTZONE)
+                       error_msg_and_die("bad blocks before data-area: cannot make fs");
+               mark_zone(currently_testing);
+               badblocks++;
+               currently_testing++;
+       }
+       if (badblocks > 1)
+               printf("%d bad blocks\n", badblocks);
+       else if (badblocks == 1)
+               printf("one bad block\n");
+}
+
+static void get_list_blocks(filename)
+char *filename;
+
+{
+       FILE *listfile;
+       unsigned long blockno;
+
+       listfile = xfopen(filename, "r");
+       while (!feof(listfile)) {
+               fscanf(listfile, "%ld\n", &blockno);
+               mark_zone(blockno);
+               badblocks++;
+       }
+       if (badblocks > 1)
+               printf("%d bad blocks\n", badblocks);
+       else if (badblocks == 1)
+               printf("one bad block\n");
+}
+
+extern int mkfs_minix_main(int argc, char **argv)
+{
+       int i=1;
+       char *tmp;
+       struct stat statbuf;
+       char *listfile = NULL;
+       int stopIt=FALSE;
+
+       if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
+               error_msg_and_die("bad inode size");
+#ifdef BB_FEATURE_MINIX2
+       if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
+               error_msg_and_die("bad inode size");
+#endif
+       
+       /* Parse options */
+       argv++;
+       while (--argc >= 0 && *argv && **argv) {
+               if (**argv == '-') {
+                       stopIt=FALSE;
+                       while (i > 0 && *++(*argv) && stopIt==FALSE) {
+                               switch (**argv) {
+                                       case 'c':
+                                               check = 1;
+                                               break;
+                                       case 'i':
+                                               {
+                                                       char *cp=NULL;
+                                                       if (*(*argv+1) != 0) {
+                                                               cp = ++(*argv);
+                                                       } else {
+                                                               if (--argc == 0) {
+                                                                       goto goodbye;
+                                                               }
+                                                               cp = *(++argv);
+                                                       }
+                                                       req_nr_inodes = strtoul(cp, &tmp, 0);
+                                                       if (*tmp)
+                                                               show_usage();
+                                                       stopIt=TRUE;
+                                                       break;
+                                               }
+                                       case 'l':
+                                               if (--argc == 0) {
+                                                       goto goodbye;
+                                               }
+                                               listfile = *(++argv);
+                                               break;
+                                       case 'n':
+                                               {
+                                                       char *cp=NULL;
+
+                                                       if (*(*argv+1) != 0) {
+                                                               cp = ++(*argv);
+                                                       } else {
+                                                               if (--argc == 0) {
+                                                                       goto goodbye;
+                                                               }
+                                                               cp = *(++argv);
+                                                       }
+                                                       i = strtoul(cp, &tmp, 0);
+                                                       if (*tmp)
+                                                               show_usage();
+                                                       if (i == 14)
+                                                               magic = MINIX_SUPER_MAGIC;
+                                                       else if (i == 30)
+                                                               magic = MINIX_SUPER_MAGIC2;
+                                                       else 
+                                                               show_usage();
+                                                       namelen = i;
+                                                       dirsize = i + 2;
+                                                       stopIt=TRUE;
+                                                       break;
+                                               }
+                                       case 'v':
+#ifdef BB_FEATURE_MINIX2
+                                               version2 = 1;
+#else
+                                               error_msg("%s: not compiled with minix v2 support",
+                                                               device_name);
+                                               exit(-1);
+#endif
+                                               break;
+                                       case '-':
+                                       case 'h':
+                                       default:
+goodbye:
+                                               show_usage();
+                               }
+                       }
+               } else {
+                       if (device_name == NULL)
+                               device_name = *argv;
+                       else if (BLOCKS == 0)
+                               BLOCKS = strtol(*argv, &tmp, 0);
+                       else {
+                               goto goodbye;
+                       }
+               }
+               argv++;
+       }
+
+       if (device_name && !BLOCKS)
+               BLOCKS = get_size(device_name) / 1024;
+       if (!device_name || BLOCKS < 10) {
+               show_usage();
+       }
+#ifdef BB_FEATURE_MINIX2
+       if (version2) {
+               if (namelen == 14)
+                       magic = MINIX2_SUPER_MAGIC;
+               else
+                       magic = MINIX2_SUPER_MAGIC2;
+       } else
+#endif
+       if (BLOCKS > 65535)
+               BLOCKS = 65535;
+       check_mount();                          /* is it already mounted? */
+       tmp = root_block;
+       *(short *) tmp = 1;
+       strcpy(tmp + 2, ".");
+       tmp += dirsize;
+       *(short *) tmp = 1;
+       strcpy(tmp + 2, "..");
+       tmp += dirsize;
+       *(short *) tmp = 2;
+       strcpy(tmp + 2, ".badblocks");
+       DEV = open(device_name, O_RDWR);
+       if (DEV < 0)
+               error_msg_and_die("unable to open %s", device_name);
+       if (fstat(DEV, &statbuf) < 0)
+               error_msg_and_die("unable to stat %s", device_name);
+       if (!S_ISBLK(statbuf.st_mode))
+               check = 0;
+       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
+               error_msg_and_die("will not try to make filesystem on '%s'", device_name);
+       setup_tables();
+       if (check)
+               check_blocks();
+       else if (listfile)
+               get_list_blocks(listfile);
+#ifdef BB_FEATURE_MINIX2
+       if (version2) {
+               make_root_inode2();
+               make_bad_inode2();
+       } else
+#endif
+       {
+               make_root_inode();
+               make_bad_inode();
+       }
+       mark_good_blocks();
+       write_tables();
+       return( 0);
+
+}
diff --git a/mknod.c b/mknod.c
new file mode 100644 (file)
index 0000000..10d026c
--- /dev/null
+++ b/mknod.c
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mknod implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+int mknod_main(int argc, char **argv)
+{
+       char *thisarg;
+       mode_t mode = 0;
+       mode_t perm = 0666;
+       dev_t dev = 0;
+
+       argc--;
+       argv++;
+
+       /* Parse any options */
+       while (argc > 1) {
+               if (**argv != '-')
+                       break;
+               thisarg = *argv;
+               thisarg++;
+               switch (*thisarg) {
+               case 'm':
+                       argc--;
+                       argv++;
+                       parse_mode(*argv, &perm);
+                       umask(0);
+                       break;
+               default:
+                       show_usage();
+               }
+               argc--;
+               argv++;
+       }
+       if (argc != 4 && argc != 2) {
+               show_usage();
+       }
+       switch (argv[1][0]) {
+       case 'c':
+       case 'u':
+               mode = S_IFCHR;
+               break;
+       case 'b':
+               mode = S_IFBLK;
+               break;
+       case 'p':
+               mode = S_IFIFO;
+               if (argc!=2) {
+                       show_usage();
+               }
+               break;
+       default:
+               show_usage();
+       }
+
+       if (mode == S_IFCHR || mode == S_IFBLK) {
+               dev = (atoi(argv[2]) << 8) | atoi(argv[3]);
+       }
+
+       mode |= perm;
+
+       if (mknod(argv[0], mode, dev) != 0)
+               perror_msg_and_die("%s", argv[0]);
+       return EXIT_SUCCESS;
+}
+
diff --git a/mkswap.c b/mkswap.c
new file mode 100644 (file)
index 0000000..bbf0209
--- /dev/null
+++ b/mkswap.c
@@ -0,0 +1,422 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkswap.c - set up a linux swap device
+ *
+ * (C) 1991 Linus Torvalds. This file may be redistributed as per
+ * the Linux copyright.
+ */
+
+/*
+ * 20.12.91  - time began. Got VM working yesterday by doing this by hand.
+ *
+ * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
+ *
+ *     -c   for readability checking. (Use it unless you are SURE!)
+ *     -vN  for swap areas version N. (Only N=0,1 known today.)
+ *      -f   for forcing swap creation even if it would smash partition table.
+ *
+ * The device may be a block device or an image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ *
+ * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
+ * size-in-blocks parameter optional added Wed Feb  8 10:33:43 1995.
+ *
+ * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
+ *
+ * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
+ * V1_MAX_PAGES fixes, jj, 990325.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ *  from util-linux -- adapted for busybox by
+ *  Erik Andersen <andersee@debian.org>. I ripped out Native Language
+ *  Support, made some stuff smaller, and fitted for life in busybox.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>                 /* for _IO */
+#include <sys/utsname.h>
+#include <asm/page.h>                  /* for PAGE_SIZE and PAGE_SHIFT */
+                               /* we also get PAGE_SIZE via getpagesize() */
+#include "busybox.h"
+
+#ifndef _IO
+/* pre-1.3.45 */
+static const int BLKGETSIZE = 0x1260;
+#else
+/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
+#define BLKGETSIZE _IO(0x12,96)
+#endif
+
+static char *device_name = NULL;
+static int DEV = -1;
+static long PAGES = 0;
+static int check = 0;
+static int badpages = 0;
+static int version = -1;
+
+#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
+
+/*
+ * The definition of the union swap_header uses the constant PAGE_SIZE.
+ * Unfortunately, on some architectures this depends on the hardware model,
+ * and can only be found at run time -- we use getpagesize().
+ */
+
+static int pagesize;
+static int *signature_page;
+
+static struct swap_header_v1 {
+       char bootbits[1024];            /* Space for disklabel etc. */
+       unsigned int version;
+       unsigned int last_page;
+       unsigned int nr_badpages;
+       unsigned int padding[125];
+       unsigned int badpages[1];
+} *p;
+
+static inline void init_signature_page()
+{
+       pagesize = getpagesize();
+
+#ifdef PAGE_SIZE
+       if (pagesize != PAGE_SIZE)
+               error_msg("Assuming pages of size %d", pagesize);
+#endif
+       signature_page = (int *) xmalloc(pagesize);
+       memset(signature_page, 0, pagesize);
+       p = (struct swap_header_v1 *) signature_page;
+}
+
+static inline void write_signature(char *sig)
+{
+       char *sp = (char *) signature_page;
+
+       strncpy(sp + pagesize - 10, sig, 10);
+}
+
+#define V0_MAX_PAGES   (8 * (pagesize - 10))
+/* Before 2.2.0pre9 */
+#define V1_OLD_MAX_PAGES       ((0x7fffffff / pagesize) - 1)
+/* Since 2.2.0pre9:
+   error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
+   with variations on
+       #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+       #define SWP_OFFSET(entry) ((entry) >> 8)
+   on the various architectures. Below the result - yuk.
+
+   Machine     pagesize        SWP_ENTRY       SWP_OFFSET      bound+1 oldbound+2
+   i386                2^12            o<<8            e>>8            1<<24   1<<19
+   mips                2^12            o<<15           e>>15           1<<17   1<<19
+   alpha       2^13            o<<40           e>>40           1<<24   1<<18
+   m68k                2^12            o<<12           e>>12           1<<20   1<<19
+   sparc       2^{12,13}       (o&0x3ffff)<<9  (e>>9)&0x3ffff  1<<18   1<<{19,18}
+   sparc64     2^13            o<<13           e>>13           1<<51   1<<18
+   ppc         2^12            o<<8            e>>8            1<<24   1<<19
+   armo                2^{13,14,15}    o<<8            e>>8            1<<24   1<<{18,17,16}
+   armv                2^12            o<<9            e>>9            1<<23   1<<19
+
+   assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
+
+   The bad part is that we need to know this since the kernel will
+   refuse a swap space if it is too large.
+*/
+/* patch from jj - why does this differ from the above? */
+#if defined(__alpha__)
+#define V1_MAX_PAGES           ((1 << 24) - 1)
+#elif defined(__mips__)
+#define V1_MAX_PAGES           ((1 << 17) - 1)
+#elif defined(__sparc_v9__)
+#define V1_MAX_PAGES           ((3 << 29) - 1)
+#elif defined(__sparc__)
+#define V1_MAX_PAGES           (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
+#else
+#define V1_MAX_PAGES           V1_OLD_MAX_PAGES
+#endif
+/* man page now says:
+The maximum useful size of a swap area now depends on the architecture.
+It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
+128GB on alpha and 3TB on sparc64.
+*/
+
+#define MAX_BADPAGES   ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
+
+static inline void bit_set(unsigned int *addr, unsigned int nr)
+{
+       unsigned int r, m;
+
+       addr += nr / (8 * sizeof(int));
+
+       r = *addr;
+       m = 1 << (nr & (8 * sizeof(int) - 1));
+
+       *addr = r | m;
+}
+
+static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
+{
+       unsigned int r, m;
+
+       addr += nr / (8 * sizeof(int));
+
+       r = *addr;
+       m = 1 << (nr & (8 * sizeof(int) - 1));
+
+       *addr = r & ~m;
+       return (r & m) != 0;
+}
+
+
+static void page_ok(int page)
+{
+       if (version == 0)
+               bit_set(signature_page, page);
+}
+
+static inline void page_bad(int page)
+{
+       if (version == 0)
+               bit_test_and_clear(signature_page, page);
+       else {
+               if (badpages == MAX_BADPAGES)
+                       error_msg_and_die("too many bad pages");
+               p->badpages[badpages] = page;
+       }
+       badpages++;
+}
+
+static void check_blocks(void)
+{
+       unsigned int current_page;
+       int do_seek = 1;
+       char *buffer;
+
+       buffer = xmalloc(pagesize);
+       current_page = 0;
+       while (current_page < PAGES) {
+               if (!check) {
+                       page_ok(current_page++);
+                       continue;
+               }
+               if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
+                       current_page * pagesize)
+                       error_msg_and_die("seek failed in check_blocks");
+               if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
+                       page_bad(current_page++);
+                       continue;
+               }
+               page_ok(current_page++);
+       }
+       if (badpages == 1)
+               printf("one bad page\n");
+       else if (badpages > 1)
+               printf("%d bad pages\n", badpages);
+}
+
+static long valid_offset(int fd, int offset)
+{
+       char ch;
+
+       if (lseek(fd, offset, 0) < 0)
+               return 0;
+       if (read(fd, &ch, 1) < 1)
+               return 0;
+       return 1;
+}
+
+static int find_size(int fd)
+{
+       unsigned int high, low;
+
+       low = 0;
+       for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
+               low = high;
+       while (low < high - 1) {
+               const int mid = (low + high) / 2;
+
+               if (valid_offset(fd, mid))
+                       low = mid;
+               else
+                       high = mid;
+       }
+       return (low + 1);
+}
+
+/* return size in pages, to avoid integer overflow */
+static long get_size(const char *file)
+{
+       int fd;
+       long size;
+
+       if ((fd = open(file, O_RDONLY)) < 0)
+               perror_msg_and_die("%s", file);
+       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+               int sectors_per_page = pagesize / 512;
+
+               size /= sectors_per_page;
+       } else {
+               size = find_size(fd) / pagesize;
+       }
+       close(fd);
+       return size;
+}
+
+int mkswap_main(int argc, char **argv)
+{
+       char *tmp;
+       struct stat statbuf;
+       int sz;
+       int maxpages;
+       int goodpages;
+       int offset;
+       int force = 0;
+
+       init_signature_page();          /* get pagesize */
+
+       while (argc-- > 1) {
+               argv++;
+               if (argv[0][0] != '-') {
+                       if (device_name) {
+                               int blocks_per_page = pagesize / 1024;
+
+                               PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
+                               if (*tmp)
+                                       show_usage();
+                       } else
+                               device_name = argv[0];
+               } else {
+                       switch (argv[0][1]) {
+                       case 'c':
+                               check = 1;
+                               break;
+                       case 'f':
+                               force = 1;
+                               break;
+                       case 'v':
+                               version = atoi(argv[0] + 2);
+                               break;
+                       default:
+                               show_usage();
+                       }
+               }
+       }
+       if (!device_name) {
+               error_msg("error: Nowhere to set up swap on?");
+               show_usage();
+       }
+       sz = get_size(device_name);
+       if (!PAGES) {
+               PAGES = sz;
+       } else if (PAGES > sz && !force) {
+               error_msg("error: size %ld is larger than device size %d",
+                               PAGES * (pagesize / 1024), sz * (pagesize / 1024));
+               return EXIT_FAILURE;
+       }
+
+       if (version == -1) {
+               if (PAGES <= V0_MAX_PAGES)
+                       version = 0;
+               else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
+                       version = 0;
+               else if (pagesize < 2048)
+                       version = 0;
+               else
+                       version = 1;
+       }
+       if (version != 0 && version != 1) {
+               error_msg("error: unknown version %d", version);
+               show_usage();
+       }
+       if (PAGES < 10) {
+               error_msg("error: swap area needs to be at least %ldkB",
+                               (long) (10 * pagesize / 1024));
+               show_usage();
+       }
+#if 0
+       maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
+#else
+       if (!version)
+               maxpages = V0_MAX_PAGES;
+       else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
+               maxpages = V1_MAX_PAGES;
+       else {
+               maxpages = V1_OLD_MAX_PAGES;
+               if (maxpages > V1_MAX_PAGES)
+                       maxpages = V1_MAX_PAGES;
+       }
+#endif
+       if (PAGES > maxpages) {
+               PAGES = maxpages;
+               error_msg("warning: truncating swap area to %ldkB",
+                               PAGES * pagesize / 1024);
+       }
+
+       DEV = open(device_name, O_RDWR);
+       if (DEV < 0 || fstat(DEV, &statbuf) < 0)
+               perror_msg_and_die("%s", device_name);
+       if (!S_ISBLK(statbuf.st_mode))
+               check = 0;
+       else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
+               error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
+
+#ifdef __sparc__
+       if (!force && version == 0) {
+               /* Don't overwrite partition table unless forced */
+               unsigned char *buffer = (unsigned char *) signature_page;
+               unsigned short *q, sum;
+
+               if (read(DEV, buffer, 512) != 512)
+                       error_msg_and_die("fatal: first page unreadable");
+               if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
+                       q = (unsigned short *) (buffer + 510);
+                       for (sum = 0; q >= (unsigned short *) buffer;)
+                               sum ^= *q--;
+                       if (!sum) {
+                               error_msg("Device '%s' contains a valid Sun disklabel.\n"
+"This probably means creating v0 swap would destroy your partition table\n"
+"No swap created. If you really want to create swap v0 on that device, use\n"
+"the -f option to force it.", device_name);
+                               return EXIT_FAILURE;
+                       }
+               }
+       }
+#endif
+
+       if (version == 0 || check)
+               check_blocks();
+       if (version == 0 && !bit_test_and_clear(signature_page, 0))
+               error_msg_and_die("fatal: first page unreadable");
+       if (version == 1) {
+               p->version = version;
+               p->last_page = PAGES - 1;
+               p->nr_badpages = badpages;
+       }
+
+       goodpages = PAGES - badpages - 1;
+       if (goodpages <= 0)
+               error_msg_and_die("Unable to set up swap-space: unreadable");
+       printf("Setting up swapspace version %d, size = %ld bytes\n",
+                  version, (long) (goodpages * pagesize));
+       write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
+
+       offset = ((version == 0) ? 0 : 1024);
+       if (lseek(DEV, offset, SEEK_SET) != offset)
+               error_msg_and_die("unable to rewind swap-device");
+       if (write(DEV, (char *) signature_page + offset, pagesize - offset)
+               != pagesize - offset)
+               error_msg_and_die("unable to write signature page");
+
+       /*
+        * A subsequent swapon() will fail if the signature
+        * is not actually on disk. (This is a kernel bug.)
+        */
+       if (fsync(DEV))
+               error_msg_and_die("fsync failed");
+       return EXIT_SUCCESS;
+}
diff --git a/mktemp.c b/mktemp.c
new file mode 100644 (file)
index 0000000..bc47d0a
--- /dev/null
+++ b/mktemp.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mktemp implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Daniel Jacobowitz
+ * Written by Daniel Jacobowitz <dan@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int mktemp_main(int argc, char **argv)
+{
+       if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q")))
+               show_usage();
+       if(mkstemp(argv[argc-1]) < 0)
+               return EXIT_FAILURE;
+       (void) puts(argv[argc-1]);
+       return EXIT_SUCCESS;
+}
diff --git a/modprobe.c b/modprobe.c
new file mode 100644 (file)
index 0000000..3cca57d
--- /dev/null
@@ -0,0 +1,366 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * really dumb modprobe implementation for busybox
+ * Copyright (C) 2001 Lineo, davidm@lineo.com
+ *
+ * BB_FEATURE_MODPROBE_DEPEND stuff was added and is
+ * Copyright (C) 2002 Robert Griebl, griebl@gmx.de
+ *
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include "busybox.h"
+
+#define BB_FEATURE_MODPROBE_DEPEND
+
+#ifdef BB_FEATURE_MODPROBE_DEPEND
+
+#include <sys/utsname.h>
+
+/* Jump through hoops to simulate how fgets() grabs just one line at a time...
+ * Don't use any stdio since modprobe gets called from a kernel thread and
+ * stdio junk can overflow the limited stack...     */
+static char *reads ( int fd, char *buffer, size_t len )
+{            
+       ssize_t n = read ( fd, buffer, len );
+       if ( n > 0 ) {
+               char *p;
+               buffer [len-1] = 0;
+               p = strchr ( buffer, '\n' );
+               if ( p ) {
+                       off_t offset;
+                       offset = lseek ( fd, 0L, SEEK_CUR );
+                       /* Get the current file descriptor offset */
+                       lseek ( fd, offset-n + (p-buffer) + 1, SEEK_SET );
+                       /* Set the file descriptor offset to right after the \n */
+                       p[1] = 0;
+               }
+               return buffer;
+       } else {
+               return 0;
+       }
+}
+
+struct dep_t {
+       char *  m_module;
+       int     m_depcnt;
+       char ** m_deparr;
+       
+       struct dep_t * m_next;
+};
+
+
+static struct dep_t *build_dep ( void )
+{
+       int fd;
+       struct utsname un;
+       struct dep_t *first = 0;
+       struct dep_t *current = 0;
+       char buffer [256];
+       char *filename = buffer;
+       int continuation_line = 0;
+       
+       if ( uname ( &un ))
+               return 0;
+       strcpy ( filename, "/lib/modules/" );
+       strcat ( filename, un.release );
+       strcat ( filename, "/modules.dep" );
+
+       if ((fd = open ( filename, O_RDONLY )) < 0)
+               return 0;
+       
+       while ( reads ( fd, buffer, sizeof( buffer ))) {
+               char *p;
+               int l = xstrlen ( buffer );
+
+               if ( buffer [l-1] == '\n' ) {
+                       buffer [l-1] = 0;
+                       l--;
+               }
+               
+               if ( l == 0 ) {
+                       continuation_line = 0;
+                       continue;
+               }
+               
+               if ( !continuation_line ) {             
+                       char *col = strchr ( buffer, ':' );
+               
+                       if ( col ) {
+                               char *mods;
+                               char *mod;
+                               int ext = 0;
+                               
+                               *col = 0;
+                               mods = strrchr ( buffer, '/' );
+                               
+                               if ( !mods )
+                                       mods = buffer;
+                               else
+                                       mods++;
+                                       
+                               if (( *(col-2) == '.' ) && ( *(col-1) == 'o' ))
+                                       ext = 2;
+                               
+                               mod = xstrndup ( mods, col - mods - ext );
+                                       
+                               if ( !current ) {
+                                       first = current = (struct dep_t *) malloc ( sizeof ( struct dep_t ));
+                               }
+                               else {
+                                       current->m_next = (struct dep_t *) malloc ( sizeof ( struct dep_t ));
+                                       current = current->m_next;
+                               }
+                               current->m_module = mod;
+                               current->m_depcnt = 0;
+                               current->m_deparr = 0;
+                               current->m_next = 0;
+                                               
+                               //printf ( "%s:\n", mod );
+                                               
+                               p = col + 1;            
+                       }
+                       else
+                               p = 0;
+               }
+               else
+                       p = buffer;
+                       
+               if ( p && *p ) {
+                       char *end = &buffer [l-1];
+                       char *deps = strrchr ( end, '/' );
+                       char *dep;
+                       int ext = 0;
+                       
+                       while ( isblank ( *end ) || ( *end == '\\' ))
+                               end--;
+                               
+                       deps = strrchr ( p, '/' );
+                       
+                       if ( !deps || ( deps < p )) {
+                               deps = p;
+               
+                               while ( isblank ( *deps ))
+                                       deps++;
+                       }
+                       else
+                               deps++;
+                       
+                       if (( *(end-1) == '.' ) && ( *end == 'o' ))
+                               ext = 2;
+
+                       /* Cope with blank lines */
+                       if ((end-deps-ext+1) <= 0)
+                               continue;
+                       
+                       dep = xstrndup ( deps, end - deps - ext + 1 );
+                       
+                       current->m_depcnt++;
+                       current->m_deparr = (char **) xrealloc ( current->m_deparr, sizeof ( char *) * current->m_depcnt );
+                       current->m_deparr [current->m_depcnt - 1] = dep;                
+                       
+                       //printf ( "    %d) %s\n", current->m_depcnt, current->m_deparr [current->m_depcnt -1] );
+               }
+       
+               if ( buffer [l-1] == '\\' )
+                       continuation_line = 1;
+               else
+                       continuation_line = 0;
+       }
+       close ( fd );
+       
+       return first;
+}
+
+
+static struct dep_t *find_dep ( struct dep_t *dt, char *mod )
+{
+       int lm = xstrlen ( mod );
+       int extpos = 0;
+
+       if (( mod [lm-2] == '.' ) && ( mod [lm-1] == 'o' ))
+               extpos = 2;
+
+       if ( extpos > 0 )       
+               mod [lm - extpos] = 0;
+
+       while ( dt ) {
+               if ( !strcmp ( dt->m_module, mod ))
+                       break;
+
+               dt = dt->m_next;
+       }
+       if ( extpos > 0 )
+               mod [lm - extpos] = '.';
+
+       return dt;
+}
+
+#define MODPROBE_EXECUTE       0x1
+#define MODPROBE_INSERT                0x2
+#define MODPROBE_REMOVE                0x4
+
+static void check_dep ( char *mod, int do_syslog, 
+               int show_only, int verbose, int flags )
+{
+       static struct dep_t *depend = (struct dep_t *) -1;      
+       struct dep_t *dt;
+       
+       if ( depend == (struct dep_t *) -1 )
+               depend = build_dep ( );
+       
+       if (( dt = find_dep ( depend, mod ))) {
+               int i;
+                       
+               for ( i = 0; i < dt->m_depcnt; i++ ) 
+                       check_dep ( dt->m_deparr [i], do_syslog, 
+                                       show_only, verbose, flags|MODPROBE_EXECUTE);
+       }
+       if ( flags & MODPROBE_EXECUTE ) {
+               char lcmd [256];
+               if ( flags & MODPROBE_INSERT ) {
+                       snprintf(lcmd, sizeof(lcmd)-1, "insmod %s -q -k %s 2>/dev/null", 
+                                       do_syslog ? "-s" : "", mod );
+               }
+               if ( flags & MODPROBE_REMOVE ) {
+                       snprintf(lcmd, sizeof(lcmd)-1, "insmod %s -q -k %s 2>/dev/null", 
+                                       do_syslog ? "-s" : "", mod );
+               }
+               if ( flags & (MODPROBE_REMOVE|MODPROBE_INSERT) ) {
+                       if (verbose)
+                               printf("%s\n", lcmd);
+                       if (!show_only)
+                               system ( lcmd );
+               }
+       }
+}      
+
+#endif
+               
+
+extern int modprobe_main(int argc, char** argv)
+{
+       int     ch, rc = 0;
+       int     loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0;
+       int     show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0;
+       char    *load_type = NULL, *config = NULL;
+       char cmd[256];
+
+       while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1)
+               switch(ch) {
+               case 'a':
+                       loadall++;
+                       break;
+               case 'c':
+                       showconfig++;
+                       break;
+               case 'd':
+                       debug++;
+                       break;
+               case 'k':
+                       autoclean++;
+                       break;
+               case 'l':
+                       list++;
+                       break;
+               case 'n':
+                       show_only++;
+                       break;
+               case 'q':
+                       quiet++;
+                       break;
+               case 'r':
+                       remove_opt++;
+                       break;
+               case 's':
+                       do_syslog++;
+                       break;
+               case 't':
+                       load_type = optarg;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'C':
+                       config = optarg;
+                       break;
+               case 'V':
+               default:
+                       show_usage();
+                       break;
+               }
+
+       if (load_type || config) {
+               fprintf(stderr, "-t and -C not supported\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (showconfig)
+               exit(EXIT_SUCCESS);
+       
+       if (list)
+               exit(EXIT_SUCCESS);
+       
+       if (remove_opt) {
+               do {
+                       snprintf(cmd, sizeof(cmd)-1, "rmmod %s %s %s",
+                                       optind >= argc ? "-a" : "",
+                                       do_syslog ? "-s" : "",
+                                       optind < argc ? argv[optind] : "");
+                       if (do_syslog)
+                               syslog(LOG_INFO, "%s", cmd);
+                       if (verbose)
+                               printf("%s\n", cmd);
+                       if (!show_only)
+                               rc = system(cmd);
+                               
+#ifdef BB_FEATURE_MODPROBE_DEPEND
+                       if ( optind < argc )
+                               check_dep ( argv [optind], do_syslog, show_only, verbose, MODPROBE_REMOVE);
+#endif                         
+               } while (++optind < argc);
+               exit(EXIT_SUCCESS);
+       }
+
+       if (optind >= argc) {
+               fprintf(stderr, "No module or pattern provided\n");
+               exit(EXIT_FAILURE);
+       }
+
+       snprintf(cmd, sizeof(cmd)-1, "insmod %s %s %s",
+                       do_syslog ? "-s" : "",
+                       quiet ? "-q" : "",
+                       autoclean ? "-k" : "");
+
+#ifdef BB_FEATURE_MODPROBE_DEPEND
+       check_dep ( argv [optind], do_syslog, show_only, verbose, MODPROBE_INSERT);
+#endif
+
+       while (optind < argc) {
+               if (strlen(cmd) + 1 + strlen(argv[optind]) >= sizeof(cmd))
+               {
+                       error_msg_and_die("Too many module parameters!\n");
+               }
+               strcat(cmd, " ");
+               strcat(cmd, argv[optind]);
+               optind++;
+       }
+       if (do_syslog)
+               syslog(LOG_INFO, "%s", cmd);
+       if (verbose)
+               printf("%s\n", cmd);
+       if (!show_only)
+               rc = system(cmd);
+       else
+               rc = 0;
+
+       exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+
diff --git a/more.c b/more.c
new file mode 100644 (file)
index 0000000..f495880
--- /dev/null
+++ b/more.c
@@ -0,0 +1,214 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini more implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * Latest version blended by Erik Andersen <andersee@debian.org>, based
+ * on the original more implementation by Bruce, code from the Debian 
+ * boot-floppies team, and my own bits of stuff.
+ *
+ * Termios corrects by Vladimir Oleynik <vodz@usa.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+static FILE *cin;
+
+#ifdef BB_FEATURE_USE_TERMIOS
+#include <termios.h>
+#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
+#define getTermSettings(fd,argp) tcgetattr(fd, argp);
+
+static struct termios initial_settings, new_settings;
+
+static void set_tty_to_initial_mode(void)
+{
+       setTermSettings(fileno(cin), &initial_settings);
+}
+
+static void gotsig(int sig)
+{
+       putchar('\n');
+       exit(EXIT_FAILURE);
+}
+#endif /* BB_FEATURE_USE_TERMIOS */
+
+
+static int terminal_width = 79;        /* not 80 in case terminal has linefold bug */
+static int terminal_height = 24;
+
+
+extern int more_main(int argc, char **argv)
+{
+       int c, lines, input = 0;
+       int please_display_more_prompt = -1;
+       struct stat st;
+       FILE *file;
+       int len, page_height;
+
+#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
+       struct winsize win = { 0, 0, 0, 0 };
+#endif
+
+       argc--;
+       argv++;
+
+
+       /* not use inputing from terminal if usage: more > outfile */
+       if(isatty(fileno(stdout))) {
+               cin = fopen(CURRENT_TTY, "r");
+               if (!cin)
+                       cin = xfopen(CONSOLE_DEV, "r");
+               please_display_more_prompt = 0;
+#ifdef BB_FEATURE_USE_TERMIOS
+               getTermSettings(fileno(cin), &initial_settings);
+               new_settings = initial_settings;
+               new_settings.c_lflag &= ~ICANON;
+               new_settings.c_lflag &= ~ECHO;
+               new_settings.c_cc[VMIN] = 1;
+               new_settings.c_cc[VTIME] = 0;
+               setTermSettings(fileno(cin), &new_settings);
+               atexit(set_tty_to_initial_mode);
+               (void) signal(SIGINT, gotsig);
+               (void) signal(SIGQUIT, gotsig);
+               (void) signal(SIGTERM, gotsig);
+#endif
+       }
+
+       do {
+               if (argc == 0) {
+                       file = stdin;
+               } else
+                       file = wfopen(*argv, "r");
+               if(file==0)
+                       goto loop;
+                       
+               st.st_size = 0;
+               fstat(fileno(file), &st);
+
+               if(please_display_more_prompt>0)
+                       please_display_more_prompt = 0;
+
+#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS
+               ioctl(fileno(stdout), TIOCGWINSZ, &win);
+               if (win.ws_row > 4)
+                       terminal_height = win.ws_row - 2;
+               if (win.ws_col > 0)
+                       terminal_width = win.ws_col - 1;
+#endif
+               len=0;
+               lines = 0;
+               page_height = terminal_height;
+               while ((c = getc(file)) != EOF) {
+
+                       if (please_display_more_prompt>0) {
+                               len = printf("--More-- ");
+                               if (file != stdin && st.st_size > 0) {
+#if _FILE_OFFSET_BITS == 64
+                                       len += printf("(%d%% of %lld bytes)",
+                                                  (int) (100 * ((double) ftell(file) /
+                                                  (double) st.st_size)), (long long)st.st_size);
+#else
+                                       len += printf("(%d%% of %ld bytes)",
+                                                  (int) (100 * ((double) ftell(file) /
+                                                  (double) st.st_size)), (long)st.st_size);
+#endif
+                               }
+
+                               fflush(stdout);
+
+                               /*
+                                * We've just displayed the "--More--" prompt, so now we need
+                                * to get input from the user.
+                                */
+                               input = getc(cin);
+#ifndef BB_FEATURE_USE_TERMIOS
+                               printf("\033[A"); /* up cursor */
+#endif
+                               /* Erase the "More" message */
+                               putc('\r', stdout);
+                               while (--len >= 0)
+                                       putc(' ', stdout);
+                               putc('\r', stdout);
+                               fflush(stdout);
+                               len=0;
+                               lines = 0;
+                               page_height = terminal_height;
+                               please_display_more_prompt = 0;
+
+                               if (input == 'q')
+                                       goto end;
+                       }
+
+                       /* 
+                        * There are two input streams to worry about here:
+                        *
+                        * c     : the character we are reading from the file being "mored"
+                        * input : a character received from the keyboard
+                        *
+                        * If we hit a newline in the _file_ stream, we want to test and
+                        * see if any characters have been hit in the _input_ stream. This
+                        * allows the user to quit while in the middle of a file.
+                        */
+                       if (c == '\n') {
+                               /* increment by just one line if we are at
+                                * the end of this line */
+                               if (input == '\n')
+                                       if(please_display_more_prompt==0)
+                                       please_display_more_prompt = 1;
+                               /* Adjust the terminal height for any overlap, so that
+                                * no lines get lost off the top. */
+                               if (len >= terminal_width) {
+                                       int quot, rem;
+                                       quot = len / terminal_width;
+                                       rem  = len - (quot * terminal_width);
+                                       if (quot) {
+                                               if (rem)
+                                                       page_height-=quot;
+                                               else
+                                                       page_height-=(quot-1);
+                                       }
+                               }
+                               if (++lines >= page_height) {
+                                       if(please_display_more_prompt==0)
+                                       please_display_more_prompt = 1;
+                               }
+                               len=0;
+                       }
+                       /*
+                        * If we just read a newline from the file being 'mored' and any
+                        * key other than a return is hit, scroll by one page
+                        */
+                       putc(c, stdout);
+                       len++;
+               }
+               fclose(file);
+               fflush(stdout);
+loop:
+               argv++;
+       } while (--argc > 0);
+  end:
+       return 0;
+}
diff --git a/mount.c b/mount.c
new file mode 100644 (file)
index 0000000..aa77f98
--- /dev/null
+++ b/mount.c
@@ -0,0 +1,505 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mount implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * 3/21/1999   Charles P. Wright <cpwright@cpwright.com>
+ *             searches through fstab when -a is passed
+ *             will try mounting stuff with all fses when passed -t auto
+ *
+ * 1999-04-17  Dave Cinege...Rewrote -t auto. Fixed ro mtab.
+ *
+ * 1999-10-07  Erik Andersen <andersee@debian.org>.
+ *              Rewrite of a lot of code. Removed mtab usage (I plan on
+ *              putting it back as a compile-time option some time), 
+ *              major adjustments to option parsing, and some serious 
+ *              dieting all around.
+ *
+ * 1999-11-06  mtab suppport is back - andersee
+ *
+ * 2000-01-12   Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
+ *              mount to add loop support.
+ *
+ * 2000-04-30  Dave Cinege <dcinege@psychosis.com>
+ *             Rewrote fstab while loop and lower mount section. Can now do
+ *             single mounts from fstab. Can override fstab options for single
+ *             mount. Common mount_one call for single mounts and 'all'. Fixed
+ *             mtab updating and stale entries. Removed 'remount' default. 
+ *     
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <ctype.h>
+#include "busybox.h"
+#if defined BB_FEATURE_USE_DEVPS_PATCH
+#      include <linux/devmtab.h> /* For Erik's nifty devmtab device driver */
+#endif
+
+enum {
+       MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
+       MS_RDONLY = 1,      /* Mount read-only */
+       MS_NOSUID = 2,      /* Ignore suid and sgid bits */
+       MS_NODEV = 4,      /* Disallow access to device special files */
+       MS_NOEXEC = 8,      /* Disallow program execution */
+       MS_SYNCHRONOUS = 16,      /* Writes are synced at once */
+       MS_REMOUNT = 32,      /* Alter flags of a mounted FS */
+       MS_MANDLOCK = 64,      /* Allow mandatory locks on an FS */
+       S_QUOTA = 128,     /* Quota initialized for file/directory/symlink */
+       S_APPEND = 256,     /* Append-only file */
+       S_IMMUTABLE = 512,     /* Immutable file */
+       MS_NOATIME = 1024,    /* Do not update access times. */
+       MS_NODIRATIME = 2048,    /* Do not update directory access times */
+       MS_BIND = 4096,    /* Use the new linux 2.4.x "mount --bind" feature */
+};
+
+
+#if defined BB_FEATURE_MOUNT_LOOP
+#include <fcntl.h>
+#include <sys/ioctl.h>
+static int use_loop = FALSE;
+#endif
+
+extern int mount (__const char *__special_file, __const char *__dir,
+                       __const char *__fstype, unsigned long int __rwflag,
+                       __const void *__data);
+extern int umount (__const char *__special_file);
+extern int umount2 (__const char *__special_file, int __flags);
+
+extern int sysfs( int option, unsigned int fs_index, char * buf);
+
+extern const char mtab_file[]; /* Defined in utility.c */
+
+struct mount_options {
+       const char *name;
+       unsigned long and;
+       unsigned long or;
+};
+
+static const struct mount_options mount_options[] = {
+       {"async", ~MS_SYNCHRONOUS, 0},
+       {"atime", ~0, ~MS_NOATIME},
+       {"defaults", ~0, 0},
+       {"noauto", ~0, 0},
+       {"dev", ~MS_NODEV, 0},
+       {"diratime", ~0, ~MS_NODIRATIME},
+       {"exec", ~MS_NOEXEC, 0},
+       {"noatime", ~0, MS_NOATIME},
+       {"nodev", ~0, MS_NODEV},
+       {"nodiratime", ~0, MS_NODIRATIME},
+       {"noexec", ~0, MS_NOEXEC},
+       {"nosuid", ~0, MS_NOSUID},
+       {"remount", ~0, MS_REMOUNT},
+       {"ro", ~0, MS_RDONLY},
+       {"rw", ~MS_RDONLY, 0},
+       {"suid", ~MS_NOSUID, 0},
+       {"sync", ~0, MS_SYNCHRONOUS},
+       {"bind", ~0, MS_BIND},
+       {0, 0, 0}
+};
+
+static int
+do_mount(char *specialfile, char *dir, char *filesystemtype,
+                long flags, void *string_flags, int useMtab, int fakeIt,
+                char *mtab_opts, int mount_all)
+{
+       int status = 0;
+#if defined BB_FEATURE_MOUNT_LOOP
+       char *lofile = NULL;
+#endif
+
+       if (! fakeIt)
+       {
+#if defined BB_FEATURE_MOUNT_LOOP
+               if (use_loop==TRUE) {
+                       int loro = flags & MS_RDONLY;
+                       
+                       lofile = specialfile;
+
+                       specialfile = find_unused_loop_device();
+                       if (specialfile == NULL) {
+                               error_msg_and_die("Could not find a spare loop device");
+                       }
+                       if (set_loop(specialfile, lofile, 0, &loro)) {
+                               error_msg_and_die("Could not setup loop device");
+                       }
+                       if (!(flags & MS_RDONLY) && loro) {     /* loop is ro, but wanted rw */
+                               error_msg("WARNING: loop device is read-only");
+                               flags |= MS_RDONLY;
+                       }
+               }
+#endif
+               status = mount(specialfile, dir, filesystemtype, flags, string_flags);
+               if (status < 0 && errno == EROFS) {
+                       error_msg("%s is write-protected, mounting read-only", specialfile);
+                       status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags);
+               }
+               /* Don't whine about already mounted filesystems when mounting all. */
+               if (status < 0 && errno == EBUSY && mount_all)
+                       return TRUE;
+       }
+
+
+       /* If the mount was sucessful, do anything needed, then return TRUE */
+       if (status == 0 || fakeIt==TRUE) {
+
+#if defined BB_FEATURE_MTAB_SUPPORT
+               if (useMtab) {
+                       erase_mtab(specialfile);        // Clean any stale entries
+                       write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
+               }
+#endif
+               return (TRUE);
+       }
+
+       /* Bummer.  mount failed.  Clean up */
+#if defined BB_FEATURE_MOUNT_LOOP
+       if (lofile != NULL) {
+               del_loop(specialfile);
+       }
+#endif
+
+       if (errno == EPERM) {
+               error_msg_and_die("permission denied. Are you root?");
+       }
+
+       return (FALSE);
+}
+
+
+static void paste_str(char **s1, const char *s2)
+{
+       *s1 = xrealloc(*s1, strlen(*s1)+strlen(s2)+1);
+       strcat(*s1, s2);
+}
+
+/* Seperate standard mount options from the nonstandard string options */
+static void
+parse_mount_options(char *options, int *flags, char **strflags)
+{
+       while (options) {
+               int gotone = FALSE;
+               char *comma = strchr(options, ',');
+               const struct mount_options *f = mount_options;
+
+               if (comma)
+                       *comma = '\0';
+
+               while (f->name != 0) {
+                       if (strcasecmp(f->name, options) == 0) {
+
+                               *flags &= f->and;
+                               *flags |= f->or;
+                               gotone = TRUE;
+                               break;
+                       }
+                       f++;
+               }
+#if defined BB_FEATURE_MOUNT_LOOP
+               if (!strcasecmp("loop", options)) { /* loop device support */
+                       use_loop = TRUE;
+                       gotone = TRUE;
+               }
+#endif
+               if (! gotone) {
+                       if (**strflags) /* have previous parsed options */
+                               paste_str(strflags, ",");
+                       paste_str(strflags, options);
+               }
+               if (comma) {
+                       *comma = ',';
+                       options = ++comma;
+               } else {
+                       break;
+               }
+       }
+}
+
+static int
+mount_one(char *blockDevice, char *directory, char *filesystemType,
+                 unsigned long flags, char *string_flags, int useMtab, int fakeIt,
+                 char *mtab_opts, int whineOnErrors, int mount_all)
+{
+       int status = 0;
+
+#if defined BB_FEATURE_USE_DEVPS_PATCH
+       if (strcmp(filesystemType, "auto") == 0) {
+               static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 };
+               const char **noauto_fstype;
+               const int num_of_filesystems = sysfs(3, 0, 0);
+               char buf[255];
+               int i=0;
+
+               filesystemType=buf;
+
+               while(i < num_of_filesystems) {
+                       sysfs(2, i++, filesystemType);
+                       for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) {
+                               if (!strcmp(filesystemType, *noauto_fstype)) {
+                                       break;
+                               }
+                       }
+                       if (!*noauto_fstype) {
+                               status = do_mount(blockDevice, directory, filesystemType,
+                                       flags | MS_MGC_VAL, string_flags,
+                                       useMtab, fakeIt, mtab_opts, mount_all);
+                               if (status)
+                                       break;
+                       }
+               }
+       } 
+#else
+       if (strcmp(filesystemType, "auto") == 0) {
+               char buf[255];
+               FILE *f = xfopen("/proc/filesystems", "r");
+
+               while (fgets(buf, sizeof(buf), f) != NULL) {
+                       filesystemType = buf;
+                       if (*filesystemType == '\t') {  // Not a nodev filesystem
+
+                               // Add NULL termination to each line
+                               while (*filesystemType && *filesystemType != '\n')
+                                       filesystemType++;
+                               *filesystemType = '\0';
+
+                               filesystemType = buf;
+                               filesystemType++;       // hop past tab
+
+                               status = do_mount(blockDevice, directory, filesystemType,
+                                                                 flags | MS_MGC_VAL, string_flags,
+                                                                 useMtab, fakeIt, mtab_opts, mount_all);
+                               if (status)
+                                       break;
+                       }
+               }
+               fclose(f);
+       }
+#endif
+       else {
+               status = do_mount(blockDevice, directory, filesystemType,
+                               flags | MS_MGC_VAL, string_flags, useMtab,
+                               fakeIt, mtab_opts, mount_all);
+       }
+
+       if (! status) {
+               if (whineOnErrors) {
+                       perror_msg("Mounting %s on %s failed", blockDevice, directory);
+               }
+               return (FALSE);
+       }
+       return (TRUE);
+}
+
+static void show_mounts(char *onlytype)
+{
+#if defined BB_FEATURE_USE_DEVPS_PATCH
+       int fd, i, numfilesystems;
+       char device[] = "/dev/mtab";
+       struct k_mntent *mntentlist;
+
+       /* open device */ 
+       fd = open(device, O_RDONLY);
+       if (fd < 0)
+               perror_msg_and_die("open failed for `%s'", device);
+
+       /* How many mounted filesystems?  We need to know to 
+        * allocate enough space for later... */
+       numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
+       if (numfilesystems<0)
+               perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS");
+       mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent));
+               
+       /* Grab the list of mounted filesystems */
+       if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
+               perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS");
+
+       for( i = 0 ; i < numfilesystems ; i++) {
+               if ( !onlytype || ( strcmp ( mntentlist[i].mnt_type, onlytype ) == 0 )) {
+                       printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
+                                       mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
+                                       mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
+                                       mntentlist[i].mnt_passno);
+               }
+       }
+#ifdef BB_FEATURE_CLEAN_UP
+       /* Don't bother to close files or free memory.  Exit 
+        * does that automagically, so we can save a few bytes */
+       free( mntentlist);
+       close(fd);
+#endif
+       exit(EXIT_SUCCESS);
+#else
+       FILE *mountTable = setmntent(mtab_file, "r");
+
+       if (mountTable) {
+               struct mntent *m;
+
+               while ((m = getmntent(mountTable)) != 0) {
+                       char *blockDevice = m->mnt_fsname;
+                       if (strcmp(blockDevice, "/dev/root") == 0) {
+                               blockDevice = find_real_root_device_name(blockDevice);
+                       }
+                       if ( !onlytype || ( strcmp ( m-> mnt_type, onlytype ) == 0 )) {
+                               printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
+                                               m->mnt_type, m->mnt_opts);
+                       }
+#ifdef BB_FEATURE_CLEAN_UP
+                       if(blockDevice != m->mnt_fsname)
+                               free(blockDevice);
+#endif
+               }
+               endmntent(mountTable);
+       } else {
+               perror_msg_and_die("%s", mtab_file);
+       }
+       exit(EXIT_SUCCESS);
+#endif
+}
+
+extern int mount_main(int argc, char **argv)
+{
+       struct stat statbuf;
+       char *string_flags = xstrdup("");
+       char *extra_opts;
+       int flags = 0;
+       char *filesystemType = "auto";
+       int got_filesystemType = 0;
+       char *device = xmalloc(PATH_MAX);
+       char *directory = xmalloc(PATH_MAX);
+       struct mntent *m = NULL;
+       int all = FALSE;
+       int fakeIt = FALSE;
+       int useMtab = TRUE;
+       int rc = EXIT_FAILURE;
+       FILE *f = 0;
+       int opt;
+
+       /* Parse options */
+       while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
+               switch (opt) {
+               case 'o':
+                       parse_mount_options(optarg, &flags, &string_flags);
+                       break;
+               case 'r':
+                       flags |= MS_RDONLY;
+                       break;
+               case 't':
+                       filesystemType = optarg;
+                       got_filesystemType = 1;
+                       break;
+               case 'w':
+                       flags &= ~MS_RDONLY;
+                       break;
+               case 'a':
+                       all = TRUE;
+                       break;
+               case 'f':
+                       fakeIt = TRUE;
+                       break;
+#ifdef BB_FEATURE_MTAB_SUPPORT
+               case 'n':
+                       useMtab = FALSE;
+                       break;
+#endif
+               case 'v':
+                       break; /* ignore -v */
+               }
+       }
+
+       if (!all && optind == argc)
+               show_mounts(got_filesystemType ? filesystemType : 0);
+
+       if (optind < argc) {
+               /* if device is a filename get its real path */
+               if (stat(argv[optind], &statbuf) == 0) {
+                       char *tmp = simplify_path(argv[optind]);
+                       safe_strncpy(device, tmp, PATH_MAX);
+               } else {
+                       safe_strncpy(device, argv[optind], PATH_MAX);
+               }
+       }
+
+       if (optind + 1 < argc)
+               directory = simplify_path(argv[optind + 1]);
+
+       if (all || optind + 1 == argc) {
+               f = setmntent("/etc/fstab", "r");
+
+               if (f == NULL)
+                       perror_msg_and_die( "\nCannot read /etc/fstab");
+
+               while ((m = getmntent(f)) != NULL) {
+                       if (! all && optind + 1 == argc && (
+                               (strcmp(device, m->mnt_fsname) != 0) &&
+                               (strcmp(device, m->mnt_dir) != 0) ) ) {
+                               continue;
+                       }
+                       
+                       if (all && (                                                    // If we're mounting 'all'
+                               (strstr(m->mnt_opts, "noauto")) ||      // and the file system isn't noauto,
+                               (strstr(m->mnt_type, "swap")) ||        // and isn't swap or nfs, then mount it
+                               (strstr(m->mnt_type, "nfs")) ) ) {
+                               continue;
+                       }
+                       
+                       if (all || flags == 0) {        // Allow single mount to override fstab flags
+                               flags = 0;
+                               string_flags[0] = 0;
+                               parse_mount_options(m->mnt_opts, &flags, &string_flags);
+                       }
+                       
+                       strcpy(device, m->mnt_fsname);
+                       strcpy(directory, m->mnt_dir);
+                       filesystemType = xstrdup(m->mnt_type);
+singlemount:                   
+                       extra_opts = string_flags;
+                       rc = EXIT_SUCCESS;
+#ifdef BB_NFSMOUNT
+                       if (strchr(device, ':') != NULL) {
+                               filesystemType = "nfs";
+                               if (nfsmount (device, directory, &flags, &extra_opts,
+                                                       &string_flags, 1)) {
+                                       perror_msg("nfsmount failed");
+                                       rc = EXIT_FAILURE;
+                               }
+                       }
+#endif
+                       if (!mount_one(device, directory, filesystemType, flags,
+                                       string_flags, useMtab, fakeIt, extra_opts, TRUE, all))
+                               rc = EXIT_FAILURE;
+                               
+                       if (! all)
+                               break;
+               }
+               if (f)
+                       endmntent(f);
+                       
+               if (! all && f && m == NULL)
+                       fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
+       
+               return rc;
+       }
+       
+       goto singlemount;
+}
diff --git a/msh.c b/msh.c
new file mode 100644 (file)
index 0000000..f3890d7
--- /dev/null
+++ b/msh.c
@@ -0,0 +1,4759 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Minix shell port for busybox
+ *
+ * This version of the Minix shell was adapted for use in busybox
+ * by Erik Andersen <andersee@debian.org> and
+ *    Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+/* -------- sh.h -------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <time.h>
+#include <sys/times.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/dir.h>
+#include <limits.h>
+
+
+#include "cmdedit.h"
+#include "busybox.h"
+
+/* define this to use fork on MMU-systems instead of vfork */
+#if defined(__uClinux__)
+#undef USE_FORK
+#else
+#define USE_FORK
+#endif
+
+#ifdef test
+//#undef BB_FEATURE_COMMAND_EDITING
+const char *applet_name = "msh";
+
+#define TEST_NEW_VERSION
+#define Abort() { fprintf(stderr, "Abort %d\n", __LINE__); abort(); }
+#else
+#undef TEST_NEW_VERSION
+#define Abort() abort()
+#endif
+
+/*
+ * shell
+ */
+
+#define LINELIM 4096
+#define NPUSH   8                              /* limit to input nesting */
+
+#ifndef NOFILE
+#define NOFILE  20                             /* Number of open files */
+#endif
+#define NUFILE  10                             /* Number of user-accessible files */
+#define FDBASE  10                             /* First file usable by Shell */
+
+/*
+ * values returned by wait
+ */
+#define WAITSIG(s) ((s)&0177)
+#define WAITVAL(s) (((s)>>8)&0377)
+#define WAITCORE(s) (((s)&0200)!=0)
+
+/*
+ * library and system defintions
+ */
+typedef void xint;                             /* base type of jmp_buf, for not broken compilers */
+
+/*
+ * shell components
+ */
+
+#define QUOTE   0200
+
+#define NOBLOCK ((struct op *)NULL)
+#define NOWORD  ((char *)NULL)
+#define NOWORDS ((char **)NULL)
+#define NOPIPE  ((int *)NULL)
+
+/*
+ * Description of a command or an operation on commands.
+ * Might eventually use a union.
+ */
+struct op {
+       int type;                                       /* operation type, see below */
+       char **words;                           /* arguments to a command */
+       struct ioword **ioact;          /* IO actions (eg, < > >>) */
+       struct op *left;
+       struct op *right;
+       char *str;                                      /* identifier for case and for */
+};
+
+#define TCOM    1                              /* command */
+#define TPAREN  2                              /* (c-list) */
+#define TPIPE   3                              /* a | b */
+#define TLIST   4                              /* a [&;] b */
+#define TOR     5                              /* || */
+#define TAND    6                              /* && */
+#define TFOR    7
+#define TDO     8
+#define TCASE   9
+#define TIF     10
+#define TWHILE  11
+#define TUNTIL  12
+#define TELIF   13
+#define TPAT    14                             /* pattern in case */
+#define TBRACE  15                             /* {c-list} */
+#define TASYNC  16                             /* c & */
+
+/*
+ * actions determining the environment of a process
+ */
+#define BIT(i)  (1<<(i))
+#define FEXEC   BIT(0)                 /* execute without forking */
+
+/*
+ * flags to control evaluation of words
+ */
+#define DOSUB   1                              /* interpret $, `, and quotes */
+#define DOBLANK 2                              /* perform blank interpretation */
+#define DOGLOB  4                              /* interpret [?* */
+#define DOKEY   8                              /* move words with `=' to 2nd arg. list */
+#define DOTRIM  16                             /* trim resulting string */
+
+#define DOALL   (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
+
+static char **dolv;
+static int dolc;
+static int exstat;
+static char gflg;
+static int interactive;                        /* interactive (interactive-type wireless) */
+static int execflg;
+static int multiline;                  /* \n changed to ; */
+static struct op *outtree;             /* result from parser */
+
+static xint *failpt;
+static xint *errpt;
+
+struct brkcon {
+       jmp_buf brkpt;
+       struct brkcon *nextlev;
+};
+static struct brkcon *brklist;
+static int isbreak;
+
+/*
+ * redirection
+ */
+struct ioword {
+       short io_unit;                          /* unit affected */
+       short io_flag;                          /* action (below) */
+       char *io_name;                          /* file name */
+};
+
+#define IOREAD  1                              /* < */
+#define IOHERE  2                              /* << (here file) */
+#define IOWRITE 4                              /* > */
+#define IOCAT   8                              /* >> */
+#define IOXHERE 16                             /* ${}, ` in << */
+#define IODUP   32                             /* >&digit */
+#define IOCLOSE 64                             /* >&- */
+
+#define IODEFAULT (-1)                 /* token for default IO unit */
+
+struct wdblock {
+       short w_bsize;
+       short w_nword;
+       /* bounds are arbitrary */
+       char *w_words[1];
+};
+
+static struct wdblock *wdlist;
+static struct wdblock *iolist;
+
+/*
+ * parsing & execution environment
+ */
+static struct env {
+       char *linep;
+       struct io *iobase;
+       struct io *iop;
+       xint *errpt;
+       int iofd;
+       struct env *oenv;
+} e;
+
+/*
+ * flags:
+ * -e: quit on error
+ * -k: look for name=value everywhere on command line
+ * -n: no execution
+ * -t: exit after reading and executing one command
+ * -v: echo as read
+ * -x: trace
+ * -u: unset variables net diagnostic
+ */
+static char *flag;
+
+static char *null;                             /* null value for variable */
+static int intr;                               /* interrupt pending */
+
+static char *trap[_NSIG + 1];
+static char ourtrap[_NSIG + 1];
+static int trapset;                            /* trap pending */
+
+static int heedint;                            /* heed interrupt signals */
+
+static int yynerrs;                            /* yacc */
+
+static char line[LINELIM];
+static char *elinep;
+
+/*
+ * other functions
+ */
+static int (*inbuilt(char *s)) (void);
+
+static char *rexecve(char *c, char **v, char **envp);
+static char *space(int n);
+static char *strsave(char *s, int a);
+static char *evalstr(char *cp, int f);
+static char *putn(int n);
+static char *itoa(unsigned u, int n);
+static char *unquote(char *as);
+static struct var *lookup(char *n);
+static int rlookup(char *n);
+static struct wdblock *glob(char *cp, struct wdblock *wb);
+static int subgetc(int ec, int quoted);
+static char **makenv(int all);
+static char **eval(char **ap, int f);
+static int setstatus(int s);
+static int waitfor(int lastpid, int canintr);
+
+static void onintr(int s);             /* SIGINT handler */
+
+static int newenv(int f);
+static void quitenv(void);
+static void err(char *s);
+static int anys(char *s1, char *s2);
+static int any(int c, char *s);
+static void next(int f);
+static void setdash(void);
+static void onecommand(void);
+static void runtrap(int i);
+static int letter(int c);
+static int digit(int c);
+static int letnum(int c);
+static int gmatch(char *s, char *p);
+
+/*
+ * error handling
+ */
+static void leave(void) __attribute__ ((noreturn));    /* abort shell (or fail in subshell) */
+static void fail(void);                        /* fail but return to process next command */
+static void warn(char *s);
+static void sig(int i);                        /* default signal handler */
+
+/* -------- var.h -------- */
+
+struct var {
+       char *value;
+       char *name;
+       struct var *next;
+       char status;
+};
+
+#define COPYV   1                              /* flag to setval, suggesting copy */
+#define RONLY   01                             /* variable is read-only */
+#define EXPORT  02                             /* variable is to be exported */
+#define GETCELL 04                             /* name & value space was got with getcell */
+
+static struct var *vlist;              /* dictionary */
+
+static struct var *homedir;            /* home directory */
+static struct var *prompt;             /* main prompt */
+static struct var *cprompt;            /* continuation prompt */
+static struct var *path;               /* search path for commands */
+static struct var *shell;              /* shell to interpret command files */
+static struct var *ifs;                        /* field separators */
+
+static int yyparse(void);
+static struct var *lookup(char *n);
+static void setval(struct var *vp, char *val);
+static void nameval(struct var *vp, char *val, char *name);
+static void export(struct var *vp);
+static void ronly(struct var *vp);
+static int isassign(char *s);
+static int checkname(char *cp);
+static int assign(char *s, int cf);
+static void putvlist(int f, int out);
+static int eqname(char *n1, char *n2);
+
+static int execute(struct op *t, int *pin, int *pout, int act);
+
+/* -------- io.h -------- */
+/* io buffer */
+struct iobuf {
+       unsigned id;                            /* buffer id */
+       char buf[512];                          /* buffer */
+       char *bufp;                                     /* pointer into buffer */
+       char *ebufp;                            /* pointer to end of buffer */
+};
+
+/* possible arguments to an IO function */
+struct ioarg {
+       char *aword;
+       char **awordlist;
+       int afile;                                      /* file descriptor */
+       unsigned afid;                          /* buffer id */
+       long afpos;                                     /* file position */
+       struct iobuf *afbuf;            /* buffer for this file */
+};
+static struct ioarg ioargstack[NPUSH];
+
+#define AFID_NOBUF      (~0)
+#define AFID_ID         0
+
+/* an input generator's state */
+struct io {
+       int (*iofn) ();
+       struct ioarg *argp;
+       int peekc;
+       char prev;                                      /* previous character read by readc() */
+       char nlcount;                           /* for `'s */
+       char xchar;                                     /* for `'s */
+       char task;                                      /* reason for pushed IO */
+};
+static struct io iostack[NPUSH];
+
+#define XOTHER  0                              /* none of the below */
+#define XDOLL   1                              /* expanding ${} */
+#define XGRAVE  2                              /* expanding `'s */
+#define XIO     3                              /* file IO */
+
+/* in substitution */
+#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
+
+/*
+ * input generators for IO structure
+ */
+static int nlchar(struct ioarg *ap);
+static int strchar(struct ioarg *ap);
+static int qstrchar(struct ioarg *ap);
+static int filechar(struct ioarg *ap);
+static int herechar(struct ioarg *ap);
+static int linechar(struct ioarg *ap);
+static int gravechar(struct ioarg *ap, struct io *iop);
+static int qgravechar(struct ioarg *ap, struct io *iop);
+static int dolchar(struct ioarg *ap);
+static int wdchar(struct ioarg *ap);
+static void scraphere(void);
+static void freehere(int area);
+static void gethere(void);
+static void markhere(char *s, struct ioword *iop);
+static int herein(char *hname, int xdoll);
+static int run(struct ioarg *argp, int (*f) (struct ioarg * ap));
+
+/*
+ * IO functions
+ */
+static int eofc(void);
+static int getqc(int ec);
+static int readc(void);
+static void unget(int c);
+static void ioecho(int c);
+static void prs(char *s);
+static void put1c(int c);
+static void prn(unsigned u);
+static void closef(int i);
+static void closeall(void);
+
+/*
+ * IO control
+ */
+static void pushio(struct ioarg *argp, int (*fn) ());
+static int remap(int fd);
+static int openpipe(int *pv);
+static void closepipe(int *pv);
+static struct io *setbase(struct io *ip);
+
+static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 };      /* temporary for PUSHIO */
+
+#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
+#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
+
+/* -------- word.h -------- */
+
+static struct wdblock *addword(char *wd, struct wdblock *wb);
+static struct wdblock *newword(int nw);
+static char **getwords(struct wdblock *wb);
+
+/* -------- area.h -------- */
+
+/*
+ * storage allocation
+ */
+static char *getcell(unsigned nbytes);
+static void garbage(void);
+static void setarea(char *cp, int a);
+static int getarea(char *cp);
+static void freearea(int a);
+static void freecell(void *cp);
+
+static int areanum;                            /* current allocation area */
+
+#define NEW(type) (type *)getcell(sizeof(type))
+/* -------- sh.c -------- */
+/*
+ * shell
+ */
+
+static int intr;
+static int inparse;
+static char flags['z' - 'a' + 1];
+static char *flag = flags - 'a';
+static char *elinep = line + sizeof(line) - 5;
+static char *null = "";
+static int heedint = 1;
+static struct env e = { line, iostack, iostack - 1,
+       (xint *) NULL, FDBASE, (struct env *) NULL
+};
+
+extern char **environ;                 /* environment pointer */
+
+/*
+ * default shell, search rules
+ */
+static char shellname[] = "/bin/sh";
+static char search[] = ":/bin:/usr/bin";
+
+static void (*qflag) (int) = SIG_IGN;
+
+static int newfile(char *s);
+static char *findeq(char *cp);
+static char *cclass(char *p, int sub);
+static void initarea(void);
+
+struct here {
+       char *h_tag;
+       int h_dosub;
+       struct ioword *h_iop;
+       struct here *h_next;
+};
+
+static struct here *inhere;            /* list of hear docs while parsing */
+static struct here *acthere;   /* list of active here documents */
+
+#ifdef BB_FEATURE_COMMAND_EDITING
+static char *current_prompt;
+#endif
+
+#ifdef test
+int main(int argc, char **argv)
+#else
+int msh_main(int argc, char **argv)
+#endif
+{
+       register int f;
+       register char *s;
+       int cflag;
+       char *name, **ap;
+       int (*iof) ();
+
+       initarea();
+       if ((ap = environ) != NULL) {
+               while (*ap)
+                       assign(*ap++, !COPYV);
+               for (ap = environ; *ap;)
+                       export(lookup(*ap++));
+       }
+       closeall();
+       areanum = 1;
+
+       shell = lookup("SHELL");
+       if (shell->value == null)
+               setval(shell, shellname);
+       export(shell);
+
+       homedir = lookup("HOME");
+       if (homedir->value == null)
+               setval(homedir, "/");
+       export(homedir);
+#ifdef TEST_NEW_VERSION
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+       cwd = xgetcwd(0);
+       if (cwd == 0)
+               cwd = (char *) unknown;
+#endif
+#endif
+       setval(lookup("$"), itoa(getpid(), 5));
+
+       path = lookup("PATH");
+       if (path->value == null)
+               setval(path, search);
+       export(path);
+
+       ifs = lookup("IFS");
+       if (ifs->value == null)
+               setval(ifs, " \t\n");
+
+       prompt = lookup("PS1");
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+       if (prompt->value == null)
+#endif
+               setval(prompt, "$ ");
+
+       if (geteuid() == 0) {
+               setval(prompt, "# ");
+               prompt->status &= ~EXPORT;
+       }
+       cprompt = lookup("PS2");
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+       if (cprompt->value == null)
+#endif
+               setval(cprompt, "> ");
+
+       iof = filechar;
+       cflag = 0;
+       name = *argv++;
+       if (--argc >= 1) {
+               if (argv[0][0] == '-' && argv[0][1] != '\0') {
+                       for (s = argv[0] + 1; *s; s++)
+                               switch (*s) {
+                               case 'c':
+                                       prompt->status &= ~EXPORT;
+                                       cprompt->status &= ~EXPORT;
+                                       setval(prompt, "");
+                                       setval(cprompt, "");
+                                       cflag = 1;
+                                       if (--argc > 0)
+                                               PUSHIO(aword, *++argv, iof = nlchar);
+                                       break;
+
+                               case 'q':
+                                       qflag = SIG_DFL;
+                                       break;
+
+                               case 's':
+                                       /* standard input */
+                                       break;
+
+                               case 't':
+                                       prompt->status &= ~EXPORT;
+                                       setval(prompt, "");
+                                       iof = linechar;
+                                       break;
+
+                               case 'i':
+                                       interactive++;
+                               default:
+                                       if (*s >= 'a' && *s <= 'z')
+                                               flag[(int) *s]++;
+                               }
+               } else {
+                       argv--;
+                       argc++;
+               }
+               if (iof == filechar && --argc > 0) {
+                       setval(prompt, "");
+                       setval(cprompt, "");
+                       prompt->status &= ~EXPORT;
+                       cprompt->status &= ~EXPORT;
+                       if (newfile(name = *++argv))
+                               exit(1);
+               }
+       }
+       setdash();
+       if (e.iop < iostack) {
+               PUSHIO(afile, 0, iof);
+               if (isatty(0) && isatty(1) && !cflag) {
+                       interactive++;
+                       printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
+                       printf( "Enter 'help' for a list of built-in commands.\n\n");
+               }
+       }
+       signal(SIGQUIT, qflag);
+       if (name && name[0] == '-') {
+               interactive++;
+               if ((f = open(".profile", 0)) >= 0)
+                       next(remap(f));
+               if ((f = open("/etc/profile", 0)) >= 0)
+                       next(remap(f));
+       }
+       if (interactive)
+               signal(SIGTERM, sig);
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, onintr);
+       dolv = argv;
+       dolc = argc;
+       dolv[0] = name;
+       if (dolc > 1)
+               for (ap = ++argv; --argc > 0;) {
+                       if (assign(*ap = *argv++, !COPYV))
+                               dolc--;                 /* keyword */
+                       else
+                               ap++;
+               }
+       setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
+
+       for (;;) {
+               if (interactive && e.iop <= iostack)
+#ifdef BB_FEATURE_COMMAND_EDITING
+                       current_prompt = prompt->value;
+#else
+                       prs(prompt->value);
+#endif
+               onecommand();
+               /* Ensure that getenv("PATH") stays current */
+               setenv("PATH", path->value, 1);
+       }
+}
+
+void setdash()
+{
+       register char *cp, c;
+       char m['z' - 'a' + 1];
+
+       cp = m;
+       for (c = 'a'; c <= 'z'; c++)
+               if (flag[(int) c])
+                       *cp++ = c;
+       *cp = 0;
+       setval(lookup("-"), m);
+}
+
+int newfile(s)
+register char *s;
+{
+       int f;
+
+       if (strcmp(s, "-") != 0) {
+               f = open(s, 0);
+               if (f < 0) {
+                       prs(s);
+                       err(": cannot open");
+                       return (1);
+               }
+       } else
+               f = 0;
+       next(remap(f));
+       return (0);
+}
+
+void onecommand()
+{
+       int i;
+       jmp_buf m1;
+
+       while (e.oenv)
+               quitenv();
+       areanum = 1;
+       freehere(areanum);
+       freearea(areanum);
+       garbage();
+       wdlist = 0;
+       iolist = 0;
+       e.errpt = 0;
+       e.linep = line;
+       yynerrs = 0;
+       multiline = 0;
+       inparse = 1;
+       intr = 0;
+       execflg = 0;
+       setjmp(failpt = m1);            /* Bruce Evans' fix */
+       if (setjmp(failpt = m1) || yyparse() || intr) {
+               while (e.oenv)
+                       quitenv();
+               scraphere();
+               if (!interactive && intr)
+                       leave();
+               inparse = 0;
+               intr = 0;
+               return;
+       }
+       inparse = 0;
+       brklist = 0;
+       intr = 0;
+       execflg = 0;
+       if (!flag['n'])
+               execute(outtree, NOPIPE, NOPIPE, 0);
+       if (!interactive && intr) {
+               execflg = 0;
+               leave();
+       }
+       if ((i = trapset) != 0) {
+               trapset = 0;
+               runtrap(i);
+       }
+}
+
+void fail()
+{
+       longjmp(failpt, 1);
+       /* NOTREACHED */
+}
+
+void leave()
+{
+       if (execflg)
+               fail();
+       scraphere();
+       freehere(1);
+       runtrap(0);
+       _exit(exstat);
+       /* NOTREACHED */
+}
+
+void warn(s)
+register char *s;
+{
+       if (*s) {
+               prs(s);
+               exstat = -1;
+       }
+       prs("\n");
+       if (flag['e'])
+               leave();
+}
+
+void err(s)
+char *s;
+{
+       warn(s);
+       if (flag['n'])
+               return;
+       if (!interactive)
+               leave();
+       if (e.errpt)
+               longjmp(e.errpt, 1);
+       closeall();
+       e.iop = e.iobase = iostack;
+}
+
+int newenv(f)
+int f;
+{
+       register struct env *ep;
+
+       if (f) {
+               quitenv();
+               return (1);
+       }
+       ep = (struct env *) space(sizeof(*ep));
+       if (ep == NULL) {
+               while (e.oenv)
+                       quitenv();
+               fail();
+       }
+       *ep = e;
+       e.oenv = ep;
+       e.errpt = errpt;
+       return (0);
+}
+
+void quitenv()
+{
+       register struct env *ep;
+       int fd;
+
+       if ((ep = e.oenv) != NULL) {
+               fd = e.iofd;
+               e = *ep;
+               /* should close `'d files */
+               freecell(ep);
+               while (--fd >= e.iofd)
+                       close(fd);
+       }
+}
+
+/*
+ * Is any character from s1 in s2?
+ */
+int anys(s1, s2)
+register char *s1, *s2;
+{
+       while (*s1)
+               if (any(*s1++, s2))
+                       return (1);
+       return (0);
+}
+
+/*
+ * Is character c in s?
+ */
+int any(c, s)
+register int c;
+register char *s;
+{
+       while (*s)
+               if (*s++ == c)
+                       return (1);
+       return (0);
+}
+
+char *putn(n)
+register int n;
+{
+       return (itoa(n, -1));
+}
+
+char *itoa(u, n)
+register unsigned u;
+int n;
+{
+       register char *cp;
+       static char s[20];
+       int m;
+
+       m = 0;
+       if (n < 0 && (int) u < 0) {
+               m++;
+               u = -u;
+       }
+       cp = s + sizeof(s);
+       *--cp = 0;
+       do {
+               *--cp = u % 10 + '0';
+               u /= 10;
+       } while (--n > 0 || u);
+       if (m)
+               *--cp = '-';
+       return (cp);
+}
+
+void next(f)
+int f;
+{
+       PUSHIO(afile, f, filechar);
+}
+
+void onintr(s)
+int s;                                                 /* ANSI C requires a parameter */
+{
+       signal(SIGINT, onintr);
+       intr = 1;
+       if (interactive) {
+               if (inparse) {
+                       prs("\n");
+                       fail();
+               }
+       } else if (heedint) {
+               execflg = 0;
+               leave();
+       }
+}
+
+int letter(c)
+int c;
+{
+       return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
+}
+
+int digit(c)
+int c;
+{
+       return (c >= '0' && c <= '9');
+}
+
+int letnum(c)
+int c;
+{
+       return (letter(c) || digit(c));
+}
+
+char *space(n)
+int n;
+{
+       register char *cp;
+
+       if ((cp = getcell(n)) == 0)
+               err("out of string space");
+       return (cp);
+}
+
+char *strsave(s, a)
+register char *s;
+int a;
+{
+       register char *cp, *xp;
+
+       if ((cp = space(strlen(s) + 1)) != NULL) {
+               setarea((char *) cp, a);
+               for (xp = cp; (*xp++ = *s++) != '\0';);
+               return (cp);
+       }
+       return ("");
+}
+
+/*
+ * trap handling
+ */
+void sig(i)
+register int i;
+{
+       trapset = i;
+       signal(i, sig);
+}
+
+void runtrap(i)
+int i;
+{
+       char *trapstr;
+
+       if ((trapstr = trap[i]) == NULL)
+               return;
+       if (i == 0)
+               trap[i] = 0;
+       RUN(aword, trapstr, nlchar);
+}
+
+/* -------- var.c -------- */
+
+/*
+ * Find the given name in the dictionary
+ * and return its value.  If the name was
+ * not previously there, enter it now and
+ * return a null value.
+ */
+struct var *lookup(n)
+register char *n;
+{
+       register struct var *vp;
+       register char *cp;
+       register int c;
+       static struct var dummy;
+
+       if (digit(*n)) {
+               dummy.name = n;
+               for (c = 0; digit(*n) && c < 1000; n++)
+                       c = c * 10 + *n - '0';
+               dummy.status = RONLY;
+               dummy.value = c <= dolc ? dolv[c] : null;
+               return (&dummy);
+       }
+       for (vp = vlist; vp; vp = vp->next)
+               if (eqname(vp->name, n))
+                       return (vp);
+       cp = findeq(n);
+       vp = (struct var *) space(sizeof(*vp));
+       if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
+               dummy.name = dummy.value = "";
+               return (&dummy);
+       }
+       for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
+       if (*cp == 0)
+               *cp = '=';
+       *++cp = 0;
+       setarea((char *) vp, 0);
+       setarea((char *) vp->name, 0);
+       vp->value = null;
+       vp->next = vlist;
+       vp->status = GETCELL;
+       vlist = vp;
+       return (vp);
+}
+
+/*
+ * give variable at `vp' the value `val'.
+ */
+void setval(vp, val)
+struct var *vp;
+char *val;
+{
+       nameval(vp, val, (char *) NULL);
+}
+
+/*
+ * if name is not NULL, it must be
+ * a prefix of the space `val',
+ * and end with `='.
+ * this is all so that exporting
+ * values is reasonably painless.
+ */
+void nameval(vp, val, name)
+register struct var *vp;
+char *val, *name;
+{
+       register char *cp, *xp;
+       char *nv;
+       int fl;
+
+       if (vp->status & RONLY) {
+               for (xp = vp->name; *xp && *xp != '=';)
+                       put1c(*xp++);
+               err(" is read-only");
+               return;
+       }
+       fl = 0;
+       if (name == NULL) {
+               xp = space(strlen(vp->name) + strlen(val) + 2);
+               if (xp == 0)
+                       return;
+               /* make string:  name=value */
+               setarea((char *) xp, 0);
+               name = xp;
+               for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
+               if (*xp++ == 0)
+                       xp[-1] = '=';
+               nv = xp;
+               for (cp = val; (*xp++ = *cp++) != '\0';);
+               val = nv;
+               fl = GETCELL;
+       }
+       if (vp->status & GETCELL)
+               freecell(vp->name);             /* form new string `name=value' */
+       vp->name = name;
+       vp->value = val;
+       vp->status |= fl;
+}
+
+void export(vp)
+struct var *vp;
+{
+       vp->status |= EXPORT;
+}
+
+void ronly(vp)
+struct var *vp;
+{
+       if (letter(vp->name[0]))        /* not an internal symbol ($# etc) */
+               vp->status |= RONLY;
+}
+
+int isassign(s)
+register char *s;
+{
+       if (!letter((int) *s))
+               return (0);
+       for (; *s != '='; s++)
+               if (*s == 0 || !letnum(*s))
+                       return (0);
+       return (1);
+}
+
+int assign(s, cf)
+register char *s;
+int cf;
+{
+       register char *cp;
+       struct var *vp;
+
+       if (!letter(*s))
+               return (0);
+       for (cp = s; *cp != '='; cp++)
+               if (*cp == 0 || !letnum(*cp))
+                       return (0);
+       vp = lookup(s);
+       nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
+       if (cf != COPYV)
+               vp->status &= ~GETCELL;
+       return (1);
+}
+
+int checkname(cp)
+register char *cp;
+{
+       if (!letter(*cp++))
+               return (0);
+       while (*cp)
+               if (!letnum(*cp++))
+                       return (0);
+       return (1);
+}
+
+void putvlist(f, out)
+register int f, out;
+{
+       register struct var *vp;
+
+       for (vp = vlist; vp; vp = vp->next)
+               if (vp->status & f && letter(*vp->name)) {
+                       if (vp->status & EXPORT)
+                               write(out, "export ", 7);
+                       if (vp->status & RONLY)
+                               write(out, "readonly ", 9);
+                       write(out, vp->name, (int) (findeq(vp->name) - vp->name));
+                       write(out, "\n", 1);
+               }
+}
+
+int eqname(n1, n2)
+register char *n1, *n2;
+{
+       for (; *n1 != '=' && *n1 != 0; n1++)
+               if (*n2++ != *n1)
+                       return (0);
+       return (*n2 == 0 || *n2 == '=');
+}
+
+static char *findeq(cp)
+register char *cp;
+{
+       while (*cp != '\0' && *cp != '=')
+               cp++;
+       return (cp);
+}
+
+/* -------- gmatch.c -------- */
+/*
+ * int gmatch(string, pattern)
+ * char *string, *pattern;
+ *
+ * Match a pattern as in sh(1).
+ */
+
+#define CMASK   0377
+#define QUOTE   0200
+#define QMASK   (CMASK&~QUOTE)
+#define NOT     '!'                            /* might use ^ */
+
+int gmatch(s, p)
+register char *s, *p;
+{
+       register int sc, pc;
+
+       if (s == NULL || p == NULL)
+               return (0);
+       while ((pc = *p++ & CMASK) != '\0') {
+               sc = *s++ & QMASK;
+               switch (pc) {
+               case '[':
+                       if ((p = cclass(p, sc)) == NULL)
+                               return (0);
+                       break;
+
+               case '?':
+                       if (sc == 0)
+                               return (0);
+                       break;
+
+               case '*':
+                       s--;
+                       do {
+                               if (*p == '\0' || gmatch(s, p))
+                                       return (1);
+                       } while (*s++ != '\0');
+                       return (0);
+
+               default:
+                       if (sc != (pc & ~QUOTE))
+                               return (0);
+               }
+       }
+       return (*s == 0);
+}
+
+static char *cclass(p, sub)
+register char *p;
+register int sub;
+{
+       register int c, d, not, found;
+
+       if ((not = *p == NOT) != 0)
+               p++;
+       found = not;
+       do {
+               if (*p == '\0')
+                       return ((char *) NULL);
+               c = *p & CMASK;
+               if (p[1] == '-' && p[2] != ']') {
+                       d = p[2] & CMASK;
+                       p++;
+               } else
+                       d = c;
+               if (c == sub || (c <= sub && sub <= d))
+                       found = !not;
+       } while (*++p != ']');
+       return (found ? p + 1 : (char *) NULL);
+}
+
+/* -------- area.c -------- */
+#define REGSIZE         sizeof(struct region)
+#define GROWBY          256
+#define FREE 32767
+#define BUSY 0
+#define ALIGN (sizeof(int)-1)
+
+/* #include "area.h" */
+
+struct region {
+       struct region *next;
+       int area;
+};
+
+/*
+ * All memory between (char *)areabot and (char *)(areatop+1) is
+ * exclusively administered by the area management routines.
+ */
+#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
+
+static struct region *areabot; /* bottom of area */
+static struct region *areatop; /* top of area */
+static struct region *areanxt; /* starting point of scan */
+
+static void *brktop;
+static void *brkaddr;
+
+static void initarea()
+{
+       brkaddr = malloc(65000);
+       brktop = brkaddr + 65000;
+
+       while ((int) sbrk(0) & ALIGN)
+               sbrk(1);
+       areabot = (struct region *) sbrk(REGSIZE);
+
+       areabot->next = areabot;
+       areabot->area = BUSY;
+       areatop = areabot;
+       areanxt = areabot;
+}
+
+char *getcell(nbytes)
+unsigned nbytes;
+{
+       int nregio;
+       register struct region *p, *q;
+       int i;
+
+       if (nbytes == 0)                        /* silly and defeats the algorithm */
+               Abort();
+
+       /*
+        * round upwards and add administration area
+        */
+       nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
+       for (p = areanxt;;) {
+               if (p->area > areanum) {
+                       /*
+                        * merge free cells
+                        */
+                       while ((q = p->next)->area > areanum && q != areanxt)
+                               p->next = q->next;
+                       /*
+                        * exit loop if cell big enough
+                        */
+                       if (q >= p + nregio)
+                               goto found;
+               }
+               p = p->next;
+               if (p == areanxt)
+                       break;
+       }
+       i = nregio >= GROWBY ? nregio : GROWBY;
+       p = (struct region *) sbrk(i * REGSIZE);
+       if (p == (struct region *) -1)
+               return ((char *) NULL);
+       p--;
+       if (p != areatop)                       /* allocated areas are contiguous */
+               Abort();
+
+       q = p + i;
+       p->next = q;
+       p->area = FREE;
+       q->next = areabot;
+       q->area = BUSY;
+       areatop = q;
+  found:
+       /*
+        * we found a FREE area big enough, pointed to by 'p', and up to 'q'
+        */
+       areanxt = p + nregio;
+       if (areanxt < q) {
+               /*
+                * split into requested area and rest
+                */
+               if (areanxt + 1 > q)    /* insufficient space left for admin */
+                       Abort();
+
+               areanxt->next = q;
+               areanxt->area = FREE;
+               p->next = areanxt;
+       }
+       p->area = areanum;
+       return ((char *) (p + 1));
+}
+
+
+void freecell(void *cp)
+{
+       register struct region *p;
+
+       if ((p = (struct region *) cp) != NULL) {
+               p--;
+               if (p < areanxt)
+                       areanxt = p;
+               p->area = FREE;
+       }
+}
+
+void freearea(a)
+register int a;
+{
+       register struct region *p, *top;
+
+       top = areatop;
+       for (p = areabot; p != top; p = p->next)
+               if (p->area >= a)
+                       p->area = FREE;
+}
+
+void setarea(cp, a)
+char *cp;
+int a;
+{
+       register struct region *p;
+
+       if ((p = (struct region *) cp) != NULL)
+               (p - 1)->area = a;
+}
+
+int getarea(cp)
+char *cp;
+{
+       return ((struct region *) cp - 1)->area;
+}
+
+void garbage()
+{
+       register struct region *p, *q, *top;
+
+       top = areatop;
+       for (p = areabot; p != top; p = p->next) {
+               if (p->area > areanum) {
+                       while ((q = p->next)->area > areanum)
+                               p->next = q->next;
+                       areanxt = p;
+               }
+       }
+}
+
+/* -------- csyn.c -------- */
+/*
+ * shell: syntax (C version)
+ */
+
+typedef union {
+       char *cp;
+       char **wp;
+       int i;
+       struct op *o;
+} YYSTYPE;
+
+#define WORD    256
+#define LOGAND  257
+#define LOGOR   258
+#define BREAK   259
+#define IF      260
+#define THEN    261
+#define ELSE    262
+#define ELIF    263
+#define FI      264
+#define CASE    265
+#define ESAC    266
+#define FOR     267
+#define WHILE   268
+#define UNTIL   269
+#define DO      270
+#define DONE    271
+#define IN      272
+#define YYERRCODE 300
+
+/* flags to yylex */
+#define CONTIN  01                             /* skip new lines to complete command */
+
+#define SYNTAXERR       zzerr()
+static int startl;
+static int peeksym;
+static int nlseen;
+static int iounit = IODEFAULT;
+
+static YYSTYPE yylval;
+
+static struct op *pipeline(int cf);
+static struct op *andor(void);
+static struct op *c_list(void);
+static int synio(int cf);
+static void musthave(int c, int cf);
+static struct op *simple(void);
+static struct op *nested(int type, int mark);
+static struct op *command(int cf);
+static struct op *dogroup(int onlydone);
+static struct op *thenpart(void);
+static struct op *elsepart(void);
+static struct op *caselist(void);
+static struct op *casepart(void);
+static char **pattern(void);
+static char **wordlist(void);
+static struct op *list(struct op *t1, struct op *t2);
+static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
+static struct op *newtp(void);
+static struct op *namelist(struct op *t);
+static char **copyw(void);
+static void word(char *cp);
+static struct ioword **copyio(void);
+static struct ioword *io(int u, int f, char *cp);
+static void zzerr(void);
+static void yyerror(char *s);
+static int yylex(int cf);
+static int collect(int c, int c1);
+static int dual(int c);
+static void diag(int ec);
+static char *tree(unsigned size);
+
+int yyparse()
+{
+       startl = 1;
+       peeksym = 0;
+       yynerrs = 0;
+       outtree = c_list();
+       musthave('\n', 0);
+       return (yynerrs != 0);
+}
+
+static struct op *pipeline(cf)
+int cf;
+{
+       register struct op *t, *p;
+       register int c;
+
+       t = command(cf);
+       if (t != NULL) {
+               while ((c = yylex(0)) == '|') {
+                       if ((p = command(CONTIN)) == NULL)
+                               SYNTAXERR;
+                       if (t->type != TPAREN && t->type != TCOM) {
+                               /* shell statement */
+                               t = block(TPAREN, t, NOBLOCK, NOWORDS);
+                       }
+                       t = block(TPIPE, t, p, NOWORDS);
+               }
+               peeksym = c;
+       }
+       return (t);
+}
+
+static struct op *andor()
+{
+       register struct op *t, *p;
+       register int c;
+
+       t = pipeline(0);
+       if (t != NULL) {
+               while ((c = yylex(0)) == LOGAND || c == LOGOR) {
+                       if ((p = pipeline(CONTIN)) == NULL)
+                               SYNTAXERR;
+                       t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
+               }
+               peeksym = c;
+       }
+       return (t);
+}
+
+static struct op *c_list()
+{
+       register struct op *t, *p;
+       register int c;
+
+       t = andor();
+       if (t != NULL) {
+               if ((peeksym = yylex(0)) == '&')
+                       t = block(TASYNC, t, NOBLOCK, NOWORDS);
+               while ((c = yylex(0)) == ';' || c == '&'
+                          || (multiline && c == '\n')) {
+                       if ((p = andor()) == NULL)
+                               return (t);
+                       if ((peeksym = yylex(0)) == '&')
+                               p = block(TASYNC, p, NOBLOCK, NOWORDS);
+                       t = list(t, p);
+               }
+               peeksym = c;
+       }
+       return (t);
+}
+
+
+static int synio(cf)
+int cf;
+{
+       register struct ioword *iop;
+       register int i;
+       register int c;
+
+       if ((c = yylex(cf)) != '<' && c != '>') {
+               peeksym = c;
+               return (0);
+       }
+       i = yylval.i;
+       musthave(WORD, 0);
+       iop = io(iounit, i, yylval.cp);
+       iounit = IODEFAULT;
+       if (i & IOHERE)
+               markhere(yylval.cp, iop);
+       return (1);
+}
+
+static void musthave(c, cf)
+int c, cf;
+{
+       if ((peeksym = yylex(cf)) != c)
+               SYNTAXERR;
+       peeksym = 0;
+}
+
+static struct op *simple()
+{
+       register struct op *t;
+
+       t = NULL;
+       for (;;) {
+               switch (peeksym = yylex(0)) {
+               case '<':
+               case '>':
+                       (void) synio(0);
+                       break;
+
+               case WORD:
+                       if (t == NULL) {
+                               t = newtp();
+                               t->type = TCOM;
+                       }
+                       peeksym = 0;
+                       word(yylval.cp);
+                       break;
+
+               default:
+                       return (t);
+               }
+       }
+}
+
+static struct op *nested(type, mark)
+int type, mark;
+{
+       register struct op *t;
+
+       multiline++;
+       t = c_list();
+       musthave(mark, 0);
+       multiline--;
+       return (block(type, t, NOBLOCK, NOWORDS));
+}
+
+static struct op *command(cf)
+int cf;
+{
+       register struct op *t;
+       struct wdblock *iosave;
+       register int c;
+
+       iosave = iolist;
+       iolist = NULL;
+       if (multiline)
+               cf |= CONTIN;
+       while (synio(cf))
+               cf = 0;
+       switch (c = yylex(cf)) {
+       default:
+               peeksym = c;
+               if ((t = simple()) == NULL) {
+                       if (iolist == NULL)
+                               return ((struct op *) NULL);
+                       t = newtp();
+                       t->type = TCOM;
+               }
+               break;
+
+       case '(':
+               t = nested(TPAREN, ')');
+               break;
+
+       case '{':
+               t = nested(TBRACE, '}');
+               break;
+
+       case FOR:
+               t = newtp();
+               t->type = TFOR;
+               musthave(WORD, 0);
+               startl = 1;
+               t->str = yylval.cp;
+               multiline++;
+               t->words = wordlist();
+               if ((c = yylex(0)) != '\n' && c != ';')
+                       peeksym = c;
+               t->left = dogroup(0);
+               multiline--;
+               break;
+
+       case WHILE:
+       case UNTIL:
+               multiline++;
+               t = newtp();
+               t->type = c == WHILE ? TWHILE : TUNTIL;
+               t->left = c_list();
+               t->right = dogroup(1);
+               t->words = NULL;
+               multiline--;
+               break;
+
+       case CASE:
+               t = newtp();
+               t->type = TCASE;
+               musthave(WORD, 0);
+               t->str = yylval.cp;
+               startl++;
+               multiline++;
+               musthave(IN, CONTIN);
+               startl++;
+               t->left = caselist();
+               musthave(ESAC, 0);
+               multiline--;
+               break;
+
+       case IF:
+               multiline++;
+               t = newtp();
+               t->type = TIF;
+               t->left = c_list();
+               t->right = thenpart();
+               musthave(FI, 0);
+               multiline--;
+               break;
+       }
+       while (synio(0));
+       t = namelist(t);
+       iolist = iosave;
+       return (t);
+}
+
+static struct op *dogroup(onlydone)
+int onlydone;
+{
+       register int c;
+       register struct op *oplist;
+
+       c = yylex(CONTIN);
+       if (c == DONE && onlydone)
+               return ((struct op *) NULL);
+       if (c != DO)
+               SYNTAXERR;
+       oplist = c_list();
+       musthave(DONE, 0);
+       return (oplist);
+}
+
+static struct op *thenpart()
+{
+       register int c;
+       register struct op *t;
+
+       if ((c = yylex(0)) != THEN) {
+               peeksym = c;
+               return ((struct op *) NULL);
+       }
+       t = newtp();
+       t->type = 0;
+       t->left = c_list();
+       if (t->left == NULL)
+               SYNTAXERR;
+       t->right = elsepart();
+       return (t);
+}
+
+static struct op *elsepart()
+{
+       register int c;
+       register struct op *t;
+
+       switch (c = yylex(0)) {
+       case ELSE:
+               if ((t = c_list()) == NULL)
+                       SYNTAXERR;
+               return (t);
+
+       case ELIF:
+               t = newtp();
+               t->type = TELIF;
+               t->left = c_list();
+               t->right = thenpart();
+               return (t);
+
+       default:
+               peeksym = c;
+               return ((struct op *) NULL);
+       }
+}
+
+static struct op *caselist()
+{
+       register struct op *t;
+
+       t = NULL;
+       while ((peeksym = yylex(CONTIN)) != ESAC)
+               t = list(t, casepart());
+       return (t);
+}
+
+static struct op *casepart()
+{
+       register struct op *t;
+
+       t = newtp();
+       t->type = TPAT;
+       t->words = pattern();
+       musthave(')', 0);
+       t->left = c_list();
+       if ((peeksym = yylex(CONTIN)) != ESAC)
+               musthave(BREAK, CONTIN);
+       return (t);
+}
+
+static char **pattern()
+{
+       register int c, cf;
+
+       cf = CONTIN;
+       do {
+               musthave(WORD, cf);
+               word(yylval.cp);
+               cf = 0;
+       } while ((c = yylex(0)) == '|');
+       peeksym = c;
+       word(NOWORD);
+       return (copyw());
+}
+
+static char **wordlist()
+{
+       register int c;
+
+       if ((c = yylex(0)) != IN) {
+               peeksym = c;
+               return ((char **) NULL);
+       }
+       startl = 0;
+       while ((c = yylex(0)) == WORD)
+               word(yylval.cp);
+       word(NOWORD);
+       peeksym = c;
+       return (copyw());
+}
+
+/*
+ * supporting functions
+ */
+static struct op *list(t1, t2)
+register struct op *t1, *t2;
+{
+       if (t1 == NULL)
+               return (t2);
+       if (t2 == NULL)
+               return (t1);
+       return (block(TLIST, t1, t2, NOWORDS));
+}
+
+static struct op *block(type, t1, t2, wp)
+int type;
+struct op *t1, *t2;
+char **wp;
+{
+       register struct op *t;
+
+       t = newtp();
+       t->type = type;
+       t->left = t1;
+       t->right = t2;
+       t->words = wp;
+       return (t);
+}
+
+static struct res {
+       char *r_name;
+       int r_val;
+} restab[] = {
+       {
+       "for", FOR}, {
+       "case", CASE}, {
+       "esac", ESAC}, {
+       "while", WHILE}, {
+       "do", DO}, {
+       "done", DONE}, {
+       "if", IF}, {
+       "in", IN}, {
+       "then", THEN}, {
+       "else", ELSE}, {
+       "elif", ELIF}, {
+       "until", UNTIL}, {
+       "fi", FI}, {
+       ";;", BREAK}, {
+       "||", LOGOR}, {
+       "&&", LOGAND}, {
+       "{", '{'}, {
+       "}", '}'}, {
+       0, 0}
+};
+
+int rlookup(n)
+register char *n;
+{
+       register struct res *rp;
+
+       for (rp = restab; rp->r_name; rp++)
+               if (strcmp(rp->r_name, n) == 0)
+                       return (rp->r_val);
+       return (0);
+}
+
+static struct op *newtp()
+{
+       register struct op *t;
+
+       t = (struct op *) tree(sizeof(*t));
+       t->type = 0;
+       t->words = NULL;
+       t->ioact = NULL;
+       t->left = NULL;
+       t->right = NULL;
+       t->str = NULL;
+       return (t);
+}
+
+static struct op *namelist(t)
+register struct op *t;
+{
+       if (iolist) {
+               iolist = addword((char *) NULL, iolist);
+               t->ioact = copyio();
+       } else
+               t->ioact = NULL;
+       if (t->type != TCOM) {
+               if (t->type != TPAREN && t->ioact != NULL) {
+                       t = block(TPAREN, t, NOBLOCK, NOWORDS);
+                       t->ioact = t->left->ioact;
+                       t->left->ioact = NULL;
+               }
+               return (t);
+       }
+       word(NOWORD);
+       t->words = copyw();
+       return (t);
+}
+
+static char **copyw()
+{
+       register char **wd;
+
+       wd = getwords(wdlist);
+       wdlist = 0;
+       return (wd);
+}
+
+static void word(cp)
+char *cp;
+{
+       wdlist = addword(cp, wdlist);
+}
+
+static struct ioword **copyio()
+{
+       register struct ioword **iop;
+
+       iop = (struct ioword **) getwords(iolist);
+       iolist = 0;
+       return (iop);
+}
+
+static struct ioword *io(u, f, cp)
+int u;
+int f;
+char *cp;
+{
+       register struct ioword *iop;
+
+       iop = (struct ioword *) tree(sizeof(*iop));
+       iop->io_unit = u;
+       iop->io_flag = f;
+       iop->io_name = cp;
+       iolist = addword((char *) iop, iolist);
+       return (iop);
+}
+
+static void zzerr()
+{
+       yyerror("syntax error");
+}
+
+void yyerror(s)
+char *s;
+{
+       yynerrs++;
+       if (interactive && e.iop <= iostack) {
+               multiline = 0;
+               while (eofc() == 0 && yylex(0) != '\n');
+       }
+       err(s);
+       fail();
+}
+
+static int yylex(cf)
+int cf;
+{
+       register int c, c1;
+       int atstart;
+
+       if ((c = peeksym) > 0) {
+               peeksym = 0;
+               if (c == '\n')
+                       startl = 1;
+               return (c);
+       }
+       nlseen = 0;
+       e.linep = line;
+       atstart = startl;
+       startl = 0;
+       yylval.i = 0;
+
+  loop:
+       while ((c = getqc(0)) == ' ' || c == '\t');
+       switch (c) {
+       default:
+               if (any(c, "0123456789")) {
+                       unget(c1 = getqc(0));
+                       if (c1 == '<' || c1 == '>') {
+                               iounit = c - '0';
+                               goto loop;
+                       }
+                       *e.linep++ = c;
+                       c = c1;
+               }
+               break;
+
+       case '#':
+               while ((c = getqc(0)) != 0 && c != '\n');
+               unget(c);
+               goto loop;
+
+       case 0:
+               return (c);
+
+       case '$':
+               *e.linep++ = c;
+               if ((c = getqc(0)) == '{') {
+                       if ((c = collect(c, '}')) != '\0')
+                               return (c);
+                       goto pack;
+               }
+               break;
+
+       case '`':
+       case '\'':
+       case '"':
+               if ((c = collect(c, c)) != '\0')
+                       return (c);
+               goto pack;
+
+       case '|':
+       case '&':
+       case ';':
+               if ((c1 = dual(c)) != '\0') {
+                       startl = 1;
+                       return (c1);
+               }
+               startl = 1;
+               return (c);
+       case '^':
+               startl = 1;
+               return ('|');
+       case '>':
+       case '<':
+               diag(c);
+               return (c);
+
+       case '\n':
+               nlseen++;
+               gethere();
+               startl = 1;
+               if (multiline || cf & CONTIN) {
+                       if (interactive && e.iop <= iostack)
+#ifdef BB_FEATURE_COMMAND_EDITING
+                               current_prompt = cprompt->value;
+#else
+                               prs(cprompt->value);
+#endif
+                       if (cf & CONTIN)
+                               goto loop;
+               }
+               return (c);
+
+       case '(':
+       case ')':
+               startl = 1;
+               return (c);
+       }
+
+       unget(c);
+
+  pack:
+       while ((c = getqc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
+               if (e.linep >= elinep)
+                       err("word too long");
+               else
+                       *e.linep++ = c;
+       unget(c);
+       if (any(c, "\"'`$"))
+               goto loop;
+       *e.linep++ = '\0';
+       if (atstart && (c = rlookup(line)) != 0) {
+               startl = 1;
+               return (c);
+       }
+       yylval.cp = strsave(line, areanum);
+       return (WORD);
+}
+
+int collect(c, c1)
+int c, c1;
+{
+       char s[2];
+
+       *e.linep++ = c;
+       while ((c = getqc(c1)) != c1) {
+               if (c == 0) {
+                       unget(c);
+                       s[0] = c1;
+                       s[1] = 0;
+                       prs("no closing ");
+                       yyerror(s);
+                       return (YYERRCODE);
+               }
+               if (interactive && c == '\n' && e.iop <= iostack)
+#ifdef BB_FEATURE_COMMAND_EDITING
+                       current_prompt = cprompt->value;
+#else
+                       prs(cprompt->value);
+#endif
+               *e.linep++ = c;
+       }
+       *e.linep++ = c;
+       return (0);
+}
+
+int dual(c)
+int c;
+{
+       char s[3];
+       register char *cp = s;
+
+       *cp++ = c;
+       *cp++ = getqc(0);
+       *cp = 0;
+       if ((c = rlookup(s)) == 0)
+               unget(*--cp);
+       return (c);
+}
+
+static void diag(ec)
+register int ec;
+{
+       register int c;
+
+       c = getqc(0);
+       if (c == '>' || c == '<') {
+               if (c != ec)
+                       zzerr();
+               yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
+               c = getqc(0);
+       } else
+               yylval.i = ec == '>' ? IOWRITE : IOREAD;
+       if (c != '&' || yylval.i == IOHERE)
+               unget(c);
+       else
+               yylval.i |= IODUP;
+}
+
+static char *tree(size)
+unsigned size;
+{
+       register char *t;
+
+       if ((t = getcell(size)) == NULL) {
+               prs("command line too complicated\n");
+               fail();
+               /* NOTREACHED */
+       }
+       return (t);
+}
+
+/* -------- exec.c -------- */
+
+/*
+ * execute tree
+ */
+
+static char *signame[] = {
+       "Signal 0",
+       "Hangup",
+       (char *) NULL,                          /* interrupt */
+       "Quit",
+       "Illegal instruction",
+       "Trace/BPT trap",
+       "Abort",
+       "EMT trap",
+       "Floating exception",
+       "Killed",
+       "Bus error",
+       "Memory fault",
+       "Bad system call",
+       (char *) NULL,                          /* broken pipe */
+       "Alarm clock",
+       "Terminated",
+};
+
+#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
+
+/*
+ * common actions when creating a new child
+ */
+#ifdef USE_FORK
+#define XFORK fork
+static int parent()
+{
+       register int i;
+
+       i = fork();
+       if (i != 0) {
+               if (i == -1)
+                       warn("try again");
+       }
+       return (i);
+}
+#else
+#  define parent vfork
+#  define XFORK  vfork
+#endif
+
+static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp,
+                                       int *pforked);
+static int iosetup(struct ioword *iop, int pipein, int pipeout);
+static void echo(char **wp);
+static struct op **find1case(struct op *t, char *w);
+static struct op *findcase(struct op *t, char *w);
+static void brkset(struct brkcon *bc);
+static int dolabel(void);
+static int dochdir(struct op *t);
+static int doshift(struct op *t);
+static int dologin(struct op *t);
+static int doumask(struct op *t);
+static int doexec(struct op *t);
+static int dodot(struct op *t);
+static int dowait(struct op *t);
+static int doread(struct op *t);
+static int doeval(struct op *t);
+static int dotrap(struct op *t);
+static int getsig(char *s);
+static void setsig(int n, void (*f) ());
+static int getn(char *as);
+static int dobreak(struct op *t);
+static int docontinue(struct op *t);
+static int brkcontin(char *cp, int val);
+static int doexit(struct op *t);
+static int doexport(struct op *t);
+static int doreadonly(struct op *t);
+static void rdexp(char **wp, void (*f) (), int key);
+static void badid(char *s);
+static int doset(struct op *t);
+static void varput(char *s, int out);
+static int dotimes(void);
+
+int execute(t, pin, pout, act)
+register struct op *t;
+int *pin, *pout;
+int act;
+{
+       register struct op *t1;
+       int i, pv[2], rv, child, a;
+       char *cp, **wp, **wp2;
+       struct var *vp;
+       struct brkcon bc;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &i;
+       (void) &rv;
+       (void) &wp;
+#endif
+
+       if (t == NULL)
+               return (0);
+       rv = 0;
+       a = areanum++;
+       wp = (wp2 = t->words) != NULL
+               ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
+               : NULL;
+
+       switch (t->type) {
+       case TPAREN:
+       case TCOM:
+               rv = forkexec(t, pin, pout, act, wp, &child);
+               if (child) {
+                       exstat = rv;
+                       leave();
+               }
+               break;
+
+       case TPIPE:
+               if ((rv = openpipe(pv)) < 0)
+                       break;
+               pv[0] = remap(pv[0]);
+               pv[1] = remap(pv[1]);
+               (void) execute(t->left, pin, pv, 0);
+               rv = execute(t->right, pv, pout, 0);
+               break;
+
+       case TLIST:
+               (void) execute(t->left, pin, pout, 0);
+               rv = execute(t->right, pin, pout, 0);
+               break;
+
+       case TASYNC:
+       {
+               /* save global vars altered by child */
+               int hinteractive = interactive;
+
+               i = parent();
+               if (i != 0) {
+                       /* restore global vars */
+                       interactive = hinteractive;
+
+                       if (i != -1) {
+                               setval(lookup("!"), putn(i));
+                               if (pin != NULL)
+                                       closepipe(pin);
+                               if (interactive) {
+                                       prs(putn(i));
+                                       prs("\n");
+                               }
+                       } else
+                               rv = -1;
+                       setstatus(rv);
+               } else {
+                       signal(SIGINT, SIG_IGN);
+                       signal(SIGQUIT, SIG_IGN);
+                       if (interactive)
+                               signal(SIGTERM, SIG_DFL);
+                       interactive = 0;
+                       if (pin == NULL) {
+                               close(0);
+                               open("/dev/null", 0);
+                       }
+                       _exit(execute(t->left, pin, pout, FEXEC));
+               }
+               break;
+       }
+       case TOR:
+       case TAND:
+               rv = execute(t->left, pin, pout, 0);
+               if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
+                       rv = execute(t1, pin, pout, 0);
+               break;
+
+       case TFOR:
+               if (wp == NULL) {
+                       wp = dolv + 1;
+                       if ((i = dolc) < 0)
+                               i = 0;
+               } else {
+                       i = -1;
+                       while (*wp++ != NULL);
+               }
+               vp = lookup(t->str);
+               while (setjmp(bc.brkpt))
+                       if (isbreak)
+                               goto broken;
+               brkset(&bc);
+               for (t1 = t->left; i-- && *wp != NULL;) {
+                       setval(vp, *wp++);
+                       rv = execute(t1, pin, pout, 0);
+               }
+               brklist = brklist->nextlev;
+               break;
+
+       case TWHILE:
+       case TUNTIL:
+               while (setjmp(bc.brkpt))
+                       if (isbreak)
+                               goto broken;
+               brkset(&bc);
+               t1 = t->left;
+               while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
+                       rv = execute(t->right, pin, pout, 0);
+               brklist = brklist->nextlev;
+               break;
+
+       case TIF:
+       case TELIF:
+               if (t->right != NULL) {
+                       rv = !execute(t->left, pin, pout, 0) ?
+                               execute(t->right->left, pin, pout, 0) :
+                               execute(t->right->right, pin, pout, 0);
+               }
+               break;
+
+       case TCASE:
+               if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
+                       cp = "";
+               if ((t1 = findcase(t->left, cp)) != NULL)
+                       rv = execute(t1, pin, pout, 0);
+               break;
+
+       case TBRACE:
+/*
+               if (iopp = t->ioact)
+                       while (*iopp)
+                               if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
+                                       rv = -1;
+                                       break;
+                               }
+*/
+               if (rv >= 0 && (t1 = t->left))
+                       rv = execute(t1, pin, pout, 0);
+               break;
+       }
+
+  broken:
+       t->words = wp2;
+       isbreak = 0;
+       freehere(areanum);
+       freearea(areanum);
+       areanum = a;
+       if (interactive && intr) {
+               closeall();
+               fail();
+       }
+       if ((i = trapset) != 0) {
+               trapset = 0;
+               runtrap(i);
+       }
+       return (rv);
+}
+
+static int forkexec(t, pin, pout, act, wp, pforked)
+register struct op *t;
+int *pin, *pout;
+int act;
+char **wp;
+int *pforked;
+{
+       int i, rv, (*shcom) ();
+       register int f;
+       char *cp = NULL;
+       struct ioword **iopp;
+       int resetsig;
+       char **owp;
+
+       int *hpin = pin;
+       int *hpout = pout;
+       int hforked;
+       char *hwp;
+       int hinteractive;
+       int hintr;
+       struct brkcon * hbrklist;
+       int hexecflg;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &pin;
+       (void) &pout;
+       (void) &wp;
+       (void) &shcom;
+       (void) &cp;
+       (void) &resetsig;
+       (void) &owp;
+#endif 
+
+       owp = wp;
+       resetsig = 0;
+       *pforked = 0;
+       shcom = NULL;
+       rv = -1;                                        /* system-detected error */
+       if (t->type == TCOM) {
+               while ((cp = *wp++) != NULL);
+               cp = *wp;
+
+               /* strip all initial assignments */
+               /* not correct wrt PATH=yyy command  etc */
+               if (flag['x'])
+                       echo(cp ? wp : owp);
+               if (cp == NULL && t->ioact == NULL) {
+                       while ((cp = *owp++) != NULL && assign(cp, COPYV));
+                       return (setstatus(0));
+               } else if (cp != NULL)
+                       shcom = inbuilt(cp);
+       }
+       t->words = wp;
+       f = act;
+       if (shcom == NULL && (f & FEXEC) == 0) {
+
+               /* save vars altered by child (needed by vfork) */
+               hpin = pin;
+               hpout = pout;
+               hforked = *pforked;
+               hwp = *wp;
+               hinteractive = interactive;
+               hintr = intr;
+               hbrklist = brklist;
+               hexecflg = execflg;
+       
+               i = parent();
+               if (i != 0) {
+                       /* restore vars altered by child (needed by vfork) */
+                       pin = hpin;
+                       pout = hpout;
+                       *pforked = hforked;
+                       *wp = hwp;
+                       interactive = hinteractive;
+                       intr = hintr;
+                       brklist = hbrklist;
+                       execflg = hexecflg;
+
+                       *pforked = 0;
+                       if (i == -1)
+                               return (rv);
+                       if (pin != NULL)
+                               closepipe(pin);
+                       return (pout == NULL ? setstatus(waitfor(i, 0)) : 0);
+               }
+               if (interactive) {
+                       signal(SIGINT, SIG_IGN);
+                       signal(SIGQUIT, SIG_IGN);
+                       resetsig = 1;
+               }
+               interactive = 0;
+               intr = 0;
+               (*pforked)++;
+               brklist = 0;
+               execflg = 0;
+       }
+       if (owp != NULL)
+               while ((cp = *owp++) != NULL && assign(cp, COPYV))
+                       if (shcom == NULL)
+                               export(lookup(cp));
+#ifdef COMPIPE
+       if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
+               err("piping to/from shell builtins not yet done");
+               return (-1);
+       }
+#endif
+       if (pin != NULL) {
+               dup2(pin[0], 0);
+               closepipe(pin);
+       }
+       if (pout != NULL) {
+               dup2(pout[1], 1);
+               closepipe(pout);
+       }
+       if ((iopp = t->ioact) != NULL) {
+               if (shcom != NULL && shcom != doexec) {
+                       prs(cp);
+                       err(": cannot redirect shell command");
+                       return (-1);
+               }
+               while (*iopp)
+                       if (iosetup(*iopp++, pin != NULL, pout != NULL))
+                               return (rv);
+       }
+       if (shcom)
+               return (setstatus((*shcom) (t)));
+       /* should use FIOCEXCL */
+       for (i = FDBASE; i < NOFILE; i++)
+               close(i);
+       if (resetsig) {
+               signal(SIGINT, SIG_DFL);
+               signal(SIGQUIT, SIG_DFL);
+       }
+       if (t->type == TPAREN)
+               _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
+       if (wp[0] == NULL)
+               _exit(0);
+       cp = rexecve(wp[0], wp, makenv(0));
+       prs(wp[0]);
+       prs(": ");
+       warn(cp);
+       if (!execflg)
+               trap[0] = NULL;
+#ifdef __uClinux__
+       _exit(1);
+#else
+       leave();
+#endif
+       /* NOTREACHED */
+}
+
+/*
+ * 0< 1> are ignored as required
+ * within pipelines.
+ */
+int iosetup(iop, pipein, pipeout)
+register struct ioword *iop;
+int pipein, pipeout;
+{
+       int u;
+       char *msg;
+       char *cp = NULL;
+
+       if (iop->io_unit == IODEFAULT)  /* take default */
+               iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
+       if (pipein && iop->io_unit == 0)
+               return (0);
+       if (pipeout && iop->io_unit == 1)
+               return (0);
+       msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
+       if ((iop->io_flag & IOHERE) == 0) {
+               cp = iop->io_name;
+               if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
+                       return (1);
+       }
+       if (iop->io_flag & IODUP) {
+               if (cp[1] || (!digit(*cp) && *cp != '-')) {
+                       prs(cp);
+                       err(": illegal >& argument");
+                       return (1);
+               }
+               if (*cp == '-')
+                       iop->io_flag = IOCLOSE;
+               iop->io_flag &= ~(IOREAD | IOWRITE);
+       }
+       switch (iop->io_flag) {
+       case IOREAD:
+               u = open(cp, 0);
+               break;
+
+       case IOHERE:
+       case IOHERE | IOXHERE:
+               u = herein(iop->io_name, iop->io_flag & IOXHERE);
+               cp = "here file ";
+               break;
+
+       case IOWRITE | IOCAT:
+               if ((u = open(cp, 1)) >= 0) {
+                       lseek(u, (long) 0, 2);
+                       break;
+               }
+       case IOWRITE:
+               u = creat(cp, 0666);
+               break;
+
+       case IODUP:
+               u = dup2(*cp - '0', iop->io_unit);
+               break;
+
+       case IOCLOSE:
+               close(iop->io_unit);
+               return (0);
+       default:
+               u = -1;
+               break;
+       }
+       if (u < 0) {
+               int sav_err = errno;
+
+               prs(cp);
+               if (iop->io_flag & IOHERE)
+                       prs(iop->io_name);
+               prs(": cannot ");
+               prs(msg);
+               prs(" (");
+               prs(strerror(sav_err));
+               warn(")");
+               return (1);
+       } else {
+               if (u != iop->io_unit) {
+                       dup2(u, iop->io_unit);
+                       close(u);
+               }
+       }
+       return (0);
+}
+
+static void echo(wp)
+register char **wp;
+{
+       int i;
+
+       prs("+");
+       for (i = 0; wp[i]; i++) {
+               if (i)
+                       prs(" ");
+               prs(wp[i]);
+       }
+       prs("\n");
+}
+
+static struct op **find1case(t, w)
+struct op *t;
+char *w;
+{
+       register struct op *t1;
+       struct op **tp;
+       register char **wp, *cp;
+
+       if (t == NULL)
+               return ((struct op **) NULL);
+       if (t->type == TLIST) {
+               if ((tp = find1case(t->left, w)) != NULL)
+                       return (tp);
+               t1 = t->right;                  /* TPAT */
+       } else
+               t1 = t;
+       for (wp = t1->words; *wp;)
+               if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
+                       return (&t1->left);
+       return ((struct op **) NULL);
+}
+
+static struct op *findcase(t, w)
+struct op *t;
+char *w;
+{
+       register struct op **tp;
+
+       return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
+}
+
+/*
+ * Enter a new loop level (marked for break/continue).
+ */
+static void brkset(bc)
+struct brkcon *bc;
+{
+       bc->nextlev = brklist;
+       brklist = bc;
+}
+
+/*
+ * Wait for the last process created.
+ * Print a message for each process found
+ * that was killed by a signal.
+ * Ignore interrupt signals while waiting
+ * unless `canintr' is true.
+ */
+int waitfor(lastpid, canintr)
+register int lastpid;
+int canintr;
+{
+       register int pid, rv;
+       int s;
+       int oheedint = heedint;
+
+       heedint = 0;
+       rv = 0;
+       do {
+               pid = wait(&s);
+               if (pid == -1) {
+                       if (errno != EINTR || canintr)
+                               break;
+               } else {
+                       if ((rv = WAITSIG(s)) != 0) {
+                               if (rv < NSIGNAL) {
+                                       if (signame[rv] != NULL) {
+                                               if (pid != lastpid) {
+                                                       prn(pid);
+                                                       prs(": ");
+                                               }
+                                               prs(signame[rv]);
+                                       }
+                               } else {
+                                       if (pid != lastpid) {
+                                               prn(pid);
+                                               prs(": ");
+                                       }
+                                       prs("Signal ");
+                                       prn(rv);
+                                       prs(" ");
+                               }
+                               if (WAITCORE(s))
+                                       prs(" - core dumped");
+                               if (rv >= NSIGNAL || signame[rv])
+                                       prs("\n");
+                               rv = -1;
+                       } else
+                               rv = WAITVAL(s);
+               }
+       } while (pid != lastpid);
+       heedint = oheedint;
+       if (intr) {
+               if (interactive) {
+                       if (canintr)
+                               intr = 0;
+               } else {
+                       if (exstat == 0)
+                               exstat = rv;
+                       onintr(0);
+               }
+       }
+       return (rv);
+}
+
+int setstatus(s)
+register int s;
+{
+       exstat = s;
+       setval(lookup("?"), putn(s));
+       return (s);
+}
+
+/*
+ * PATH-searching interface to execve.
+ * If getenv("PATH") were kept up-to-date,
+ * execvp might be used.
+ */
+char *rexecve(c, v, envp)
+char *c, **v, **envp;
+{
+       register int i;
+       register char *sp, *tp;
+       int eacces = 0, asis = 0;
+
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       char *name = c;
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       name = get_last_path_component(name);
+#endif
+       optind = 1;
+       if (find_applet_by_name(name)) {
+               /* We have to exec here since we vforked.  Running 
+                * run_applet_by_name() won't work and bad things
+                * will happen. */
+               execve("/proc/self/exe", v, envp);
+               execve("busybox", v, envp);
+       }
+#endif
+
+       sp = any('/', c)? "": path->value;
+       asis = *sp == '\0';
+       while (asis || *sp != '\0') {
+               asis = 0;
+               tp = e.linep;
+               for (; *sp != '\0'; tp++)
+                       if ((*tp = *sp++) == ':') {
+                               asis = *sp == '\0';
+                               break;
+                       }
+               if (tp != e.linep)
+                       *tp++ = '/';
+               for (i = 0; (*tp++ = c[i++]) != '\0';);
+               execve(e.linep, v, envp);
+               switch (errno) {
+               case ENOEXEC:
+                       *v = e.linep;
+                       tp = *--v;
+                       *v = e.linep;
+                       execve("/bin/sh", v, envp);
+                       *v = tp;
+                       return ("no Shell");
+
+               case ENOMEM:
+                       return ("program too big");
+
+               case E2BIG:
+                       return ("argument list too long");
+
+               case EACCES:
+                       eacces++;
+                       break;
+               }
+       }
+       return (errno == ENOENT ? "not found" : "cannot execute");
+}
+
+/*
+ * Run the command produced by generator `f'
+ * applied to stream `arg'.
+ */
+int run(argp, f)
+struct ioarg *argp;
+int (*f) ();
+{
+       struct op *otree;
+       struct wdblock *swdlist;
+       struct wdblock *siolist;
+       jmp_buf ev, rt;
+       xint *ofail;
+       int rv;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &rv;
+#endif
+       areanum++;
+       swdlist = wdlist;
+       siolist = iolist;
+       otree = outtree;
+       ofail = failpt;
+       rv = -1;
+       if (newenv(setjmp(errpt = ev)) == 0) {
+               wdlist = 0;
+               iolist = 0;
+               pushio(argp, f);
+               e.iobase = e.iop;
+               yynerrs = 0;
+               if (setjmp(failpt = rt) == 0 && yyparse() == 0)
+                       rv = execute(outtree, NOPIPE, NOPIPE, 0);
+               quitenv();
+       }
+       wdlist = swdlist;
+       iolist = siolist;
+       failpt = ofail;
+       outtree = otree;
+       freearea(areanum--);
+       return (rv);
+}
+
+/* -------- do.c -------- */
+
+/*
+ * built-in commands: doX
+ */
+
+static int
+dolabel()
+{
+       return (0);
+}
+
+static int
+dochdir(t)
+register struct op *t;
+{
+       register char *cp, *er;
+
+       if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
+               er = ": no home directory";
+       else if (chdir(cp) < 0)
+               er = ": bad directory";
+       else {
+#ifdef TEST_NEW_VERSION
+#ifdef BB_FEATURE_SH_FANCY_PROMPT
+               char *cated = NULL;
+
+               if (*cp != '/')
+                       cp = cated = concat_path_file(cwd, cp);
+               if (cwd != unknown)
+                       free(cwd);
+               cwd = simplify_path(cp);
+               free(cated);
+#endif
+#endif
+               return (0);
+       }
+       prs(cp != NULL ? cp : "cd");
+       err(er);
+       return (1);
+}
+
+int doshift(t)
+register struct op *t;
+{
+       int n;
+
+       n = t->words[1] ? getn(t->words[1]) : 1;
+       if (dolc < n) {
+               err("nothing to shift");
+               return (1);
+       }
+       dolv[n] = dolv[0];
+       dolv += n;
+       dolc -= n;
+       setval(lookup("#"), putn(dolc));
+       return (0);
+}
+
+/*
+ * execute login and newgrp directly
+ */
+int dologin(t)
+struct op *t;
+{
+       register char *cp;
+
+       if (interactive) {
+               signal(SIGINT, SIG_DFL);
+               signal(SIGQUIT, SIG_DFL);
+       }
+       cp = rexecve(t->words[0], t->words, makenv(0));
+       prs(t->words[0]);
+       prs(": ");
+       err(cp);
+       return (1);
+}
+
+int doumask(t)
+register struct op *t;
+{
+       register int i, n;
+       register char *cp;
+
+       if ((cp = t->words[1]) == NULL) {
+               i = umask(0);
+               umask(i);
+               for (n = 3 * 4; (n -= 3) >= 0;)
+                       put1c('0' + ((i >> n) & 07));
+               put1c('\n');
+       } else {
+               for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
+                       n = n * 8 + (*cp - '0');
+               umask(n);
+       }
+       return (0);
+}
+
+int doexec(t)
+register struct op *t;
+{
+       int i;
+       jmp_buf ex;
+       xint *ofail;
+
+       t->ioact = NULL;
+       for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
+       if (i == 0)
+               return (1);
+       execflg = 1;
+       ofail = failpt;
+       if (setjmp(failpt = ex) == 0)
+               execute(t, NOPIPE, NOPIPE, FEXEC);
+       failpt = ofail;
+       execflg = 0;
+       return (1);
+}
+
+int dodot(t)
+struct op *t;
+{
+       int i;
+       register char *sp, *tp;
+       char *cp;
+
+       if ((cp = t->words[1]) == NULL)
+               return (0);
+       sp = any('/', cp) ? ":" : path->value;
+       while (*sp) {
+               tp = e.linep;
+               while (*sp && (*tp = *sp++) != ':')
+                       tp++;
+               if (tp != e.linep)
+                       *tp++ = '/';
+               for (i = 0; (*tp++ = cp[i++]) != '\0';);
+               if ((i = open(e.linep, 0)) >= 0) {
+                       exstat = 0;
+                       next(remap(i));
+                       return (exstat);
+               }
+       }
+       prs(cp);
+       err(": not found");
+       return (-1);
+}
+
+int dowait(t)
+struct op *t;
+{
+       int i;
+       register char *cp;
+
+       if ((cp = t->words[1]) != NULL) {
+               i = getn(cp);
+               if (i == 0)
+                       return (0);
+       } else
+               i = -1;
+       setstatus(waitfor(i, 1));
+       return (0);
+}
+
+int doread(t)
+struct op *t;
+{
+       register char *cp, **wp;
+       int nb = 0;
+       register int nl = 0;
+
+       if (t->words[1] == NULL) {
+               err("Usage: read name ...");
+               return (1);
+       }
+       for (wp = t->words + 1; *wp; wp++) {
+               for (cp = e.linep; !nl && cp < elinep - 1; cp++)
+                       if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
+                               (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
+                               break;
+               *cp = 0;
+               if (nb <= 0)
+                       break;
+               setval(lookup(*wp), e.linep);
+       }
+       return (nb <= 0);
+}
+
+int doeval(t)
+register struct op *t;
+{
+       return (RUN(awordlist, t->words + 1, wdchar));
+}
+
+int dotrap(t)
+register struct op *t;
+{
+       register int n, i;
+       register int resetsig;
+
+       if (t->words[1] == NULL) {
+               for (i = 0; i <= _NSIG; i++)
+                       if (trap[i]) {
+                               prn(i);
+                               prs(": ");
+                               prs(trap[i]);
+                               prs("\n");
+                       }
+               return (0);
+       }
+       resetsig = digit(*t->words[1]);
+       for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
+               n = getsig(t->words[i]);
+               freecell(trap[n]);
+               trap[n] = 0;
+               if (!resetsig) {
+                       if (*t->words[1] != '\0') {
+                               trap[n] = strsave(t->words[1], 0);
+                               setsig(n, sig);
+                       } else
+                               setsig(n, SIG_IGN);
+               } else {
+                       if (interactive)
+                               if (n == SIGINT)
+                                       setsig(n, onintr);
+                               else
+                                       setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
+                       else
+                               setsig(n, SIG_DFL);
+               }
+       }
+       return (0);
+}
+
+int getsig(s)
+char *s;
+{
+       register int n;
+
+       if ((n = getn(s)) < 0 || n > _NSIG) {
+               err("trap: bad signal number");
+               n = 0;
+       }
+       return (n);
+}
+
+void setsig(n, f)
+int n;
+void (*f) (int);
+{
+       if (n == 0)
+               return;
+       if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
+               ourtrap[n] = 1;
+               signal(n, f);
+       }
+}
+
+int getn(as)
+char *as;
+{
+       register char *s;
+       int n, m;
+
+       s = as;
+       m = 1;
+       if (*s == '-') {
+               m = -1;
+               s++;
+       }
+       for (n = 0; digit(*s); s++)
+               n = (n * 10) + (*s - '0');
+       if (*s) {
+               prs(as);
+               err(": bad number");
+       }
+       return (n * m);
+}
+
+int dobreak(t)
+struct op *t;
+{
+       return (brkcontin(t->words[1], 1));
+}
+
+int docontinue(t)
+struct op *t;
+{
+       return (brkcontin(t->words[1], 0));
+}
+
+static int brkcontin(cp, val)
+register char *cp;
+int val;
+{
+       register struct brkcon *bc;
+       int nl;
+
+       nl = cp == NULL ? 1 : getn(cp);
+       if (nl <= 0)
+               nl = 999;
+       do {
+               if ((bc = brklist) == NULL)
+                       break;
+               brklist = bc->nextlev;
+       } while (--nl);
+       if (nl) {
+               err("bad break/continue level");
+               return (1);
+       }
+       isbreak = val;
+       longjmp(bc->brkpt, 1);
+       /* NOTREACHED */
+}
+
+int doexit(t)
+struct op *t;
+{
+       register char *cp;
+
+       execflg = 0;
+       if ((cp = t->words[1]) != NULL)
+               setstatus(getn(cp));
+       leave();
+       /* NOTREACHED */
+}
+
+int doexport(t)
+struct op *t;
+{
+       rdexp(t->words + 1, export, EXPORT);
+       return (0);
+}
+
+int doreadonly(t)
+struct op *t;
+{
+       rdexp(t->words + 1, ronly, RONLY);
+       return (0);
+}
+
+static void rdexp(wp, f, key)
+register char **wp;
+void (*f) ();
+int key;
+{
+       if (*wp != NULL) {
+               for (; *wp != NULL; wp++)
+                       if (checkname(*wp))
+                               (*f) (lookup(*wp));
+                       else
+                               badid(*wp);
+       } else
+               putvlist(key, 1);
+}
+
+static void badid(s)
+register char *s;
+{
+       prs(s);
+       err(": bad identifier");
+}
+
+int doset(t)
+register struct op *t;
+{
+       register struct var *vp;
+       register char *cp;
+       int n;
+
+       if ((cp = t->words[1]) == NULL) {
+               for (vp = vlist; vp; vp = vp->next)
+                       varput(vp->name, 1);
+               return (0);
+       }
+       if (*cp == '-') {
+               /* bad: t->words++; */
+               for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
+               if (*++cp == 0)
+                       flag['x'] = flag['v'] = 0;
+               else
+                       for (; *cp; cp++)
+                               switch (*cp) {
+                               case 'e':
+                                       if (!interactive)
+                                               flag['e']++;
+                                       break;
+
+                               default:
+                                       if (*cp >= 'a' && *cp <= 'z')
+                                               flag[(int) *cp]++;
+                                       break;
+                               }
+               setdash();
+       }
+       if (t->words[1]) {
+               t->words[0] = dolv[0];
+               for (n = 1; t->words[n]; n++)
+                       setarea((char *) t->words[n], 0);
+               dolc = n - 1;
+               dolv = t->words;
+               setval(lookup("#"), putn(dolc));
+               setarea((char *) (dolv - 1), 0);
+       }
+       return (0);
+}
+
+void varput(s, out)
+register char *s;
+int out;
+{
+       if (letnum(*s)) {
+               write(out, s, strlen(s));
+               write(out, "\n", 1);
+       }
+}
+
+
+#define SECS    60L
+#define MINS    3600L
+
+int dotimes()
+{
+       struct tms tbuf;
+
+       times(&tbuf);
+
+       prn((int) (tbuf.tms_cutime / MINS));
+       prs("m");
+       prn((int) ((tbuf.tms_cutime % MINS) / SECS));
+       prs("s ");
+       prn((int) (tbuf.tms_cstime / MINS));
+       prs("m");
+       prn((int) ((tbuf.tms_cstime % MINS) / SECS));
+       prs("s\n");
+       return (0);
+}
+
+struct builtin {
+       char *command;
+       int (*fn) ();
+};
+static struct builtin builtin[] = {
+       {":", dolabel},
+       {"cd", dochdir},
+       {"shift", doshift},
+       {"exec", doexec},
+       {"wait", dowait},
+       {"read", doread},
+       {"eval", doeval},
+       {"trap", dotrap},
+       {"break", dobreak},
+       {"continue", docontinue},
+       {"exit", doexit},
+       {"export", doexport},
+       {"readonly", doreadonly},
+       {"set", doset},
+       {".", dodot},
+       {"umask", doumask},
+       {"login", dologin},
+       {"newgrp", dologin},
+       {"times", dotimes},
+       {0, 0}
+};
+
+int (*inbuilt(s)) ()
+register char *s;
+{
+       register struct builtin *bp;
+
+       for (bp = builtin; bp->command != NULL; bp++)
+               if (strcmp(bp->command, s) == 0)
+                       return (bp->fn);
+       return ((int (*)()) NULL);
+}
+
+
+/* -------- eval.c -------- */
+
+/*
+ * ${}
+ * `command`
+ * blank interpretation
+ * quoting
+ * glob
+ */
+
+static int expand(char *cp, struct wdblock **wbp, int f);
+static char *blank(int f);
+static int dollar(int quoted);
+static int grave(int quoted);
+static void globname(char *we, char *pp);
+static char *generate(char *start1, char *end1, char *middle, char *end);
+static int anyspcl(struct wdblock *wb);
+static int xstrcmp(char *p1, char *p2);
+static void glob0(char *a0, unsigned int a1, int a2,
+                                 int (*a3) (char *, char *));
+static void glob1(char *base, char *lim);
+static void glob2(char *i, char *j);
+static void glob3(char *i, char *j, char *k);
+
+
+char **eval(ap, f)
+char **ap;
+int f;
+{
+       struct wdblock *wb;
+       char **wp;
+       char **wf;
+       jmp_buf ev;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &wp;
+       (void) &ap;
+#endif
+
+       wp = NULL;
+       wb = NULL;
+       wf = NULL;
+       if (newenv(setjmp(errpt = ev)) == 0) {
+               while (*ap && isassign(*ap))
+                       expand(*ap++, &wb, f & ~DOGLOB);
+               if (flag['k']) {
+                       for (wf = ap; *wf; wf++) {
+                               if (isassign(*wf))
+                                       expand(*wf, &wb, f & ~DOGLOB);
+                       }
+               }
+               for (wb = addword((char *) 0, wb); *ap; ap++) {
+                       if (!flag['k'] || !isassign(*ap))
+                               expand(*ap, &wb, f & ~DOKEY);
+               }
+               wb = addword((char *) 0, wb);
+               wp = getwords(wb);
+               quitenv();
+       } else
+               gflg = 1;
+       return (gflg ? (char **) NULL : wp);
+}
+
+/*
+ * Make the exported environment from the exported
+ * names in the dictionary. Keyword assignments
+ * will already have been done.
+ */
+char **makenv(int all)
+{
+       register struct wdblock *wb;
+       register struct var *vp;
+
+       wb = NULL;
+       for (vp = vlist; vp; vp = vp->next)
+               if (all || vp->status & EXPORT)
+                       wb = addword(vp->name, wb);
+       wb = addword((char *) 0, wb);
+       return (getwords(wb));
+}
+
+char *evalstr(cp, f)
+char *cp;
+int f;
+{
+       struct wdblock *wb;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &cp;
+#endif
+
+       wb = NULL;
+       if (expand(cp, &wb, f)) {
+               if (wb == NULL || wb->w_nword == 0
+                       || (cp = wb->w_words[0]) == NULL)
+                       cp = "";
+               freecell(wb);
+       } else
+               cp = NULL;
+       return (cp);
+}
+
+static int expand(cp, wbp, f)
+char *cp;
+register struct wdblock **wbp;
+int f;
+{
+       jmp_buf ev;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &cp;
+#endif
+
+       gflg = 0;
+       if (cp == NULL)
+               return (0);
+       if (!anys("$`'\"", cp) &&
+               !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
+               cp = strsave(cp, areanum);
+               if (f & DOTRIM)
+                       unquote(cp);
+               *wbp = addword(cp, *wbp);
+               return (1);
+       }
+       if (newenv(setjmp(errpt = ev)) == 0) {
+               PUSHIO(aword, cp, strchar);
+               e.iobase = e.iop;
+               while ((cp = blank(f)) && gflg == 0) {
+                       e.linep = cp;
+                       cp = strsave(cp, areanum);
+                       if ((f & DOGLOB) == 0) {
+                               if (f & DOTRIM)
+                                       unquote(cp);
+                               *wbp = addword(cp, *wbp);
+                       } else
+                               *wbp = glob(cp, *wbp);
+               }
+               quitenv();
+       } else
+               gflg = 1;
+       return (gflg == 0);
+}
+
+/*
+ * Blank interpretation and quoting
+ */
+static char *blank(f)
+int f;
+{
+       int c, c1;
+       register char *sp;
+       int scanequals, foundequals;
+
+       sp = e.linep;
+       scanequals = f & DOKEY;
+       foundequals = 0;
+
+  loop:
+       switch (c = subgetc('"', foundequals)) {
+       case 0:
+               if (sp == e.linep)
+                       return (0);
+               *e.linep++ = 0;
+               return (sp);
+
+       default:
+               if (f & DOBLANK && any(c, ifs->value))
+                       goto loop;
+               break;
+
+       case '"':
+       case '\'':
+               scanequals = 0;
+               if (INSUB())
+                       break;
+               for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
+                       if (c == 0)
+                               break;
+                       if (c == '\'' || !any(c, "$`\""))
+                               c |= QUOTE;
+                       *e.linep++ = c;
+               }
+               c = 0;
+       }
+       unget(c);
+       if (!letter(c))
+               scanequals = 0;
+       for (;;) {
+               c = subgetc('"', foundequals);
+               if (c == 0 ||
+                       (f & DOBLANK && any(c, ifs->value)) ||
+                       (!INSUB() && any(c, "\"'"))) {
+                       scanequals = 0;
+                       unget(c);
+                       if (any(c, "\"'"))
+                               goto loop;
+                       break;
+               }
+               if (scanequals) {
+                       if (c == '=') {
+                               foundequals = 1;
+                               scanequals = 0;
+                       } else if (!letnum(c))
+                               scanequals = 0;
+               }
+               *e.linep++ = c;
+       }
+       *e.linep++ = 0;
+       return (sp);
+}
+
+/*
+ * Get characters, substituting for ` and $
+ */
+int subgetc(ec, quoted)
+register char ec;
+int quoted;
+{
+       register char c;
+
+  again:
+       c = getqc(ec);
+       if (!INSUB() && ec != '\'') {
+               if (c == '`') {
+                       if (grave(quoted) == 0)
+                               return (0);
+                       e.iop->task = XGRAVE;
+                       goto again;
+               }
+               if (c == '$' && (c = dollar(quoted)) == 0) {
+                       e.iop->task = XDOLL;
+                       goto again;
+               }
+       }
+       return (c);
+}
+
+/*
+ * Prepare to generate the string returned by ${} substitution.
+ */
+static int dollar(quoted)
+int quoted;
+{
+       int otask;
+       struct io *oiop;
+       char *dolp;
+       register char *s, c, *cp;
+       struct var *vp;
+
+       c = readc();
+       s = e.linep;
+       if (c != '{') {
+               *e.linep++ = c;
+               if (letter(c)) {
+                       while ((c = readc()) != 0 && letnum(c))
+                               if (e.linep < elinep)
+                                       *e.linep++ = c;
+                       unget(c);
+               }
+               c = 0;
+       } else {
+               oiop = e.iop;
+               otask = e.iop->task;
+               e.iop->task = XOTHER;
+               while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
+                       if (e.linep < elinep)
+                               *e.linep++ = c;
+               if (oiop == e.iop)
+                       e.iop->task = otask;
+               if (c != '}') {
+                       err("unclosed ${");
+                       gflg++;
+                       return (c);
+               }
+       }
+       if (e.linep >= elinep) {
+               err("string in ${} too long");
+               gflg++;
+               e.linep -= 10;
+       }
+       *e.linep = 0;
+       if (*s) {
+               for (cp = s + 1; *cp; cp++)
+                       if (any(*cp, "=-+?")) {
+                               c = *cp;
+                               *cp++ = 0;
+                               break;
+                       }
+       } else {
+               cp = s;
+       }
+       if (s[1] == 0 && (*s == '*' || *s == '@')) {
+               if (dolc > 1) {
+                       /* currently this does not distinguish $* and $@ */
+                       /* should check dollar */
+                       e.linep = s;
+                       PUSHIO(awordlist, dolv + 1, dolchar);
+                       return (0);
+               } else {                                /* trap the nasty ${=} */
+                       s[0] = '1';
+                       s[1] = 0;
+               }
+       }
+       e.linep = s;
+       vp = lookup(s);
+       if ((dolp = vp->value) == null) {
+               switch (c) {
+               case '=':
+                       if (digit(*s)) {
+                               err("cannot use ${...=...} with $n");
+                               gflg++;
+                               break;
+                       }
+                       cp = evalstr(strsave(cp, areanum), DOSUB);
+                       setval(vp, cp);
+                       dolp = vp->value;
+                       break;
+
+               case '-':
+                       dolp = evalstr(strsave(cp, areanum), DOSUB);
+                       break;
+
+               case '?':
+                       if (*cp == 0) {
+                               prs("missing value for ");
+                               err(s);
+                       } else
+                               err(evalstr(strsave(cp, areanum), DOSUB));
+                       gflg++;
+                       break;
+               }
+       } else if (c == '+') {
+               dolp = evalstr(strsave(cp, areanum), DOSUB);
+       }
+       if (flag['u'] && dolp == null) {
+               prs("unset variable: ");
+               err(s);
+               gflg++;
+       }
+       PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
+       return (0);
+}
+
+/*
+ * Run the command in `...` and read its output.
+ */
+static int grave(quoted)
+int quoted;
+{
+       int otask;
+       struct io *oiop;
+       register char *cp, *s;
+       register int i, c;
+       int pf[2];
+#ifndef USE_FORK
+       char *av[4];
+       char **env;
+#endif
+
+       c = readc();
+       s = e.linep;
+       *e.linep++ = c;
+       oiop = e.iop;
+       otask = e.iop->task;
+       e.iop->task = XOTHER;
+       while ((c = subgetc('\'', 0)) != 0 && c != '`')
+               if (e.linep < elinep)
+                       *e.linep++ = c;
+       if (oiop == e.iop)
+               e.iop->task = otask;
+       if (c != '`') {
+               err("no closing `");
+               return (0);
+       }
+       if (openpipe(pf) < 0)
+               return (0);
+#ifndef USE_FORK
+       env = makenv(1);
+#endif
+       if ((i = XFORK()) == -1) {
+               closepipe(pf);
+               err("try again");
+               return (0);
+       }
+       if (i != 0) {
+               e.linep = s;
+               close(pf[1]);
+               PUSHIO(afile, remap(pf[0]), quoted ? qgravechar : gravechar);
+               return (1);
+       }
+       *e.linep = 0;
+       /* allow trapped signals */
+       for (i = 0; i <= _NSIG; i++)
+               if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
+                       signal(i, SIG_DFL);
+       dup2(pf[1], 1);
+       closepipe(pf);
+       cp = strsave(e.linep = s, 0);
+#ifdef USE_FORK
+       flag['e'] = 0;
+       flag['v'] = 0;
+       flag['n'] = 0;
+       areanum = 1;
+       inhere = acthere = (struct here *) 0;
+       freearea(areanum);                      /* free old space */
+       e.oenv = NULL;
+       e.iop = (e.iobase = iostack) - 1;
+       unquote(cp);
+       interactive = 0;
+       PUSHIO(aword, cp, nlchar);
+       onecommand();
+       exit(1);
+#else
+       /* NOTE: When we are vfork()'ing we've got to exec here.
+        * Therefore we start the command using /bin/sh -c.
+        */
+       av[0] = "sh";
+       av[1] = "-c";
+       av[2] = cp;
+       av[3] = NULL;
+       execve("/bin/sh", av, env);
+       err("grave: execlp failed\n");
+       _exit(1);
+#endif
+}
+
+char *unquote(as)
+register char *as;
+{
+       register char *s;
+
+       if ((s = as) != NULL)
+               while (*s)
+                       *s++ &= ~QUOTE;
+       return (as);
+}
+
+/* -------- glob.c -------- */
+
+/*
+ * glob
+ */
+
+#define scopy(x) strsave((x), areanum)
+#define BLKSIZ  512
+
+
+static struct wdblock *cl, *nl;
+static char spcl[] = "[?*";
+
+struct wdblock *glob(cp, wb)
+char *cp;
+struct wdblock *wb;
+{
+       int i;
+       register char *pp;
+
+       if (cp == 0)
+               return (wb);
+       i = 0;
+       for (pp = cp; *pp; pp++)
+               if (any(*pp, spcl))
+                       i++;
+               else if (!any(*pp & ~QUOTE, spcl))
+                       *pp &= ~QUOTE;
+       if (i != 0) {
+               for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
+                        cl = nl) {
+                       nl = newword(cl->w_nword * 2);
+                       for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
+                               for (pp = cl->w_words[i]; *pp; pp++)
+                                       if (any(*pp, spcl)) {
+                                               globname(cl->w_words[i], pp);
+                                               break;
+                                       }
+                               if (*pp == '\0')
+                                       nl = addword(scopy(cl->w_words[i]), nl);
+                       }
+                       for (i = 0; i < cl->w_nword; i++)
+                               freecell(cl->w_words[i]);
+                       freecell(cl);
+               }
+               for (i = 0; i < cl->w_nword; i++)
+                       unquote(cl->w_words[i]);
+               glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
+               if (cl->w_nword) {
+                       for (i = 0; i < cl->w_nword; i++)
+                               wb = addword(cl->w_words[i], wb);
+                       freecell(cl);
+                       return (wb);
+               }
+       }
+       wb = addword(unquote(cp), wb);
+       return (wb);
+}
+
+void globname(we, pp)
+char *we;
+register char *pp;
+{
+       register char *np, *cp;
+       char *name, *gp, *dp;
+       int k;
+       DIR *dirp;
+       struct dirent *de;
+       char dname[NAME_MAX + 1];
+       struct stat dbuf;
+
+       for (np = we; np != pp; pp--)
+               if (pp[-1] == '/')
+                       break;
+       for (dp = cp = space((int) (pp - np) + 3); np < pp;)
+               *cp++ = *np++;
+       *cp++ = '.';
+       *cp = '\0';
+       for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
+               *cp++ = *np++;
+       *cp = '\0';
+       dirp = opendir(dp);
+       if (dirp == 0) {
+               freecell(dp);
+               freecell(gp);
+               return;
+       }
+       dname[NAME_MAX] = '\0';
+       while ((de = readdir(dirp)) != NULL) {
+               strncpy(dname, de->d_name, NAME_MAX);
+               if (dname[0] == '.')
+                       if (*gp != '.')
+                               continue;
+               for (k = 0; k < NAME_MAX; k++)
+                       if (any(dname[k], spcl))
+                               dname[k] |= QUOTE;
+               if (gmatch(dname, gp)) {
+                       name = generate(we, pp, dname, np);
+                       if (*np && !anys(np, spcl)) {
+                               if (stat(name, &dbuf)) {
+                                       freecell(name);
+                                       continue;
+                               }
+                       }
+                       nl = addword(name, nl);
+               }
+       }
+       closedir(dirp);
+       freecell(dp);
+       freecell(gp);
+}
+
+/*
+ * generate a pathname as below.
+ * start..end1 / middle end
+ * the slashes come for free
+ */
+static char *generate(start1, end1, middle, end)
+char *start1;
+register char *end1;
+char *middle, *end;
+{
+       char *p;
+       register char *op, *xp;
+
+       p = op =
+               space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
+       for (xp = start1; xp != end1;)
+               *op++ = *xp++;
+       for (xp = middle; (*op++ = *xp++) != '\0';);
+       op--;
+       for (xp = end; (*op++ = *xp++) != '\0';);
+       return (p);
+}
+
+static int anyspcl(wb)
+register struct wdblock *wb;
+{
+       int i;
+       register char **wd;
+
+       wd = wb->w_words;
+       for (i = 0; i < wb->w_nword; i++)
+               if (anys(spcl, *wd++))
+                       return (1);
+       return (0);
+}
+
+static int xstrcmp(p1, p2)
+char *p1, *p2;
+{
+       return (strcmp(*(char **) p1, *(char **) p2));
+}
+
+/* -------- word.c -------- */
+
+#define NSTART  16                             /* default number of words to allow for initially */
+
+struct wdblock *newword(nw)
+register int nw;
+{
+       register struct wdblock *wb;
+
+       wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
+       wb->w_bsize = nw;
+       wb->w_nword = 0;
+       return (wb);
+}
+
+struct wdblock *addword(wd, wb)
+char *wd;
+register struct wdblock *wb;
+{
+       register struct wdblock *wb2;
+       int nw;
+
+       if (wb == NULL)
+               wb = newword(NSTART);
+       if ((nw = wb->w_nword) >= wb->w_bsize) {
+               wb2 = newword(nw * 2);
+               memcpy(wb2->w_words, wb->w_words, nw * sizeof(char *));
+               wb2->w_nword = nw;
+               freecell(wb);
+               wb = wb2;
+       }
+       wb->w_words[wb->w_nword++] = wd;
+       return (wb);
+}
+
+char **getwords(wb)
+register struct wdblock *wb;
+{
+       register char **wd;
+       int nb;
+
+       if (wb == NULL)
+               return ((char **) NULL);
+       if (wb->w_nword == 0) {
+               freecell(wb);
+               return ((char **) NULL);
+       }
+       wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
+       memcpy(wd, wb->w_words, nb);
+       freecell(wb);                           /* perhaps should done by caller */
+       return (wd);
+}
+
+static int (*func) (char *, char *);
+static int globv;
+
+void glob0(a0, a1, a2, a3)
+char *a0;
+unsigned a1;
+int a2;
+int (*a3) (char *, char *);
+{
+       func = a3;
+       globv = a2;
+       glob1(a0, a0 + a1 * a2);
+}
+
+void glob1(base, lim)
+char *base, *lim;
+{
+       register char *i, *j;
+       int v2;
+       char *lptr, *hptr;
+       int c;
+       unsigned n;
+
+
+       v2 = globv;
+
+  top:
+       if ((n = (int) (lim - base)) <= v2)
+               return;
+       n = v2 * (n / (2 * v2));
+       hptr = lptr = base + n;
+       i = base;
+       j = lim - v2;
+       for (;;) {
+               if (i < lptr) {
+                       if ((c = (*func) (i, lptr)) == 0) {
+                               glob2(i, lptr -= v2);
+                               continue;
+                       }
+                       if (c < 0) {
+                               i += v2;
+                               continue;
+                       }
+               }
+
+         begin:
+               if (j > hptr) {
+                       if ((c = (*func) (hptr, j)) == 0) {
+                               glob2(hptr += v2, j);
+                               goto begin;
+                       }
+                       if (c > 0) {
+                               if (i == lptr) {
+                                       glob3(i, hptr += v2, j);
+                                       i = lptr += v2;
+                                       goto begin;
+                               }
+                               glob2(i, j);
+                               j -= v2;
+                               i += v2;
+                               continue;
+                       }
+                       j -= v2;
+                       goto begin;
+               }
+
+
+               if (i == lptr) {
+                       if (lptr - base >= lim - hptr) {
+                               glob1(hptr + v2, lim);
+                               lim = lptr;
+                       } else {
+                               glob1(base, lptr);
+                               base = hptr + v2;
+                       }
+                       goto top;
+               }
+
+
+               glob3(j, lptr -= v2, i);
+               j = hptr -= v2;
+       }
+}
+
+void glob2(i, j)
+char *i, *j;
+{
+       register char *index1, *index2, c;
+       int m;
+
+       m = globv;
+       index1 = i;
+       index2 = j;
+       do {
+               c = *index1;
+               *index1++ = *index2;
+               *index2++ = c;
+       } while (--m);
+}
+
+void glob3(i, j, k)
+char *i, *j, *k;
+{
+       register char *index1, *index2, *index3;
+       int c;
+       int m;
+
+       m = globv;
+       index1 = i;
+       index2 = j;
+       index3 = k;
+       do {
+               c = *index1;
+               *index1++ = *index3;
+               *index3++ = *index2;
+               *index2++ = c;
+       } while (--m);
+}
+
+/* -------- io.c -------- */
+
+/*
+ * shell IO
+ */
+
+static struct iobuf sharedbuf = { AFID_NOBUF };
+static struct iobuf mainbuf = { AFID_NOBUF };
+static unsigned bufid = AFID_ID;       /* buffer id counter */
+
+
+static void readhere(char **name, char *s, int ec);
+static void pushio(struct ioarg *argp, int (*fn) ());
+static int xxchar(struct ioarg *ap);
+static void tempname(char *tname);
+
+int getqc(ec)
+register int ec;
+{
+       register int c;
+
+       if (e.linep > elinep) {
+               while ((c = readc()) != '\n' && c);
+               err("input line too long");
+               gflg++;
+               return (c);
+       }
+       c = readc();
+       if (ec != '\'' && e.iop->task != XGRAVE) {
+               if (c == '\\') {
+                       c = readc();
+                       if (c == '\n' && ec != '\"')
+                               return (getqc(ec));
+                       c |= QUOTE;
+               }
+       }
+       return (c);
+}
+
+void unget(c)
+int c;
+{
+       if (e.iop >= e.iobase)
+               e.iop->peekc = c;
+}
+
+int eofc()
+{
+       return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
+}
+
+int readc()
+{
+       int c;
+
+       for (; e.iop >= e.iobase; e.iop--)
+               if ((c = e.iop->peekc) != '\0') {
+                       e.iop->peekc = 0;
+                       return (c);
+               } else {
+                       if (e.iop->prev != 0) {
+                               if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
+                                       if (c == -1) {
+                                               e.iop++;
+                                               continue;
+                                       }
+                                       if (e.iop == iostack)
+                                               ioecho(c);
+                                       return (e.iop->prev = c);
+                               } else if (e.iop->task == XIO && e.iop->prev != '\n') {
+                                       e.iop->prev = 0;
+                                       if (e.iop == iostack)
+                                               ioecho('\n');
+                                       return '\n';
+                               }
+                       }
+                       if (e.iop->task == XIO) {
+                               if (multiline)
+                                       return e.iop->prev = 0;
+                               if (interactive && e.iop == iostack + 1)
+#ifdef BB_FEATURE_COMMAND_EDITING
+                                       current_prompt = prompt->value;
+#else
+                                       prs(prompt->value);
+#endif
+                       }
+               }
+       if (e.iop >= iostack)
+               return (0);
+       leave();
+       /* NOTREACHED */
+}
+
+void ioecho(c)
+char c;
+{
+       if (flag['v'])
+               write(2, &c, sizeof c);
+}
+
+void pushio(argp, fn)
+struct ioarg *argp;
+int (*fn) ();
+{
+       if (++e.iop >= &iostack[NPUSH]) {
+               e.iop--;
+               err("Shell input nested too deeply");
+               gflg++;
+               return;
+       }
+       e.iop->iofn = fn;
+
+       if (argp->afid != AFID_NOBUF)
+               e.iop->argp = argp;
+       else {
+               e.iop->argp = ioargstack + (e.iop - iostack);
+               *e.iop->argp = *argp;
+               e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
+               if (isatty(e.iop->argp->afile) == 0 &&
+                       (e.iop == &iostack[0] ||
+                        lseek(e.iop->argp->afile, 0L, 1) != -1)) {
+                       if (++bufid == AFID_NOBUF)
+                               bufid = AFID_ID;
+                       e.iop->argp->afid = bufid;
+               }
+       }
+
+       e.iop->prev = ~'\n';
+       e.iop->peekc = 0;
+       e.iop->xchar = 0;
+       e.iop->nlcount = 0;
+       if (fn == filechar || fn == linechar)
+               e.iop->task = XIO;
+       else if (fn == gravechar || fn == qgravechar)
+               e.iop->task = XGRAVE;
+       else
+               e.iop->task = XOTHER;
+}
+
+struct io *setbase(ip)
+struct io *ip;
+{
+       register struct io *xp;
+
+       xp = e.iobase;
+       e.iobase = ip;
+       return (xp);
+}
+
+/*
+ * Input generating functions
+ */
+
+/*
+ * Produce the characters of a string, then a newline, then EOF.
+ */
+int nlchar(ap)
+register struct ioarg *ap;
+{
+       register int c;
+
+       if (ap->aword == NULL)
+               return (0);
+       if ((c = *ap->aword++) == 0) {
+               ap->aword = NULL;
+               return ('\n');
+       }
+       return (c);
+}
+
+/*
+ * Given a list of words, produce the characters
+ * in them, with a space after each word.
+ */
+int wdchar(ap)
+register struct ioarg *ap;
+{
+       register char c;
+       register char **wl;
+
+       if ((wl = ap->awordlist) == NULL)
+               return (0);
+       if (*wl != NULL) {
+               if ((c = *(*wl)++) != 0)
+                       return (c & 0177);
+               ap->awordlist++;
+               return (' ');
+       }
+       ap->awordlist = NULL;
+       return ('\n');
+}
+
+/*
+ * Return the characters of a list of words,
+ * producing a space between them.
+ */
+int dolchar(ap)
+register struct ioarg *ap;
+{
+       register char *wp;
+
+       if ((wp = *ap->awordlist++) != NULL) {
+               PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
+               return (-1);
+       }
+       return (0);
+}
+
+static int xxchar(ap)
+register struct ioarg *ap;
+{
+       register int c;
+
+       if (ap->aword == NULL)
+               return (0);
+       if ((c = *ap->aword++) == '\0') {
+               ap->aword = NULL;
+               return (' ');
+       }
+       return (c);
+}
+
+/*
+ * Produce the characters from a single word (string).
+ */
+int strchar(ap)
+register struct ioarg *ap;
+{
+       register int c;
+
+       if (ap->aword == NULL || (c = *ap->aword++) == 0)
+               return (0);
+       return (c);
+}
+
+/*
+ * Produce quoted characters from a single word (string).
+ */
+int qstrchar(ap)
+register struct ioarg *ap;
+{
+       register int c;
+
+       if (ap->aword == NULL || (c = *ap->aword++) == 0)
+               return (0);
+       return (c | QUOTE);
+}
+
+/*
+ * Return the characters from a file.
+ */
+int filechar(ap)
+register struct ioarg *ap;
+{
+       register int i;
+       char c;
+       struct iobuf *bp = ap->afbuf;
+
+       if (ap->afid != AFID_NOBUF) {
+               if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
+                       if (i)
+                               lseek(ap->afile, ap->afpos, 0);
+                       i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
+                       if (i <= 0) {
+                               closef(ap->afile);
+                               return 0;
+                       }
+                       bp->id = ap->afid;
+                       bp->ebufp = (bp->bufp = bp->buf) + i;
+               }
+               ap->afpos++;
+               return *bp->bufp++ & 0177;
+       }
+#ifdef BB_FEATURE_COMMAND_EDITING
+       if (interactive && ap->afile == 0) {
+               static char mycommand[BUFSIZ];
+               static int position = 0, size = 0;
+
+               while (size == 0 || position >= size) {
+                       size = cmdedit_read_input(current_prompt, mycommand);
+                       position = 0;
+               }
+               c = mycommand[position];
+               position++;
+               return (c);
+       } else
+#endif
+       {
+               i = safe_read(ap->afile, &c, sizeof(c));
+               return (i == sizeof(c) ? c & 0177 : (closef(ap->afile), 0));
+       }
+}
+
+/*
+ * Return the characters from a here temp file.
+ */
+int herechar(ap)
+register struct ioarg *ap;
+{
+       char c;
+
+
+       if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
+               close(ap->afile);
+               c = 0;
+       }
+       return (c);
+
+}
+
+/*
+ * Return the characters produced by a process (`...`).
+ * Quote them if required, and remove any trailing newline characters.
+ */
+int gravechar(ap, iop)
+struct ioarg *ap;
+struct io *iop;
+{
+       register int c;
+
+       if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
+               c = ' ';
+       return (c);
+}
+
+int qgravechar(ap, iop)
+register struct ioarg *ap;
+struct io *iop;
+{
+       register int c;
+
+       if (iop->xchar) {
+               if (iop->nlcount) {
+                       iop->nlcount--;
+                       return ('\n' | QUOTE);
+               }
+               c = iop->xchar;
+               iop->xchar = 0;
+       } else if ((c = filechar(ap)) == '\n') {
+               iop->nlcount = 1;
+               while ((c = filechar(ap)) == '\n')
+                       iop->nlcount++;
+               iop->xchar = c;
+               if (c == 0)
+                       return (c);
+               iop->nlcount--;
+               c = '\n';
+       }
+       return (c != 0 ? c | QUOTE : 0);
+}
+
+/*
+ * Return a single command (usually the first line) from a file.
+ */
+int linechar(ap)
+register struct ioarg *ap;
+{
+       register int c;
+
+       if ((c = filechar(ap)) == '\n') {
+               if (!multiline) {
+                       closef(ap->afile);
+                       ap->afile = -1;         /* illegal value */
+               }
+       }
+       return (c);
+}
+
+void prs(s)
+register char *s;
+{
+       fputs(s, stderr);
+}
+
+void put1c(c)
+char c;
+{
+       putc(c, stderr);
+}
+
+void prn(u)
+unsigned u;
+{
+       prs(itoa(u, 0));
+}
+
+void closef(i)
+register int i;
+{
+       if (i > 2)
+               close(i);
+}
+
+void closeall()
+{
+       int u;
+
+       for (u = NUFILE; u < NOFILE;)
+               close(u++);
+}
+
+/*
+ * remap fd into Shell's fd space
+ */
+int remap(fd)
+register int fd;
+{
+       register int i;
+       int map[NOFILE];
+
+       if (fd < e.iofd) {
+               for (i = 0; i < NOFILE; i++)
+                       map[i] = 0;
+               do {
+                       map[fd] = 1;
+                       fd = dup(fd);
+               } while (fd >= 0 && fd < e.iofd);
+               for (i = 0; i < NOFILE; i++)
+                       if (map[i])
+                               close(i);
+               if (fd < 0)
+                       err("too many files open in shell");
+       }
+       return (fd);
+}
+
+int openpipe(pv)
+register int *pv;
+{
+       register int i;
+
+       if ((i = pipe(pv)) < 0)
+               err("can't create pipe - try again");
+       return (i);
+}
+
+void closepipe(pv)
+register int *pv;
+{
+       if (pv != NULL) {
+               close(*pv++);
+               close(*pv);
+       }
+}
+
+/* -------- here.c -------- */
+
+/*
+ * here documents
+ */
+
+void markhere(s, iop)
+register char *s;
+struct ioword *iop;
+{
+       register struct here *h, *lh;
+
+       h = (struct here *) space(sizeof(struct here));
+       if (h == 0)
+               return;
+       h->h_tag = evalstr(s, DOSUB);
+       if (h->h_tag == 0)
+               return;
+       h->h_iop = iop;
+       iop->io_name = 0;
+       h->h_next = NULL;
+       if (inhere == 0)
+               inhere = h;
+       else
+               for (lh = inhere; lh != NULL; lh = lh->h_next)
+                       if (lh->h_next == 0) {
+                               lh->h_next = h;
+                               break;
+                       }
+       iop->io_flag |= IOHERE | IOXHERE;
+       for (s = h->h_tag; *s; s++)
+               if (*s & QUOTE) {
+                       iop->io_flag &= ~IOXHERE;
+                       *s &= ~QUOTE;
+               }
+       h->h_dosub = iop->io_flag & IOXHERE;
+}
+
+void gethere()
+{
+       register struct here *h, *hp;
+
+       /* Scan here files first leaving inhere list in place */
+       for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
+               readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
+
+       /* Make inhere list active - keep list intact for scraphere */
+       if (hp != NULL) {
+               hp->h_next = acthere;
+               acthere = inhere;
+               inhere = NULL;
+       }
+}
+
+static void readhere(name, s, ec)
+char **name;
+register char *s;
+int ec;
+{
+       int tf;
+       char tname[30];
+       int c;
+       jmp_buf ev;
+       char read_line[LINELIM + 1];
+       char *next_read_line;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &tf;
+#endif
+
+       tempname(tname);
+       *name = strsave(tname, areanum);
+       tf = creat(tname, 0600);
+       if (tf < 0)
+               return;
+       if (newenv(setjmp(errpt = ev)) != 0)
+               unlink(tname);
+       else {
+               pushio(e.iop->argp, e.iop->iofn);
+               e.iobase = e.iop;
+               for (;;) {
+                       if (interactive && e.iop <= iostack)
+#ifdef BB_FEATURE_COMMAND_EDITING
+                               current_prompt = cprompt->value;
+#else
+                               prs(cprompt->value);
+#endif
+                       next_read_line = read_line;
+                       while ((c = readc()) != '\n' && c) {
+                               if (next_read_line >= &read_line[LINELIM]) {
+                                       c = 0;
+                                       break;
+                               }
+                               *next_read_line++ = c;
+                       }
+                       *next_read_line = 0;
+                       if (strcmp(s, read_line) == 0 || c == 0)
+                               break;
+                       *next_read_line++ = '\n';
+                       write(tf, read_line, (int) (next_read_line - read_line));
+               }
+               if (c == 0) {
+                       prs("here document `");
+                       prs(s);
+                       err("' unclosed");
+               }
+               quitenv();
+       }
+       close(tf);
+}
+
+/*
+ * open here temp file.
+ * if unquoted here, expand here temp file into second temp file.
+ */
+int herein(hname, xdoll)
+char *hname;
+int xdoll;
+{
+       int hf, tf;
+
+#if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &tf;
+#endif
+
+       if (hname == 0)
+               return (-1);
+       hf = open(hname, 0);
+       if (hf < 0)
+               return (-1);
+       if (xdoll) {
+               char c;
+               char tname[30];
+               jmp_buf ev;
+
+               tempname(tname);
+               if ((tf = creat(tname, 0600)) < 0)
+                       return (-1);
+               if (newenv(setjmp(errpt = ev)) == 0) {
+                       PUSHIO(afile, hf, herechar);
+                       setbase(e.iop);
+                       while ((c = subgetc(0, 0)) != 0) {
+                               char c1 = c & ~QUOTE;
+
+                               if (c & QUOTE && !any(c1, "`$\\"))
+                                       write(tf, "\\", 1);
+                               write(tf, &c1, 1);
+                       }
+                       quitenv();
+               } else
+                       unlink(tname);
+               close(tf);
+               tf = open(tname, 0);
+               unlink(tname);
+               return (tf);
+       } else
+               return (hf);
+}
+
+void scraphere()
+{
+       register struct here *h;
+
+       for (h = inhere; h != NULL; h = h->h_next) {
+               if (h->h_iop && h->h_iop->io_name)
+                       unlink(h->h_iop->io_name);
+       }
+       inhere = NULL;
+}
+
+/* unlink here temp files before a freearea(area) */
+void freehere(area)
+int area;
+{
+       register struct here *h, *hl;
+
+       hl = NULL;
+       for (h = acthere; h != NULL; h = h->h_next)
+               if (getarea((char *) h) >= area) {
+                       if (h->h_iop->io_name != NULL)
+                               unlink(h->h_iop->io_name);
+                       if (hl == NULL)
+                               acthere = h->h_next;
+                       else
+                               hl->h_next = h->h_next;
+               } else
+                       hl = h;
+}
+
+void tempname(tname)
+char *tname;
+{
+       static int inc;
+       register char *cp, *lp;
+
+       for (cp = tname, lp = "/tmp/shtm"; (*cp = *lp++) != '\0'; cp++);
+       lp = putn(getpid() * 1000 + inc++);
+       for (; (*cp = *lp++) != '\0'; cp++);
+}
+
+/*
+ * Copyright (c) 1987,1997, Prentice Hall
+ * All rights reserved.
+ *
+ * Redistribution and use of the MINIX operating system in source and
+ * binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Prentice Hall nor the names of the software
+ * authors or contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/mt.c b/mt.c
new file mode 100644 (file)
index 0000000..49dc70a
--- /dev/null
+++ b/mt.c
@@ -0,0 +1,121 @@
+/* vi: set sw=4 ts=4: */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mtio.h>
+#include <sys/fcntl.h>
+#include "busybox.h"
+
+struct mt_opcodes {
+       char *name;
+       short value;
+};
+
+/* missing: eod/seod, stoptions, stwrthreshold, densities */
+static const struct mt_opcodes opcodes[] = {
+       {"bsf", MTBSF},
+       {"bsfm", MTBSFM},
+       {"bsr", MTBSR},
+       {"bss", MTBSS},
+       {"datacompression", MTCOMPRESSION},
+       {"eom", MTEOM},
+       {"erase", MTERASE},
+       {"fsf", MTFSF},
+       {"fsfm", MTFSFM},
+       {"fsr", MTFSR},
+       {"fss", MTFSS},
+       {"load", MTLOAD},
+       {"lock", MTLOCK},
+       {"mkpart", MTMKPART},
+       {"nop", MTNOP},
+       {"offline", MTOFFL},
+       {"rewoffline", MTOFFL},
+       {"ras1", MTRAS1},
+       {"ras2", MTRAS2},
+       {"ras3", MTRAS3},
+       {"reset", MTRESET},
+       {"retension", MTRETEN},
+       {"rewind", MTREW},
+       {"seek", MTSEEK},
+       {"setblk", MTSETBLK},
+       {"setdensity", MTSETDENSITY},
+       {"drvbuffer", MTSETDRVBUFFER},
+       {"setpart", MTSETPART},
+       {"tell", MTTELL},
+       {"wset", MTWSM},
+       {"unload", MTUNLOAD},
+       {"unlock", MTUNLOCK},
+       {"eof", MTWEOF},
+       {"weof", MTWEOF},
+       {0, 0}
+};
+
+extern int mt_main(int argc, char **argv)
+{
+       const char *file = "/dev/tape";
+       const struct mt_opcodes *code = opcodes;
+       struct mtop op;
+       struct mtpos position;
+       int fd, mode;
+       
+       if (argc < 2) {
+               show_usage();
+       }
+
+       if (strcmp(argv[1], "-f") == 0) {
+               if (argc < 4) {
+                       show_usage();
+               }
+               file = argv[2];
+               argv += 2;
+               argc -= 2;
+       }
+
+       while (code->name != 0) {
+               if (strcmp(code->name, argv[1]) == 0)
+                       break;
+               code++;
+       }
+
+       if (code->name == 0) {
+               error_msg("unrecognized opcode %s.", argv[1]);
+               return EXIT_FAILURE;
+       }
+
+       op.mt_op = code->value;
+       if (argc >= 3)
+               op.mt_count = atoi(argv[2]);
+       else
+               op.mt_count = 1;                /* One, not zero, right? */
+
+       switch (code->value) {
+               case MTWEOF:
+               case MTERASE:
+               case MTWSM:
+               case MTSETDRVBUFFER:
+                       mode = O_WRONLY;
+                       break;
+
+               default:
+                       mode = O_RDONLY;
+                       break;
+       }
+
+       if ((fd = open(file, mode, 0)) < 0)
+               perror_msg_and_die("%s", file);
+
+       switch (code->value) {
+               case MTTELL:
+                       if (ioctl(fd, MTIOCPOS, &position) < 0)
+                               perror_msg_and_die("%s", file);
+                       printf ("At block %d.\n", (int) position.mt_blkno);
+                       break;
+
+               default:
+                       if (ioctl(fd, MTIOCTOP, &op) != 0)
+                               perror_msg_and_die("%s", file);
+                       break;
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/mv.c b/mv.c
new file mode 100644 (file)
index 0000000..b890abf
--- /dev/null
+++ b/mv.c
@@ -0,0 +1,168 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mv implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+static int flags;
+
+static int manual_rename(const char *source, const char *dest)
+{
+       struct stat source_stat;
+       struct stat dest_stat;
+       int source_exists = 1;
+       int dest_exists = 1;
+
+       if (stat(source, &source_stat) < 0) {
+               if (errno != ENOENT) {
+                       perror_msg("unable to stat `%s'", source);
+                       return -1;
+               }
+               source_exists = 0;
+       }
+
+       if (stat(dest, &dest_stat) < 0) {
+               if (errno != ENOENT) {
+                       perror_msg("unable to stat `%s'", dest);
+                       return -1;
+               }
+               dest_exists = 0;
+       }
+
+       if (dest_exists) {
+               if (S_ISDIR(dest_stat.st_mode) &&
+                         (!source_exists || !S_ISDIR(source_stat.st_mode))) {
+                       error_msg("cannot overwrite directory with non-directory");
+                       return -1;
+               }
+
+               if (!S_ISDIR(dest_stat.st_mode) && source_exists &&
+                               S_ISDIR(source_stat.st_mode)) {
+                       error_msg("cannot overwrite non-directory with directory");
+                       return -1;
+               }
+
+               if (unlink(dest) < 0) {
+                       perror_msg("cannot remove `%s'", dest);
+                       return -1;
+               }
+       }
+
+       if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS |
+                       FILEUTILS_PRESERVE_SYMLINKS) < 0)
+               return -1;
+
+       if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int move_file(const char *source, const char *dest)
+{
+       struct stat dest_stat;
+       int dest_exists = 1;
+
+       if (stat(dest, &dest_stat) < 0) {
+               if (errno != ENOENT) {
+                       perror_msg("unable to stat `%s'", dest);
+                       return -1;
+               }
+               dest_exists = 0;
+       }
+
+       if (dest_exists && !(flags & FILEUTILS_FORCE) &&
+                       ((access(dest, W_OK) < 0 && isatty(0)) ||
+                        (flags & FILEUTILS_INTERACTIVE))) {
+               fprintf(stderr, "mv: overwrite `%s'? ", dest);
+               if (!ask_confirmation())
+                       return 0;
+       }
+
+       if (rename(source, dest) < 0) {
+               if (errno == EXDEV)
+                       return manual_rename(source, dest);
+
+               perror_msg("unable to rename `%s'", source);
+               return -1;
+       }
+       
+       return 0;
+}
+
+extern int mv_main(int argc, char **argv)
+{
+       int status = 0;
+       int opt;
+       int i;
+
+       while ((opt = getopt(argc, argv, "fi")) != -1)
+               switch (opt) {
+               case 'f':
+                       flags &= ~FILEUTILS_INTERACTIVE;
+                       flags |= FILEUTILS_FORCE;
+                       break;
+               case 'i':
+                       flags &= ~FILEUTILS_FORCE;
+                       flags |= FILEUTILS_INTERACTIVE;
+                       break;
+               default:
+                       show_usage();
+               }
+
+       if (optind + 2 > argc)
+               show_usage();
+
+       if (optind + 2 == argc) {
+               struct stat dest_stat;
+               int dest_exists = 1;
+
+               if (stat(argv[optind + 1], &dest_stat) < 0) {
+                       if (errno != ENOENT)
+                               perror_msg_and_die("unable to stat `%s'", argv[optind + 1]);
+                       dest_exists = 0;
+               }
+
+               if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) {
+                       if (move_file(argv[optind], argv[optind + 1]) < 0)
+                               status = 1;
+                       return status;
+               }
+       }
+
+       for (i = optind; i < argc - 1; i++) {
+               char *dest = concat_path_file(argv[argc - 1],
+                               get_last_path_component(argv[i]));
+               if (move_file(argv[i], dest) < 0)
+                       status = 1;
+               free(dest);
+       }
+
+       return status;
+}
diff --git a/nc.c b/nc.c
new file mode 100644 (file)
index 0000000..87e67e4
--- /dev/null
+++ b/nc.c
@@ -0,0 +1,171 @@
+/* vi: set sw=4 ts=4: */
+/*  nc: mini-netcat - built from the ground up for LRP
+    Copyright (C) 1998  Charles P. Wright
+
+    0.0.1   6K      It works.
+    0.0.2   5K      Smaller and you can also check the exit condition if you wish.
+    0.0.3          Uses select()       
+
+    19980918 Busy Boxed! Dave Cinege
+    19990512 Uses Select. Charles P. Wright
+    19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+#define GAPING_SECURITY_HOLE
+
+int nc_main(int argc, char **argv)
+{
+       int do_listen = 0, lport = 0, tmpfd, opt, sfd, x;
+       char buf[BUFSIZ];
+#ifdef GAPING_SECURITY_HOLE
+       char * pr00gie = NULL;                  
+#endif
+
+       struct sockaddr_in address;
+       struct hostent *hostinfo;
+
+       fd_set readfds, testfds;
+
+       while ((opt = getopt(argc, argv, "lp:")) > 0) {
+               switch (opt) {
+                       case 'l':
+                               do_listen++;
+                               break;
+                       case 'p':
+                               lport = atoi(optarg);
+                               break;
+#ifdef GAPING_SECURITY_HOLE
+                       case 'e':
+                               pr00gie = optarg;
+                               break;
+#endif
+                       default:
+                               show_usage();
+               }
+       }
+
+#ifdef GAPING_SECURITY_HOLE
+       if (pr00gie) {
+               /* won't need stdin */
+               close (fileno(stdin));                          
+       }
+#endif /* GAPING_SECURITY_HOLE */
+
+
+       if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
+               show_usage();
+
+       if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+               perror_msg_and_die("socket");
+       x = 1;
+       if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
+               perror_msg_and_die ("reuseaddr failed");
+       address.sin_family = AF_INET;
+
+       if (lport != 0) {
+               memset(&address.sin_addr, 0, sizeof(address.sin_addr));
+               address.sin_port = htons(lport);
+
+               if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
+                       perror_msg_and_die("bind");
+       }
+
+       if (do_listen) {
+               socklen_t addrlen = sizeof(address);
+
+               if (listen(sfd, 1) < 0)
+                       perror_msg_and_die("listen");
+
+               if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
+                       perror_msg_and_die("accept");
+
+               close(sfd);
+               sfd = tmpfd;
+       } else {
+               hostinfo = xgethostbyname(argv[optind]);
+
+               address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
+               address.sin_port = htons(atoi(argv[optind+1]));
+
+               if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
+                       perror_msg_and_die("connect");
+       }
+
+#ifdef GAPING_SECURITY_HOLE
+       /* -e given? */
+       if (pr00gie) {
+               dup2(sfd, 0);
+               close(sfd);
+               dup2 (0, 1);
+               dup2 (0, 2);
+               execl (pr00gie, pr00gie, NULL);
+               /* Don't print stuff or it will go over the wire.... */
+               _exit(-1);
+       }
+#endif /* GAPING_SECURITY_HOLE */
+
+
+       FD_ZERO(&readfds);
+       FD_SET(sfd, &readfds);
+       FD_SET(STDIN_FILENO, &readfds);
+
+       while (1) {
+               int fd;
+               int ofd;
+               int nread;
+
+               testfds = readfds;
+
+               if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
+                       perror_msg_and_die("select");
+
+               for (fd = 0; fd < FD_SETSIZE; fd++) {
+                       if (FD_ISSET(fd, &testfds)) {
+                               if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
+                                       perror_msg_and_die("read");
+
+                               if (fd == sfd) {
+                                       if (nread == 0)
+                                               exit(0);
+                                       ofd = STDOUT_FILENO;
+                               } else {
+                                       if (nread == 0)
+                                               shutdown(sfd, 1);
+                                       ofd = sfd;
+                               }
+
+                               if (full_write(ofd, buf, nread) < 0)
+                                       perror_msg_and_die("write");
+                       }
+               }
+       }
+}
diff --git a/nfsmount.c b/nfsmount.c
new file mode 100644 (file)
index 0000000..cd722ac
--- /dev/null
@@ -0,0 +1,977 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * nfsmount.c -- Linux NFS mount
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ *
+ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
+ * Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ * 
+ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
+ * plus NFSv3 stuff.
+ */
+
+/*
+ * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include "busybox.h"
+#undef TRUE
+#undef FALSE
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <linux/nfs.h>  /* For the kernels nfs stuff */
+#include "nfsmount.h"
+
+#ifndef NFS_FHSIZE
+static const int NFS_FHSIZE = 32;
+#endif
+#ifndef NFS_PORT
+static const int NFS_PORT = 2049;
+#endif
+
+/* Disable the nls stuff */
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)
+
+static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
+static const int MS_RDONLY = 1;      /* Mount read-only */
+static const int MS_NOSUID = 2;      /* Ignore suid and sgid bits */
+static const int MS_NODEV = 4;      /* Disallow access to device special files */
+static const int MS_NOEXEC = 8;      /* Disallow program execution */
+static const int MS_SYNCHRONOUS = 16;      /* Writes are synced at once */
+static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS */
+static const int MS_MANDLOCK = 64;      /* Allow mandatory locks on an FS */
+static const int S_QUOTA = 128;     /* Quota initialized for file/directory/symlink */
+static const int S_APPEND = 256;     /* Append-only file */
+static const int S_IMMUTABLE = 512;     /* Immutable file */
+static const int MS_NOATIME = 1024;    /* Do not update access times. */
+static const int MS_NODIRATIME = 2048;    /* Do not update directory access times */
+
+
+/*
+ * We want to be able to compile mount on old kernels in such a way
+ * that the binary will work well on more recent kernels.
+ * Thus, if necessary we teach nfsmount.c the structure of new fields
+ * that will come later.
+ *
+ * Moreover, the new kernel includes conflict with glibc includes
+ * so it is easiest to ignore the kernel altogether (at compile time).
+ */
+
+/* NOTE: Do not make this into a 'static const int' because the pre-processor
+ * needs to test this value in some #if statements. */
+#define NFS_MOUNT_VERSION 4
+
+struct nfs2_fh {
+        char                    data[32];
+};
+struct nfs3_fh {
+        unsigned short          size;
+        unsigned char           data[64];
+};
+
+struct nfs_mount_data {
+       int             version;                /* 1 */
+       int             fd;                     /* 1 */
+       struct nfs2_fh  old_root;               /* 1 */
+       int             flags;                  /* 1 */
+       int             rsize;                  /* 1 */
+       int             wsize;                  /* 1 */
+       int             timeo;                  /* 1 */
+       int             retrans;                /* 1 */
+       int             acregmin;               /* 1 */
+       int             acregmax;               /* 1 */
+       int             acdirmin;               /* 1 */
+       int             acdirmax;               /* 1 */
+       struct sockaddr_in addr;                /* 1 */
+       char            hostname[256];          /* 1 */
+       int             namlen;                 /* 2 */
+       unsigned int    bsize;                  /* 3 */
+       struct nfs3_fh  root;                   /* 4 */
+};
+
+/* bits in the flags field */
+
+static const int NFS_MOUNT_SOFT = 0x0001;      /* 1 */
+static const int NFS_MOUNT_INTR = 0x0002;      /* 1 */
+static const int NFS_MOUNT_SECURE = 0x0004;    /* 1 */
+static const int NFS_MOUNT_POSIX = 0x0008;     /* 1 */
+static const int NFS_MOUNT_NOCTO = 0x0010;     /* 1 */
+static const int NFS_MOUNT_NOAC = 0x0020;      /* 1 */
+static const int NFS_MOUNT_TCP = 0x0040;       /* 2 */
+static const int NFS_MOUNT_VER3 = 0x0080;      /* 3 */
+static const int NFS_MOUNT_KERBEROS = 0x0100;  /* 3 */
+static const int NFS_MOUNT_NONLM = 0x0200;     /* 3 */
+
+
+#define UTIL_LINUX_VERSION "2.10m"
+#define util_linux_version "util-linux-2.10m"
+
+#define HAVE_inet_aton
+#define HAVE_scsi_h
+#define HAVE_blkpg_h
+#define HAVE_kd_h
+#define HAVE_termcap
+#define HAVE_locale_h
+#define HAVE_libintl_h
+#define ENABLE_NLS
+#define HAVE_langinfo_h
+#define HAVE_progname
+#define HAVE_openpty
+#define HAVE_nanosleep
+#define HAVE_personality
+#define HAVE_tm_gmtoff
+
+static char *nfs_strerror(int status);
+
+#define MAKE_VERSION(p,q,r)    (65536*(p) + 256*(q) + (r))
+#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
+
+static const int EX_FAIL = 32;       /* mount failure */
+static const int EX_BG = 256;       /* retry in background (internal only) */
+
+
+/*
+ * nfs_mount_version according to the sources seen at compile time.
+ */
+static int nfs_mount_version;
+
+/*
+ * Unfortunately, the kernel prints annoying console messages
+ * in case of an unexpected nfs mount version (instead of
+ * just returning some error).  Therefore we'll have to try
+ * and figure out what version the kernel expects.
+ *
+ * Variables:
+ *     KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
+ *     NFS_MOUNT_VERSION: these nfsmount sources at compile time
+ *     nfs_mount_version: version this source and running kernel can handle
+ */
+static void
+find_kernel_nfs_mount_version(void)
+{
+       static int kernel_version = 0;
+
+       if (kernel_version)
+               return;
+
+       nfs_mount_version = NFS_MOUNT_VERSION; /* default */
+
+       kernel_version = get_kernel_revision();
+       if (kernel_version) {
+               if (kernel_version < MAKE_VERSION(2,1,32))
+                       nfs_mount_version = 1;
+               else if (kernel_version < MAKE_VERSION(2,2,18) ||
+                               (kernel_version >=   MAKE_VERSION(2,3,0) &&
+                                kernel_version < MAKE_VERSION(2,3,99)))
+                       nfs_mount_version = 3;
+               else
+                       nfs_mount_version = 4; /* since 2.3.99pre4 */
+       }
+       if (nfs_mount_version > NFS_MOUNT_VERSION)
+               nfs_mount_version = NFS_MOUNT_VERSION;
+}
+
+static struct pmap *
+get_mountport(struct sockaddr_in *server_addr,
+      long unsigned prog,
+      long unsigned version,
+      long unsigned proto,
+      long unsigned port)
+{
+struct pmaplist *pmap;
+static struct pmap p = {0, 0, 0, 0};
+
+server_addr->sin_port = PMAPPORT;
+pmap = pmap_getmaps(server_addr);
+
+if (version > MAX_NFSPROT)
+       version = MAX_NFSPROT;
+if (!prog)
+       prog = MOUNTPROG;
+p.pm_prog = prog;
+p.pm_vers = version;
+p.pm_prot = proto;
+p.pm_port = port;
+
+while (pmap) {
+       if (pmap->pml_map.pm_prog != prog)
+               goto next;
+       if (!version && p.pm_vers > pmap->pml_map.pm_vers)
+               goto next;
+       if (version > 2 && pmap->pml_map.pm_vers != version)
+               goto next;
+       if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
+               goto next;
+       if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
+           (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
+           (port && pmap->pml_map.pm_port != port))
+               goto next;
+       memcpy(&p, &pmap->pml_map, sizeof(p));
+next:
+       pmap = pmap->pml_next;
+}
+if (!p.pm_vers)
+       p.pm_vers = MOUNTVERS;
+if (!p.pm_port)
+       p.pm_port = MOUNTPORT;
+if (!p.pm_prot)
+       p.pm_prot = IPPROTO_TCP;
+return &p;
+}
+
+int nfsmount(const char *spec, const char *node, int *flags,
+            char **extra_opts, char **mount_opts, int running_bg)
+{
+       static char *prev_bg_host;
+       char hostdir[1024];
+       CLIENT *mclient;
+       char *hostname;
+       char *pathname;
+       char *old_opts;
+       char *mounthost=NULL;
+       char new_opts[1024];
+       struct timeval total_timeout;
+       enum clnt_stat clnt_stat;
+       static struct nfs_mount_data data;
+       char *opt, *opteq;
+       int val;
+       struct hostent *hp;
+       struct sockaddr_in server_addr;
+       struct sockaddr_in mount_server_addr;
+       struct pmap* pm_mnt;
+       int msock, fsock;
+       struct timeval retry_timeout;
+       union {
+               struct fhstatus nfsv2;
+               struct mountres3 nfsv3;
+       } status;
+       struct stat statbuf;
+       char *s;
+       int port;
+       int mountport;
+       int proto;
+       int bg;
+       int soft;
+       int intr;
+       int posix;
+       int nocto;
+       int noac;
+       int nolock;
+       int retry;
+       int tcp;
+       int mountprog;
+       int mountvers;
+       int nfsprog;
+       int nfsvers;
+       int retval;
+       time_t t;
+       time_t prevt;
+       time_t timeout;
+
+       find_kernel_nfs_mount_version();
+
+       retval = EX_FAIL;
+       msock = fsock = -1;
+       mclient = NULL;
+       if (strlen(spec) >= sizeof(hostdir)) {
+               error_msg("excessively long host:dir argument");
+               goto fail;
+       }
+       strcpy(hostdir, spec);
+       if ((s = strchr(hostdir, ':'))) {
+               hostname = hostdir;
+               pathname = s + 1;
+               *s = '\0';
+               /* Ignore all but first hostname in replicated mounts
+                  until they can be fully supported. (mack@sgi.com) */
+               if ((s = strchr(hostdir, ','))) {
+                       *s = '\0';
+                       error_msg("warning: multiple hostnames not supported");
+               }
+       } else {
+               error_msg("directory to mount not in host:dir format");
+               goto fail;
+       }
+
+       server_addr.sin_family = AF_INET;
+#ifdef HAVE_inet_aton
+       if (!inet_aton(hostname, &server_addr.sin_addr))
+#endif
+       {
+               if ((hp = gethostbyname(hostname)) == NULL) {
+                       herror_msg("%s", hostname);
+                       goto fail;
+               } else {
+                       if (hp->h_length > sizeof(struct in_addr)) {
+                               error_msg("got bad hp->h_length");
+                               hp->h_length = sizeof(struct in_addr);
+                       }
+                       memcpy(&server_addr.sin_addr,
+                              hp->h_addr, hp->h_length);
+               }
+       }
+
+       memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
+
+       /* add IP address to mtab options for use when unmounting */
+
+       s = inet_ntoa(server_addr.sin_addr);
+       old_opts = *extra_opts;
+       if (!old_opts)
+               old_opts = "";
+       if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
+               error_msg("excessively long option argument");
+               goto fail;
+       }
+       sprintf(new_opts, "%s%saddr=%s",
+               old_opts, *old_opts ? "," : "", s);
+       *extra_opts = xstrdup(new_opts);
+
+       /* Set default options.
+        * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
+        * let the kernel decide.
+        * timeo is filled in after we know whether it'll be TCP or UDP. */
+       memset(&data, 0, sizeof(data));
+       data.retrans    = 3;
+       data.acregmin   = 3;
+       data.acregmax   = 60;
+       data.acdirmin   = 30;
+       data.acdirmax   = 60;
+#if NFS_MOUNT_VERSION >= 2
+       data.namlen     = NAME_MAX;
+#endif
+
+       bg = 0;
+       soft = 0;
+       intr = 0;
+       posix = 0;
+       nocto = 0;
+       nolock = 0;
+       noac = 0;
+       retry = 10000;          /* 10000 minutes ~ 1 week */
+       tcp = 0;
+
+       mountprog = MOUNTPROG;
+       mountvers = 0;
+       port = 0;
+       mountport = 0;
+       nfsprog = NFS_PROGRAM;
+       nfsvers = 0;
+
+       /* parse options */
+
+       for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+               if ((opteq = strchr(opt, '='))) {
+                       val = atoi(opteq + 1);  
+                       *opteq = '\0';
+                       if (!strcmp(opt, "rsize"))
+                               data.rsize = val;
+                       else if (!strcmp(opt, "wsize"))
+                               data.wsize = val;
+                       else if (!strcmp(opt, "timeo"))
+                               data.timeo = val;
+                       else if (!strcmp(opt, "retrans"))
+                               data.retrans = val;
+                       else if (!strcmp(opt, "acregmin"))
+                               data.acregmin = val;
+                       else if (!strcmp(opt, "acregmax"))
+                               data.acregmax = val;
+                       else if (!strcmp(opt, "acdirmin"))
+                               data.acdirmin = val;
+                       else if (!strcmp(opt, "acdirmax"))
+                               data.acdirmax = val;
+                       else if (!strcmp(opt, "actimeo")) {
+                               data.acregmin = val;
+                               data.acregmax = val;
+                               data.acdirmin = val;
+                               data.acdirmax = val;
+                       }
+                       else if (!strcmp(opt, "retry"))
+                               retry = val;
+                       else if (!strcmp(opt, "port"))
+                               port = val;
+                       else if (!strcmp(opt, "mountport"))
+                               mountport = val;
+                       else if (!strcmp(opt, "mounthost"))
+                               mounthost=xstrndup(opteq+1,
+                                                 strcspn(opteq+1," \t\n\r,"));
+                       else if (!strcmp(opt, "mountprog"))
+                               mountprog = val;
+                       else if (!strcmp(opt, "mountvers"))
+                               mountvers = val;
+                       else if (!strcmp(opt, "nfsprog"))
+                               nfsprog = val;
+                       else if (!strcmp(opt, "nfsvers") ||
+                                !strcmp(opt, "vers"))
+                               nfsvers = val;
+                       else if (!strcmp(opt, "proto")) {
+                               if (!strncmp(opteq+1, "tcp", 3))
+                                       tcp = 1;
+                               else if (!strncmp(opteq+1, "udp", 3))
+                                       tcp = 0;
+                               else
+                                       printf(_("Warning: Unrecognized proto= option.\n"));
+                       } else if (!strcmp(opt, "namlen")) {
+#if NFS_MOUNT_VERSION >= 2
+                               if (nfs_mount_version >= 2)
+                                       data.namlen = val;
+                               else
+#endif
+                               printf(_("Warning: Option namlen is not supported.\n"));
+                       } else if (!strcmp(opt, "addr"))
+                               /* ignore */;
+                       else {
+                               printf(_("unknown nfs mount parameter: "
+                                      "%s=%d\n"), opt, val);
+                               goto fail;
+                       }
+               }
+               else {
+                       val = 1;
+                       if (!strncmp(opt, "no", 2)) {
+                               val = 0;
+                               opt += 2;
+                       }
+                       if (!strcmp(opt, "bg")) 
+                               bg = val;
+                       else if (!strcmp(opt, "fg")) 
+                               bg = !val;
+                       else if (!strcmp(opt, "soft"))
+                               soft = val;
+                       else if (!strcmp(opt, "hard"))
+                               soft = !val;
+                       else if (!strcmp(opt, "intr"))
+                               intr = val;
+                       else if (!strcmp(opt, "posix"))
+                               posix = val;
+                       else if (!strcmp(opt, "cto"))
+                               nocto = !val;
+                       else if (!strcmp(opt, "ac"))
+                               noac = !val;
+                       else if (!strcmp(opt, "tcp"))
+                               tcp = val;
+                       else if (!strcmp(opt, "udp"))
+                               tcp = !val;
+                       else if (!strcmp(opt, "lock")) {
+                               if (nfs_mount_version >= 3)
+                                       nolock = !val;
+                               else
+                                       printf(_("Warning: option nolock is not supported.\n"));
+                       } else {
+                               printf(_("unknown nfs mount option: "
+                                          "%s%s\n"), val ? "" : "no", opt);
+                               goto fail;
+                       }
+               }
+       }
+       proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
+
+       data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+               | (intr ? NFS_MOUNT_INTR : 0)
+               | (posix ? NFS_MOUNT_POSIX : 0)
+               | (nocto ? NFS_MOUNT_NOCTO : 0)
+               | (noac ? NFS_MOUNT_NOAC : 0);
+#if NFS_MOUNT_VERSION >= 2
+       if (nfs_mount_version >= 2)
+               data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+#endif
+#if NFS_MOUNT_VERSION >= 3
+       if (nfs_mount_version >= 3)
+               data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
+#endif
+       if (nfsvers > MAX_NFSPROT) {
+               error_msg("NFSv%d not supported!", nfsvers);
+               return 0;
+       }
+       if (mountvers > MAX_NFSPROT) {
+               error_msg("NFSv%d not supported!", nfsvers);
+               return 0;
+       }
+       if (nfsvers && !mountvers)
+               mountvers = (nfsvers < 3) ? 1 : nfsvers;
+       if (nfsvers && nfsvers < mountvers) {
+               mountvers = nfsvers;
+       }
+
+       /* Adjust options if none specified */
+       if (!data.timeo)
+               data.timeo = tcp ? 70 : 7;
+
+#ifdef NFS_MOUNT_DEBUG
+       printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+               data.rsize, data.wsize, data.timeo, data.retrans);
+       printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+               data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+       printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
+               port, bg, retry, data.flags);
+       printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
+               mountprog, mountvers, nfsprog, nfsvers);
+       printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
+               (data.flags & NFS_MOUNT_SOFT) != 0,
+               (data.flags & NFS_MOUNT_INTR) != 0,
+               (data.flags & NFS_MOUNT_POSIX) != 0,
+               (data.flags & NFS_MOUNT_NOCTO) != 0,
+               (data.flags & NFS_MOUNT_NOAC) != 0);
+#if NFS_MOUNT_VERSION >= 2
+       printf("tcp = %d\n",
+               (data.flags & NFS_MOUNT_TCP) != 0);
+#endif
+#endif
+
+       data.version = nfs_mount_version;
+       *mount_opts = (char *) &data;
+
+       if (*flags & MS_REMOUNT)
+               return 0;
+
+       /*
+        * If the previous mount operation on the same host was
+        * backgrounded, and the "bg" for this mount is also set,
+        * give up immediately, to avoid the initial timeout.
+        */
+       if (bg && !running_bg &&
+           prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
+               if (retry > 0)
+                       retval = EX_BG;
+               return retval;
+       }
+
+       /* create mount deamon client */
+       /* See if the nfs host = mount host. */
+       if (mounthost) {
+         if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+           mount_server_addr.sin_family = AF_INET;
+           mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+         } else {
+                 if ((hp = gethostbyname(mounthost)) == NULL) {
+                         herror_msg("%s", mounthost);
+                         goto fail;
+                 } else {
+                         if (hp->h_length > sizeof(struct in_addr)) {
+                                 error_msg("got bad hp->h_length?");
+                                 hp->h_length = sizeof(struct in_addr);
+                         }
+                         mount_server_addr.sin_family = AF_INET;
+                         memcpy(&mount_server_addr.sin_addr,
+                                hp->h_addr, hp->h_length);
+                 }
+         }
+       }
+
+       /*
+        * The following loop implements the mount retries. On the first
+        * call, "running_bg" is 0. When the mount times out, and the
+        * "bg" option is set, the exit status EX_BG will be returned.
+        * For a backgrounded mount, there will be a second call by the
+        * child process with "running_bg" set to 1.
+        *
+        * The case where the mount point is not present and the "bg"
+        * option is set, is treated as a timeout. This is done to
+        * support nested mounts.
+        *
+        * The "retry" count specified by the user is the number of
+        * minutes to retry before giving up.
+        *
+        * Only the first error message will be displayed.
+        */
+       retry_timeout.tv_sec = 3;
+       retry_timeout.tv_usec = 0;
+       total_timeout.tv_sec = 20;
+       total_timeout.tv_usec = 0;
+       timeout = time(NULL) + 60 * retry;
+       prevt = 0;
+       t = 30;
+       val = 1;
+       for (;;) {
+               if (bg && stat(node, &statbuf) == -1) {
+                       if (running_bg) {
+                               sleep(val);     /* 1, 2, 4, 8, 16, 30, ... */
+                               val *= 2;
+                               if (val > 30)
+                                       val = 30;
+                       }
+               } else {
+                       /* be careful not to use too many CPU cycles */
+                       if (t - prevt < 30)
+                               sleep(30);
+
+                       pm_mnt = get_mountport(&mount_server_addr,
+                                      mountprog,
+                                      mountvers,
+                                      proto,
+                                      mountport);
+
+                       /* contact the mount daemon via TCP */
+                       mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+                       msock = RPC_ANYSOCK;
+
+                       switch (pm_mnt->pm_prot) {
+                       case IPPROTO_UDP:
+                               mclient = clntudp_create(&mount_server_addr,
+                                                pm_mnt->pm_prog,
+                                                pm_mnt->pm_vers,
+                                                retry_timeout,
+                                                &msock);
+                 if (mclient)
+                         break;
+                 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+                 msock = RPC_ANYSOCK;
+               case IPPROTO_TCP:
+                       mclient = clnttcp_create(&mount_server_addr,
+                                                pm_mnt->pm_prog,
+                                                pm_mnt->pm_vers,
+                                                &msock, 0, 0);
+                       break;
+               default:
+                       mclient = 0;
+                       }
+                       if (mclient) {
+                               /* try to mount hostname:pathname */
+                               mclient->cl_auth = authunix_create_default();
+
+                       /* make pointers in xdr_mountres3 NULL so
+                        * that xdr_array allocates memory for us
+                        */
+                       memset(&status, 0, sizeof(status));
+
+                       if (pm_mnt->pm_vers == 3)
+                               clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
+                                                     (xdrproc_t) xdr_dirpath,
+                                                     (caddr_t) &pathname,
+                                                     (xdrproc_t) xdr_mountres3,
+                                                     (caddr_t) &status,
+                                       total_timeout);
+                       else
+                               clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
+                                                     (xdrproc_t) xdr_dirpath,
+                                                     (caddr_t) &pathname,
+                                                     (xdrproc_t) xdr_fhstatus,
+                                                     (caddr_t) &status,
+                                                     total_timeout);
+
+                               if (clnt_stat == RPC_SUCCESS)
+                                       break;          /* we're done */
+                               if (errno != ECONNREFUSED) {
+                                       clnt_perror(mclient, "mount");
+                                       goto fail;      /* don't retry */
+                               }
+                               if (!running_bg && prevt == 0)
+                                       clnt_perror(mclient, "mount");
+                               auth_destroy(mclient->cl_auth);
+                               clnt_destroy(mclient);
+                               mclient = 0;
+                               close(msock);
+                       } else {
+                               if (!running_bg && prevt == 0)
+                                       clnt_pcreateerror("mount");
+                       }
+                       prevt = t;
+               }
+               if (!bg)
+                       goto fail;
+               if (!running_bg) {
+                       prev_bg_host = xstrdup(hostname);
+                       if (retry > 0)
+                               retval = EX_BG;
+                       goto fail;
+               }
+               t = time(NULL);
+               if (t >= timeout)
+                       goto fail;
+       }
+       nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
+
+       if (nfsvers == 2) {
+               if (status.nfsv2.fhs_status != 0) {
+                       error_msg("%s:%s failed, reason given by server: %s",
+                               hostname, pathname,
+                               nfs_strerror(status.nfsv2.fhs_status));
+                       goto fail;
+               }
+               memcpy(data.root.data,
+                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+                      NFS_FHSIZE);
+#if NFS_MOUNT_VERSION >= 4
+               data.root.size = NFS_FHSIZE;
+               memcpy(data.old_root.data,
+                      (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+                      NFS_FHSIZE);
+#endif
+       } else {
+#if NFS_MOUNT_VERSION >= 4
+               fhandle3 *my_fhandle;
+               if (status.nfsv3.fhs_status != 0) {
+                       error_msg("%s:%s failed, reason given by server: %s",
+                               hostname, pathname,
+                               nfs_strerror(status.nfsv3.fhs_status));
+                       goto fail;
+               }
+               my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+               memset(data.old_root.data, 0, NFS_FHSIZE);
+               memset(&data.root, 0, sizeof(data.root));
+               data.root.size = my_fhandle->fhandle3_len;
+               memcpy(data.root.data,
+                      (char *) my_fhandle->fhandle3_val,
+                      my_fhandle->fhandle3_len);
+
+               data.flags |= NFS_MOUNT_VER3;
+#endif
+       }
+
+       /* create nfs socket for kernel */
+
+       if (tcp) {
+               if (nfs_mount_version < 3) {
+                       printf(_("NFS over TCP is not supported.\n"));
+                       goto fail;
+               }
+               fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       } else
+               fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (fsock < 0) {
+               perror(_("nfs socket"));
+               goto fail;
+       }
+       if (bindresvport(fsock, 0) < 0) {
+               perror(_("nfs bindresvport"));
+               goto fail;
+       }
+       if (port == 0) {
+               server_addr.sin_port = PMAPPORT;
+               port = pmap_getport(&server_addr, nfsprog, nfsvers,
+                       tcp ? IPPROTO_TCP : IPPROTO_UDP);
+               if (port == 0)
+                       port = NFS_PORT;
+#ifdef NFS_MOUNT_DEBUG
+               else
+                       printf(_("used portmapper to find NFS port\n"));
+#endif
+       }
+#ifdef NFS_MOUNT_DEBUG
+       printf(_("using port %d for nfs deamon\n"), port);
+#endif
+       server_addr.sin_port = htons(port);
+        /*
+         * connect() the socket for kernels 1.3.10 and below only,
+         * to avoid problems with multihomed hosts.
+         * --Swen
+         */
+       if (get_kernel_revision() <= 66314
+           && connect(fsock, (struct sockaddr *) &server_addr,
+                      sizeof (server_addr)) < 0) {
+               perror(_("nfs connect"));
+               goto fail;
+       }
+
+       /* prepare data structure for kernel */
+
+       data.fd = fsock;
+       memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+       strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+       /* clean up */
+
+       auth_destroy(mclient->cl_auth);
+       clnt_destroy(mclient);
+       close(msock);
+       return 0;
+
+       /* abort */
+
+fail:
+       if (msock != -1) {
+               if (mclient) {
+                       auth_destroy(mclient->cl_auth);
+                       clnt_destroy(mclient);
+               }
+               close(msock);
+       }
+       if (fsock != -1)
+               close(fsock);
+       return retval;
+}      
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ *
+ * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ *  it cannot even be used as a struct tag or field name".
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+static struct {
+       enum nfs_stat stat;
+       int errnum;
+} nfs_errtbl[] = {
+       { NFS_OK,               0               },
+       { NFSERR_PERM,          EPERM           },
+       { NFSERR_NOENT,         ENOENT          },
+       { NFSERR_IO,            EIO             },
+       { NFSERR_NXIO,          ENXIO           },
+       { NFSERR_ACCES,         EACCES          },
+       { NFSERR_EXIST,         EEXIST          },
+       { NFSERR_NODEV,         ENODEV          },
+       { NFSERR_NOTDIR,        ENOTDIR         },
+       { NFSERR_ISDIR,         EISDIR          },
+#ifdef NFSERR_INVAL
+       { NFSERR_INVAL,         EINVAL          },      /* that Sun forgot */
+#endif
+       { NFSERR_FBIG,          EFBIG           },
+       { NFSERR_NOSPC,         ENOSPC          },
+       { NFSERR_ROFS,          EROFS           },
+       { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
+       { NFSERR_NOTEMPTY,      ENOTEMPTY       },
+       { NFSERR_DQUOT,         EDQUOT          },
+       { NFSERR_STALE,         ESTALE          },
+#ifdef EWFLUSH
+       { NFSERR_WFLUSH,        EWFLUSH         },
+#endif
+       /* Throw in some NFSv3 values for even more fun (HP returns these) */
+       { 71,                   EREMOTE         },
+
+       { -1,                   EIO             }
+};
+
+static char *nfs_strerror(int status)
+{
+       int i;
+       static char buf[256];
+
+       for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+               if (nfs_errtbl[i].stat == status)
+                       return strerror(nfs_errtbl[i].errnum);
+       }
+       sprintf(buf, _("unknown nfs status return value: %d"), status);
+       return buf;
+}
+
+static bool_t
+xdr_fhandle (XDR *xdrs, fhandle objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_opaque (xdrs, objp, FHSIZE))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_fhstatus (XDR *xdrs, fhstatus *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_u_int (xdrs, &objp->fhs_status))
+                return FALSE;
+       switch (objp->fhs_status) {
+       case 0:
+                if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
+                        return FALSE;
+               break;
+       default:
+               break;
+       }
+       return TRUE;
+}
+
+bool_t
+xdr_dirpath (XDR *xdrs, dirpath *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_string (xdrs, objp, MNTPATHLEN))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_fhandle3 (xdrs, &objp->fhandle))
+                return FALSE;
+        if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
+               sizeof (int), (xdrproc_t) xdr_int))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_mountres3 (XDR *xdrs, mountres3 *objp)
+{
+       //register int32_t *buf;
+
+        if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
+                return FALSE;
+       switch (objp->fhs_status) {
+       case MNT_OK:
+                if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
+                        return FALSE;
+               break;
+       default:
+               break;
+       }
+       return TRUE;
+}
+
diff --git a/nfsmount.h b/nfsmount.h
new file mode 100644 (file)
index 0000000..b3d5a51
--- /dev/null
@@ -0,0 +1,242 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * This file was originally generated using rpcgen.
+ * But now we edit it by hand as needed to make it
+ * shut up...
+ */
+
+#ifndef _NFSMOUNT_H_RPCGEN
+#define _NFSMOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+ */
+
+/* from @(#)mount.x    1.3 91/03/11 TIRPC 1.0 */
+#ifndef _rpcsvc_mount_h
+#define _rpcsvc_mount_h
+#include <asm/types.h>
+#define MOUNTPORT 635
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+#define FHSIZE3 64
+
+typedef char fhandle[FHSIZE];
+
+typedef struct {
+       u_int fhandle3_len;
+       char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+       MNT_OK = 0,
+       MNT3ERR_PERM = 1,
+       MNT3ERR_NOENT = 2,
+       MNT3ERR_IO = 5,
+       MNT3ERR_ACCES = 13,
+       MNT3ERR_NOTDIR = 20,
+       MNT3ERR_INVAL = 22,
+       MNT3ERR_NAMETOOLONG = 63,
+       MNT3ERR_NOTSUPP = 10004,
+       MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct fhstatus {
+       u_int fhs_status;
+       union {
+               fhandle fhs_fhandle;
+       } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+
+struct mountres3_ok {
+       fhandle3 fhandle;
+       struct {
+               u_int auth_flavours_len;
+               int *auth_flavours_val;
+       } auth_flavours;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+       mountstat3 fhs_status;
+       union {
+               mountres3_ok mountinfo;
+       } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+       name ml_hostname;
+       dirpath ml_directory;
+       mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+       name gr_name;
+       groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+       dirpath ex_dir;
+       groups ex_groups;
+       exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct ppathcnf {
+       int pc_link_max;
+       short pc_max_canon;
+       short pc_max_input;
+       short pc_name_max;
+       short pc_path_max;
+       short pc_pipe_buf;
+       u_char pc_vdisable;
+       char pc_xxx;
+       short pc_mask[2];
+};
+typedef struct ppathcnf ppathcnf;
+#endif /*!_rpcsvc_mount_h*/
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
+
+#define MOUNTPROC_NULL 0
+extern  void * mountproc_null_1(void *, CLIENT *);
+extern  void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT 1
+extern  fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern  fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP 2
+extern  mountlist * mountproc_dump_1(void *, CLIENT *);
+extern  mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT 3
+extern  void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern  void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL 4
+extern  void * mountproc_umntall_1(void *, CLIENT *);
+extern  void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT 5
+extern  exports * mountproc_export_1(void *, CLIENT *);
+extern  exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL 6
+extern  exports * mountproc_exportall_1(void *, CLIENT *);
+extern  exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#define MOUNTVERS_POSIX 2
+
+extern  void * mountproc_null_2(void *, CLIENT *);
+extern  void * mountproc_null_2_svc(void *, struct svc_req *);
+extern  fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
+extern  fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
+extern  mountlist * mountproc_dump_2(void *, CLIENT *);
+extern  mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
+extern  void * mountproc_umnt_2(dirpath *, CLIENT *);
+extern  void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
+extern  void * mountproc_umntall_2(void *, CLIENT *);
+extern  void * mountproc_umntall_2_svc(void *, struct svc_req *);
+extern  exports * mountproc_export_2(void *, CLIENT *);
+extern  exports * mountproc_export_2_svc(void *, struct svc_req *);
+extern  exports * mountproc_exportall_2(void *, CLIENT *);
+extern  exports * mountproc_exportall_2_svc(void *, struct svc_req *);
+#define MOUNTPROC_PATHCONF 7
+extern  ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
+extern  ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
+extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#define MOUNT_V3 3
+
+#define MOUNTPROC3_NULL 0
+extern  void * mountproc3_null_3(void *, CLIENT *);
+extern  void * mountproc3_null_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_MNT 1
+extern  mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
+extern  mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_DUMP 2
+extern  mountlist * mountproc3_dump_3(void *, CLIENT *);
+extern  mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_UMNT 3
+extern  void * mountproc3_umnt_3(dirpath *, CLIENT *);
+extern  void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_UMNTALL 4
+extern  void * mountproc3_umntall_3(void *, CLIENT *);
+extern  void * mountproc3_umntall_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_EXPORT 5
+extern  exports * mountproc3_export_3(void *, CLIENT *);
+extern  exports * mountproc3_export_3_svc(void *, struct svc_req *);
+extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+/* the xdr functions */
+
+static  bool_t xdr_fhandle (XDR *, fhandle);
+extern  bool_t xdr_fhandle3 (XDR *, fhandle3*);
+extern  bool_t xdr_mountstat3 (XDR *, mountstat3*);
+extern  bool_t xdr_fhstatus (XDR *, fhstatus*);
+extern  bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
+extern  bool_t xdr_mountres3 (XDR *, mountres3*);
+extern  bool_t xdr_dirpath (XDR *, dirpath*);
+extern  bool_t xdr_name (XDR *, name*);
+extern  bool_t xdr_mountlist (XDR *, mountlist*);
+extern  bool_t xdr_mountbody (XDR *, mountbody*);
+extern  bool_t xdr_groups (XDR *, groups*);
+extern  bool_t xdr_groupnode (XDR *, groupnode*);
+extern  bool_t xdr_exports (XDR *, exports*);
+extern  bool_t xdr_exportnode (XDR *, exportnode*);
+extern  bool_t xdr_ppathcnf (XDR *, ppathcnf*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NFSMOUNT_H_RPCGEN */
diff --git a/nslookup.c b/nslookup.c
new file mode 100644 (file)
index 0000000..2139afd
--- /dev/null
@@ -0,0 +1,180 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini nslookup implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/inet.h>
+#include "busybox.h"
+
+/*
+ |  I'm only implementing non-interactive mode;
+ |  I totally forgot nslookup even had an interactive mode.
+ |
+ |  [ TODO ]
+ |  + find out how to use non-default name servers
+ */
+
+/* only works for IPv4 */
+static int addr_fprint(char *addr)
+{
+       u_int8_t split[4];
+       u_int32_t ip;
+       u_int32_t *x = (u_int32_t *) addr;
+
+       ip = ntohl(*x);
+       split[0] = (ip & 0xff000000) >> 24;
+       split[1] = (ip & 0x00ff0000) >> 16;
+       split[2] = (ip & 0x0000ff00) >> 8;
+       split[3] = (ip & 0x000000ff);
+       printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
+       return 0;
+}
+
+/* takes the NULL-terminated array h_addr_list, and
+ * prints its contents appropriately
+ */
+static int addr_list_fprint(char **h_addr_list)
+{
+       int i, j;
+       char *addr_string = (h_addr_list[1])
+               ? "Addresses: " : "Address:   ";
+
+       printf("%s ", addr_string);
+       for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
+               addr_fprint(h_addr_list[i]);
+
+               /* real nslookup does this */
+               if (j == 4) {
+                       if (h_addr_list[i + 1]) {
+                               printf("\n          ");
+                       }
+                       j = 0;
+               } else {
+                       if (h_addr_list[i + 1]) {
+                               printf(", ");
+                       }
+               }
+
+       }
+       printf("\n");
+       return 0;
+}
+
+/* print the results as nslookup would */
+static struct hostent *hostent_fprint(struct hostent *host, int is_server)
+{
+       char *format;
+       if (is_server) {
+               format = "Server:     ";
+       } else {
+               format = "Name:       ";
+       }
+       if (host) {
+               printf("%s%s\n", format, host->h_name);
+               addr_list_fprint(host->h_addr_list);
+       } else {
+               printf("*** Unknown host\n");
+       }
+       return host;
+}
+
+/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
+ * into a u_int32_t
+ */
+static u_int32_t str_to_addr(const char *addr)
+{
+       u_int32_t split[4];
+       u_int32_t ip;
+
+       sscanf(addr, "%d.%d.%d.%d",
+                  &split[0], &split[1], &split[2], &split[3]);
+
+       /* assuming sscanf worked */
+       ip = (split[0] << 24) |
+               (split[1] << 16) | (split[2] << 8) | (split[3]);
+
+       return htonl(ip);
+}
+
+/* gethostbyaddr wrapper */
+static struct hostent *gethostbyaddr_wrapper(const char *address)
+{
+       struct in_addr addr;
+
+       addr.s_addr = str_to_addr(address);
+       return gethostbyaddr((char *) &addr, 4, AF_INET);       /* IPv4 only for now */
+}
+
+/* lookup the default nameserver and display it */
+static inline void server_print(void)
+{
+       struct sockaddr_in def = _res.nsaddr_list[0];
+       char *ip = inet_ntoa(def.sin_addr);
+
+       hostent_fprint(gethostbyaddr_wrapper(ip), 1);
+       printf("\n");
+}
+
+/* naive function to check whether char *s is an ip address */
+static int is_ip_address(const char *s)
+{
+       while (*s) {
+               if ((isdigit(*s)) || (*s == '.')) {
+                       s++;
+                       continue;
+               }
+               return 0;
+       }
+       return 1;
+}
+
+/* ________________________________________________________________________ */
+int nslookup_main(int argc, char **argv)
+{
+       struct hostent *host;
+
+       if (argc < 2 || *argv[1]=='-') {
+               show_usage();
+       }
+
+       res_init();
+       server_print();
+       if (is_ip_address(argv[1])) {
+               host = gethostbyaddr_wrapper(argv[1]);
+       } else {
+               host = gethostbyname(argv[1]);
+       }
+       hostent_fprint(host, 0);
+       return EXIT_SUCCESS;
+}
+
+/* $Id: nslookup.c,v 1.28 2002/04/27 04:03:59 andersen Exp $ */
diff --git a/pidof.c b/pidof.c
new file mode 100644 (file)
index 0000000..c75571a
--- /dev/null
+++ b/pidof.c
@@ -0,0 +1,79 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pidof implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include "busybox.h"
+
+
+extern int pidof_main(int argc, char **argv)
+{
+       int opt, n = 0;
+
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
+               switch (opt) {
+#if 0
+                       case 'g':
+                               break;
+                       case 'e':
+                               break;
+#endif
+                       default:
+                               show_usage();
+               }
+       }
+
+       /* if we didn't get a process name, then we need to choke and die here */
+       if (argv[optind] == NULL)
+               show_usage();
+
+       /* Looks like everything is set to go. */
+       while(optind < argc) {
+               long* pidList;
+
+               pidList = find_pid_by_name( argv[optind]);
+               if (!pidList || *pidList<=0) {
+                       break;
+               }
+
+               for(; pidList && *pidList!=0; pidList++) {
+                       printf("%s%ld", (n++ ? " " : ""), (long)*pidList);
+               }
+               /* Note that we don't bother to free the memory
+                * allocated in find_pid_by_name().  It will be freed
+                * upon exit, so we can save a byte or two */
+               optind++;
+       }
+       printf("\n");
+
+       return EXIT_SUCCESS;
+}
diff --git a/ping.c b/ping.c
new file mode 100644 (file)
index 0000000..74ff614
--- /dev/null
+++ b/ping.c
@@ -0,0 +1,555 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * $Id: ping.c,v 1.47 2002/09/17 07:56:26 andersen Exp $
+ * Mini ping implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This version of ping is adapted from the ping in netkit-base 0.10,
+ * which is:
+ *
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ * 
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/signal.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+
+/* It turns out that libc5 doesn't have proper icmp support
+ * built into it header files, so we have to supplement it */
+#if __GNU_LIBRARY__ < 5
+static const int ICMP_MINLEN = 8;                              /* abs minimum */
+
+struct icmp_ra_addr
+{
+  u_int32_t ira_addr;
+  u_int32_t ira_preference;
+};
+
+
+struct icmp
+{
+  u_int8_t  icmp_type; /* type of message, see below */
+  u_int8_t  icmp_code; /* type sub code */
+  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
+  union
+  {
+    u_char ih_pptr;            /* ICMP_PARAMPROB */
+    struct in_addr ih_gwaddr;  /* gateway address */
+    struct ih_idseq            /* echo datagram */
+    {
+      u_int16_t icd_id;
+      u_int16_t icd_seq;
+    } ih_idseq;
+    u_int32_t ih_void;
+
+    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+    struct ih_pmtu
+    {
+      u_int16_t ipm_void;
+      u_int16_t ipm_nextmtu;
+    } ih_pmtu;
+
+    struct ih_rtradv
+    {
+      u_int8_t irt_num_addrs;
+      u_int8_t irt_wpa;
+      u_int16_t irt_lifetime;
+    } ih_rtradv;
+  } icmp_hun;
+#define        icmp_pptr       icmp_hun.ih_pptr
+#define        icmp_gwaddr     icmp_hun.ih_gwaddr
+#define        icmp_id         icmp_hun.ih_idseq.icd_id
+#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
+#define        icmp_void       icmp_hun.ih_void
+#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
+#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
+#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
+#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
+#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
+  union
+  {
+    struct
+    {
+      u_int32_t its_otime;
+      u_int32_t its_rtime;
+      u_int32_t its_ttime;
+    } id_ts;
+    struct
+    {
+      struct ip idi_ip;
+      /* options and then 64 bits of data */
+    } id_ip;
+    struct icmp_ra_addr id_radv;
+    u_int32_t   id_mask;
+    u_int8_t    id_data[1];
+  } icmp_dun;
+#define        icmp_otime      icmp_dun.id_ts.its_otime
+#define        icmp_rtime      icmp_dun.id_ts.its_rtime
+#define        icmp_ttime      icmp_dun.id_ts.its_ttime
+#define        icmp_ip         icmp_dun.id_ip.idi_ip
+#define        icmp_radv       icmp_dun.id_radv
+#define        icmp_mask       icmp_dun.id_mask
+#define        icmp_data       icmp_dun.id_data
+};
+#endif
+
+static const int DEFDATALEN = 56;
+static const int MAXIPLEN = 60;
+static const int MAXICMPLEN = 76;
+static const int MAXPACKET = 65468;
+#define        MAX_DUP_CHK     (8 * 128)
+static const int MAXWAIT = 10;
+static const int PINGINTERVAL = 1;             /* second */
+
+#define O_QUIET         (1 << 0)
+
+#define        A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
+#define        B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
+#define        SET(bit)        (A(bit) |= B(bit))
+#define        CLR(bit)        (A(bit) &= (~B(bit)))
+#define        TST(bit)        (A(bit) & B(bit))
+
+static void ping(const char *host);
+
+/* common routines */
+static int in_cksum(unsigned short *buf, int sz)
+{
+       int nleft = sz;
+       int sum = 0;
+       unsigned short *w = buf;
+       unsigned short ans = 0;
+
+       while (nleft > 1) {
+               sum += *w++;
+               nleft -= 2;
+       }
+
+       if (nleft == 1) {
+               *(unsigned char *) (&ans) = *(unsigned char *) w;
+               sum += ans;
+       }
+
+       sum = (sum >> 16) + (sum & 0xFFFF);
+       sum += (sum >> 16);
+       ans = ~sum;
+       return (ans);
+}
+
+/* simple version */
+#ifndef BB_FEATURE_FANCY_PING
+static char *hostname = NULL;
+
+static void noresp(int ign)
+{
+       printf("No response from %s\n", hostname);
+       exit(0);
+}
+
+static void ping(const char *host)
+{
+       struct hostent *h;
+       struct sockaddr_in pingaddr;
+       struct icmp *pkt;
+       int pingsock, c;
+       char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
+
+       pingsock = create_icmp_socket();
+
+       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
+
+       pingaddr.sin_family = AF_INET;
+       h = xgethostbyname(host);
+       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
+       hostname = h->h_name;
+
+       pkt = (struct icmp *) packet;
+       memset(pkt, 0, sizeof(packet));
+       pkt->icmp_type = ICMP_ECHO;
+       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
+
+       c = sendto(pingsock, packet, sizeof(packet), 0,
+                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
+
+       if (c < 0 || c != sizeof(packet))
+               perror_msg_and_die("sendto");
+
+       signal(SIGALRM, noresp);
+       alarm(5);                                       /* give the host 5000ms to respond */
+       /* listen for replies */
+       while (1) {
+               struct sockaddr_in from;
+               socklen_t fromlen = sizeof(from);
+
+               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
+                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       perror_msg("recvfrom");
+                       continue;
+               }
+               if (c >= 76) {                  /* ip + icmp */
+                       struct iphdr *iphdr = (struct iphdr *) packet;
+
+                       pkt = (struct icmp *) (packet + (iphdr->ihl << 2));     /* skip ip hdr */
+                       if (pkt->icmp_type == ICMP_ECHOREPLY)
+                               break;
+               }
+       }
+       printf("%s is alive!\n", hostname);
+       return;
+}
+
+extern int ping_main(int argc, char **argv)
+{
+       argc--;
+       argv++;
+       if (argc < 1)
+               show_usage();
+       ping(*argv);
+       return EXIT_SUCCESS;
+}
+
+#else /* ! BB_FEATURE_FANCY_PING */
+/* full(er) version */
+static char *hostname = NULL;
+static struct sockaddr_in pingaddr;
+static int pingsock = -1;
+static int datalen; /* intentionally uninitialized to work around gcc bug */
+
+static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0;
+static int myid = 0, options = 0;
+static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0;
+static char rcvd_tbl[MAX_DUP_CHK / 8];
+
+static void sendping(int);
+static void pingstats(int);
+static void unpack(char *, int, struct sockaddr_in *);
+
+/**************************************************************************/
+
+static void pingstats(int junk)
+{
+       int status;
+
+       signal(SIGINT, SIG_IGN);
+
+       printf("\n--- %s ping statistics ---\n", hostname);
+       printf("%ld packets transmitted, ", ntransmitted);
+       printf("%ld packets received, ", nreceived);
+       if (nrepeats)
+               printf("%ld duplicates, ", nrepeats);
+       if (ntransmitted)
+               printf("%ld%% packet loss\n",
+                          (ntransmitted - nreceived) * 100 / ntransmitted);
+       if (nreceived)
+               printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
+                          tmin / 10, tmin % 10,
+                          (tsum / (nreceived + nrepeats)) / 10,
+                          (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
+       if (nreceived != 0)
+               status = EXIT_SUCCESS;
+       else
+               status = EXIT_FAILURE;
+       exit(status);
+}
+
+static void sendping(int junk)
+{
+       struct icmp *pkt;
+       int i;
+       char packet[datalen + 8];
+
+       pkt = (struct icmp *) packet;
+
+       pkt->icmp_type = ICMP_ECHO;
+       pkt->icmp_code = 0;
+       pkt->icmp_cksum = 0;
+       pkt->icmp_seq = ntransmitted++;
+       pkt->icmp_id = myid;
+       CLR(pkt->icmp_seq % MAX_DUP_CHK);
+
+       gettimeofday((struct timeval *) &packet[8], NULL);
+       pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
+
+       i = sendto(pingsock, packet, sizeof(packet), 0,
+                          (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
+
+       if (i < 0)
+               perror_msg_and_die("sendto");
+       else if ((size_t)i != sizeof(packet))
+               error_msg_and_die("ping wrote %d chars; %d expected", i,
+                          (int)sizeof(packet));
+
+       signal(SIGALRM, sendping);
+       if (pingcount == 0 || ntransmitted < pingcount) {       /* schedule next in 1s */
+               alarm(PINGINTERVAL);
+       } else {                                        /* done, wait for the last ping to come back */
+               /* todo, don't necessarily need to wait so long... */
+               signal(SIGALRM, pingstats);
+               alarm(MAXWAIT);
+       }
+}
+
+static char *icmp_type_name (int id)
+{
+       switch (id) {
+       case ICMP_ECHOREPLY:            return "Echo Reply";
+       case ICMP_DEST_UNREACH:         return "Destination Unreachable";
+       case ICMP_SOURCE_QUENCH:        return "Source Quench";
+       case ICMP_REDIRECT:             return "Redirect (change route)";
+       case ICMP_ECHO:                         return "Echo Request";
+       case ICMP_TIME_EXCEEDED:        return "Time Exceeded";
+       case ICMP_PARAMETERPROB:        return "Parameter Problem";
+       case ICMP_TIMESTAMP:            return "Timestamp Request";
+       case ICMP_TIMESTAMPREPLY:       return "Timestamp Reply";
+       case ICMP_INFO_REQUEST:         return "Information Request";
+       case ICMP_INFO_REPLY:           return "Information Reply";
+       case ICMP_ADDRESS:                      return "Address Mask Request";
+       case ICMP_ADDRESSREPLY:         return "Address Mask Reply";
+       default:                                        return "unknown ICMP type";
+       }
+}
+
+static void unpack(char *buf, int sz, struct sockaddr_in *from)
+{
+       struct icmp *icmppkt;
+       struct iphdr *iphdr;
+       struct timeval tv, *tp;
+       int hlen, dupflag;
+       unsigned long triptime;
+
+       gettimeofday(&tv, NULL);
+
+       /* check IP header */
+       iphdr = (struct iphdr *) buf;
+       hlen = iphdr->ihl << 2;
+       /* discard if too short */
+       if (sz < (datalen + ICMP_MINLEN))
+               return;
+
+       sz -= hlen;
+       icmppkt = (struct icmp *) (buf + hlen);
+
+       if (icmppkt->icmp_id != myid)
+           return;                             /* not our ping */
+
+       if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
+           ++nreceived;
+               tp = (struct timeval *) icmppkt->icmp_data;
+
+               if ((tv.tv_usec -= tp->tv_usec) < 0) {
+                       --tv.tv_sec;
+                       tv.tv_usec += 1000000;
+               }
+               tv.tv_sec -= tp->tv_sec;
+
+               triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
+               tsum += triptime;
+               if (triptime < tmin)
+                       tmin = triptime;
+               if (triptime > tmax)
+                       tmax = triptime;
+
+               if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) {
+                       ++nrepeats;
+                       --nreceived;
+                       dupflag = 1;
+               } else {
+                       SET(icmppkt->icmp_seq % MAX_DUP_CHK);
+                       dupflag = 0;
+               }
+
+               if (options & O_QUIET)
+                       return;
+
+               printf("%d bytes from %s: icmp_seq=%u", sz,
+                          inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
+                          icmppkt->icmp_seq);
+               printf(" ttl=%d", iphdr->ttl);
+               printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
+               if (dupflag)
+                       printf(" (DUP!)");
+               printf("\n");
+       } else 
+               if (icmppkt->icmp_type != ICMP_ECHO)
+                       error_msg("Warning: Got ICMP %d (%s)",
+                                       icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
+}
+
+static void ping(const char *host)
+{
+       struct hostent *h;
+       char buf[MAXHOSTNAMELEN];
+       char packet[datalen + MAXIPLEN + MAXICMPLEN];
+       int sockopt;
+
+       pingsock = create_icmp_socket();
+
+       memset(&pingaddr, 0, sizeof(struct sockaddr_in));
+
+       pingaddr.sin_family = AF_INET;
+       h = xgethostbyname(host);
+       if (h->h_addrtype != AF_INET)
+               error_msg_and_die("unknown address type; only AF_INET is currently supported.");
+
+       memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
+       strncpy(buf, h->h_name, sizeof(buf) - 1);
+       hostname = buf;
+
+       /* enable broadcast pings */
+       sockopt = 1;
+       setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
+                          sizeof(sockopt));
+
+       /* set recv buf for broadcast pings */
+       sockopt = 48 * 1024;
+       setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
+                          sizeof(sockopt));
+
+       printf("PING %s (%s): %d data bytes\n",
+                  hostname,
+                  inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
+                  datalen);
+
+       signal(SIGINT, pingstats);
+
+       /* start the ping's going ... */
+       sendping(0);
+
+       /* listen for replies */
+       while (1) {
+               struct sockaddr_in from;
+               socklen_t fromlen = (socklen_t) sizeof(from);
+               int c;
+
+               if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
+                                                 (struct sockaddr *) &from, &fromlen)) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       perror_msg("recvfrom");
+                       continue;
+               }
+               unpack(packet, c, &from);
+               if (pingcount > 0 && nreceived >= pingcount)
+                       break;
+       }
+       pingstats(0);
+}
+
+extern int ping_main(int argc, char **argv)
+{
+       char *thisarg;
+
+       datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
+
+       argc--;
+       argv++;
+       options = 0;
+       /* Parse any options */
+       while (argc >= 1 && **argv == '-') {
+               thisarg = *argv;
+               thisarg++;
+               switch (*thisarg) {
+               case 'q':
+                       options |= O_QUIET;
+                       break;
+               case 'c':
+                       if (--argc <= 0)
+                               show_usage();
+                       argv++;
+                       pingcount = atoi(*argv);
+                       break;
+               case 's':
+                       if (--argc <= 0)
+                               show_usage();
+                       argv++;
+                       datalen = atoi(*argv);
+                       break;
+               default:
+                       show_usage();
+               }
+               argc--;
+               argv++;
+       }
+       if (argc < 1)
+               show_usage();
+
+       myid = getpid() & 0xFFFF;
+       ping(*argv);
+       return EXIT_SUCCESS;
+}
+#endif /* ! BB_FEATURE_FANCY_PING */
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ */
diff --git a/pivot_root.c b/pivot_root.c
new file mode 100644 (file)
index 0000000..ba26b9c
--- /dev/null
@@ -0,0 +1,35 @@
+/* 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. 
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "busybox.h"
+
+extern int pivot_root(const char * new_root,const char * put_old);
+
+int pivot_root_main(int argc, char **argv)
+{
+    if (argc != 3)
+        show_usage();
+
+       if (pivot_root(argv[1],argv[2]) < 0)
+               perror_msg_and_die("pivot_root");
+
+    return EXIT_SUCCESS;
+
+}
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/poweroff.c b/poweroff.c
new file mode 100644 (file)
index 0000000..443b70f
--- /dev/null
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini poweroff implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include <signal.h>
+
+extern int poweroff_main(int argc, char **argv)
+{
+#ifdef BB_FEATURE_LINUXRC
+       /* don't assume init's pid == 1 */
+       long *pid = find_pid_by_name("init");
+       if (!pid || *pid<=0) {
+               pid = find_pid_by_name("linuxrc");
+               if (!pid || *pid<=0)
+                       error_msg_and_die("no process killed");
+       }
+       return(kill(*pid, SIGUSR2));
+#else
+       return(kill(1, SIGUSR2));
+#endif
+}
diff --git a/printf.c b/printf.c
new file mode 100644 (file)
index 0000000..d579a9b
--- /dev/null
+++ b/printf.c
@@ -0,0 +1,455 @@
+/* vi: set sw=4 ts=4: */
+/* printf - format and print data
+   Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Usage: printf format [argument...]
+
+   A front end to the printf function that lets it be used from the shell.
+
+   Backslash escapes:
+
+   \" = double quote
+   \\ = backslash
+   \a = alert (bell)
+   \b = backspace
+   \c = produce no further output
+   \f = form feed
+   \n = new line
+   \r = carriage return
+   \t = horizontal tab
+   \v = vertical tab
+   \0ooo = octal number (ooo is 0 to 3 digits)
+   \xhhh = hexadecimal number (hhh is 1 to 3 digits)
+
+   Additional directive:
+
+   %b = print an argument string, interpreting backslash escapes
+
+   The `format' argument is re-used as many times as necessary
+   to convert all of the given arguments.
+
+   David MacKenzie <djm@gnu.ai.mit.edu> */
+
+
+//   19990508 Busy Boxed! Dave Cinege
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "busybox.h"
+
+
+#ifndef S_IFMT
+static const int S_IFMT = 0170000;
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+# define       S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+# define       S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# define       S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+# define       S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+# define       S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+# define       S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+# define       S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB)      /* V7 */
+# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK)      /* HP/UX */
+# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+#define IN_CTYPE_DOMAIN(c) 1
+
+#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+#define ISDIGIT(c) (((unsigned char) (c)) - '0' <= 9)
+
+#define isodigit(c) ((c) >= '0' && (c) <= '7')
+#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
+#define octtobin(c) ((c) - '0')
+
+static double xstrtod __P((char *s));
+static int print_esc __P((char *escstart));
+static int print_formatted __P((char *format, int argc, char **argv));
+static long xstrtol __P((char *s));
+static unsigned long xstrtoul __P((char *s));
+static void print_direc
+__P(
+
+       (char *start, size_t length, int field_width, int precision,
+        char *argument));
+static void print_esc_char __P((int c));
+static void print_esc_string __P((char *str));
+static void verify __P((char *s, char *end));
+
+/* The value to return to the calling program.  */
+static int exit_status;
+
+int printf_main(int argc, char **argv)
+{
+       char *format;
+       int args_used;
+
+       exit_status = 0;
+       if (argc <= 1 || **(argv + 1) == '-') {
+               show_usage();
+       }
+
+       format = argv[1];
+       argc -= 2;
+       argv += 2;
+
+       do {
+               args_used = print_formatted(format, argc, argv);
+               argc -= args_used;
+               argv += args_used;
+       }
+       while (args_used > 0 && argc > 0);
+
+/*
+  if (argc > 0)
+    fprintf(stderr, "excess args ignored");
+*/
+
+       return(exit_status);
+}
+
+/* Print the text in FORMAT, using ARGV (with ARGC elements) for
+   arguments to any `%' directives.
+   Return the number of elements of ARGV used.  */
+
+static int print_formatted(char *format, int argc, char **argv)
+{
+       int save_argc = argc;           /* Preserve original value.  */
+       char *f;                                        /* Pointer into `format'.  */
+       char *direc_start;                      /* Start of % directive.  */
+       size_t direc_length;            /* Length of % directive.  */
+       int field_width;                        /* Arg to first '*', or -1 if none.  */
+       int precision;                          /* Arg to second '*', or -1 if none.  */
+
+       for (f = format; *f; ++f) {
+               switch (*f) {
+               case '%':
+                       direc_start = f++;
+                       direc_length = 1;
+                       field_width = precision = -1;
+                       if (*f == '%') {
+                               putchar('%');
+                               break;
+                       }
+                       if (*f == 'b') {
+                               if (argc > 0) {
+                                       print_esc_string(*argv);
+                                       ++argv;
+                                       --argc;
+                               }
+                               break;
+                       }
+                       if (strchr("-+ #", *f)) {
+                               ++f;
+                               ++direc_length;
+                       }
+                       if (*f == '*') {
+                               ++f;
+                               ++direc_length;
+                               if (argc > 0) {
+                                       field_width = xstrtoul(*argv);
+                                       ++argv;
+                                       --argc;
+                               } else
+                                       field_width = 0;
+                       } else
+                               while (ISDIGIT(*f)) {
+                                       ++f;
+                                       ++direc_length;
+                               }
+                       if (*f == '.') {
+                               ++f;
+                               ++direc_length;
+                               if (*f == '*') {
+                                       ++f;
+                                       ++direc_length;
+                                       if (argc > 0) {
+                                               precision = xstrtoul(*argv);
+                                               ++argv;
+                                               --argc;
+                                       } else
+                                               precision = 0;
+                               } else
+                                       while (ISDIGIT(*f)) {
+                                               ++f;
+                                               ++direc_length;
+                                       }
+                       }
+                       if (*f == 'l' || *f == 'L' || *f == 'h') {
+                               ++f;
+                               ++direc_length;
+                       }
+                       /*  
+                          if (!strchr ("diouxXfeEgGcs", *f))
+                          fprintf(stderr, "%%%c: invalid directive", *f);
+                        */
+                       ++direc_length;
+                       if (argc > 0) {
+                               print_direc(direc_start, direc_length, field_width,
+                                                       precision, *argv);
+                               ++argv;
+                               --argc;
+                       } else
+                               print_direc(direc_start, direc_length, field_width,
+                                                       precision, "");
+                       break;
+
+               case '\\':
+                       f += print_esc(f);
+                       break;
+
+               default:
+                       putchar(*f);
+               }
+       }
+
+       return save_argc - argc;
+}
+
+/* Print a \ escape sequence starting at ESCSTART.
+   Return the number of characters in the escape sequence
+   besides the backslash. */
+
+static int print_esc(char *escstart)
+{
+       register char *p = escstart + 1;
+       int esc_value = 0;                      /* Value of \nnn escape. */
+       int esc_length;                         /* Length of \nnn escape. */
+
+       /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
+       if (*p == 'x') {
+               for (esc_length = 0, ++p;
+                        esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
+                       esc_value = esc_value * 16 + hextobin(*p);
+/*      if (esc_length == 0)
+       fprintf(stderr, "missing hex in esc");
+*/
+               putchar(esc_value);
+       } else if (*p == '0') {
+               for (esc_length = 0, ++p;
+                        esc_length < 3 && isodigit(*p); ++esc_length, ++p)
+                       esc_value = esc_value * 8 + octtobin(*p);
+               putchar(esc_value);
+       } else if (strchr("\"\\abcfnrtv", *p))
+               print_esc_char(*p++);
+/*  else
+    fprintf(stderr, "\\%c: invalid esc", *p);
+*/
+       return p - escstart - 1;
+}
+
+/* Output a single-character \ escape.  */
+
+static void print_esc_char(int c)
+{
+       switch (c) {
+       case 'a':                                       /* Alert. */
+               putchar(7);
+               break;
+       case 'b':                                       /* Backspace. */
+               putchar(8);
+               break;
+       case 'c':                                       /* Cancel the rest of the output. */
+               exit(0);
+               break;
+       case 'f':                                       /* Form feed. */
+               putchar(12);
+               break;
+       case 'n':                                       /* New line. */
+               putchar(10);
+               break;
+       case 'r':                                       /* Carriage return. */
+               putchar(13);
+               break;
+       case 't':                                       /* Horizontal tab. */
+               putchar(9);
+               break;
+       case 'v':                                       /* Vertical tab. */
+               putchar(11);
+               break;
+       default:
+               putchar(c);
+               break;
+       }
+}
+
+/* Print string STR, evaluating \ escapes. */
+
+static void print_esc_string(char *str)
+{
+       for (; *str; str++)
+               if (*str == '\\')
+                       str += print_esc(str);
+               else
+                       putchar(*str);
+}
+
+static void
+print_direc(char *start, size_t length, int field_width, int precision,
+                       char *argument)
+{
+       char *p;                                        /* Null-terminated copy of % directive. */
+
+       p = xmalloc((unsigned) (length + 1));
+       strncpy(p, start, length);
+       p[length] = 0;
+
+       switch (p[length - 1]) {
+       case 'd':
+       case 'i':
+               if (field_width < 0) {
+                       if (precision < 0)
+                               printf(p, xstrtol(argument));
+                       else
+                               printf(p, precision, xstrtol(argument));
+               } else {
+                       if (precision < 0)
+                               printf(p, field_width, xstrtol(argument));
+                       else
+                               printf(p, field_width, precision, xstrtol(argument));
+               }
+               break;
+
+       case 'o':
+       case 'u':
+       case 'x':
+       case 'X':
+               if (field_width < 0) {
+                       if (precision < 0)
+                               printf(p, xstrtoul(argument));
+                       else
+                               printf(p, precision, xstrtoul(argument));
+               } else {
+                       if (precision < 0)
+                               printf(p, field_width, xstrtoul(argument));
+                       else
+                               printf(p, field_width, precision, xstrtoul(argument));
+               }
+               break;
+
+       case 'f':
+       case 'e':
+       case 'E':
+       case 'g':
+       case 'G':
+               if (field_width < 0) {
+                       if (precision < 0)
+                               printf(p, xstrtod(argument));
+                       else
+                               printf(p, precision, xstrtod(argument));
+               } else {
+                       if (precision < 0)
+                               printf(p, field_width, xstrtod(argument));
+                       else
+                               printf(p, field_width, precision, xstrtod(argument));
+               }
+               break;
+
+       case 'c':
+               printf(p, *argument);
+               break;
+
+       case 's':
+               if (field_width < 0) {
+                       if (precision < 0)
+                               printf(p, argument);
+                       else
+                               printf(p, precision, argument);
+               } else {
+                       if (precision < 0)
+                               printf(p, field_width, argument);
+                       else
+                               printf(p, field_width, precision, argument);
+               }
+               break;
+       }
+
+       free(p);
+}
+
+static unsigned long xstrtoul(char *s)
+{
+       char *end;
+       unsigned long val;
+
+       errno = 0;
+       val = strtoul(s, &end, 0);
+       verify(s, end);
+       return val;
+}
+
+static long xstrtol(char *s)
+{
+       char *end;
+       long val;
+
+       errno = 0;
+       val = strtol(s, &end, 0);
+       verify(s, end);
+       return val;
+}
+
+static double xstrtod(char *s)
+{
+       char *end;
+       double val;
+
+       errno = 0;
+       val = strtod(s, &end);
+       verify(s, end);
+       return val;
+}
+
+static void verify(char *s, char *end)
+{
+       if (errno) {
+               fprintf(stderr, "%s", s);
+               exit_status = 1;
+       } else if (*end) {
+               /*
+                  if (s == end)
+                  fprintf(stderr, "%s: expected numeric", s);
+                  else
+                  fprintf(stderr, "%s: not completely converted", s);
+                */
+               exit_status = 1;
+       }
+}
diff --git a/pristine_setup.sh b/pristine_setup.sh
new file mode 100755 (executable)
index 0000000..62f3f30
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# To compile BusyBox without touching the original sources
+# (as might be interesting for multi-target builds), create 
+# an empty directory, cd into it, and run this program by
+# giving its explicit path (kind of like how you would run
+# configure, if BusyBox had one).  Then you should be ready
+# to "make".  Files in the build tree, in particular Config.h,
+# will override those in the pristine source tree.
+#
+# If you use a ? in your path name, you lose, see sed command below.
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+DIR=${0%%/pristine_setup.sh}
+if [ ! -d $DIR ]; then
+  echo "unexpected problem: $DIR is not a directory.  Aborting pristine setup"
+  exit
+fi
+
+echo " "
+
+if [ -e ./Config.h ]; then
+    echo "./Config.h already exists: not overwriting"
+    exit
+fi
+
+if [ -e ./Makefile ]; then
+    echo "./Makefile already exists: not overwriting"
+fi
+
+sed -e "s?BB_SRC_DIR =.*?BB_SRC_DIR = $DIR?" <$DIR/Makefile >Makefile || exit
+cp $DIR/Config.h Config.h || exit
+#mkdir -p pwd_grp
+
+echo " "
+echo "You may now type 'make' to build busybox in this directory"
+echo "($PWD) using the pristine sources in $DIR"
+echo " "
+
diff --git a/ps.c b/ps.c
new file mode 100644 (file)
index 0000000..d16d55b
--- /dev/null
+++ b/ps.c
@@ -0,0 +1,384 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini ps implementation(s) for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ *
+ * This contains _two_ implementations of ps for Linux.  One uses the
+ * traditional /proc virtual filesystem, and the other use the devps kernel
+ * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <linux/major.h>
+#include "busybox.h"
+
+static const int TERMINAL_WIDTH = 79;      /* not 80 in case terminal has linefold bug */
+
+
+
+#if ! defined BB_FEATURE_USE_DEVPS_PATCH
+
+/* The following is the first ps implementation --
+ * the one using the /proc virtual filesystem.
+ */
+
+typedef struct proc_s {
+       char cmd[16];                                   /* basename of executable file in call to exec(2) */
+       int ruid;                                               /* real only (sorry) */
+       int pid;                                                /* process id */
+       int ppid;                                               /* pid of parent process */
+       char state;                                             /* single-char code for process state (S=sleeping) */
+       unsigned int vmsize;                    /* size of process as far as the vm is concerned */
+       char ttyname[9];                                /* tty device */
+} proc_t;
+
+
+
+static int file2str(char *filename, char *ret, int cap)
+{
+       int fd, num_read;
+
+       if ((fd = open(filename, O_RDONLY, 0)) == -1)
+               return -1;
+       if ((num_read = read(fd, ret, cap - 1)) <= 0)
+               return -1;
+       ret[num_read] = 0;
+       close(fd);
+       return num_read;
+}
+
+
+static char master[] = "pqrstuvwxyzabcde";
+#define MAJOR(x) ((x) >> 8)
+#define MINOR(x) ((x) & 0xff)
+
+static void dev_to_name(dev_t dev, char *name)
+{
+       if (MAJOR(dev) == TTY_MAJOR)
+               if (MINOR(dev) < 64)
+                       sprintf(name,"tty%d", (int)MINOR(dev));
+               else
+                       sprintf(name,"ttyS%d", (int)MINOR(dev)-64);
+       else if (MAJOR(dev) == PTY_SLAVE_MAJOR)
+               sprintf(name,"tty%c%x", master[MINOR(dev) / 16], (int)MINOR(dev) & 0xf);
+       else
+               strcpy(name, "");
+}
+
+
+static void parse_proc_status(char *S, proc_t * P)
+{
+       char *tmp;
+
+       memset(P->cmd, 0, sizeof P->cmd);
+       sscanf(S, "Name:\t%15c", P->cmd);
+       tmp = strchr(P->cmd, '\n');
+       if (tmp)
+               *tmp = '\0';
+       tmp = strstr(S, "State");
+       sscanf(tmp, "State:\t%c", &P->state);
+
+       P->vmsize = 0;
+       tmp = strstr(S, "Pid:");
+       if (tmp)
+               sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid);
+       else
+               error_msg("Internal error!");
+
+       /* For busybox, ignoring effective, saved, etc. */
+       tmp = strstr(S, "Uid:");
+       if (tmp)
+               sscanf(tmp, "Uid:\t%d", &P->ruid);
+       else
+               error_msg("Internal error!");
+
+       P->vmsize = 0;
+       if ((tmp = strstr(S, "VmSize:")) != NULL)
+               sscanf(tmp, "VmSize:\t%d", &P->vmsize);
+       else if ((tmp = strstr(S, "Mem:")) != NULL)
+               sscanf(tmp, "MemSize:\t%d", &P->vmsize);
+#if 0
+       else
+               error_msg("Internal error!");
+#endif
+}
+
+
+static void parse_proc_stat(char *S, proc_t * P)
+{
+       char *tmp;
+
+       /* pid (name) */
+       tmp = strrchr(S, ')');
+       /* state */
+       tmp += 4;
+       /* ppid */
+       tmp = strchr(tmp, ' ')+1;
+       /* pgrp */
+       tmp = strchr(tmp, ' ')+1;
+       /* session */
+       tmp = strchr(tmp, ' ')+1;
+       /* tty */
+       dev_to_name(atoi(tmp), P->ttyname);
+       tmp = strchr(tmp, ' ')+1;
+
+#if 0
+       /* tty_pgrp */
+       tmp = strchr(tmp, ' ')+1;
+       /* flags */
+       tmp = strchr(tmp, ' ')+1;
+       /* min_flt */
+       tmp = strchr(tmp, ' ')+1;
+       /* cmin_flt */
+       tmp = strchr(tmp, ' ')+1;
+       /* maj_flt */
+       tmp = strchr(tmp, ' ')+1;
+       /* cmaj_flt */
+       tmp = strchr(tmp, ' ')+1;
+       /* utime */
+       tmp = strchr(tmp, ' ')+1;
+       /* stime */
+       tmp = strchr(tmp, ' ')+1;
+       /* cutime */
+       tmp = strchr(tmp, ' ')+1;
+       /* cstime */
+       tmp = strchr(tmp, ' ')+1;
+       /* priority */
+       tmp = strchr(tmp, ' ')+1;
+       /* nice */
+       tmp = strchr(tmp, ' ')+1;
+       /* timeout */
+       tmp = strchr(tmp, ' ')+1;
+       /* it_real_value */
+       tmp = strchr(tmp, ' ')+1;
+       /* start_time */
+       tmp = strchr(tmp, ' ')+1;
+       /* vsize */
+       tmp = strchr(tmp, ' ')+1;
+       /* rss */
+       tmp = strchr(tmp, ' ')+1;
+       /* rsslim*/
+       tmp = strchr(tmp, ' ')+1;
+       /* start_code */
+       tmp = strchr(tmp, ' ')+1;
+       /* end_code */
+       tmp = strchr(tmp, ' ')+1;
+       /* start_stack */
+       tmp = strchr(tmp, ' ')+1;
+       /* sp */
+       tmp = strchr(tmp, ' ')+1;
+       /* ip */
+       tmp = strchr(tmp, ' ')+1;
+       /* signal */
+       tmp = strchr(tmp, ' ')+1;
+       /* blocked */
+       tmp = strchr(tmp, ' ')+1;
+       /* sigignore */
+       tmp = strchr(tmp, ' ')+1;
+       /* sigcatch */
+       tmp = strchr(tmp, ' ')+1;
+       /* wchan */
+       tmp = strchr(tmp, ' ')+1;
+       /* nswap */
+       tmp = strchr(tmp, ' ')+1;
+       /* cnswap */
+       tmp = strchr(tmp, ' ')+1;
+#endif 
+}
+
+
+extern int ps_main(int argc, char **argv)
+{
+       proc_t p;
+       DIR *dir;
+       FILE *file;
+       struct dirent *entry;
+       char path[32], sbuf[512];
+       char uidName[9];
+       int len, i, c;
+#ifdef BB_FEATURE_AUTOWIDTH
+       struct winsize win = { 0, 0, 0, 0 };
+       int terminal_width = TERMINAL_WIDTH;
+#else
+#define terminal_width  TERMINAL_WIDTH
+#endif
+
+
+
+       dir = opendir("/proc");
+       if (!dir)
+               error_msg_and_die("Can't open /proc");
+
+#ifdef BB_FEATURE_AUTOWIDTH
+               ioctl(fileno(stdout), TIOCGWINSZ, &win);
+               if (win.ws_col > 0)
+                       terminal_width = win.ws_col - 1;
+#endif
+
+       printf("%5s %-7s %-8s %6s %5s %s\n", "PID", "TTY", "Uid",
+                       "Size", "State", "Command");
+       while ((entry = readdir(dir)) != NULL) {
+               if (!isdigit(*entry->d_name))
+                       continue;
+               sprintf(path, "/proc/%s/status", entry->d_name);
+               if ((file2str(path, sbuf, sizeof sbuf)) != -1) {
+                       parse_proc_status(sbuf, &p);
+               }
+
+               sprintf(path, "/proc/%s/stat", entry->d_name);
+               if ((file2str(path, sbuf, sizeof sbuf)) != -1) {
+                       parse_proc_stat(sbuf, &p);
+               }
+
+               /* Make some adjustments as needed */
+               my_getpwuid(uidName, p.ruid);
+               if (*uidName == '\0')
+                       sprintf(uidName, "%d", p.ruid);
+
+               sprintf(path, "/proc/%s/cmdline", entry->d_name);
+               file = fopen(path, "r");
+               if (file == NULL)
+                       continue;
+               i = 0;
+               len = printf("%5d %-7s %-8s %6d   %c   ",
+                               p.pid, p.ttyname, uidName, p.vmsize, p.state);
+               while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) {
+                       i++;
+                       if (c == '\0')
+                               c = ' ';
+                       putc(c, stdout);
+               }
+               fclose(file);
+               if (i == 0)
+                       printf("[%s]", p.cmd);
+               putchar('\n');
+       }
+       closedir(dir);
+       return EXIT_SUCCESS;
+}
+
+
+#else /* BB_FEATURE_USE_DEVPS_PATCH */
+
+
+/* The following is the second ps implementation --
+ * this one uses the nifty new devps kernel device.
+ */
+
+#include <linux/devps.h> /* For Erik's nifty devps device driver */
+
+
+extern int ps_main(int argc, char **argv)
+{
+       char device[] = "/dev/ps";
+       int i, j, len, fd;
+       pid_t num_pids;
+       pid_t* pid_array = NULL;
+       struct pid_info info;
+       char uidName[9];
+#ifdef BB_FEATURE_AUTOWIDTH
+       struct winsize win = { 0, 0, 0, 0 };
+       int terminal_width = TERMINAL_WIDTH;
+#else
+#define terminal_width  TERMINAL_WIDTH
+#endif
+
+       if (argc > 1 && **(argv + 1) == '-') 
+               show_usage();
+
+       /* open device */ 
+       fd = open(device, O_RDONLY);
+       if (fd < 0) 
+               perror_msg_and_die( "open failed for `%s'", device);
+
+       /* Find out how many processes there are */
+       if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
+               perror_msg_and_die( "\nDEVPS_GET_PID_LIST");
+       
+       /* Allocate some memory -- grab a few extras just in case 
+        * some new processes start up while we wait. The kernel will
+        * just ignore any extras if we give it too many, and will trunc.
+        * the list if we give it too few.  */
+       pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
+       pid_array[0] = num_pids+10;
+
+       /* Now grab the pid list */
+       if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
+               perror_msg_and_die("\nDEVPS_GET_PID_LIST");
+
+#ifdef BB_FEATURE_AUTOWIDTH
+               ioctl(fileno(stdout), TIOCGWINSZ, &win);
+               if (win.ws_col > 0)
+                       terminal_width = win.ws_col - 1;
+#endif
+
+       /* Print up a ps listing */
+       printf("  PID  Uid     Stat Command\n");
+
+       for (i=1; i<pid_array[0] ; i++) {
+           info.pid = pid_array[i];
+
+           if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+                       perror_msg_and_die("\nDEVPS_GET_PID_INFO");
+           
+               /* Make some adjustments as needed */
+               my_getpwuid(uidName, info.euid);
+               if (*uidName == '\0')
+                       sprintf(uidName, "%ld", info.euid);
+
+               len = printf("%5d %-8s %c    ", info.pid, uidName, info.state);
+
+               if (strlen(info.command_line) > 1) {
+                       for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) {
+                               if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') {
+                                       *(info.command_line+j) = ' ';
+                               }
+                       }
+                       *(info.command_line+j) = '\0';
+                       puts(info.command_line);
+               } else {
+                       printf("[%s]\n", info.name);
+               }
+       }
+
+       /* Free memory */
+       free( pid_array);
+
+       /* close device */
+       if (close (fd) != 0) 
+               perror_msg_and_die("close failed for `%s'", device);
+       exit (0);
+}
+
+#endif /* BB_FEATURE_USE_DEVPS_PATCH */
+
diff --git a/pwd.c b/pwd.c
new file mode 100644 (file)
index 0000000..9c5d70c
--- /dev/null
+++ b/pwd.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini pwd implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int pwd_main(int argc, char **argv)
+{
+       static char *buf; 
+       
+       buf = xgetcwd(buf);
+       
+       if (buf != NULL) {
+               puts(buf);
+               return EXIT_SUCCESS;
+       }
+       return EXIT_FAILURE;
+}
diff --git a/pwd_grp/.indent.pro b/pwd_grp/.indent.pro
new file mode 100644 (file)
index 0000000..492ecf1
--- /dev/null
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/pwd_grp/__getgrent.c b/pwd_grp/__getgrent.c
new file mode 100644 (file)
index 0000000..ffdfb75
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * __getgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "grp.h"
+#include "config.h"
+
+/*
+ * This is the core group-file read function.  It behaves exactly like
+ * getgrent() except that it is passed a file descriptor.  getgrent()
+ * is just a wrapper for this function.
+ */
+struct group *__getgrent(int grp_fd)
+{
+#ifndef GR_SCALE_DYNAMIC
+       static char line_buff[GR_MAX_LINE_LEN];
+       static char *members[GR_MAX_MEMBERS];
+#else
+       static char *line_buff = NULL;
+       static char **members = NULL;
+       short line_index;
+       short buff_size;
+#endif
+       static struct group group;
+       register char *ptr;
+       char *field_begin;
+       int member_num;
+       char *endptr;
+       int line_len;
+
+
+       /* We use the restart label to handle malformatted lines */
+  restart:
+#ifdef GR_SCALE_DYNAMIC
+       line_index = 0;
+       buff_size = 256;
+#endif
+
+#ifndef GR_SCALE_DYNAMIC
+       /* Read the line into the static buffer */
+       if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0)
+               return NULL;
+       field_begin = strchr(line_buff, '\n');
+       if (field_begin != NULL)
+               lseek(grp_fd, (long) (1 + field_begin - (line_buff + line_len)),
+                         SEEK_CUR);
+       else {                                          /* The line is too long - skip it :-\ */
+
+               do {
+                       if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0)
+                               return NULL;
+               } while (!(field_begin = strchr(line_buff, '\n')));
+               lseek(grp_fd, (long) ((field_begin - line_buff) - line_len + 1),
+                         SEEK_CUR);
+               goto restart;
+       }
+       if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' ||
+               *line_buff == '\t')
+               goto restart;
+       *field_begin = '\0';
+
+#else                                                  /* !GR_SCALE_DYNAMIC */
+       line_buff = realloc(line_buff, buff_size);
+       while (1) {
+               if ((line_len = read(grp_fd, line_buff + line_index,
+                                                        buff_size - line_index)) <= 0)
+                       return NULL;
+               field_begin = strchr(line_buff, '\n');
+               if (field_begin != NULL) {
+                       lseek(grp_fd,
+                                 (long) (1 + field_begin -
+                                                 (line_len + line_index + line_buff)), SEEK_CUR);
+                       *field_begin = '\0';
+                       if (*line_buff == '#' || *line_buff == ' '
+                               || *line_buff == '\n' || *line_buff == '\t')
+                               goto restart;
+                       break;
+               } else {                                /* Allocate some more space */
+
+                       line_index = buff_size;
+                       buff_size += 256;
+                       line_buff = realloc(line_buff, buff_size);
+               }
+       }
+#endif                                                 /* GR_SCALE_DYNAMIC */
+
+       /* Now parse the line */
+       group.gr_name = line_buff;
+       ptr = strchr(line_buff, ':');
+       if (ptr == NULL)
+               goto restart;
+       *ptr++ = '\0';
+
+       group.gr_passwd = ptr;
+       ptr = strchr(ptr, ':');
+       if (ptr == NULL)
+               goto restart;
+       *ptr++ = '\0';
+
+       field_begin = ptr;
+       ptr = strchr(ptr, ':');
+       if (ptr == NULL)
+               goto restart;
+       *ptr++ = '\0';
+
+       group.gr_gid = (gid_t) strtoul(field_begin, &endptr, 10);
+       if (*endptr != '\0')
+               goto restart;
+
+       member_num = 0;
+       field_begin = ptr;
+
+#ifndef GR_SCALE_DYNAMIC
+       while ((ptr = strchr(ptr, ',')) != NULL) {
+               *ptr = '\0';
+               ptr++;
+               members[member_num] = field_begin;
+               field_begin = ptr;
+               member_num++;
+       }
+       if (*field_begin == '\0')
+               members[member_num] = NULL;
+       else {
+               members[member_num] = field_begin;
+               members[member_num + 1] = NULL;
+       }
+#else                                                  /* !GR_SCALE_DYNAMIC */
+       if (members != NULL)
+           free(members);
+       members = (char **) malloc((member_num + 1) * sizeof(char *));
+       for ( ; field_begin && *field_begin != '\0'; field_begin = ptr) {
+           if ((ptr = strchr(field_begin, ',')) != NULL)
+               *ptr++ = '\0';
+           members[member_num++] = field_begin;
+           members = (char **) realloc(members,
+                   (member_num + 1) * sizeof(char *));
+       }
+       members[member_num] = NULL;
+#endif                                                 /* GR_SCALE_DYNAMIC */
+
+       group.gr_mem = members;
+       return &group;
+}
diff --git a/pwd_grp/__getpwent.c b/pwd_grp/__getpwent.c
new file mode 100644 (file)
index 0000000..f60bfec
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include "pwd.h"
+
+#define PWD_BUFFER_SIZE 256
+
+/* This isn't as flash as my previous version -- it doesn't dynamically
+  scale down the gecos on too-long lines, but it also makes fewer syscalls,
+  so it's probably nicer.  Write me if you want the old version.  Maybe I
+  should include it as a build-time option... ?
+  -Nat <ndf@linux.mit.edu> */
+
+struct passwd *__getpwent(int pwd_fd)
+{
+       static char line_buff[PWD_BUFFER_SIZE];
+       static struct passwd passwd;
+       char *field_begin;
+       char *endptr;
+       char *gid_ptr=NULL;
+       char *uid_ptr=NULL;
+       int line_len;
+       int i;
+
+       /* We use the restart label to handle malformatted lines */
+  restart:
+       /* Read the passwd line into the static buffer using a minimal of
+          syscalls. */
+       if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
+               return NULL;
+       field_begin = strchr(line_buff, '\n');
+       if (field_begin != NULL)
+               lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)),
+                         SEEK_CUR);
+       else {                                          /* The line is too long - skip it. :-\ */
+
+               do {
+                       if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
+                               return NULL;
+               } while (!(field_begin = strchr(line_buff, '\n')));
+               lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1,
+                         SEEK_CUR);
+               goto restart;
+       }
+       if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' ||
+               *line_buff == '\t')
+               goto restart;
+       *field_begin = '\0';
+
+       /* We've read the line; now parse it. */
+       field_begin = line_buff;
+       for (i = 0; i < 7; i++) {
+               switch (i) {
+               case 0:
+                       passwd.pw_name = field_begin;
+                       break;
+               case 1:
+                       passwd.pw_passwd = field_begin;
+                       break;
+               case 2:
+                       uid_ptr = field_begin;
+                       break;
+               case 3:
+                       gid_ptr = field_begin;
+                       break;
+               case 4:
+                       passwd.pw_gecos = field_begin;
+                       break;
+               case 5:
+                       passwd.pw_dir = field_begin;
+                       break;
+               case 6:
+                       passwd.pw_shell = field_begin;
+                       break;
+               }
+               if (i < 6) {
+                       field_begin = strchr(field_begin, ':');
+                       if (field_begin == NULL)
+                               goto restart;
+                       *field_begin++ = '\0';
+               }
+       }
+       passwd.pw_gid = (gid_t) strtoul(gid_ptr, &endptr, 10);
+       if (*endptr != '\0')
+               goto restart;
+
+       passwd.pw_uid = (uid_t) strtoul(uid_ptr, &endptr, 10);
+       if (*endptr != '\0')
+               goto restart;
+
+       return &passwd;
+}
diff --git a/pwd_grp/config.h b/pwd_grp/config.h
new file mode 100644 (file)
index 0000000..eb029a3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * config.h - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef _CONFIG_GRP_H
+#define _CONFIG_GRP_H
+
+/*
+ * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
+ * so that lines of any length can be used.  On very very small systems,
+ * you may want to leave this undefined becasue it will make the grp functions
+ * somewhat larger (because of the inclusion of malloc and the code necessary).
+ * On larger systems, you will want to define this, because grp will _not_
+ * deal with long lines gracefully (they will be skipped).
+ */
+#undef GR_SCALE_DYNAMIC
+
+#ifndef GR_SCALE_DYNAMIC
+/*
+ * If scaling is not dynamic, the buffers will be statically allocated, and
+ * maximums must be chosen.  GR_MAX_LINE_LEN is the maximum number of
+ * characters per line in the group file.  GR_MAX_MEMBERS is the maximum
+ * number of members of any given group.
+ */
+#define GR_MAX_LINE_LEN 128
+/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
+#define GR_MAX_MEMBERS 11
+
+#endif /* !GR_SCALE_DYNAMIC */
+
+
+/*
+ * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
+ * space for it's GID array before calling setgroups().  This is probably
+ * unnecessary scalage, so it's undefined by default.
+ */
+#undef GR_DYNAMIC_GROUP_LIST
+
+#ifndef GR_DYNAMIC_GROUP_LIST
+/*
+ * GR_MAX_GROUPS is the size of the static array initgroups() uses for
+ * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined.
+ */
+#define GR_MAX_GROUPS 64
+
+#endif /* !GR_DYNAMIC_GROUP_LIST */
+
+#endif /* !_CONFIG_GRP_H */
diff --git a/pwd_grp/fgetgrent.c b/pwd_grp/fgetgrent.c
new file mode 100644 (file)
index 0000000..cefe6e7
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "grp.h"
+
+struct group *fgetgrent(FILE * file)
+{
+       if (file == NULL) {
+               errno = EINTR;
+               return NULL;
+       }
+
+       return __getgrent(fileno(file));
+}
diff --git a/pwd_grp/fgetpwent.c b/pwd_grp/fgetpwent.c
new file mode 100644 (file)
index 0000000..294d334
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include "pwd.h"
+
+struct passwd *fgetpwent(FILE * file)
+{
+       if (file == NULL) {
+               errno = EINTR;
+               return NULL;
+       }
+
+       return __getpwent(fileno(file));
+}
diff --git a/pwd_grp/getgrgid.c b/pwd_grp/getgrgid.c
new file mode 100644 (file)
index 0000000..620a853
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * getgrgid.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "grp.h"
+
+struct group *getgrgid(const gid_t gid)
+{
+       struct group *group;
+       int grp_fd;
+
+       if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
+               return NULL;
+
+       while ((group = __getgrent(grp_fd)) != NULL)
+               if (group->gr_gid == gid) {
+                       close(grp_fd);
+                       return group;
+               }
+
+       close(grp_fd);
+       return NULL;
+}
diff --git a/pwd_grp/getgrnam.c b/pwd_grp/getgrnam.c
new file mode 100644 (file)
index 0000000..55825b1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * getgrnam.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "grp.h"
+
+struct group *getgrnam(const char *name)
+{
+       int grp_fd;
+       struct group *group;
+
+       if (name == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
+               return NULL;
+
+       while ((group = __getgrent(grp_fd)) != NULL)
+               if (!strcmp(group->gr_name, name)) {
+                       close(grp_fd);
+                       return group;
+               }
+
+       close(grp_fd);
+       return NULL;
+}
diff --git a/pwd_grp/getpw.c b/pwd_grp/getpw.c
new file mode 100644 (file)
index 0000000..dc33da2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * getpw.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include "pwd.h"
+
+int getpw(uid_t uid, char *buf)
+{
+       struct passwd *passwd;
+
+       if (buf == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+       if ((passwd = getpwuid(uid)) == NULL)
+               return -1;
+
+       if (sprintf (buf, "%s:%s:%u:%u:%s:%s:%s", passwd->pw_name, passwd->pw_passwd,
+                passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos, passwd->pw_dir,
+                passwd->pw_shell) < 0) {
+               errno = ENOBUFS;
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/pwd_grp/getpwnam.c b/pwd_grp/getpwnam.c
new file mode 100644 (file)
index 0000000..cdd1655
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "pwd.h"
+
+
+struct passwd *getpwnam(const char *name)
+{
+       int passwd_fd;
+       struct passwd *passwd;
+
+       if (name == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
+               return NULL;
+
+       while ((passwd = __getpwent(passwd_fd)) != NULL)
+               if (!strcmp(passwd->pw_name, name)) {
+                       close(passwd_fd);
+                       return passwd;
+               }
+
+       close(passwd_fd);
+       return NULL;
+}
diff --git a/pwd_grp/getpwuid.c b/pwd_grp/getpwuid.c
new file mode 100644 (file)
index 0000000..7182119
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "pwd.h"
+
+struct passwd *getpwuid(uid_t uid)
+{
+       int passwd_fd;
+       struct passwd *passwd;
+
+       if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
+               return NULL;
+
+       while ((passwd = __getpwent(passwd_fd)) != NULL)
+               if (passwd->pw_uid == uid) {
+                       close(passwd_fd);
+                       return passwd;
+               }
+
+       close(passwd_fd);
+       return NULL;
+}
diff --git a/pwd_grp/grent.c b/pwd_grp/grent.c
new file mode 100644 (file)
index 0000000..7e16236
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * grent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * setgrent(), endgrent(), and getgrent() are mutually-dependent functions,
+ * so they are all included in the same object file, and thus all linked
+ * in together.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include "grp.h"
+
+static int grp_fd = -1;
+
+void setgrent(void)
+{
+       if (grp_fd != -1)
+               close(grp_fd);
+       grp_fd = open("/etc/group", O_RDONLY);
+}
+
+void endgrent(void)
+{
+       if (grp_fd != -1)
+               close(grp_fd);
+       grp_fd = -1;
+}
+
+struct group *getgrent(void)
+{
+       if (grp_fd == -1)
+               return NULL;
+       return __getgrent(grp_fd);
+}
diff --git a/pwd_grp/grp.h b/pwd_grp/grp.h
new file mode 100644 (file)
index 0000000..87d4115
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef        __BB_GRP_H
+#define        __BB_GRP_H
+
+#if defined USE_SYSTEM_PWD_GRP
+#include <grp.h>
+#else
+
+#include <sys/types.h>
+#include <features.h>
+#include <stdio.h>
+
+/* The group structure */
+struct group
+{
+  char *gr_name;               /* Group name.  */
+  char *gr_passwd;             /* Password.    */
+  gid_t gr_gid;                        /* Group ID.    */
+  char **gr_mem;               /* Member list. */
+};
+
+extern void setgrent __P ((void));
+extern void endgrent __P ((void));
+extern struct group * getgrent __P ((void));
+
+extern struct group * getgrgid __P ((__const gid_t gid));
+extern struct group * getgrnam __P ((__const char * name));
+
+extern struct group * fgetgrent __P ((FILE * file));
+
+extern int setgroups __P ((size_t n, __const gid_t * groups));
+extern int initgroups __P ((__const char * user, gid_t gid));
+
+extern struct group * __getgrent __P ((int grp_fd));
+
+#endif /* USE_SYSTEM_PWD_GRP */
+#endif /* __BB_GRP_H */
+
diff --git a/pwd_grp/initgroups.c b/pwd_grp/initgroups.c
new file mode 100644 (file)
index 0000000..d45badd
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * initgroups.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include "grp.h"
+#include "config.h"
+
+int initgroups(__const char *user, gid_t gid)
+{
+       register struct group *group;
+
+#ifndef GR_DYNAMIC_GROUP_LIST
+       gid_t group_list[GR_MAX_GROUPS];
+#else
+       gid_t *group_list = NULL;
+#endif
+       register char **tmp_mem;
+       int num_groups;
+       int grp_fd;
+
+
+       if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
+               return -1;
+
+       num_groups = 0;
+#ifdef GR_DYNAMIC_GROUP_LIST
+       group_list = (gid_t *) realloc(group_list, 1);
+#endif
+       group_list[num_groups] = gid;
+#ifndef GR_DYNAMIC_GROUP_LIST
+       while (num_groups < GR_MAX_GROUPS &&
+                  (group = __getgrent(grp_fd)) != NULL)
+#else
+       while ((group = __getgrent(grp_fd)) != NULL)
+#endif
+       {
+               if (group->gr_gid != gid)
+               {
+                       tmp_mem = group->gr_mem;
+                       while (*tmp_mem != NULL) {
+                               if (!strcmp(*tmp_mem, user)) {
+                                       num_groups++;
+#ifdef GR_DYNAMIC_GROUP_LIST
+                                       group_list = (gid_t *) realloc(group_list, num_groups *
+                                               sizeof(gid_t *));
+#endif
+                                       group_list[num_groups-1] = group->gr_gid;
+                               }
+                               tmp_mem++;
+                       }
+               }
+       }
+       close(grp_fd);
+       return setgroups(num_groups, group_list);
+}
diff --git a/pwd_grp/putpwent.c b/pwd_grp/putpwent.c
new file mode 100644 (file)
index 0000000..a54fde6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * putpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "pwd.h"
+
+int putpwent(const struct passwd *passwd, FILE * f)
+{
+       if (passwd == NULL || f == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+       if (fprintf (f, "%s:%s:%u:%u:%s:%s:%s\n", passwd->pw_name, passwd->pw_passwd,
+                passwd->pw_uid, passwd->pw_gid, passwd->pw_gecos, passwd->pw_dir,
+                passwd->pw_shell) < 0)
+               return -1;
+
+       return 0;
+}
diff --git a/pwd_grp/pwd.h b/pwd_grp/pwd.h
new file mode 100644 (file)
index 0000000..e603a96
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef        __BB_PWD_H
+#define        __BB_PWD_H
+
+#if defined USE_SYSTEM_PWD_GRP
+#include <pwd.h>
+#else
+
+#include <sys/types.h>
+#include <features.h>
+#include <stdio.h>
+
+/* The passwd structure.  */
+struct passwd
+{
+  char *pw_name;               /* Username.  */
+  char *pw_passwd;             /* Password.  */
+  uid_t pw_uid;                        /* User ID.  */
+  gid_t pw_gid;                        /* Group ID.  */
+  char *pw_gecos;              /* Real name.  */
+  char *pw_dir;                        /* Home directory.  */
+  char *pw_shell;              /* Shell program.  */
+};
+
+extern void setpwent __P ((void));
+extern void endpwent __P ((void));
+extern struct passwd * getpwent __P ((void));
+
+extern int putpwent __P ((__const struct passwd * __p, FILE * __f));
+extern int getpw __P ((uid_t uid, char *buf));
+
+extern struct passwd * fgetpwent __P ((FILE * file));
+
+extern struct passwd * getpwuid __P ((__const uid_t));
+extern struct passwd * getpwnam __P ((__const char *));
+
+extern struct passwd * __getpwent __P ((__const int passwd_fd));
+
+#endif /* USE_SYSTEM_PWD_GRP */
+#endif /* __BB_PWD_H  */
+
diff --git a/pwd_grp/pwent.c b/pwd_grp/pwent.c
new file mode 100644 (file)
index 0000000..e72e41d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * pwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "pwd.h"
+#include <fcntl.h>
+
+/*
+ * setpwent(), endpwent(), and getpwent() are included in the same object
+ * file, since one cannot be used without the other two, so it makes sense to
+ * link them all in together.
+ */
+
+/* file descriptor for the password file currently open */
+static int pw_fd = -1;
+
+void setpwent(void)
+{
+       if (pw_fd != -1)
+               close(pw_fd);
+
+       pw_fd = open("/etc/passwd", O_RDONLY);
+}
+
+void endpwent(void)
+{
+       if (pw_fd != -1)
+               close(pw_fd);
+       pw_fd = -1;
+}
+
+struct passwd *getpwent(void)
+{
+       if (pw_fd != -1)
+               return (__getpwent(pw_fd));
+       return NULL;
+}
diff --git a/pwd_grp/setgroups.c b/pwd_grp/setgroups.c
new file mode 100644 (file)
index 0000000..e371cb8
--- /dev/null
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Taken from the set of syscalls for uClibc
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h" 
+
+#include <errno.h>
+#include <unistd.h>
+#include <features.h>
+#include <sys/types.h>
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+   _syscall* defined.  */
+#define __LIBRARY__
+#include <sys/syscall.h>
+#include "grp_.h"
+
+#if __GNU_LIBRARY__ < 5
+//#define __NR_setgroups        81
+_syscall2(int, setgroups, size_t, size, const gid_t *, list);
+#else
+int setgroups(size_t size, const gid_t * list)
+{
+       return(syscall(__NR_setgroups, size, list));
+}
+#endif
diff --git a/rdate.c b/rdate.c
new file mode 100644 (file)
index 0000000..50be4de
--- /dev/null
+++ b/rdate.c
@@ -0,0 +1,116 @@
+/* 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>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+
+static const int RFC_868_BIAS = 2208988800UL;
+
+static time_t askremotedate(const char *host)
+{
+       struct hostent *h;
+       struct sockaddr_in s_in;
+       struct servent *tserv;
+       unsigned long int nett, localt;
+       int fd;
+
+       h = xgethostbyname(host);         /* get the IP addr */
+
+       if ((tserv = getservbyname("time", "tcp")) == NULL)   /* find port # */
+               perror_msg_and_die("time");
+
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    /* get net connection */
+               perror_msg_and_die("socket");
+
+       memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr));
+       s_in.sin_port= tserv->s_port;
+       s_in.sin_family = AF_INET;
+
+       if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)      /* connect to time server */
+               perror_msg_and_die("%s", host);
+
+       if (read(fd, (void *)&nett, 4) != 4)    /* read time from server */
+               error_msg_and_die("%s did not send the complete time", host);
+
+       close(fd);
+
+       /* convert from network byte order to local byte order.
+        * RFC 868 time is the number of seconds
+        *  since 00:00 (midnight) 1 January 1900 GMT
+        *  the RFC 868 time 2,208,988,800 corresponds to 00:00  1 Jan 1970 GMT
+        * Subtract the RFC 868 time  to get Linux epoch
+        */
+       localt= ntohl(nett) - RFC_868_BIAS;
+
+       return(localt);
+}
+
+int rdate_main(int argc, char **argv)
+{
+       time_t remote_time;
+       int opt;
+       int setdate = 1;
+       int printdate = 1;
+
+       /* Interpret command line args */
+       while ((opt = getopt(argc, argv, "sp")) > 0) {
+               switch (opt) {
+                       case 's':
+                               printdate = 0;
+                               setdate = 1;
+                               break;
+                       case 'p':
+                               printdate = 1;
+                               setdate = 0;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (optind == argc)
+               show_usage();
+
+       remote_time = askremotedate(argv[optind]);
+
+       if (setdate) {
+               if (stime(&remote_time) < 0)
+                       perror_msg_and_die("Could not set time of day");
+       }
+
+       if (printdate)
+               printf("%s", ctime(&remote_time));
+
+       return EXIT_SUCCESS;
+}
diff --git a/readlink.c b/readlink.c
new file mode 100644 (file)
index 0000000..fc5b7c2
--- /dev/null
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini readlink implementation for busybox
+ *
+ * Copyright (C) 1999,2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+int readlink_main(int argc, char **argv)
+{
+       char *buf = NULL;
+
+       /* no options, no getopt */
+
+       if (argc != 2)
+               show_usage();
+
+       buf = xreadlink(argv[1]);
+       if (!buf)
+               return EXIT_FAILURE;
+       puts(buf);
+#ifdef BB_FEATURE_CLEAN_UP
+       free(buf);
+#endif
+
+       return EXIT_SUCCESS;
+}
diff --git a/reboot.c b/reboot.c
new file mode 100644 (file)
index 0000000..456865e
--- /dev/null
+++ b/reboot.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini reboot implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) 
+  #include <sys/reboot.h>
+  #define init_reboot(magic) reboot(magic)
+#else
+  #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
+#endif
+#ifndef RB_ENABLE_CAD
+static const int RB_ENABLE_CAD = 0x89abcdef;
+static const int RB_AUTOBOOT = 0x01234567;
+#endif
+
+extern int reboot_main(int argc, char **argv)
+{
+       int delay = 0; /* delay in seconds before rebooting */
+       int rc;
+
+       while ((rc = getopt(argc, argv, "d:")) > 0) {
+               switch (rc) {
+               case 'd':
+                       delay = atoi(optarg);
+                       break;
+
+               default:
+                       show_usage();
+                       break;
+               }
+       }
+
+       if(delay > 0)
+               sleep(delay);
+
+#ifdef CONFIG_USER_INIT
+               /* Don't kill ourself */
+        signal(SIGTERM,SIG_IGN);
+        signal(SIGHUP,SIG_IGN);
+        setpgrp();
+
+               /* Allow Ctrl-Alt-Del to reboot system. */
+               init_reboot(RB_ENABLE_CAD);
+
+               message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n");
+               sync();
+
+               /* Send signals to every process _except_ pid 1 */
+               message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n");
+               kill(-1, SIGTERM);
+               sleep(1);
+               sync();
+
+               message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n");
+               kill(-1, SIGKILL);
+               sleep(1);
+
+               sync();
+               if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) {
+                       /* bdflush, kupdate not needed for kernels >2.2.11 */
+                       bdflush(1, 0);
+                       sync();
+               }
+
+               init_reboot(RB_AUTOBOOT);
+               exit(0); /* Shrug */
+#else
+#ifdef BB_FEATURE_LINUXRC
+       {
+               /* don't assume init's pid == 1 */
+               long *pid = find_pid_by_name("init");
+               if (!pid || *pid<=0)
+                       pid = find_pid_by_name("linuxrc");
+               if (!pid || *pid<=0)
+                       error_msg_and_die("no process killed");
+               fflush(stdout);
+               return(kill(*pid, SIGTERM));
+       }
+#else
+       return(kill(1, SIGTERM));
+#endif
+#endif
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/renice.c b/renice.c
new file mode 100644 (file)
index 0000000..ec35bdc
--- /dev/null
+++ b/renice.c
@@ -0,0 +1,54 @@
+/*
+ * Mini renice implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include "busybox.h"
+
+
+extern int renice_main(int argc, char **argv)
+{
+       int prio, status = EXIT_SUCCESS;
+       
+       if (argc < 3)   show_usage();
+               
+       prio = atoi(*++argv);
+       if (prio > 20)          prio = 20;
+       if (prio < -20)         prio = -20;
+       
+       while (*++argv) {
+               int ps = atoi(*argv);
+               int oldp = getpriority(PRIO_PROCESS, ps);
+               
+               if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
+                       printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
+               } else {
+                       perror_msg("%d: setpriority", ps);
+                       status = EXIT_FAILURE;
+               }
+       }
+
+       return status;
+}
diff --git a/reset.c b/reset.c
new file mode 100644 (file)
index 0000000..76244ca
--- /dev/null
+++ b/reset.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini reset implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *        and Kent Robotti <robotti@metconnect.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int reset_main(int argc, char **argv)
+{
+          printf("\033[?25h\033c\033[J");
+       return EXIT_SUCCESS;
+}
+
diff --git a/rm.c b/rm.c
new file mode 100644 (file)
index 0000000..51c9f4c
--- /dev/null
+++ b/rm.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rm implementation for busybox
+ *
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include "busybox.h"
+
+extern int rm_main(int argc, char **argv)
+{
+       int status = 0;
+       int opt;
+       int flags = 0;
+       int i;
+
+       while ((opt = getopt(argc, argv, "fiRr")) != -1) {
+               switch (opt) {
+               case 'f':
+                       flags &= ~FILEUTILS_INTERACTIVE;
+                       flags |= FILEUTILS_FORCE;
+                       break;
+               case 'i':
+                       flags &= ~FILEUTILS_FORCE;
+                       flags |= FILEUTILS_INTERACTIVE;
+                       break;
+               case 'R':
+               case 'r':
+                       flags |= FILEUTILS_RECUR;
+                       break;
+               }
+       }
+
+       if (!(flags & FILEUTILS_FORCE) && optind == argc)
+               show_usage();
+
+       for (i = optind; i < argc; i++) {
+               char *base = get_last_path_component(argv[i]);
+
+               if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) {
+                       error_msg("cannot remove `.' or `..'");
+                       status = 1;
+                       continue;
+               }
+
+               if (remove_file(argv[i], flags) < 0)
+                       status = 1;
+       }
+
+       return status;
+}
diff --git a/rmdir.c b/rmdir.c
new file mode 100644 (file)
index 0000000..4508ad4
--- /dev/null
+++ b/rmdir.c
@@ -0,0 +1,97 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rmdir implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+
+/* Return true if a path is composed of multiple components.  */
+
+static int
+multiple_components_p (const char *path)
+{
+       const char *s = path;
+
+       while (s[0] != '\0' && s[0] != '/')
+               s++;
+
+       while (s[0] == '/')
+               s++;
+
+       return (s[0] != '\0');
+}
+
+
+/* Remove a directory.  Returns 0 if successful, -1 on error.  */
+
+static int
+remove_directory (char *path, int flags)
+{
+       if (!(flags & FILEUTILS_RECUR)) {
+               if (rmdir (path) < 0) {
+                       perror_msg ("unable to remove `%s'", path);
+                       return -1;
+               }
+       } else {
+               if (remove_directory (path, 0) < 0)
+                       return -1;
+
+               if (multiple_components_p (path))
+                       if (remove_directory (dirname (path), flags) < 0)
+                               return -1;
+       }
+
+       return 0;
+}
+
+
+extern int
+rmdir_main (int argc, char **argv)
+{
+       int status = EXIT_SUCCESS;
+       int flags = 0;
+       int i, opt;
+
+       while ((opt = getopt (argc, argv, "p")) != -1)
+               switch (opt) {
+                       case 'p':
+                               flags |= FILEUTILS_RECUR;
+                               break;
+
+                       default:
+                               show_usage ();
+               }
+
+       if (optind == argc)
+               show_usage();
+
+       for (i = optind; i < argc; i++)
+               if (remove_directory (argv[i], flags) < 0)
+                       status = EXIT_FAILURE;
+
+       return status;
+}
diff --git a/rmmod.c b/rmmod.c
new file mode 100644 (file)
index 0000000..affe975
--- /dev/null
+++ b/rmmod.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rmmod implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "busybox.h"
+
+extern int delete_module(const char * name);
+
+
+extern int rmmod_main(int argc, char **argv)
+{
+       int n, ret = EXIT_SUCCESS;
+
+       /* Parse command line. */
+       while ((n = getopt(argc, argv, "a")) != EOF) {
+               switch (n) {
+                       case 'a':
+                               /* Unload _all_ unused modules via NULL delete_module() call */
+                               if (delete_module(NULL))
+                                       perror_msg_and_die("rmmod");
+                               return EXIT_SUCCESS;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (optind == argc)
+                       show_usage();
+
+       for (n = optind; n < argc; n++) {
+               if (delete_module(argv[n]) < 0) {
+                       perror_msg("%s", argv[n]);
+                       ret = EXIT_FAILURE;
+               }
+       }
+
+       return(ret);
+}
diff --git a/route.c b/route.c
new file mode 100644 (file)
index 0000000..d18d4ae
--- /dev/null
+++ b/route.c
@@ -0,0 +1,457 @@
+/* route
+ *
+ * Similar to the standard Unix route, but with only the necessary
+ * parts for AF_INET
+ *
+ * Bjorn Wesen, Axis Communications AB
+ *
+ * Author of the original route:
+ *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *              (derived from FvK's 'route.c     1.70    01/04/94')
+ *
+ * This program is free software; you can redistribute it
+ * and/or  modify it under  the terms of  the GNU General
+ * Public  License as  published  by  the  Free  Software
+ * Foundation;  either  version 2 of the License, or  (at
+ * your option) any later version.
+ *
+ * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
+ * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <linux/param.h>  // HZ
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "busybox.h"
+
+#define _(x) x
+
+#define RTACTION_ADD   1
+#define RTACTION_DEL   2
+#define RTACTION_HELP  3
+#define RTACTION_FLUSH 4
+#define RTACTION_SHOW  5
+
+#define E_NOTFOUND      8
+#define E_SOCK          7
+#define E_LOOKUP        6
+#define E_VERSION       5
+#define E_USAGE         4
+#define E_OPTERR        3
+#define E_INTERN        2
+#define E_NOSUPP        1
+
+/* resolve XXX.YYY.ZZZ.QQQ -> binary */
+
+static int
+INET_resolve(char *name, struct sockaddr *sa)
+{
+       struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
+
+       s_in->sin_family = AF_INET;
+       s_in->sin_port = 0;
+
+       /* Default is special, meaning 0.0.0.0. */
+       if (strcmp(name, "default")==0) {
+               s_in->sin_addr.s_addr = INADDR_ANY;
+               return 1;
+       }
+       /* Look to see if it's a dotted quad. */
+       if (inet_aton(name, &s_in->sin_addr)) {
+               return 0;
+       }
+       /* guess not.. */
+       return -1;
+}
+
+#if defined (SIOCADDRTOLD) || defined (RTF_IRTT)        /* route */
+#define HAVE_NEW_ADDRT 1
+#endif
+#ifdef RTF_IRTT                 /* route */
+#define HAVE_RTF_IRTT 1
+#endif
+#ifdef RTF_REJECT               /* route */
+#define HAVE_RTF_REJECT 1
+#endif
+
+#if HAVE_NEW_ADDRT
+#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
+#define full_mask(x) (x)
+#else
+#define mask_in_addr(x) ((x).rt_genmask)
+#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
+#endif
+
+/* add or delete a route depending on action */
+
+static int
+INET_setroute(int action, int options, char **args)
+{
+       struct rtentry rt;
+       char target[128], gateway[128] = "NONE", netmask[128] = "default";
+       int xflag, isnet;
+       int skfd;
+
+       xflag = 0;
+
+       if (*args == NULL)
+           show_usage();
+       if (strcmp(*args, "-net")==0) {
+               xflag = 1;
+               args++;
+       } else if (strcmp(*args, "-host")==0) {
+               xflag = 2;
+               args++;
+       }
+       safe_strncpy(target, *args++, (sizeof target));
+
+       /* Clean out the RTREQ structure. */
+       memset((char *) &rt, 0, sizeof(struct rtentry));
+
+
+       if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
+               error_msg(_("can't resolve %s"), target);
+               return EXIT_FAILURE;   /* XXX change to E_something */
+       }
+
+       switch (xflag) {
+               case 1:
+                       isnet = 1;
+                       break;
+
+               case 2:
+                       isnet = 0;
+                       break;
+
+               default:
+                       break;
+       }
+
+       /* Fill in the other fields. */
+       rt.rt_flags = (RTF_UP | RTF_HOST);
+       if (isnet)
+               rt.rt_flags &= ~RTF_HOST;
+
+       while (*args) {
+               if (strcmp(*args, "metric")==0) {
+                       int metric;
+
+                       args++;
+                       if (!*args || !isdigit(**args))
+                               show_usage();
+                       metric = atoi(*args);
+#if HAVE_NEW_ADDRT
+                       rt.rt_metric = metric + 1;
+#else
+                       ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");  /* XXX Fixme */
+#endif
+                       args++;
+                       continue;
+               }
+
+               if (strcmp(*args, "netmask")==0) {
+                       struct sockaddr mask;
+
+                       args++;
+                       if (!*args || mask_in_addr(rt))
+                               show_usage();
+                       safe_strncpy(netmask, *args, (sizeof netmask));
+                       if ((isnet = INET_resolve(netmask, &mask)) < 0) {
+                               error_msg(_("can't resolve netmask %s"), netmask);
+                               return E_LOOKUP;
+                       }
+                       rt.rt_genmask = full_mask(mask);
+                       args++;
+                       continue;
+               }
+
+               if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
+                       args++;
+                       if (!*args)
+                               show_usage();
+                       if (rt.rt_flags & RTF_GATEWAY)
+                               show_usage();
+                       safe_strncpy(gateway, *args, (sizeof gateway));
+                       if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
+                               error_msg(_("can't resolve gw %s"), gateway);
+                               return E_LOOKUP;
+                       }
+                       if (isnet) {
+                               error_msg(
+                                       _("%s: cannot use a NETWORK as gateway!"),
+                                       gateway);
+                               return E_OPTERR;
+                       }
+                       rt.rt_flags |= RTF_GATEWAY;
+                       args++;
+                       continue;
+               }
+
+               if (strcmp(*args, "mss")==0) {
+                       args++;
+                       rt.rt_flags |= RTF_MSS;
+                       if (!*args)
+                               show_usage();
+                       rt.rt_mss = atoi(*args);
+                       args++;
+                       if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
+                               error_msg(_("Invalid MSS."));
+                               return E_OPTERR;
+                       }
+                       continue;
+               }
+
+               if (strcmp(*args, "window")==0) {
+                       args++;
+                       if (!*args)
+                               show_usage();
+                       rt.rt_flags |= RTF_WINDOW;
+                       rt.rt_window = atoi(*args);
+                       args++;
+                       if (rt.rt_window < 128) {
+                               error_msg(_("Invalid window."));
+                               return E_OPTERR;
+                       }
+                       continue;
+               }
+
+               if (strcmp(*args, "irtt")==0) {
+                       args++;
+                       if (!*args)
+                               show_usage();
+                       args++;
+#if HAVE_RTF_IRTT
+                       rt.rt_flags |= RTF_IRTT;
+                       rt.rt_irtt = atoi(*(args - 1));
+                       rt.rt_irtt *= (HZ / 100);       /* FIXME */
+#if 0                           /* FIXME: do we need to check anything of this? */
+                       if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
+                               error_msg(_("Invalid initial rtt."));
+                               return E_OPTERR;
+                       }
+#endif
+#else
+                       ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
+#endif
+                       continue;
+               }
+
+               if (strcmp(*args, "reject")==0) {
+                       args++;
+#if HAVE_RTF_REJECT
+                       rt.rt_flags |= RTF_REJECT;
+#else
+                       ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
+#endif
+                       continue;
+               }
+               if (strcmp(*args, "mod")==0) {
+                       args++;
+                       rt.rt_flags |= RTF_MODIFIED;
+                       continue;
+               }
+               if (strcmp(*args, "dyn")==0) {
+                       args++;
+                       rt.rt_flags |= RTF_DYNAMIC;
+                       continue;
+               }
+               if (strcmp(*args, "reinstate")==0) {
+                       args++;
+                       rt.rt_flags |= RTF_REINSTATE;
+                       continue;
+               }
+               if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
+                       args++;
+                       if (rt.rt_dev || *args == NULL)
+                               show_usage();
+                       rt.rt_dev = *args++;
+                       continue;
+               }
+               /* nothing matches */
+               if (!rt.rt_dev) {
+                       rt.rt_dev = *args++;
+                       if (*args)
+                               show_usage();   /* must be last to catch typos */
+               } else {
+                       show_usage();
+               }
+       }
+
+#if HAVE_RTF_REJECT
+       if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
+               rt.rt_dev = "lo";
+#endif
+
+       /* sanity checks.. */
+       if (mask_in_addr(rt)) {
+               unsigned long mask = mask_in_addr(rt);
+               mask = ~ntohl(mask);
+               if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
+                       error_msg(
+                               _("netmask %.8x doesn't make sense with host route"),
+                               (unsigned int)mask);
+                       return E_OPTERR;
+               }
+               if (mask & (mask + 1)) {
+                       error_msg(_("bogus netmask %s"), netmask);
+                       return E_OPTERR;
+               }
+               mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
+               if (mask & ~mask_in_addr(rt)) {
+                       error_msg(_("netmask doesn't match route address"));
+                       return E_OPTERR;
+               }
+       }
+       /* Fill out netmask if still unset */
+       if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
+               mask_in_addr(rt) = 0xffffffff;
+
+       /* Create a socket to the INET kernel. */
+       if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror("socket");
+               return E_SOCK;
+       }
+       /* Tell the kernel to accept this route. */
+       if (action == RTACTION_DEL) {
+               if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
+                       perror("SIOCDELRT");
+                       close(skfd);
+                       return E_SOCK;
+               }
+       } else {
+               if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
+                       perror("SIOCADDRT");
+                       close(skfd);
+                       return E_SOCK;
+               }
+       }
+
+       /* Close the socket. */
+       (void) close(skfd);
+       return EXIT_SUCCESS;
+}
+
+#ifndef RTF_UP
+/* Keep this in sync with /usr/src/linux/include/linux/route.h */
+#define RTF_UP          0x0001          /* route usable                 */
+#define RTF_GATEWAY     0x0002          /* destination is a gateway     */
+#define RTF_HOST        0x0004          /* host entry (net otherwise)   */
+#define RTF_REINSTATE   0x0008          /* reinstate route after tmout  */
+#define RTF_DYNAMIC     0x0010          /* created dyn. (by redirect)   */
+#define RTF_MODIFIED    0x0020          /* modified dyn. (by redirect)  */
+#define RTF_MTU         0x0040          /* specific MTU for this route  */
+#ifndef RTF_MSS
+#define RTF_MSS         RTF_MTU         /* Compatibility :-(            */
+#endif
+#define RTF_WINDOW      0x0080          /* per route window clamping    */
+#define RTF_IRTT        0x0100          /* Initial round trip time      */
+#define RTF_REJECT      0x0200          /* Reject route                 */
+#endif
+
+static void displayroutes(int numeric)
+{
+       char buff[256];
+       int  nl = 0 ;
+       struct in_addr dest;
+       struct in_addr gw;
+       struct in_addr mask;
+       int flgs, ref, use, metric;
+       char flags[64];
+       unsigned long int d,g,m;
+
+       char sdest[16], sgw[16];
+
+
+       FILE *fp = xfopen("/proc/net/route", "r");
+
+       while( fgets(buff, sizeof(buff), fp) != NULL ) {
+               if(nl) {
+                       int ifl = 0;
+                       while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
+                               ifl++;
+                       buff[ifl]=0;    /* interface */
+                       if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx",
+                          &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
+                               error_msg_and_die( "Unsuported kernel route format\n");
+                       }
+                       if(nl==1)
+                       printf("Kernel IP routing table\n"
+                               "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface\n");
+
+                       ifl = 0;        /* parse flags */
+                       if(flgs&RTF_UP) {
+                               if(flgs&RTF_REJECT)
+                                       flags[ifl++]='!';
+                               else
+                                       flags[ifl++]='U';
+                               if(flgs&RTF_GATEWAY)
+                                       flags[ifl++]='G';
+                               if(flgs&RTF_HOST)
+                                       flags[ifl++]='H';
+                               if(flgs&RTF_REINSTATE)
+                                       flags[ifl++]='R';
+                               if(flgs&RTF_DYNAMIC)
+                                       flags[ifl++]='D';
+                               if(flgs&RTF_MODIFIED)
+                                       flags[ifl++]='M';
+                               flags[ifl]=0;
+                               dest.s_addr = d;
+                               gw.s_addr   = g;
+                               mask.s_addr = m;
+                               strcpy(sdest,  (numeric == 0 && dest.s_addr==0 ? "default" :
+                                       inet_ntoa(dest)));
+                               strcpy(sgw,    (numeric == 0 && gw.s_addr==0   ? "*"       :
+                                       inet_ntoa(gw)));
+                               printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
+                                       sdest, sgw,
+                                       inet_ntoa(mask),
+                                       flags, metric, ref, use, buff);
+                       }
+               }
+               nl++;
+       }
+}
+
+int route_main(int argc, char **argv)
+{
+       int what = 0;
+       int numeric = 0;
+
+       argc--;
+       argv++;
+
+       if (argc>0 && strcmp(argv[0], "-n")==0) {
+               numeric = 1;
+               argc--;
+               argv++;
+       }
+
+       if (*argv == NULL) {
+               displayroutes(numeric);
+               return EXIT_SUCCESS;
+       } else {
+               /* check verb */
+               if (strcmp(*argv, "add")==0)
+                       what = RTACTION_ADD;
+               else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
+                       what = RTACTION_DEL;
+               else if (strcmp(*argv, "flush")==0)
+                       what = RTACTION_FLUSH;
+               else
+                       show_usage();
+       }
+
+       return INET_setroute(what, 0, ++argv);
+}
diff --git a/rpm2cpio.c b/rpm2cpio.c
new file mode 100644 (file)
index 0000000..8d639d6
--- /dev/null
@@ -0,0 +1,91 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini rpm2cpio implementation for busybox
+ *
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "busybox.h"
+#include <netinet/in.h> /* For ntohl & htonl function */
+#include <string.h>
+
+#define RPM_MAGIC "\355\253\356\333"
+#define RPM_HEADER_MAGIC "\216\255\350"
+
+struct rpm_lead {
+    unsigned char magic[4];
+    u_int8_t major, minor;
+    u_int16_t type;
+    u_int16_t archnum;
+    char name[66];
+    u_int16_t osnum;
+    u_int16_t signature_type;
+    char reserved[16];
+};
+
+struct rpm_header {
+       char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
+       u_int8_t version; /* 1 byte version number */
+       u_int32_t reserved; /* 4 bytes reserved */
+       u_int32_t entries; /* Number of entries in header (4 bytes) */
+       u_int32_t size; /* Size of store (4 bytes) */
+};
+
+void skip_header(FILE *rpmfile)
+{
+       struct rpm_header header;
+
+       fread(&header, sizeof(struct rpm_header), 1, rpmfile);
+       if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */
+       if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */
+       header.entries = ntohl(header.entries);
+       header.size = ntohl(header.size);
+       fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
+       fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */
+}
+
+/* No getopt required */
+extern int rpm2cpio_main(int argc, char **argv)
+{
+       struct rpm_lead lead;
+       int gunzip_pid;
+       FILE *rpmfile, *cpiofile;
+
+       if (argc == 1) {
+               rpmfile = stdin;
+       } else {
+               rpmfile = fopen(argv[1], "r");
+               if (!rpmfile) perror_msg_and_die("Can't open rpm file");
+               /* set the buffer size */
+               setvbuf(rpmfile, NULL, _IOFBF, 0x8000);
+       }
+
+       fread (&lead, sizeof(struct rpm_lead), 1, rpmfile);
+       if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
+       /* Skip the signature header */
+       skip_header(rpmfile);
+       fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */
+       /* Skip the main header */
+       skip_header(rpmfile);
+
+       cpiofile = gz_open(rpmfile, &gunzip_pid);
+
+       copyfd(fileno(cpiofile), fileno(stdout));
+       gz_close(gunzip_pid);
+       fclose(rpmfile);
+       return 0;
+}
diff --git a/scripts/depmod.pl b/scripts/depmod.pl
new file mode 100755 (executable)
index 0000000..bd7767f
--- /dev/null
@@ -0,0 +1,227 @@
+#!/usr/bin/perl -w
+# vi: set ts=4:
+# Copyright (c) 2001 David Schleef <ds@schleef.org>
+# Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
+# Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
+# This program is free software; you can redistribute it and/or modify it 
+# under the same terms as Perl itself.
+
+# TODO -- use strict mode...
+#use strict;
+
+use Getopt::Long;
+use File::Find;
+
+
+# Set up some default values
+
+my $basedir="";
+my $kernel;
+my $kernelsyms;
+my $stdout=1;
+my $verbose=0;
+
+
+# get command-line options
+
+my %opt;
+
+GetOptions(
+       \%opt,
+       "help|h",
+       "basedir|b=s" => \$basedir,
+       "kernel|k=s" => \$kernel,
+       "kernelsyms|F=s" => \$kernelsyms,
+       "stdout|n" => \$stdout,
+       "verbose|v" => \$verbose,
+);
+
+if (defined $opt{help}) {
+       print
+               "$0 [OPTION]... [basedir]\n",
+               "\t-h --help\t\tShow this help screen\n",
+               "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n",
+               "\t-k --kernel\t\tKernel binary for the target\n",
+               "\t-F --kernelsyms\t\tKernel symbol file\n",
+               "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n",
+               "\t-v --verbose\t\tPrint out lots of debugging stuff\n",
+       ;
+       exit 1;
+}
+
+if($basedir !~ m-/lib/modules-) {
+    warn "WARNING: base directory does not match ..../lib/modules\n";
+}
+
+# Find the list of .o files living under $basedir 
+#if ($verbose) { printf "Locating all modules\n"; }
+my($file) = "";
+my(@liblist) = ();
+find sub { 
+       if ( -f $_  && ! -d $_ ) { 
+               $file = $File::Find::name;
+               if ( $file =~ /.o$/ ) {
+                       push(@liblist, $file);
+                       if ($verbose) { printf "$file\n"; }
+               }
+       }
+}, $basedir;
+if ($verbose) { printf "Finished locating modules\n"; }
+
+foreach $obj ( @liblist, $kernel ){
+    # turn the input file name into a target tag name
+    # vmlinux is a special that is only used to resolve symbols
+    if($obj =~ /vmlinux/) {
+        $tgtname = "vmlinux";
+    } else {
+        ($tgtname) = $obj =~ m-(/lib/modules/.*)$-;
+    }
+
+    warn "MODULE = $tgtname\n" if $verbose;
+
+    # get a list of symbols
+       @output=`nm $obj`;
+       $ksymtab=grep m/ __ksymtab/, @output;
+
+    # gather the exported symbols
+       if($ksymtab){
+        # explicitly exported
+        foreach ( @output ) {
+            / __ksymtab_(.*)$/ and do {
+                warn "sym = $1\n" if $verbose;
+                $exp->{$1} = $tgtname;
+            };
+        }
+       } else {
+        # exporting all symbols
+        foreach ( @output) {
+            / [ABCDGRST] (.*)$/ and do {
+                warn "syma = $1\n" if $verbose;
+                $exp->{$1} = $tgtname;
+            };
+        }
+       }
+    # gather the unresolved symbols
+    foreach ( @output ) {
+        !/ __this_module/ && / U (.*)$/ and do {
+            warn "und = $1\n" if $verbose;
+            push @{$dep->{$tgtname}}, $1;
+        };
+    }
+}
+
+
+# reduce dependancies: remove unresolvable and resolved from vmlinux
+# remove duplicates
+foreach $module (keys %$dep) {
+    $mod->{$module} = {};
+    foreach (@{$dep->{$module}}) {
+        if( $exp->{$_} ) { 
+            warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose;
+            next if $exp->{$_} =~ /vmlinux/;
+            $mod->{$module}{$exp->{$_}} = 1;
+        } else {
+            warn "unresolved symbol $_ in file $module\n";
+        }
+    } 
+}
+
+# resolve the dependancies for each module
+foreach $module ( keys %$mod )  {
+    print "$module:\t";
+    @sorted = sort bydep keys %{$mod->{$module}};
+    print join(" \\\n\t",@sorted);
+#    foreach $m (@sorted ) {
+#        print "\t$m\n";
+#    }
+    print "\n\n";
+}
+
+sub bydep
+{
+    foreach my $f ( keys %{$mod->{$b}} ) {
+        if($f eq $a) {
+            return 1;
+        }
+    }
+    return -1;
+}
+
+
+
+__END__
+
+=head1 NAME
+
+depmod.pl - a cross platform script to generate kernel module dependency
+               lists which can then be used by modprobe.
+
+=head1 SYNOPSIS
+
+depmod.pl [OPTION]... [FILE]...
+
+Example:
+
+       depmod.pl -F linux/System.map target/lib/modules
+
+=head1 DESCRIPTION
+
+The purpose of this script is to automagically generate a list of of kernel
+module dependancies.  This script produces dependancy lists that should be
+identical to the depmod program from the modutils package.  Unlike the depmod
+binary, however, depmod.pl is designed to be run on your host system, not
+on your target system.
+
+This script was written by David Schleef <ds@schleef.org> to be used in
+conjunction with the BusyBox modprobe applet.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-h --help>
+
+This displays the help message.
+
+=item B<-b --basedir>
+
+The base directory uner which the target's modules will be found.  This
+defaults to the /lib/modules directory.
+
+=item B<-k --kernel>
+
+Kernel binary for the target.  You must either supply a kernel binary
+or a kernel symbol file (using the -F option).
+
+=item B<-F --kernelsyms>
+
+Kernel symbol file for the target.  You must supply either a kernel symbol file
+kernel binary for the target (using the -k option).
+
+=item B<-n --stdout>
+
+Write to stdout instead of modules.dep.  This is currently hard coded...
+kernel binary for the target (using the -k option).
+
+=item B<--verbose>
+
+Be verbose (not implemented)
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright (c) 2001 David Schleef <ds@schleef.org>
+Copyright (c) 2001 Erik Andersen <andersen@codepoet.org>
+Copyright (c) 2001 Stuart Hughes <stuarth@lineo.com>
+This program is free software; you can redistribute it and/or modify it 
+under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+David Schleef <ds@schleef.org>
+
+=cut
+
+# $Id: depmod.pl,v 1.2 2001/11/19 23:57:54 andersen Exp $
+
diff --git a/scripts/inittab b/scripts/inittab
new file mode 100644 (file)
index 0000000..5716045
--- /dev/null
@@ -0,0 +1,91 @@
+# /etc/inittab init(8) configuration for BusyBox
+#
+# Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+# Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+#
+#
+# Note, BusyBox init doesn't support runlevels.  The runlevels field is
+# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
+#
+#
+# Format for each entry: <id>:<runlevels>:<action>:<process>
+#
+# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
+#
+#      The id field is used by BusyBox init to specify the controlling tty for
+#      the specified process to run on.  The contents of this field are
+#      appended to "/dev/" and used as-is.  There is no need for this field to
+#      be unique, although if it isn't you may have strange results.  If this
+#      field is left blank, it is completely ignored.  Also note that if
+#      BusyBox detects that a serial console is in use, then all entries
+#      containing non-empty id fields will _not_ be run.  BusyBox init does
+#      nothing with utmp.  We don't need no stinkin' utmp.
+#
+# <runlevels>: The runlevels field is completely ignored.
+#
+# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once, 
+#                                  restart, ctrlaltdel, and shutdown.
+#
+#       Note: askfirst acts just like respawn, but before running the specified
+#       process it displays the line "Please press Enter to activate this
+#       console." and then waits for the user to press enter before starting
+#       the specified process.
+#
+#       Note: unrecognised actions (like initdefault) will cause init to emit
+#       an error message, and then go along with its business.
+#
+# <process>: Specifies the process to be executed and it's command line.
+#
+# Note: BusyBox init works just fine without an inittab. If no inittab is
+# found, it has the following default behavior:
+#         ::sysinit:/etc/init.d/rcS
+#         ::askfirst:/bin/sh
+#         ::ctrlaltdel:/sbin/reboot
+#         ::shutdown:/sbin/swapoff -a
+#         ::shutdown:/bin/umount -a -r
+#         ::restart:/sbin/init
+#
+# if it detects that /dev/console is _not_ a serial console, it will
+# also run:
+#         tty2::askfirst:/bin/sh
+#         tty3::askfirst:/bin/sh
+#         tty4::askfirst:/bin/sh
+#
+# Boot-time system configuration/initialization script.
+# This is run first except when booting in single-user mode.
+#
+::sysinit:/etc/init.d/rcS
+
+# /bin/sh invocations on selected ttys
+#
+# Note below that we prefix the shell commands with a "-" to indicate to the
+# shell that it is supposed to be a login shell.  Normally this is handled by
+# login, but since we are bypassing login in this case, BusyBox lets you do
+# this yourself...
+#
+# Start an "askfirst" shell on the console (whatever that may be)
+::askfirst:-/bin/sh
+# Start an "askfirst" shell on /dev/tty2-4
+tty2::askfirst:-/bin/sh
+tty3::askfirst:-/bin/sh
+tty4::askfirst:-/bin/sh
+
+# /sbin/getty invocations for selected ttys
+tty4::respawn:/sbin/getty 38400 tty5
+tty5::respawn:/sbin/getty 38400 tty6
+
+# Example of how to put a getty on a serial line (for a terminal)
+#::respawn:/sbin/getty -L ttyS0 9600 vt100
+#::respawn:/sbin/getty -L ttyS1 9600 vt100
+#
+# Example how to put a getty on a modem line.
+#::respawn:/sbin/getty 57600 ttyS2
+
+# Stuff to do when restarting the init process
+::restart:/sbin/init
+
+# Stuff to do before rebooting
+::ctrlaltdel:/sbin/reboot
+::shutdown:/bin/umount -a -r
+::shutdown:/sbin/swapoff -a
+
diff --git a/scripts/mk2knr.pl b/scripts/mk2knr.pl
new file mode 100755 (executable)
index 0000000..aaf4963
--- /dev/null
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+#
+# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style
+#
+# How to use this script:
+#  - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert'
+#  - Review the 'convertme.pl' script generated and remove / edit any of the
+#    substitutions in there (please especially check for false positives)
+#  - Type './convertme.pl same-files-as-before'
+#  - Compile and see if it works
+#
+# BUGS: This script does not ignore strings inside comments or strings inside
+# quotes (it probably should).
+
+# set this to something else if you want
+$convertme = 'convertme.pl';
+
+# internal-use variables (don't touch)
+$convert = 0;
+%converted = ();
+
+# if no files were specified, print usage
+die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0;
+
+# prepare the "convert me" file
+open(CM, ">$convertme") or die "convertme.pl $!";
+print CM "#!/usr/bin/perl -p -i\n\n";
+
+# process each file passed on the cmd line
+while (<>) {
+
+       # if the line says "getopt" in it anywhere, we don't want to muck with it
+       # because option lists tend to include strings like "cxtzvOf:" which get
+       # matched by the "check for mixed case" regexps below
+       next if /getopt/;
+
+       # tokenize the string into just the variables
+       while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) {
+               $var = $1;
+
+               # ignore the word "BusyBox"
+               next if ($var =~ /BusyBox/);
+
+               # this checks for javaStyle or szHungarianNotation
+               $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/);
+
+               # this checks for PascalStyle
+               $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/);
+
+               # if we want to add more checks, we can add 'em here, but the above
+               # checks catch "just enough" and not too much, so prolly not.
+
+               if ($convert) {
+                       $convert = 0;
+
+                       # skip ahead if we've already dealt with this one
+                       next if ($converted{$var});
+
+                       # record that we've dealt with this var
+                       $converted{$var} = 1;
+
+                       print CM "s/\\b$var\\b/"; # more to come in just a minute
+
+                       # change the first letter to lower-case
+                       $var = lcfirst($var);
+
+                       # put underscores before all remaining upper-case letters
+                       $var =~ s/([A-Z])/_$1/g;
+
+                       # now change the remaining characters to lower-case
+                       $var = lc($var);
+
+                       print CM "$var/g;\n";
+               }
+       }
+}
+
+# tidy up and make the $convertme script executable
+close(CM);
+chmod 0755, $convertme;
+
+# print a helpful help message
+print "Done. Scheduled name changes are in $convertme.\n";
+print "Please review/modify it and then type ./$convertme to do the search & replace.\n";
diff --git a/scripts/undeb b/scripts/undeb
new file mode 100644 (file)
index 0000000..a72e1e2
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# This should work with the GNU version of tar and gzip!
+# This should work with the bash or ash shell!
+# Requires the programs (ar, tar, gzip, and the pager more or less).
+#
+usage() {
+echo "Usage: undeb -c package.deb            <Print control file info>"
+echo "       undeb -l package.deb            <List contents of deb package>"
+echo "       undeb -x package.deb /foo/boo   <Extract deb package to this directory,"
+echo "                                        put . for current directory>"  
+exit
+}
+
+deb=$2
+exist() {
+if [ "$deb" = "" ]; then
+usage
+elif [ ! -s "$deb" ]; then
+echo "Can't find $deb!"
+exit
+fi
+}
+
+if [ "$1" = "" ]; then
+usage
+elif [ "$1" = "-l" ]; then
+exist
+type more >/dev/null 2>&1 && pager=more
+type less >/dev/null 2>&1 && pager=less
+[ "$pager" = "" ] && echo "No pager found!" && exit
+(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager 
+exit
+elif [ "$1" = "-c" ]; then
+exist
+ar -p $deb control.tar.gz | tar -xzO *control  
+exit
+elif [ "$1" = "-x" ]; then
+exist
+if [ "$3" = "" ]; then
+usage
+elif [ ! -d "$3" ]; then
+echo "No such directory $3!"
+exit
+fi
+ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit 
+echo
+echo "Extracted $deb to $3!"
+exit
+else
+usage
+fi
diff --git a/scripts/unrpm b/scripts/unrpm
new file mode 100644 (file)
index 0000000..376286a
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# This should work with the GNU version of cpio and gzip!
+# This should work with the bash or ash shell!
+# Requires the programs (cpio, gzip, and the pager more or less).
+#
+usage() {
+echo "Usage: unrpm -l package.rpm            <List contents of rpm package>"
+echo "       unrpm -x package.rpm /foo/boo   <Extract rpm package to this directory,"
+echo "                                        put . for current directory>"  
+exit
+}
+
+rpm=$2
+exist() {
+if [ "$rpm" = "" ]; then
+usage
+elif [ ! -s "$rpm" ]; then
+echo "Can't find $rpm!"
+exit
+fi
+}
+
+if [ "$1" = "" ]; then
+usage
+elif [ "$1" = "-l" ]; then
+exist
+type more >/dev/null 2>&1 && pager=more
+type less >/dev/null 2>&1 && pager=less
+[ "$pager" = "" ] && echo "No pager found!" && exit
+(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager
+exit
+elif [ "$1" = "-x" ]; then
+exist
+if [ "$3" = "" ]; then
+usage
+elif [ ! -d "$3" ]; then
+echo "No such directory $3!"
+exit
+fi
+rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit
+echo
+echo "Extracted $rpm to $3!"
+exit
+else
+usage
+fi
diff --git a/sed.c b/sed.c
new file mode 100644 (file)
index 0000000..df6ccb2
--- /dev/null
+++ b/sed.c
@@ -0,0 +1,1215 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sed.c - very minimalist version of sed
+ *
+ * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
+ * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
+ * Copyright (C) 2002  Matt Kraai
+ * Copyright (C) 2003 by Glenn McGrath <bug1@optushome.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Code overview.
+
+  Files are laid out to avoid unnecessary function declarations.  So for
+  example, every function add_cmd calls occurs before add_cmd in this file.
+
+  add_cmd() is called on each line of sed command text (from a file or from
+  the command line).  It calls get_address() and parse_cmd_args().  The
+  resulting sed_cmd_t structures are appended to a linked list
+  (sed_cmd_head/sed_cmd_tail).
+
+  process_file() does actual sedding, reading data lines from an input FILE *
+  (which could be stdin) and applying the sed command list (sed_cmd_head) to
+  each of the resulting lines.
+
+  sed_main() is where external code calls into this, with a command line.
+*/
+
+
+/*
+       Supported features and commands in this version of sed:
+
+        - comments ('#')
+        - address matching: num|/matchstr/[,num|/matchstr/|$]command
+        - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
+        - edit commands: (a)ppend, (i)nsert, (c)hange
+        - file commands: (r)ead
+        - backreferences in substitution expressions (\1, \2...\9)
+        - grouped commands: {cmd1;cmd2}
+        - transliteration (y/source-chars/dest-chars/)
+        - pattern space hold space storing / swapping (g, h, x)
+        - labels / branching (: label, b, t)
+
+        (Note: Specifying an address (range) to match is *optional*; commands
+        default to the whole pattern space if no specific address match was
+        requested.)
+
+       Unsupported features:
+
+        - GNU extensions
+        - and more.
+
+       Todo:
+
+        - Create a wrapper around regex to make libc's regex conform with sed
+        - Fix bugs
+
+
+       Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
+*/
+
+#include <stdio.h>
+#include <unistd.h>            /* for getopt() */
+#include <regex.h>
+#include <string.h>            /* for strdup() */
+#include <errno.h>
+#include <ctype.h>             /* for isspace() */
+#include <stdlib.h>
+#include "busybox.h"
+
+typedef struct sed_cmd_s {
+    /* Ordered by alignment requirements: currently 36 bytes on x86 */
+
+    /* address storage */
+    regex_t *beg_match;        /* sed -e '/match/cmd' */
+    regex_t *end_match;        /* sed -e '/match/,/end_match/cmd' */
+    regex_t *sub_match;        /* For 's/sub_match/string/' */
+    int beg_line;              /* 'sed 1p'   0 == apply commands to all lines */
+    int end_line;              /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
+
+    FILE *file;                        /* File (sr) command writes to, -1 for none. */
+    char *string;              /* Data string for (saicytb) commands. */
+
+    unsigned short which_match;                /* (s) Which match to replace (0 for all) */
+
+    /* Bitfields (gcc won't group them if we don't) */
+    unsigned int invert:1;                     /* the '!' after the address */
+    unsigned int in_match:1;           /* Next line also included in match? */
+    unsigned int no_newline:1;         /* Last line written by (sr) had no '\n' */
+    unsigned int sub_p:1;                      /* (s) print option */
+
+
+    /* GENERAL FIELDS */
+    char cmd;                          /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
+    struct sed_cmd_s *next;    /* Next command (linked list, NULL terminated) */
+} sed_cmd_t;
+
+/* globals */
+/* options */
+static int be_quiet = 0;
+
+static const char bad_format_in_subst[] =
+       "bad format in substitution expression";
+const char *const semicolon_whitespace = "; \n\r\t\v";
+
+regmatch_t regmatch[10];
+static regex_t *previous_regex_ptr = NULL;
+
+/* linked list of sed commands */
+static sed_cmd_t sed_cmd_head;
+static sed_cmd_t *sed_cmd_tail = &sed_cmd_head;
+
+/* Linked list of append lines */
+struct append_list {
+       char *string;
+       struct append_list *next;
+};
+struct append_list *append_head=NULL, *append_tail=NULL;
+
+/* If size is 0 copy until EOF */
+extern size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size, 
+               ssize_t (*action)(int fd, const void *, size_t))
+{
+       size_t read_total = 0;
+       RESERVE_BB_BUFFER(buffer,BUFSIZ);
+
+       while ((size == 0) || (read_total < size)) {
+               size_t read_try;
+               ssize_t read_actual;
+
+               if ((size == 0) || (size - read_total > BUFSIZ)) {
+                       read_try = BUFSIZ;
+               } else {
+                       read_try = size - read_total;
+               }
+
+               read_actual = safe_read(src_fd, buffer, read_try);
+               if (read_actual > 0) {
+                       if (action && (action(dst_fd, buffer, (size_t) read_actual) != read_actual)) {
+                               perror_msg(write_error);        /* match Read error below */
+                               break;
+                       }
+               }
+               else if (read_actual == 0) {
+                       if (size) {
+                               error_msg("Unable to read all data");
+                       }
+                       break;
+               } else {
+                       /* read_actual < 0 */
+                       perror_msg("Read error");
+                       break;
+               }
+
+               read_total += read_actual;
+       }
+
+       RELEASE_BB_BUFFER(buffer);
+
+       return(read_total);
+}
+
+extern int bb_copyfd_eof(int fd1, int fd2)
+{
+       return(bb_full_fd_action(fd1, fd2, 0, full_write));
+}
+
+extern void bb_xprint_and_close_file(FILE *file)
+{
+       fflush(stdout);
+       /* Note: Do not use STDOUT_FILENO here, as this is a lib routine
+        *       and the calling code may have reassigned stdout. */
+       if (bb_copyfd_eof(fileno(file), fileno(stdout)) == -1) {
+               /* bb_copyfd outputs any needed messages, so just die. */
+               exit(EXIT_FAILURE);
+       }
+       /* Note: Since we're reading, don't bother checking the return value
+        *       of fclose().  The only possible failure is EINTR which
+        *       should already have been taken care of. */
+       fclose(file);
+}
+
+#ifdef BB_FEATURE_CLEAN_UP
+static void free_and_close_stuff(void)
+{
+       sed_cmd_t *sed_cmd = sed_cmd_head.next;
+
+       while(append_head) {
+               append_tail=append_head->next;
+               free(append_head->string);
+               free(append_head);
+               append_head=append_tail;
+       }
+
+       while (sed_cmd) {
+               sed_cmd_t *sed_cmd_next = sed_cmd->next;
+
+               if(sed_cmd->file)
+                       bb_xprint_and_close_file(sed_cmd->file);
+
+               if (sed_cmd->beg_match) {
+                       regfree(sed_cmd->beg_match);
+                       free(sed_cmd->beg_match);
+               }
+               if (sed_cmd->end_match) {
+                       regfree(sed_cmd->end_match);
+                       free(sed_cmd->end_match);
+               }
+               if (sed_cmd->sub_match) {
+                       regfree(sed_cmd->sub_match);
+                       free(sed_cmd->sub_match);
+               }
+               free(sed_cmd->string);
+               free(sed_cmd);
+               sed_cmd = sed_cmd_next;
+       }
+}
+#endif
+
+/* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */
+
+static void parse_escapes(char *dest, const char *string, int len, char from, char to)
+{
+       int i=0;
+
+       while(i<len) {
+               if(string[i] == '\\') {
+                       if(!to || string[i+1] == from) {
+                               *(dest++) = to ? to : string[i+1];
+                               i+=2;
+                               continue;
+                       } else *(dest++)=string[i++];
+               }
+               *(dest++) = string[i++];
+       }
+       *dest=0;
+}
+
+static char *copy_parsing_slashn(const char *string, int len)
+{
+       char *dest=xmalloc(len+1);
+
+       parse_escapes(dest,string,len,'n','\n');
+       return dest;
+}
+
+
+/*
+ * index_of_next_unescaped_regexp_delim - walks left to right through a string
+ * beginning at a specified index and returns the index of the next regular
+ * expression delimiter (typically a forward * slash ('/')) not preceeded by 
+ * a backslash ('\').
+ */
+static int index_of_next_unescaped_regexp_delim(const char delimiter,
+       const char *str)
+{
+       int bracket = -1;
+       int escaped = 0;
+       int idx = 0;
+       char ch;
+
+       for (; (ch = str[idx]); idx++) {
+               if (bracket != -1) {
+                       if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2
+                                       && str[idx - 1] == '^')))
+                               bracket = -1;
+               } else if (escaped)
+                       escaped = 0;
+               else if (ch == '\\')
+                       escaped = 1;
+               else if (ch == '[')
+                       bracket = idx;
+               else if (ch == delimiter)
+                       return idx;
+       }
+
+       /* if we make it to here, we've hit the end of the string */
+       return -1;
+}
+
+/*
+ *  Returns the index of the third delimiter
+ */
+static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
+{
+       const char *cmdstr_ptr = cmdstr;
+       char delimiter;
+       int idx = 0;
+
+       /* verify that the 's' or 'y' is followed by something.  That something
+        * (typically a 'slash') is now our regexp delimiter... */
+       if (*cmdstr == '\0') error_msg_and_die(bad_format_in_subst);
+       delimiter = *(cmdstr_ptr++);
+
+       /* save the match string */
+       idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
+       if (idx == -1) {
+               error_msg_and_die(bad_format_in_subst);
+       }
+       *match = copy_parsing_slashn(cmdstr_ptr, idx);
+
+       /* save the replacement string */
+       cmdstr_ptr += idx + 1;
+       idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
+       if (idx == -1) {
+               error_msg_and_die(bad_format_in_subst);
+       }
+       *replace = copy_parsing_slashn(cmdstr_ptr, idx);
+
+       return ((cmdstr_ptr - cmdstr) + idx);
+}
+
+static void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+       int ret;
+       if ((ret = regcomp(preg, regex, cflags)) != 0) {
+               int errmsgsz = regerror(ret, preg, NULL, 0);
+               char *errmsg = xmalloc(errmsgsz);
+               regerror(ret, preg, errmsg, errmsgsz);
+               error_msg_and_die("xregcomp: %s", errmsg);
+       }
+}
+
+/*
+ * returns the index in the string just past where the address ends.
+ */
+static int get_address(char *my_str, int *linenum, regex_t ** regex)
+{
+       char *pos = my_str;
+
+       if (isdigit(*my_str)) {
+               *linenum = strtol(my_str, &pos, 10);
+               /* endstr shouldnt ever equal NULL */
+       } else if (*my_str == '$') {
+               *linenum = -1;
+               pos++;
+       } else if (*my_str == '/' || *my_str == '\\') {
+               int next;
+               char delimiter;
+               char *temp;
+
+               if (*my_str == '\\') delimiter = *(++pos);
+               else delimiter = '/';
+               next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
+               if (next == -1)
+                       error_msg_and_die("unterminated match expression");
+               
+               temp=copy_parsing_slashn(pos,next);
+               *regex = (regex_t *) xmalloc(sizeof(regex_t));
+               xregcomp(*regex, temp, REG_NEWLINE);
+               free(temp);
+               /* Move position to next character after last delimiter */
+               pos+=(next+1);
+       }
+       return pos - my_str;
+}
+
+/* Grab a filename.  Whitespace at start is skipped, then goes to EOL. */
+static int parse_file_cmd(sed_cmd_t * sed_cmd, const char *filecmdstr, char **retval)
+{
+       int start = 0, idx, hack=0;
+
+       /* Skip whitespace, then grab filename to end of line */
+       while (isspace(filecmdstr[start])) start++;
+       idx=start;
+       while(filecmdstr[idx] && filecmdstr[idx]!='\n') idx++;
+       /* If lines glued together, put backslash back. */
+       if(filecmdstr[idx]=='\n') hack=1;
+       if(idx==start) error_msg_and_die("Empty filename");
+       *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
+       if(hack) *(idx+*retval)='\\';
+
+       return idx;
+}
+
+static int parse_subst_cmd(sed_cmd_t * const sed_cmd, char *substr)
+{
+       int cflags = 0;
+       char *match;
+       int idx = 0;
+
+       /*
+        * A substitution command should look something like this:
+        *    s/match/replace/ #gIpw
+        *    ||     |        |||
+        *    mandatory       optional
+        */
+       idx = parse_regex_delim(substr, &match, &sed_cmd->string);
+
+       /* determine the number of back references in the match string */
+       /* Note: we compute this here rather than in the do_subst_command()
+        * function to save processor time, at the expense of a little more memory
+        * (4 bits) per sed_cmd */
+
+       /* process the flags */
+
+       sed_cmd->which_match=1;
+       while (substr[++idx]) {
+               /* Parse match number */
+               if(isdigit(substr[idx])) {
+                       if(match[0]!='^') {
+                               /* Match 0 treated as all, multiple matches we take the last one. */
+                               char *pos=substr+idx;
+                               sed_cmd->which_match=(unsigned short)strtol(substr+idx,&pos,10);
+                               idx=pos-substr;
+                       }
+                       continue;
+               }
+               /* Skip spaces */
+               if(isspace(substr[idx])) continue;
+               switch (substr[idx]) {
+                       /* Replace all occurrences */
+                       case 'g':
+                               if (match[0] != '^') sed_cmd->which_match = 0;
+                               break;
+                       /* Print pattern space */
+                       case 'p':
+                               sed_cmd->sub_p = 1;
+                               break;
+                       case 'w':
+                       {
+                               char *temp;
+                               idx+=parse_file_cmd(sed_cmd,substr+idx,&temp);
+                               
+                               break;
+                       }
+                       /* Ignore case (gnu exension) */
+                       case 'I':
+                               cflags |= REG_ICASE;
+                               break;
+                       case ';':
+                       case '}':
+                               goto out;
+                       default:
+                               error_msg_and_die("bad option in substitution expression");
+               }
+       }
+out:
+       /* compile the match string into a regex */
+       if (*match != '\0') {
+               /* If match is empty, we use last regex used at runtime */
+               sed_cmd->sub_match = (regex_t *) xmalloc(sizeof(regex_t));
+               xregcomp(sed_cmd->sub_match, match, cflags);
+       }
+       free(match);
+
+       return idx;
+}
+
+/*
+ *  Process the commands arguments
+ */
+static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr)
+{
+       /* handle (s)ubstitution command */
+       if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
+       /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
+       else if (strchr("aic", sed_cmd->cmd)) {
+               if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
+                       error_msg_and_die
+                               ("only a beginning address can be specified for edit commands");
+               while(isspace(*cmdstr)) cmdstr++;
+               sed_cmd->string = xstrdup(cmdstr);
+               parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0);
+               cmdstr += strlen(cmdstr);
+       /* handle file cmds: (r)ead */
+       } else if(strchr("rw", sed_cmd->cmd)) {
+               if (sed_cmd->end_line || sed_cmd->end_match)
+                       error_msg_and_die("Command only uses one address");
+               cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string);
+               if(sed_cmd->cmd=='w')
+                       sed_cmd->file=xfopen(sed_cmd->string,"w");
+       /* handle branch commands */
+       } else if (strchr(":bt", sed_cmd->cmd)) {
+               int length;
+
+               while(isspace(*cmdstr)) cmdstr++;
+               length = strcspn(cmdstr, semicolon_whitespace);
+               if (length) {
+                       sed_cmd->string = strndup(cmdstr, length);
+                       cmdstr += length;
+               }
+       }
+       /* translation command */
+       else if (sed_cmd->cmd == 'y') {
+               char *match, *replace;
+               int i=cmdstr[0];
+
+               cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1;
+               /* \n already parsed, but \delimiter needs unescaping. */
+               parse_escapes(match,match,strlen(match),i,i);
+               parse_escapes(replace,replace,strlen(replace),i,i);
+
+               sed_cmd->string = xcalloc(1, (strlen(match) + 1) * 2);
+               for (i = 0; match[i] && replace[i]; i++) {
+                       sed_cmd->string[i * 2] = match[i];
+                       sed_cmd->string[(i * 2) + 1] = replace[i];
+               }
+               free(match);
+               free(replace);
+       }
+       /* if it wasnt a single-letter command that takes no arguments
+        * then it must be an invalid command.
+        */
+       else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
+               error_msg_and_die("Unsupported command %c", sed_cmd->cmd);
+       }
+
+       /* give back whatever's left over */
+       return (cmdstr);
+}
+
+
+/* Parse address+command sets, skipping comment lines. */
+
+void add_cmd(char *cmdstr)
+{
+       static char *add_cmd_line=NULL;
+       sed_cmd_t *sed_cmd;
+       int temp;
+
+       /* Append this line to any unfinished line from last time. */
+       if(add_cmd_line) {
+               int lastlen=strlen(add_cmd_line);
+               char *tmp=xmalloc(lastlen+strlen(cmdstr)+2);
+
+               memcpy(tmp,add_cmd_line,lastlen);
+               tmp[lastlen]='\n';
+               strcpy(tmp+lastlen+1,cmdstr);
+               free(add_cmd_line);
+               cmdstr=add_cmd_line=tmp;
+       } else add_cmd_line=NULL;
+
+       /* If this line ends with backslash, request next line. */
+       temp=strlen(cmdstr);
+       if(temp && cmdstr[temp-1]=='\\') {
+               if(!add_cmd_line) add_cmd_line=strdup(cmdstr);
+               add_cmd_line[temp-1]=0;
+               return;
+       }
+
+       /* Loop parsing all commands in this line. */
+       while(*cmdstr) {
+               /* Skip leading whitespace and semicolons */
+               cmdstr += strspn(cmdstr, semicolon_whitespace);
+
+               /* If no more commands, exit. */
+               if(!*cmdstr) break;
+
+               /* if this is a comment, jump past it and keep going */
+               if (*cmdstr == '#') {
+                       /* "#n" is the same as using -n on the command line */
+                       if (cmdstr[1] == 'n') be_quiet++;
+                       if(!(cmdstr=strpbrk(cmdstr, "\n\r"))) break;
+                       continue;
+               }
+
+               /* parse the command
+                * format is: [addr][,addr][!]cmd
+                *            |----||-----||-|
+                *            part1 part2  part3
+                */
+
+               sed_cmd = xcalloc(1, sizeof(sed_cmd_t));
+
+               /* first part (if present) is an address: either a '$', a number or a /regex/ */
+               cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
+
+               /* second part (if present) will begin with a comma */
+               if (*cmdstr == ',') {
+                       int idx;
+
+                       cmdstr++;
+                       idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
+                       if (!idx) error_msg_and_die("get_address: no address found in string\n");
+                       cmdstr += idx;
+               }
+
+               /* skip whitespace before the command */
+               while (isspace(*cmdstr)) cmdstr++;
+
+               /* Check for inversion flag */
+               if (*cmdstr == '!') {
+                       sed_cmd->invert = 1;
+                       cmdstr++;
+
+                       /* skip whitespace before the command */
+                       while (isspace(*cmdstr)) cmdstr++;
+               }
+
+               /* last part (mandatory) will be a command */
+               if (!*cmdstr) error_msg_and_die("missing command");
+               sed_cmd->cmd = *(cmdstr++);
+               cmdstr = parse_cmd_args(sed_cmd, cmdstr);
+
+               /* Add the command to the command array */
+               sed_cmd_tail->next = sed_cmd;
+               sed_cmd_tail = sed_cmd_tail->next;
+       }
+
+       /* If we glued multiple lines together, free the memory. */
+       if(add_cmd_line) {
+               free(add_cmd_line);
+               add_cmd_line=NULL;
+       }
+}
+
+struct pipeline {
+       char *buf;      /* Space to hold string */
+       int idx;        /* Space used */
+       int len;        /* Space allocated */
+} pipeline;
+
+#define PIPE_GROW 64
+
+void pipe_putc(char c)
+{
+       if(pipeline.idx==pipeline.len) {
+               pipeline.buf = xrealloc(pipeline.buf, pipeline.len + PIPE_GROW);
+               pipeline.len+=PIPE_GROW;
+       }
+       pipeline.buf[pipeline.idx++] = (c);
+}
+
+static void do_subst_w_backrefs(const char *line, const char *replace)
+{
+       int i,j;
+
+       /* go through the replacement string */
+       for (i = 0; replace[i]; i++) {
+               /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
+               if (replace[i] == '\\' && replace[i+1]>'0' && replace[i+1]<='9') {
+                       int backref=replace[++i]-'0';
+
+                       /* print out the text held in regmatch[backref] */
+                       if(regmatch[backref].rm_so != -1)
+                               for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++)
+                                       pipe_putc(line[j]);
+               }
+
+               /* if we find a backslash escaped character, print the character */
+               else if (replace[i] == '\\') pipe_putc(replace[++i]);
+
+               /* if we find an unescaped '&' print out the whole matched text. */
+               else if (replace[i] == '&')
+                       for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++)
+                               pipe_putc(line[j]);
+               /* Otherwise just output the character. */
+               else pipe_putc(replace[i]);
+       }
+}
+
+static int do_subst_command(sed_cmd_t * sed_cmd, char **line)
+{
+       char *oldline = *line;
+       int altered = 0;
+       int match_count=0;
+       regex_t *current_regex;
+
+       /* Handle empty regex. */
+       if (sed_cmd->sub_match == NULL) {
+               current_regex = previous_regex_ptr;
+               if(!current_regex)
+                       error_msg_and_die("No previous regexp.");
+       } else previous_regex_ptr = current_regex = sed_cmd->sub_match;
+
+       /* Find the first match */
+       if(REG_NOMATCH==regexec(current_regex, oldline, 10, regmatch, 0))
+               return 0;
+
+       /* Initialize temporary output buffer. */
+       pipeline.buf=xmalloc(PIPE_GROW);
+       pipeline.len=PIPE_GROW;
+       pipeline.idx=0;
+
+       /* Now loop through, substituting for matches */
+       do {
+               int i;
+
+               match_count++;
+
+               /* If we aren't interested in this match, output old line to
+                  end of match and continue */
+               if(sed_cmd->which_match && sed_cmd->which_match!=match_count) {
+                       for(i=0;i<regmatch[0].rm_eo;i++)
+                               pipe_putc(oldline[i]);
+                       continue;
+               }
+
+               /* print everything before the match */
+               for (i = 0; i < regmatch[0].rm_so; i++) pipe_putc(oldline[i]);
+
+               /* then print the substitution string */
+               do_subst_w_backrefs(oldline, sed_cmd->string);
+
+               /* advance past the match */
+               oldline += regmatch[0].rm_eo;
+               /* flag that something has changed */
+               altered++;
+
+               /* if we're not doing this globally, get out now */
+               if (sed_cmd->which_match) break;
+       } while (*oldline && (regexec(current_regex, oldline, 10, regmatch, 0) != REG_NOMATCH));
+
+       /* Copy rest of string into output pipeline */
+
+       while(*oldline) pipe_putc(*(oldline++));
+       pipe_putc(0);
+
+       free(*line);
+       *line = pipeline.buf;
+       return altered;
+}
+
+/* Set command pointer to point to this label.  (Does not handle null label.) */
+static sed_cmd_t *branch_to(const char *label)
+{
+       sed_cmd_t *sed_cmd;
+
+       for (sed_cmd = sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
+               if ((sed_cmd->cmd == ':') && (sed_cmd->string) && (strcmp(sed_cmd->string, label) == 0)) {
+                       return (sed_cmd);
+               }
+       }
+       error_msg_and_die("Can't find label for jump to `%s'", label);
+}
+
+/* Append copy of string to append buffer */
+static void append(char *s)
+{
+       struct append_list *temp=calloc(1,sizeof(struct append_list));
+
+       if(append_head)
+               append_tail=(append_tail->next=temp);
+       else append_head=append_tail=temp;
+       temp->string=strdup(s);
+}
+
+static void flush_append(void)
+{
+       /* Output appended lines. */
+       while(append_head) {
+               puts(append_head->string);
+               append_tail=append_head->next;
+               free(append_head->string);
+               free(append_head);
+               append_head=append_tail;
+       }
+       append_head=append_tail=NULL;
+}
+
+/* Get next line of input, flushing append buffer and noting if we hit EOF
+ * without a newline on the last line.
+ */
+static char *get_next_line(FILE * file, int *no_newline)
+{
+       char *temp;
+       int len;
+
+       flush_append();
+       temp=get_line_from_file(file);
+       if(temp) {
+               len=strlen(temp);
+               if(len && temp[len-1]=='\n') temp[len-1]=0;
+               else *no_newline=1;
+       }
+
+       return temp;
+}
+
+/* Output line of text.  missing_newline means the last line output did not
+   end with a newline.  no_newline means this line does not end with a
+   newline. */
+
+static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline)
+{
+       if(missing_newline) fputc('\n',file);
+       fputs(s,file);
+       if(!no_newline) fputc('\n',file);
+
+       return no_newline;
+}
+
+#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,stdout,missing_newline,n)
+
+static void process_file(FILE * file)
+{
+       char *pattern_space, *next_line, *hold_space=NULL;
+       static int linenum = 0, missing_newline=0;
+       int no_newline,next_no_newline=0;
+
+       next_line = get_next_line(file,&next_no_newline);
+
+       /* go through every line in the file */
+       for(;;) {
+               sed_cmd_t *sed_cmd;
+               int substituted=0;
+
+               /* Advance to next line.  Stop if out of lines. */
+               if(!(pattern_space=next_line)) break;
+               no_newline=next_no_newline;
+
+               /* Read one line in advance so we can act on the last line, the '$' address */
+               next_line = get_next_line(file,&next_no_newline);
+               linenum++;
+restart:
+               /* for every line, go through all the commands */
+               for (sed_cmd = sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
+                       int old_matched, matched;
+
+                       old_matched = sed_cmd->in_match;
+
+                       /* Determine if this command matches this line: */
+
+                       /* Are we continuing a previous multi-line match? */
+
+                       sed_cmd->in_match = sed_cmd->in_match
+
+                       /* Or is no range necessary? */
+                               || (!sed_cmd->beg_line && !sed_cmd->end_line
+                                       && !sed_cmd->beg_match && !sed_cmd->end_match)
+
+                       /* Or did we match the start of a numerical range? */
+                               || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
+
+                       /* Or does this line match our begin address regex? */
+                               || (sed_cmd->beg_match &&
+                                   !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0))
+
+                       /* Or did we match last line of input? */
+                               || (sed_cmd->beg_line == -1 && next_line == NULL);
+
+                       /* Snapshot the value */
+
+                       matched = sed_cmd->in_match;
+
+                       /* Is this line the end of the current match? */
+
+                       if(matched) {
+                               sed_cmd->in_match = !(
+                                       /* has the ending line come, or is this a single address command? */
+                                       (sed_cmd->end_line ?
+                                               sed_cmd->end_line==-1 ?
+                                                       !next_line
+                                                       : sed_cmd->end_line<=linenum
+                                               : !sed_cmd->end_match)
+                                       /* or does this line matches our last address regex */
+                                       || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0))
+                               );
+                       }
+
+                       /* Skip blocks of commands we didn't match. */
+                       if (sed_cmd->cmd == '{') {
+                               if(sed_cmd->invert ? matched : !matched)
+                                       while(sed_cmd && sed_cmd->cmd!='}') sed_cmd=sed_cmd->next;
+                               if(!sed_cmd) error_msg_and_die("Unterminated {");
+                               continue;
+                       }
+
+                       /* Okay, so did this line match? */
+                       if (sed_cmd->invert ? !matched : matched) {
+                               /* Update last used regex in case a blank substitute BRE is found */
+                               if (sed_cmd->beg_match) {
+                                       previous_regex_ptr = sed_cmd->beg_match;
+                               }
+
+                               /* actual sedding */
+                               switch (sed_cmd->cmd) {
+
+                                       /* Print line number */
+                                       case '=':
+                                               printf("%d\n", linenum);
+                                               break;
+
+                                       /* Write the current pattern space up to the first newline */
+                                       case 'P':
+                                       {
+                                               char *tmp = strchr(pattern_space, '\n');
+
+                                               if (tmp) {
+                                                       *tmp = '\0';
+                                                       sed_puts(pattern_space,1);
+                                                       *tmp = '\n';
+                                                       break;
+                                               }
+                                               /* Fall Through */
+                                       }
+
+                                       /* Write the current pattern space to output */
+                                       case 'p':
+                                               sed_puts(pattern_space,no_newline);
+                                               break;
+                                       /* Delete up through first newline */
+                                       case 'D':
+                                       {
+                                               char *tmp = strchr(pattern_space,'\n');
+
+                                               if(tmp) {
+                                                       tmp=xstrdup(tmp+1);
+                                                       free(pattern_space);
+                                                       pattern_space=tmp;
+                                                       goto restart;
+                                               }
+                                       }
+                                       /* discard this line. */
+                                       case 'd':
+                                               goto discard_line;
+
+                                       /* Substitute with regex */
+                                       case 's':
+                                               if(do_subst_command(sed_cmd, &pattern_space)) {
+                                                       substituted|=1;
+
+                                                       /* handle p option */
+                                                       if(sed_cmd->sub_p)
+                                                               sed_puts(pattern_space,no_newline);
+                                                       /* handle w option */
+                                                       if(sed_cmd->file)
+                                                               sed_cmd->no_newline=puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline);
+
+                                               }
+                                               break;
+
+                                       /* Append line to linked list to be printed later */
+                                       case 'a':
+                                       {
+                                               append(sed_cmd->string);
+                                               break;
+                                       }
+
+                                       /* Insert text before this line */
+                                       case 'i':
+                                               sed_puts(sed_cmd->string,1);
+                                               break;
+
+                                       /* Cut and paste text (replace) */
+                                       case 'c':
+                                               /* Only triggers on last line of a matching range. */
+                                               if (!sed_cmd->in_match) sed_puts(sed_cmd->string,1);
+                                               goto discard_line;
+
+                                       /* Read file, append contents to output */
+                                       case 'r':
+                                       {
+                                               FILE *outfile;
+
+                                               outfile = fopen(sed_cmd->string, "r");
+                                               if (outfile) {
+                                                       char *line;
+
+                                                       while ((line = get_chomped_line_from_file(outfile))
+                                                                       != NULL)
+                                                               append(line);
+                                                       bb_xprint_and_close_file(outfile);
+                                               }
+
+                                               break;
+                                       }
+
+                                       /* Write pattern space to file. */
+                                       case 'w':
+                                               sed_cmd->no_newline=puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline);
+                                               break;
+
+                                       /* Read next line from input */
+                                       case 'n':
+                                               if (!be_quiet)
+                                                       sed_puts(pattern_space,no_newline);
+                                               if (next_line) {
+                                                       free(pattern_space);
+                                                       pattern_space = next_line;
+                                                       no_newline=next_no_newline;
+                                                       next_line = get_next_line(file,&next_no_newline);
+                                                       linenum++;
+                                                       break;
+                                               }
+                                               /* fall through */
+
+                                       /* Quit.  End of script, end of input. */
+                                       case 'q':
+                                               /* Exit the outer while loop */
+                                               free(next_line);
+                                               next_line = NULL;
+                                               goto discard_commands;
+
+                                       /* Append the next line to the current line */
+                                       case 'N':
+                                       {
+                                               /* If no next line, jump to end of script and exit. */
+                                               if (next_line == NULL) {
+                                                       /* Jump to end of script and exit */
+                                                       free(next_line);
+                                                       next_line = NULL;
+                                                       goto discard_line;
+                                               /* append next_line, read new next_line. */
+                                               } else {
+                                                       int len=strlen(pattern_space);
+
+                                                       pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
+                                                       pattern_space[len]='\n';
+                                                       strcpy(pattern_space+len+1, next_line);
+                                                       no_newline=next_no_newline;
+                                                       next_line = get_next_line(file,&next_no_newline);
+                                                       linenum++;
+                                               }
+                                               break;
+                                       }
+
+                                       /* Test if substition worked, branch if so. */
+                                       case 't':
+                                               if (!substituted) break;
+                                               substituted=0;
+                                                       /* Fall through */
+                                       /* Branch to label */
+                                       case 'b':
+                                               if (!sed_cmd->string) goto discard_commands;
+                                               else sed_cmd = branch_to(sed_cmd->string);
+                                               break;
+                                       /* Transliterate characters */
+                                       case 'y':
+                                       {
+                                               int i;
+
+                                               for (i = 0; pattern_space[i]; i++) {
+                                                       int j;
+
+                                                       for (j = 0; sed_cmd->string[j]; j += 2) {
+                                                               if (pattern_space[i] == sed_cmd->string[j]) {
+                                                                       pattern_space[i] = sed_cmd->string[j + 1];
+                                                               }
+                                                       }
+                                               }
+
+                                               break;
+                                       }
+                                       case 'g':       /* Replace pattern space with hold space */
+                                               free(pattern_space);
+                                               if (hold_space) {
+                                                       pattern_space = strdup(hold_space);
+                                                       no_newline=0;
+                                               }
+                                               break;
+                                       case 'G':       /* Append newline and hold space to pattern space */
+                                       {
+                                               int pattern_space_size = 2;
+                                               int hold_space_size = 0;
+
+                                               if (pattern_space)
+                                                       pattern_space_size += strlen(pattern_space);
+                                               if (hold_space) hold_space_size = strlen(hold_space);
+                                               pattern_space = xrealloc(pattern_space, pattern_space_size + hold_space_size);
+                                               if (pattern_space_size == 2) pattern_space[0]=0;
+                                               strcat(pattern_space, "\n");
+                                               if (hold_space) strcat(pattern_space, hold_space);
+                                               no_newline=0;
+
+                                               break;
+                                       }
+                                       case 'h':       /* Replace hold space with pattern space */
+                                               free(hold_space);
+                                               hold_space = strdup(pattern_space);
+                                               break;
+                                       case 'H':       /* Append newline and pattern space to hold space */
+                                       {
+                                               int hold_space_size = 2;
+                                               int pattern_space_size = 0;
+
+                                               if (hold_space) hold_space_size += strlen(hold_space);
+                                               if (pattern_space)
+                                                       pattern_space_size = strlen(pattern_space);
+                                               hold_space = xrealloc(hold_space,
+                                                                                       hold_space_size + pattern_space_size);
+
+                                               if (hold_space_size == 2) hold_space[0]=0;
+                                               strcat(hold_space, "\n");
+                                               if (pattern_space) strcat(hold_space, pattern_space);
+
+                                               break;
+                                       }
+                                       case 'x': /* Exchange hold and pattern space */
+                                       {
+                                               char *tmp = pattern_space;
+                                               pattern_space = hold_space;
+                                               no_newline=0;
+                                               hold_space = tmp;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               /*
+                * exit point from sedding...
+                */
+discard_commands:
+               /* we will print the line unless we were told to be quiet ('-n')
+                  or if the line was suppressed (ala 'd'elete) */
+               if (!be_quiet) sed_puts(pattern_space,no_newline);
+
+               /* Delete and such jump here. */
+discard_line:
+               flush_append();
+               free(pattern_space);
+       }
+}
+
+/* It is possible to have a command line argument with embedded
+   newlines.  This counts as multiple command lines. */
+
+static void add_cmd_block(char *cmdstr)
+{
+       int go=1;
+       char *temp=xstrdup(cmdstr),*temp2=temp;
+
+       while(go) {
+               int len=strcspn(temp2,"\n");
+               if(!temp2[len]) go=0;
+               else temp2[len]=0;
+               add_cmd(temp2);
+               temp2+=len+1;
+       }
+       free(temp);
+}
+
+extern int sed_main(int argc, char **argv)
+{
+       int opt, status = EXIT_SUCCESS;
+
+#ifdef BB_FEATURE_CLEAN_UP
+       /* destroy command strings on exit */
+       if (atexit(free_and_close_stuff) == -1)
+               perror_msg_and_die("atexit");
+#endif
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "ne:f:")) > 0) {
+               switch (opt) {
+               case 'n':
+                       be_quiet++;
+                       break;
+               case 'e':
+                       add_cmd_block(optarg);
+                       break;
+               case 'f':
+               {
+                       FILE *cmdfile;
+                       char *line;
+
+                       cmdfile = xfopen(optarg, "r");
+
+                       while ((line = get_chomped_line_from_file(cmdfile))
+                                != NULL) {
+                               add_cmd(line);
+                               free(line);
+                       }
+                       bb_xprint_and_close_file(cmdfile);
+
+                       break;
+               }
+               default:
+                       show_usage();
+               }
+       }
+
+       /* if we didn't get a pattern from a -e and no command file was specified,
+        * argv[optind] should be the pattern. no pattern, no worky */
+       if (sed_cmd_head.next == NULL) {
+               if (argv[optind] == NULL)
+                       show_usage();
+               else
+                       add_cmd_block(argv[optind++]);
+       }
+       /* Flush any unfinished commands. */
+       add_cmd("");
+
+       /* argv[(optind)..(argc-1)] should be names of file to process. If no
+        * files were specified or '-' was specified, take input from stdin.
+        * Otherwise, we process all the files specified. */
+       if (argv[optind] == NULL) {
+               process_file(stdin);
+       } else {
+               int i;
+               FILE *file;
+
+               for (i = optind; i < argc; i++) {
+                       if(!strcmp(argv[i], "-")) {
+                               process_file(stdin);
+                       } else {
+                               file = wfopen(argv[i], "r");
+                               if (file) {
+                                       process_file(file);
+                                       fclose(file);
+                               } else {
+                                       status = EXIT_FAILURE;
+                               }
+                       }
+               }
+       }
+
+       return status;
+}
diff --git a/setkeycodes.c b/setkeycodes.c
new file mode 100644 (file)
index 0000000..85612c8
--- /dev/null
@@ -0,0 +1,72 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * setkeycodes
+ *
+ * Copyright (C) 1994-1998 Andries E. Brouwer <aeb@cwi.nl>
+ *
+ * Adjusted for BusyBox by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+
+/* From <linux/kd.h> */
+struct kbkeycode {
+       unsigned int scancode, keycode;
+};
+static const int KDSETKEYCODE = 0x4B4D;  /* write kernel keycode table entry */
+
+extern int 
+setkeycodes_main(int argc, char** argv)
+{
+    char *ep;
+    int fd, sc;
+    struct kbkeycode a;
+
+    if (argc % 2 != 1 || argc < 2) {
+      show_usage();
+       }
+        
+       fd = get_console_fd();
+
+    while (argc > 2) {
+       a.keycode = atoi(argv[2]);
+       a.scancode = sc = strtol(argv[1], &ep, 16);
+       if (*ep) {
+      error_msg_and_die("error reading SCANCODE: '%s'", argv[1]);
+       }
+       if (a.scancode > 127) {
+           a.scancode -= 0xe000;
+           a.scancode += 128;
+       }
+       if (a.scancode > 255 || a.keycode > 127) {
+      error_msg_and_die("SCANCODE or KEYCODE outside bounds");
+       }
+       if (ioctl(fd,KDSETKEYCODE,&a)) {
+           perror("KDSETKEYCODE");
+               error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode);
+       }
+       argc -= 2;
+       argv += 2;
+    }
+       return EXIT_SUCCESS;
+}
diff --git a/sleep.c b/sleep.c
new file mode 100644 (file)
index 0000000..7bc98d8
--- /dev/null
+++ b/sleep.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini sleep implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int sleep_main(int argc, char **argv)
+{
+       if ((argc < 2) || (**(argv + 1) == '-')) {
+               show_usage();
+       }
+
+       if (sleep(atoi(*(++argv))) != 0)
+               perror_msg_and_die("sleep");
+       return EXIT_SUCCESS;
+}
diff --git a/sort.c b/sort.c
new file mode 100644 (file)
index 0000000..4f4979c
--- /dev/null
+++ b/sort.c
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini sort implementation for busybox
+ *
+ *
+ * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+static int compare_ascii(const void *x, const void *y)
+{
+       return strcmp(*(char **)x, *(char **)y);
+}
+
+static int compare_numeric(const void *x, const void *y)
+{
+       int z = atoi(*(char **)x) - atoi(*(char **)y);
+       return z ? z : strcmp(*(char **)x, *(char **)y);
+}
+
+int sort_main(int argc, char **argv)
+{
+       FILE *fp;
+       char *line, **lines = NULL;
+       int i, opt, nlines = 0;
+       int (*compare)(const void *, const void *) = compare_ascii;
+#ifdef BB_FEATURE_SORT_REVERSE
+       int reverse = FALSE;
+#endif
+#ifdef BB_FEATURE_SORT_UNIQUE
+       int unique = FALSE;
+#endif
+
+       while ((opt = getopt(argc, argv, "nru")) != -1) {
+               switch (opt) {
+                       case 'n':
+                               compare = compare_numeric;
+                               break;
+#ifdef BB_FEATURE_SORT_REVERSE
+                       case 'r':
+                               reverse = TRUE;
+                               break;
+#endif
+#ifdef BB_FEATURE_SORT_UNIQUE
+                       case 'u':
+                               unique = TRUE;
+                               break;
+#endif
+                       default:
+                               show_usage();
+               }
+       }
+
+       /* read the input */
+       for (i = optind; i == optind || i < argc; i++) {
+               if (argv[i] == NULL)
+                       fp = stdin;
+               else
+                       fp = xfopen(argv[i], "r");
+
+               while ((line = get_line_from_file(fp)) != NULL) {
+                       lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
+                       chomp(line);
+                       lines[nlines++] = line;
+               }
+       }
+
+       /* sort it */
+       qsort(lines, nlines, sizeof(char *), compare);
+
+       /* print it */
+#ifdef BB_FEATURE_SORT_REVERSE
+       if (reverse) {
+               for (i = --nlines; 0 <= i; i--)
+#ifdef BB_FEATURE_SORT_UNIQUE
+                       if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i])))
+#endif
+                               puts(lines[i]);
+       } else
+#endif
+               for (i = 0; i < nlines; i++)
+#ifdef BB_FEATURE_SORT_UNIQUE
+                       if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i])))
+#endif
+                               puts(lines[i]);
+       return EXIT_SUCCESS;
+}
diff --git a/stty.c b/stty.c
new file mode 100644 (file)
index 0000000..a67a17c
--- /dev/null
+++ b/stty.c
@@ -0,0 +1,1395 @@
+/* vi: set sw=4 ts=4: */
+/* stty -- change and print terminal line settings
+   Copyright (C) 1990-1999 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Usage: stty [-ag] [-F device] [setting...]
+
+   Options:
+   -a Write all current settings to stdout in human-readable form.
+   -g Write all current settings to stdout in stty-readable form.
+   -F Open and use the specified device instead of stdin
+
+   If no args are given, write to stdout the baud rate and settings that
+   have been changed from their defaults.  Mode reading and changes
+   are done on the specified device, or stdin if none was specified.
+
+   David MacKenzie <djm@gnu.ai.mit.edu>
+
+   Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
+
+   */
+
+//#define TEST
+
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <getopt.h>
+
+#include <sys/param.h>
+#include <unistd.h>
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <memory.h>
+#include <fcntl.h>
+#include "busybox.h"
+
+#define STREQ(a, b) (strcmp ((a), (b)) == 0)
+
+
+#ifndef _POSIX_VDISABLE
+# define _POSIX_VDISABLE ((unsigned char) 0)
+#endif
+
+#define Control(c) ((c) & 0x1f)
+/* Canonical values for control characters. */
+#ifndef CINTR
+# define CINTR Control ('c')
+#endif
+#ifndef CQUIT
+# define CQUIT 28
+#endif
+#ifndef CERASE
+# define CERASE 127
+#endif
+#ifndef CKILL
+# define CKILL Control ('u')
+#endif
+#ifndef CEOF
+# define CEOF Control ('d')
+#endif
+#ifndef CEOL
+# define CEOL _POSIX_VDISABLE
+#endif
+#ifndef CSTART
+# define CSTART Control ('q')
+#endif
+#ifndef CSTOP
+# define CSTOP Control ('s')
+#endif
+#ifndef CSUSP
+# define CSUSP Control ('z')
+#endif
+#if defined(VEOL2) && !defined(CEOL2)
+# define CEOL2 _POSIX_VDISABLE
+#endif
+/* ISC renamed swtch to susp for termios, but we'll accept either name.  */
+#if defined(VSUSP) && !defined(VSWTCH)
+# define VSWTCH VSUSP
+# define CSWTCH CSUSP
+#endif
+#if defined(VSWTCH) && !defined(CSWTCH)
+# define CSWTCH _POSIX_VDISABLE
+#endif
+
+/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
+   So the default is to disable `swtch.'  */
+#if defined (__sparc__) && defined (__svr4__)
+# undef CSWTCH
+# define CSWTCH _POSIX_VDISABLE
+#endif
+
+#if defined(VWERSE) && !defined (VWERASE)       /* AIX-3.2.5 */
+# define VWERASE VWERSE
+#endif
+#if defined(VDSUSP) && !defined (CDSUSP)
+# define CDSUSP Control ('y')
+#endif
+#if !defined(VREPRINT) && defined(VRPRNT)       /* Irix 4.0.5 */
+# define VREPRINT VRPRNT
+#endif
+#if defined(VREPRINT) && !defined(CRPRNT)
+# define CRPRNT Control ('r')
+#endif
+#if defined(VWERASE) && !defined(CWERASE)
+# define CWERASE Control ('w')
+#endif
+#if defined(VLNEXT) && !defined(CLNEXT)
+# define CLNEXT Control ('v')
+#endif
+#if defined(VDISCARD) && !defined(VFLUSHO)
+# define VFLUSHO VDISCARD
+#endif
+#if defined(VFLUSH) && !defined(VFLUSHO)        /* Ultrix 4.2 */
+# define VFLUSHO VFLUSH
+#endif
+#if defined(CTLECH) && !defined(ECHOCTL)        /* Ultrix 4.3 */
+# define ECHOCTL CTLECH
+#endif
+#if defined(TCTLECH) && !defined(ECHOCTL)       /* Ultrix 4.2 */
+# define ECHOCTL TCTLECH
+#endif
+#if defined(CRTKIL) && !defined(ECHOKE)         /* Ultrix 4.2 and 4.3 */
+# define ECHOKE CRTKIL
+#endif
+#if defined(VFLUSHO) && !defined(CFLUSHO)
+# define CFLUSHO Control ('o')
+#endif
+#if defined(VSTATUS) && !defined(CSTATUS)
+# define CSTATUS Control ('t')
+#endif
+
+/* Which speeds to set.  */
+enum speed_setting {
+       input_speed, output_speed, both_speeds
+};
+
+/* What to output and how.  */
+enum output_type {
+       changed, all, recoverable       /* Default, -a, -g.  */
+};
+
+/* Which member(s) of `struct termios' a mode uses.  */
+enum mode_type {
+       control, input, output, local, combination
+};
+
+
+static const char evenp     [] = "evenp";
+static const char raw       [] = "raw";
+static const char stty_min  [] = "min";
+static const char stty_time [] = "time";
+static const char stty_swtch[] = "swtch";
+static const char stty_eol  [] = "eol";
+static const char stty_eof  [] = "eof";
+static const char parity    [] = "parity";
+static const char stty_oddp [] = "oddp";
+static const char stty_nl   [] = "nl";
+static const char stty_ek   [] = "ek";
+static const char stty_sane [] = "sane";
+static const char cbreak    [] = "cbreak";
+static const char stty_pass8[] = "pass8";
+static const char litout    [] = "litout";
+static const char cooked    [] = "cooked";
+static const char decctlq   [] = "decctlq";
+static const char stty_tabs [] = "tabs";
+static const char stty_lcase[] = "lcase";
+static const char stty_LCASE[] = "LCASE";
+static const char stty_crt  [] = "crt";
+static const char stty_dec  [] = "dec";
+
+
+/* Flags for `struct mode_info'. */
+#define SANE_SET 1              /* Set in `sane' mode.                  */
+#define SANE_UNSET 2            /* Unset in `sane' mode.                */
+#define REV 4                   /* Can be turned off by prepending `-'. */
+#define OMIT 8                  /* Don't display value.                 */
+
+/* Each mode.  */
+struct mode_info {
+       const char *name;       /* Name given on command line.           */
+       enum mode_type type;    /* Which structure element to change.    */
+       char flags;             /* Setting and display options.          */
+       unsigned long bits;     /* Bits to set for this mode.            */
+       unsigned long mask;     /* Other bits to turn off for this mode. */
+};
+
+static const struct  mode_info mode_info[] = {
+       {"parenb",   control,     REV,               PARENB,     0 },
+       {"parodd",   control,     REV,               PARODD,     0 },
+       {"cs5",      control,     0,                 CS5,     CSIZE},
+       {"cs6",      control,     0,                 CS6,     CSIZE},
+       {"cs7",      control,     0,                 CS7,     CSIZE},
+       {"cs8",      control,     0,                 CS8,     CSIZE},
+       {"hupcl",    control,     REV,               HUPCL,      0 },
+       {"hup",      control,     REV        | OMIT, HUPCL,      0 },
+       {"cstopb",   control,     REV,               CSTOPB,     0 },
+       {"cread",    control,     SANE_SET   | REV,  CREAD,      0 },
+       {"clocal",   control,     REV,               CLOCAL,     0 },
+#ifdef CRTSCTS
+       {"crtscts",  control,     REV,               CRTSCTS,    0 },
+#endif
+       {"ignbrk",   input,       SANE_UNSET | REV,  IGNBRK,     0 },
+       {"brkint",   input,       SANE_SET   | REV,  BRKINT,     0 },
+       {"ignpar",   input,       REV,               IGNPAR,     0 },
+       {"parmrk",   input,       REV,               PARMRK,     0 },
+       {"inpck",    input,       REV,               INPCK,      0 },
+       {"istrip",   input,       REV,               ISTRIP,     0 },
+       {"inlcr",    input,       SANE_UNSET | REV,  INLCR,      0 },
+       {"igncr",    input,       SANE_UNSET | REV,  IGNCR,      0 },
+       {"icrnl",    input,       SANE_SET   | REV,  ICRNL,      0 },
+       {"ixon",     input,       REV,               IXON,       0 },
+       {"ixoff",    input,       SANE_UNSET | REV,  IXOFF,      0 },
+       {"tandem",   input,       REV        | OMIT, IXOFF,      0 },
+#ifdef IUCLC
+       {"iuclc",    input,       SANE_UNSET | REV,  IUCLC,      0 },
+#endif
+#ifdef IXANY
+       {"ixany",    input,       SANE_UNSET | REV,  IXANY,      0 },
+#endif
+#ifdef IMAXBEL
+       {"imaxbel",  input,       SANE_SET   | REV,  IMAXBEL,    0 },
+#endif
+       {"opost",    output,      SANE_SET   | REV,  OPOST,      0 },
+#ifdef OLCUC
+       {"olcuc",    output,      SANE_UNSET | REV,  OLCUC,      0 },
+#endif
+#ifdef OCRNL
+       {"ocrnl",    output,      SANE_UNSET | REV,  OCRNL,      0 },
+#endif
+#ifdef ONLCR
+       {"onlcr",    output,      SANE_SET   | REV,  ONLCR,      0 },
+#endif
+#ifdef ONOCR
+       {"onocr",    output,      SANE_UNSET | REV,  ONOCR,      0 },
+#endif
+#ifdef ONLRET
+       {"onlret",   output,      SANE_UNSET | REV,  ONLRET,     0 },
+#endif
+#ifdef OFILL
+       {"ofill",    output,      SANE_UNSET | REV,  OFILL,      0 },
+#endif
+#ifdef OFDEL
+       {"ofdel",    output,      SANE_UNSET | REV,  OFDEL,      0 },
+#endif
+#ifdef NLDLY
+       {"nl1",      output,      SANE_UNSET,        NL1,     NLDLY},
+       {"nl0",      output,      SANE_SET,          NL0,     NLDLY},
+#endif
+#ifdef CRDLY
+       {"cr3",      output,      SANE_UNSET,        CR3,     CRDLY},
+       {"cr2",      output,      SANE_UNSET,        CR2,     CRDLY},
+       {"cr1",      output,      SANE_UNSET,        CR1,     CRDLY},
+       {"cr0",      output,      SANE_SET,          CR0,     CRDLY},
+#endif
+
+#ifdef TABDLY
+       {"tab3",     output,      SANE_UNSET,        TAB3,   TABDLY},
+       {"tab2",     output,      SANE_UNSET,        TAB2,   TABDLY},
+       {"tab1",     output,      SANE_UNSET,        TAB1,   TABDLY},
+       {"tab0",     output,      SANE_SET,          TAB0,   TABDLY},
+#else
+# ifdef OXTABS
+       {"tab3",     output,      SANE_UNSET,        OXTABS,     0 },
+# endif
+#endif
+
+#ifdef BSDLY
+       {"bs1",      output,      SANE_UNSET,        BS1,     BSDLY},
+       {"bs0",      output,      SANE_SET,          BS0,     BSDLY},
+#endif
+#ifdef VTDLY
+       {"vt1",      output,      SANE_UNSET,        VT1,     VTDLY},
+       {"vt0",      output,      SANE_SET,          VT0,     VTDLY},
+#endif
+#ifdef FFDLY
+       {"ff1",      output,      SANE_UNSET,        FF1,     FFDLY},
+       {"ff0",      output,      SANE_SET,          FF0,     FFDLY},
+#endif
+       {"isig",     local,       SANE_SET   | REV,  ISIG,       0 },
+       {"icanon",   local,       SANE_SET   | REV,  ICANON,     0 },
+#ifdef IEXTEN
+       {"iexten",   local,       SANE_SET   | REV,  IEXTEN,     0 },
+#endif
+       {"echo",     local,       SANE_SET   | REV,  ECHO,       0 },
+       {"echoe",    local,       SANE_SET   | REV,  ECHOE,      0 },
+       {"crterase", local,       REV        | OMIT, ECHOE,      0 },
+       {"echok",    local,       SANE_SET   | REV,  ECHOK,      0 },
+       {"echonl",   local,       SANE_UNSET | REV,  ECHONL,     0 },
+       {"noflsh",   local,       SANE_UNSET | REV,  NOFLSH,     0 },
+#ifdef XCASE
+       {"xcase",    local,       SANE_UNSET | REV,  XCASE,      0 },
+#endif
+#ifdef TOSTOP
+       {"tostop",   local,       SANE_UNSET | REV,  TOSTOP,     0 },
+#endif
+#ifdef ECHOPRT
+       {"echoprt",  local,       SANE_UNSET | REV,  ECHOPRT,    0 },
+       {"prterase", local,       REV | OMIT,        ECHOPRT,    0 },
+#endif
+#ifdef ECHOCTL
+       {"echoctl",  local,       SANE_SET   | REV,  ECHOCTL,    0 },
+       {"ctlecho",  local,       REV        | OMIT, ECHOCTL,    0 },
+#endif
+#ifdef ECHOKE
+       {"echoke",   local,       SANE_SET   | REV,  ECHOKE,     0 },
+       {"crtkill",  local,       REV        | OMIT, ECHOKE,     0 },
+#endif
+       {evenp,      combination, REV        | OMIT, 0,          0 },
+       {parity,     combination, REV        | OMIT, 0,          0 },
+       {stty_oddp,  combination, REV        | OMIT, 0,          0 },
+       {stty_nl,    combination, REV        | OMIT, 0,          0 },
+       {stty_ek,    combination, OMIT,              0,          0 },
+       {stty_sane,  combination, OMIT,              0,          0 },
+       {cooked,     combination, REV        | OMIT, 0,          0 },
+       {raw,        combination, REV        | OMIT, 0,          0 },
+       {stty_pass8, combination, REV        | OMIT, 0,          0 },
+       {litout,     combination, REV        | OMIT, 0,          0 },
+       {cbreak,     combination, REV        | OMIT, 0,          0 },
+#ifdef IXANY
+       {decctlq,    combination, REV        | OMIT, 0,          0 },
+#endif
+#if defined (TABDLY) || defined (OXTABS)
+       {stty_tabs,  combination, REV        | OMIT, 0,          0 },
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+       {stty_lcase, combination, REV        | OMIT, 0,          0 },
+       {stty_LCASE, combination, REV        | OMIT, 0,          0 },
+#endif
+       {stty_crt,   combination, OMIT,              0,          0 },
+       {stty_dec,   combination, OMIT,              0,          0 },
+};
+
+static const int NUM_mode_info =
+
+       (sizeof(mode_info) / sizeof(struct mode_info));
+
+/* Control character settings.  */
+struct control_info {
+       const char *name;                       /* Name given on command line.  */
+       unsigned char saneval;          /* Value to set for `stty sane'.  */
+       int offset;                                     /* Offset in c_cc.  */
+};
+
+/* Control characters. */
+
+static const struct  control_info control_info[] = {
+       {"intr",     CINTR,   VINTR},
+       {"quit",     CQUIT,   VQUIT},
+       {"erase",    CERASE,  VERASE},
+       {"kill",     CKILL,   VKILL},
+       {stty_eof,   CEOF,    VEOF},
+       {stty_eol,   CEOL,    VEOL},
+#ifdef VEOL2
+       {"eol2",     CEOL2,   VEOL2},
+#endif
+#ifdef VSWTCH
+       {stty_swtch, CSWTCH,  VSWTCH},
+#endif
+       {"start",    CSTART,  VSTART},
+       {"stop",     CSTOP,   VSTOP},
+       {"susp",     CSUSP,   VSUSP},
+#ifdef VDSUSP
+       {"dsusp",    CDSUSP,  VDSUSP},
+#endif
+#ifdef VREPRINT
+       {"rprnt",    CRPRNT,  VREPRINT},
+#endif
+#ifdef VWERASE
+       {"werase",   CWERASE, VWERASE},
+#endif
+#ifdef VLNEXT
+       {"lnext",    CLNEXT,  VLNEXT},
+#endif
+#ifdef VFLUSHO
+       {"flush",    CFLUSHO, VFLUSHO},
+#endif
+#ifdef VSTATUS
+       {"status",   CSTATUS, VSTATUS},
+#endif
+       /* These must be last because of the display routines. */
+       {stty_min,   1,       VMIN},
+       {stty_time,  0,       VTIME},
+};
+
+static const int NUM_control_info =
+       (sizeof(control_info) / sizeof(struct control_info));
+
+
+static const char *  visible(unsigned int ch);
+static unsigned long baud_to_value(speed_t speed);
+static int           recover_mode(char *arg, struct termios *mode);
+static int           screen_columns(void);
+static int           set_mode(const struct mode_info *info,
+                                       int reversed, struct termios *mode);
+static speed_t       string_to_baud(const char *arg);
+static tcflag_t*     mode_type_flag(enum mode_type type, struct termios *mode);
+static void          display_all(struct termios *mode, int fd,
+                                       const char *device_name);
+static void          display_changed(struct termios *mode);
+static void          display_recoverable(struct termios *mode);
+static void          display_settings(enum output_type output_type,
+                                       struct termios *mode, int fd,
+                                       const char *device_name);
+static void          display_speed(struct termios *mode, int fancy);
+static void          display_window_size(int fancy, int fd,
+                                       const char *device_name);
+static void          sane_mode(struct termios *mode);
+static void          set_control_char(const struct control_info *info,
+                                       const char *arg, struct termios *mode);
+static void          set_speed(enum speed_setting type,
+                                       const char *arg, struct termios *mode);
+static void          set_window_size(int rows, int cols, int fd,
+                                       const char *device_name);
+
+/* The width of the screen, for output wrapping. */
+static int max_col;
+
+/* Current position, to know when to wrap. */
+static int current_col;
+
+/* Print format string MESSAGE and optional args.
+   Wrap to next line first if it won't fit.
+   Print a space first unless MESSAGE will start a new line. */
+
+static void wrapf(const char *message, ...)
+{
+       va_list args;
+       char buf[1024];                 /* Plenty long for our needs. */
+       int buflen;
+
+       va_start(args, message);
+       vsprintf(buf, message, args);
+       va_end(args);
+       buflen = strlen(buf);
+       if (current_col + (current_col > 0) + buflen >= max_col) {
+               putchar('\n');
+               current_col = 0;
+       }
+       if (current_col > 0) {
+               putchar(' ');
+               current_col++;
+       }
+       fputs(buf, stdout);
+       current_col += buflen;
+}
+
+static const struct suffix_mult stty_suffixes[] = {
+       {"b",  512 },
+       {"k",  1024},
+       {"B",  1024},
+       {NULL, 0   }
+};
+
+#ifndef TEST
+extern int stty_main(int argc, char **argv)
+#else
+extern int main(int argc, char **argv)
+#endif
+{
+       struct termios mode;
+       enum   output_type output_type;
+       int    optc;
+       int    require_set_attr;
+       int    speed_was_set;
+       int    verbose_output;
+       int    recoverable_output;
+       int    k;
+       int    noargs = 1;
+       char * file_name = NULL;
+       int    fd;
+       const char *device_name;
+
+       output_type = changed;
+       verbose_output = 0;
+       recoverable_output = 0;
+
+       /* Don't print error messages for unrecognized options.  */
+       opterr = 0;
+
+       while ((optc = getopt(argc, argv, "agF:")) != -1) {
+               switch (optc) {
+               case 'a':
+                       verbose_output = 1;
+                       output_type = all;
+                       break;
+
+               case 'g':
+                       recoverable_output = 1;
+                       output_type = recoverable;
+                       break;
+
+               case 'F':
+                       if (file_name)
+                               error_msg_and_die("only one device may be specified");
+                       file_name = optarg;
+                       break;
+
+               default:                /* unrecognized option */
+                       noargs = 0;
+                       break;
+               }
+
+               if (noargs == 0)
+                       break;
+       }
+
+       if (optind < argc)
+               noargs = 0;
+
+       /* Specifying both -a and -g gets an error.  */
+       if (verbose_output && recoverable_output)
+               error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
+
+       /* Specifying any other arguments with -a or -g gets an error.  */
+       if (!noargs && (verbose_output || recoverable_output))
+               error_msg_and_die ("modes may not be set when specifying an output style");
+
+       /* FIXME: it'd be better not to open the file until we've verified
+          that all arguments are valid.  Otherwise, we could end up doing
+          only some of the requested operations and then failing, probably
+          leaving things in an undesirable state.  */
+
+       if (file_name) {
+               int fdflags;
+
+               device_name = file_name;
+               fd = open(device_name, O_RDONLY | O_NONBLOCK);
+               if (fd < 0)
+                       perror_msg_and_die("%s", device_name);
+               if ((fdflags = fcntl(fd, F_GETFL)) == -1
+                       || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+                       perror_msg_and_die("%s: couldn't reset non-blocking mode",
+                                                          device_name);
+       } else {
+               fd = 0;
+               device_name = "standard input";
+       }
+
+       /* Initialize to all zeroes so there is no risk memcmp will report a
+          spurious difference in an uninitialized portion of the structure.  */
+       memset(&mode, 0, sizeof(mode));
+       if (tcgetattr(fd, &mode))
+               perror_msg_and_die("%s", device_name);
+
+       if (verbose_output || recoverable_output || noargs) {
+               max_col = screen_columns();
+               current_col = 0;
+               display_settings(output_type, &mode, fd, device_name);
+               return EXIT_SUCCESS;
+       }
+
+       speed_was_set = 0;
+       require_set_attr = 0;
+       k = 0;
+       while (++k < argc) {
+               int match_found = 0;
+               int reversed = 0;
+               int i;
+
+               if (argv[k][0] == '-') {
+                       char *find_dev_opt;
+
+                       ++argv[k];
+
+     /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
+       Find the options that have been parsed.  This is really
+       gross, but it's needed because stty SETTINGS look like options to
+       getopt(), so we need to work around things in a really horrible
+       way.  If any new options are ever added to stty, the short option
+       MUST NOT be a letter which is the first letter of one of the
+       possible stty settings.
+     */
+                       find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
+                       if(find_dev_opt) {
+                               if(find_dev_opt[1]==0)  /* -*F   /dev/foo */
+                                       k++;            /* skip  /dev/foo */
+                               continue;   /* else -*F/dev/foo - no skip */
+                       }
+                       if(argv[k][0]=='a' || argv[k][0]=='g')
+                               continue;
+                       /* Is not options - is reverse params */
+                       reversed = 1;
+               }
+               for (i = 0; i < NUM_mode_info; ++i)
+                       if (STREQ(argv[k], mode_info[i].name)) {
+                               match_found = set_mode(&mode_info[i], reversed, &mode);
+                               require_set_attr = 1;
+                               break;
+                       }
+
+               if (match_found == 0 && reversed)
+                       error_msg_and_die("invalid argument `%s'", --argv[k]);
+
+               if (match_found == 0)
+                       for (i = 0; i < NUM_control_info; ++i)
+                               if (STREQ(argv[k], control_info[i].name)) {
+                                       if (k == argc - 1)
+                                           error_msg_and_die("missing argument to `%s'", argv[k]);
+                                       match_found = 1;
+                                       ++k;
+                                       set_control_char(&control_info[i], argv[k], &mode);
+                                       require_set_attr = 1;
+                                       break;
+                               }
+
+               if (match_found == 0) {
+                       if (STREQ(argv[k], "ispeed")) {
+                               if (k == argc - 1)
+                                   error_msg_and_die("missing argument to `%s'", argv[k]);
+                               ++k;
+                               set_speed(input_speed, argv[k], &mode);
+                               speed_was_set = 1;
+                               require_set_attr = 1;
+                       } else if (STREQ(argv[k], "ospeed")) {
+                               if (k == argc - 1)
+                                   error_msg_and_die("missing argument to `%s'", argv[k]);
+                               ++k;
+                               set_speed(output_speed, argv[k], &mode);
+                               speed_was_set = 1;
+                               require_set_attr = 1;
+                       }
+#ifdef TIOCGWINSZ
+                       else if (STREQ(argv[k], "rows")) {
+                               if (k == argc - 1)
+                                   error_msg_and_die("missing argument to `%s'", argv[k]);
+                               ++k;
+                               set_window_size((int) parse_number(argv[k], stty_suffixes),
+                                                               -1, fd, device_name);
+                       } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
+                               if (k == argc - 1)
+                                   error_msg_and_die("missing argument to `%s'", argv[k]);
+                               ++k;
+                               set_window_size(-1,
+                                               (int) parse_number(argv[k], stty_suffixes),
+                                               fd, device_name);
+                       } else if (STREQ(argv[k], "size")) {
+                               max_col = screen_columns();
+                               current_col = 0;
+                               display_window_size(0, fd, device_name);
+                       }
+#endif
+#ifdef HAVE_C_LINE
+                       else if (STREQ(argv[k], "line")) {
+                               if (k == argc - 1)
+                                       error_msg_and_die("missing argument to `%s'", argv[k]);
+                               ++k;
+                               mode.c_line = parse_number(argv[k], stty_suffixes);
+                               require_set_attr = 1;
+                       }
+#endif
+                       else if (STREQ(argv[k], "speed")) {
+                               max_col = screen_columns();
+                               display_speed(&mode, 0);
+                       } else if (recover_mode(argv[k], &mode) == 1)
+                               require_set_attr = 1;
+                       else if (string_to_baud(argv[k]) != (speed_t) - 1) {
+                               set_speed(both_speeds, argv[k], &mode);
+                               speed_was_set = 1;
+                               require_set_attr = 1;
+                       } else
+                               error_msg_and_die("invalid argument `%s'", argv[k]);
+               }
+       }
+
+       if (require_set_attr) {
+               struct termios new_mode;
+
+               if (tcsetattr(fd, TCSADRAIN, &mode))
+                       perror_msg_and_die("%s", device_name);
+
+               /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
+                  it performs *any* of the requested operations.  This means it
+                  can report `success' when it has actually failed to perform
+                  some proper subset of the requested operations.  To detect
+                  this partial failure, get the current terminal attributes and
+                  compare them to the requested ones.  */
+
+               /* Initialize to all zeroes so there is no risk memcmp will report a
+                  spurious difference in an uninitialized portion of the structure.  */
+               memset(&new_mode, 0, sizeof(new_mode));
+               if (tcgetattr(fd, &new_mode))
+                       perror_msg_and_die("%s", device_name);
+
+               /* Normally, one shouldn't use memcmp to compare structures that
+                  may have `holes' containing uninitialized data, but we have been
+                  careful to initialize the storage of these two variables to all
+                  zeroes.  One might think it more efficient simply to compare the
+                  modified fields, but that would require enumerating those fields --
+                  and not all systems have the same fields in this structure.  */
+
+               if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
+#ifdef CIBAUD
+                       /* SunOS 4.1.3 (at least) has the problem that after this sequence,
+                          tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
+                          sometimes (m1 != m2).  The only difference is in the four bits
+                          of the c_cflag field corresponding to the baud rate.  To save
+                          Sun users a little confusion, don't report an error if this
+                          happens.  But suppress the error only if we haven't tried to
+                          set the baud rate explicitly -- otherwise we'd never give an
+                          error for a true failure to set the baud rate.  */
+
+                       new_mode.c_cflag &= (~CIBAUD);
+                       if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
+#endif
+                               error_msg_and_die ("%s: unable to perform all requested operations",
+                                        device_name);
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
+
+/* Return 0 if not applied because not reversible; otherwise return 1.  */
+
+static int
+set_mode(const struct mode_info *info, int reversed, struct termios *mode)
+{
+       tcflag_t *bitsp;
+
+       if (reversed && (info->flags & REV) == 0)
+               return 0;
+
+       bitsp = mode_type_flag(info->type, mode);
+
+       if (bitsp == NULL) {
+               /* Combination mode. */
+               if (info->name == evenp || info->name == parity) {
+                       if (reversed)
+                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+                       else
+                               mode->c_cflag =
+                                       (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
+               } else if (info->name == stty_oddp) {
+                       if (reversed)
+                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+                       else
+                               mode->c_cflag =
+                                       (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
+               } else if (info->name == stty_nl) {
+                       if (reversed) {
+                               mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
+                               mode->c_oflag = (mode->c_oflag
+#ifdef ONLCR
+                                                                | ONLCR
+#endif
+                                       )
+#ifdef OCRNL
+                                       & ~OCRNL
+#endif
+#ifdef ONLRET
+                                       & ~ONLRET
+#endif
+                                       ;
+                       } else {
+                               mode->c_iflag = mode->c_iflag & ~ICRNL;
+#ifdef ONLCR
+                               mode->c_oflag = mode->c_oflag & ~ONLCR;
+#endif
+                       }
+               } else if (info->name == stty_ek) {
+                       mode->c_cc[VERASE] = CERASE;
+                       mode->c_cc[VKILL] = CKILL;
+               } else if (info->name == stty_sane)
+                       sane_mode(mode);
+               else if (info->name == cbreak) {
+                       if (reversed)
+                               mode->c_lflag |= ICANON;
+                       else
+                               mode->c_lflag &= ~ICANON;
+               } else if (info->name == stty_pass8) {
+                       if (reversed) {
+                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+                               mode->c_iflag |= ISTRIP;
+                       } else {
+                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+                               mode->c_iflag &= ~ISTRIP;
+                       }
+               } else if (info->name == litout) {
+                       if (reversed) {
+                               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+                               mode->c_iflag |= ISTRIP;
+                               mode->c_oflag |= OPOST;
+                       } else {
+                               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+                               mode->c_iflag &= ~ISTRIP;
+                               mode->c_oflag &= ~OPOST;
+                       }
+               } else if (info->name == raw || info->name == cooked) {
+                       if ((info->name[0] == 'r' && reversed)
+                               || (info->name[0] == 'c' && !reversed)) {
+                               /* Cooked mode. */
+                               mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
+                               mode->c_oflag |= OPOST;
+                               mode->c_lflag |= ISIG | ICANON;
+#if VMIN == VEOF
+                               mode->c_cc[VEOF] = CEOF;
+#endif
+#if VTIME == VEOL
+                               mode->c_cc[VEOL] = CEOL;
+#endif
+                       } else {
+                               /* Raw mode. */
+                               mode->c_iflag = 0;
+                               mode->c_oflag &= ~OPOST;
+                               mode->c_lflag &= ~(ISIG | ICANON
+#ifdef XCASE
+                                                                  | XCASE
+#endif
+                                       );
+                               mode->c_cc[VMIN] = 1;
+                               mode->c_cc[VTIME] = 0;
+                       }
+               }
+#ifdef IXANY
+               else if (info->name == decctlq) {
+                       if (reversed)
+                               mode->c_iflag |= IXANY;
+                       else
+                               mode->c_iflag &= ~IXANY;
+               }
+#endif
+#ifdef TABDLY
+               else if (info->name == stty_tabs) {
+                       if (reversed)
+                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
+                       else
+                               mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
+               }
+#else
+# ifdef OXTABS
+               else if (info->name == stty_tabs) {
+                       if (reversed)
+                               mode->c_oflag = mode->c_oflag | OXTABS;
+                       else
+                               mode->c_oflag = mode->c_oflag & ~OXTABS;
+               }
+# endif
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+               else if (info->name == stty_lcase || info->name == stty_LCASE) {
+                       if (reversed) {
+                               mode->c_lflag &= ~XCASE;
+                               mode->c_iflag &= ~IUCLC;
+                               mode->c_oflag &= ~OLCUC;
+                       } else {
+                               mode->c_lflag |= XCASE;
+                               mode->c_iflag |= IUCLC;
+                               mode->c_oflag |= OLCUC;
+                       }
+               }
+#endif
+               else if (info->name == stty_crt)
+                       mode->c_lflag |= ECHOE
+#ifdef ECHOCTL
+                               | ECHOCTL
+#endif
+#ifdef ECHOKE
+                               | ECHOKE
+#endif
+                               ;
+               else if (info->name == stty_dec) {
+                       mode->c_cc[VINTR] = 3;  /* ^C */
+                       mode->c_cc[VERASE] = 127;       /* DEL */
+                       mode->c_cc[VKILL] = 21; /* ^U */
+                       mode->c_lflag |= ECHOE
+#ifdef ECHOCTL
+                               | ECHOCTL
+#endif
+#ifdef ECHOKE
+                               | ECHOKE
+#endif
+                               ;
+#ifdef IXANY
+                       mode->c_iflag &= ~IXANY;
+#endif
+               }
+       } else if (reversed)
+               *bitsp = *bitsp & ~info->mask & ~info->bits;
+       else
+               *bitsp = (*bitsp & ~info->mask) | info->bits;
+
+       return 1;
+}
+
+static void
+set_control_char(const struct control_info *info, const char *arg,
+                                struct termios *mode)
+{
+       unsigned char value;
+
+       if (info->name == stty_min || info->name == stty_time)
+               value = parse_number(arg, stty_suffixes);
+       else if (arg[0] == '\0' || arg[1] == '\0')
+               value = arg[0];
+       else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
+               value = _POSIX_VDISABLE;
+       else if (arg[0] == '^' && arg[1] != '\0') {     /* Ignore any trailing junk. */
+               if (arg[1] == '?')
+                       value = 127;
+               else
+                       value = arg[1] & ~0140; /* Non-letters get weird results. */
+       } else
+               value = parse_number(arg, stty_suffixes);
+       mode->c_cc[info->offset] = value;
+}
+
+static void
+set_speed(enum speed_setting type, const char *arg, struct termios *mode)
+{
+       speed_t baud;
+
+       baud = string_to_baud(arg);
+       if (type == input_speed || type == both_speeds)
+               cfsetispeed(mode, baud);
+       if (type == output_speed || type == both_speeds)
+               cfsetospeed(mode, baud);
+}
+
+#ifdef TIOCGWINSZ
+
+static int get_win_size(int fd, struct winsize *win)
+{
+       int err = ioctl(fd, TIOCGWINSZ, (char *) win);
+
+       return err;
+}
+
+static void
+set_window_size(int rows, int cols, int fd, const char *device_name)
+{
+       struct winsize win;
+
+       if (get_win_size(fd, &win)) {
+               if (errno != EINVAL)
+                       perror_msg_and_die("%s", device_name);
+               memset(&win, 0, sizeof(win));
+       }
+
+       if (rows >= 0)
+               win.ws_row = rows;
+       if (cols >= 0)
+               win.ws_col = cols;
+
+# ifdef TIOCSSIZE
+       /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
+          The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
+          This comment from sys/ttold.h describes Sun's twisted logic - a better
+          test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
+          At any rate, the problem is gone in Solaris 2.x. */
+
+       if (win.ws_row == 0 || win.ws_col == 0) {
+               struct ttysize ttysz;
+
+               ttysz.ts_lines = win.ws_row;
+               ttysz.ts_cols = win.ws_col;
+
+               win.ws_row = 1;
+               win.ws_col = 1;
+
+               if (ioctl(fd, TIOCSWINSZ, (char *) &win))
+                       perror_msg_and_die("%s", device_name);
+
+               if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
+                       perror_msg_and_die("%s", device_name);
+               return;
+       }
+# endif
+
+       if (ioctl(fd, TIOCSWINSZ, (char *) &win))
+               perror_msg_and_die("%s", device_name);
+}
+
+static void display_window_size(int fancy, int fd, const char *device_name)
+{
+       struct winsize win;
+
+       if (get_win_size(fd, &win)) {
+               if (errno != EINVAL)
+                       perror_msg_and_die("%s", device_name);
+               if (!fancy)
+                       perror_msg_and_die("%s: no size information for this device",
+                                                          device_name);
+       } else {
+               wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
+                         win.ws_row, win.ws_col);
+               if (!fancy)
+                       current_col = 0;
+       }
+}
+#endif
+
+static int screen_columns(void)
+{
+#ifdef TIOCGWINSZ
+       struct winsize win;
+
+       /* With Solaris 2.[123], this ioctl fails and errno is set to
+          EINVAL for telnet (but not rlogin) sessions.
+          On ISC 3.0, it fails for the console and the serial port
+          (but it works for ptys).
+          It can also fail on any system when stdout isn't a tty.
+          In case of any failure, just use the default.  */
+       if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
+               return win.ws_col;
+#endif
+
+       if (getenv("COLUMNS"))
+               return atoi(getenv("COLUMNS"));
+       return 80;
+}
+
+static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
+{
+       switch (type) {
+       case control:
+               return &mode->c_cflag;
+
+       case input:
+               return &mode->c_iflag;
+
+       case output:
+               return &mode->c_oflag;
+
+       case local:
+               return &mode->c_lflag;
+
+       default:                                        /* combination: */
+               return NULL;
+       }
+}
+
+static void
+display_settings(enum output_type output_type, struct termios *mode,
+                                int fd, const char *device_name)
+{
+       switch (output_type) {
+       case changed:
+               display_changed(mode);
+               break;
+
+       case all:
+               display_all(mode, fd, device_name);
+               break;
+
+       case recoverable:
+               display_recoverable(mode);
+               break;
+       }
+}
+
+static void display_changed(struct termios *mode)
+{
+       int i;
+       int empty_line;
+       tcflag_t *bitsp;
+       unsigned long mask;
+       enum mode_type prev_type = control;
+
+       display_speed(mode, 1);
+#ifdef HAVE_C_LINE
+       wrapf("line = %d;", mode->c_line);
+#endif
+       putchar('\n');
+       current_col = 0;
+
+       empty_line = 1;
+       for (i = 0; control_info[i].name != stty_min; ++i) {
+               if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
+                       continue;
+               /* If swtch is the same as susp, don't print both.  */
+#if VSWTCH == VSUSP
+               if (control_info[i].name == stty_swtch)
+                       continue;
+#endif
+               /* If eof uses the same slot as min, only print whichever applies.  */
+#if VEOF == VMIN
+               if ((mode->c_lflag & ICANON) == 0
+                       && (control_info[i].name == stty_eof
+                               || control_info[i].name == stty_eol)) continue;
+#endif
+
+               empty_line = 0;
+               wrapf("%s = %s;", control_info[i].name,
+                         visible(mode->c_cc[control_info[i].offset]));
+       }
+       if ((mode->c_lflag & ICANON) == 0) {
+               wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
+                         (int) mode->c_cc[VTIME]);
+       } else if (empty_line == 0)
+               putchar('\n');
+       current_col = 0;
+
+       empty_line = 1;
+       for (i = 0; i < NUM_mode_info; ++i) {
+               if (mode_info[i].flags & OMIT)
+                       continue;
+               if (mode_info[i].type != prev_type) {
+                       if (empty_line == 0) {
+                               putchar('\n');
+                               current_col = 0;
+                               empty_line = 1;
+                       }
+                       prev_type = mode_info[i].type;
+               }
+
+               bitsp = mode_type_flag(mode_info[i].type, mode);
+               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
+               if ((*bitsp & mask) == mode_info[i].bits) {
+                       if (mode_info[i].flags & SANE_UNSET) {
+                               wrapf("%s", mode_info[i].name);
+                               empty_line = 0;
+                       }
+               }
+                       else if ((mode_info[i].flags & (SANE_SET | REV)) ==
+                                        (SANE_SET | REV)) {
+                       wrapf("-%s", mode_info[i].name);
+                       empty_line = 0;
+               }
+       }
+       if (empty_line == 0)
+               putchar('\n');
+       current_col = 0;
+}
+
+static void
+display_all(struct termios *mode, int fd, const char *device_name)
+{
+       int i;
+       tcflag_t *bitsp;
+       unsigned long mask;
+       enum mode_type prev_type = control;
+
+       display_speed(mode, 1);
+#ifdef TIOCGWINSZ
+       display_window_size(1, fd, device_name);
+#endif
+#ifdef HAVE_C_LINE
+       wrapf("line = %d;", mode->c_line);
+#endif
+       putchar('\n');
+       current_col = 0;
+
+       for (i = 0; control_info[i].name != stty_min; ++i) {
+               /* If swtch is the same as susp, don't print both.  */
+#if VSWTCH == VSUSP
+               if (control_info[i].name == stty_swtch)
+                       continue;
+#endif
+               /* If eof uses the same slot as min, only print whichever applies.  */
+#if VEOF == VMIN
+               if ((mode->c_lflag & ICANON) == 0
+                       && (control_info[i].name == stty_eof
+                               || control_info[i].name == stty_eol)) continue;
+#endif
+               wrapf("%s = %s;", control_info[i].name,
+                         visible(mode->c_cc[control_info[i].offset]));
+       }
+#if VEOF == VMIN
+       if ((mode->c_lflag & ICANON) == 0)
+#endif
+               wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
+       if (current_col != 0)
+               putchar('\n');
+       current_col = 0;
+
+       for (i = 0; i < NUM_mode_info; ++i) {
+               if (mode_info[i].flags & OMIT)
+                       continue;
+               if (mode_info[i].type != prev_type) {
+                       putchar('\n');
+                       current_col = 0;
+                       prev_type = mode_info[i].type;
+               }
+
+               bitsp = mode_type_flag(mode_info[i].type, mode);
+               mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
+               if ((*bitsp & mask) == mode_info[i].bits)
+                       wrapf("%s", mode_info[i].name);
+               else if (mode_info[i].flags & REV)
+                       wrapf("-%s", mode_info[i].name);
+       }
+       putchar('\n');
+       current_col = 0;
+}
+
+static void display_speed(struct termios *mode, int fancy)
+{
+       if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
+               wrapf(fancy ? "speed %lu baud;" : "%lu\n",
+                         baud_to_value(cfgetospeed(mode)));
+       else
+               wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
+                         baud_to_value(cfgetispeed(mode)),
+                         baud_to_value(cfgetospeed(mode)));
+       if (!fancy)
+               current_col = 0;
+}
+
+static void display_recoverable(struct termios *mode)
+{
+       int i;
+
+       printf("%lx:%lx:%lx:%lx",
+                  (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
+                  (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
+       for (i = 0; i < NCCS; ++i)
+               printf(":%x", (unsigned int) mode->c_cc[i]);
+       putchar('\n');
+}
+
+static int recover_mode(char *arg, struct termios *mode)
+{
+       int i, n;
+       unsigned int chr;
+       unsigned long iflag, oflag, cflag, lflag;
+
+       /* Scan into temporaries since it is too much trouble to figure out
+          the right format for `tcflag_t'.  */
+       if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
+                          &iflag, &oflag, &cflag, &lflag, &n) != 4)
+               return 0;
+       mode->c_iflag = iflag;
+       mode->c_oflag = oflag;
+       mode->c_cflag = cflag;
+       mode->c_lflag = lflag;
+       arg += n;
+       for (i = 0; i < NCCS; ++i) {
+               if (sscanf(arg, ":%x%n", &chr, &n) != 1)
+                       return 0;
+               mode->c_cc[i] = chr;
+               arg += n;
+       }
+
+       /* Fail if there are too many fields.  */
+       if (*arg != '\0')
+               return 0;
+
+       return 1;
+}
+
+struct speed_map {
+       speed_t speed;                          /* Internal form. */
+       unsigned long value;            /* Numeric value. */
+};
+
+static const struct speed_map speeds[] = {
+       {B0, 0},
+       {B50, 50},
+       {B75, 75},
+       {B110, 110},
+       {B134, 134},
+       {B150, 150},
+       {B200, 200},
+       {B300, 300},
+       {B600, 600},
+       {B1200, 1200},
+       {B1800, 1800},
+       {B2400, 2400},
+       {B4800, 4800},
+       {B9600, 9600},
+       {B19200, 19200},
+       {B38400, 38400},
+#ifdef B57600
+       {B57600, 57600},
+#endif
+#ifdef B115200
+       {B115200, 115200},
+#endif
+#ifdef B230400
+       {B230400, 230400},
+#endif
+#ifdef B460800
+       {B460800, 460800},
+#endif
+};
+
+static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
+
+static speed_t string_to_baud(const char *arg)
+{
+       int i;
+
+       for (i = 0; i < NUM_SPEEDS; ++i)
+               if (parse_number(arg, 0) == speeds[i].value)
+                       return speeds[i].speed;
+       return (speed_t) - 1;
+}
+
+static unsigned long baud_to_value(speed_t speed)
+{
+       int i;
+
+       for (i = 0; i < NUM_SPEEDS; ++i)
+               if (speed == speeds[i].speed)
+                       return speeds[i].value;
+       return 0;
+}
+
+static void sane_mode(struct termios *mode)
+{
+       int i;
+       tcflag_t *bitsp;
+
+       for (i = 0; i < NUM_control_info; ++i) {
+#if VMIN == VEOF
+               if (control_info[i].name == stty_min)
+                       break;
+#endif
+               mode->c_cc[control_info[i].offset] = control_info[i].saneval;
+       }
+
+       for (i = 0; i < NUM_mode_info; ++i) {
+               if (mode_info[i].flags & SANE_SET) {
+                       bitsp = mode_type_flag(mode_info[i].type, mode);
+                       *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
+               } else if (mode_info[i].flags & SANE_UNSET) {
+                       bitsp = mode_type_flag(mode_info[i].type, mode);
+                       *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
+               }
+       }
+}
+
+/* Return a string that is the printable representation of character CH.  */
+/* Adapted from `cat' by Torbjorn Granlund.  */
+
+static const char *visible(unsigned int ch)
+{
+       static char buf[10];
+       char *bpout = buf;
+
+       if (ch == _POSIX_VDISABLE)
+               return "<undef>";
+
+       if (ch >= 32) {
+               if (ch < 127)
+                       *bpout++ = ch;
+               else if (ch == 127) {
+                       *bpout++ = '^';
+                       *bpout++ = '?';
+               } else {
+                       *bpout++ = 'M', *bpout++ = '-';
+                       if (ch >= 128 + 32) {
+                               if (ch < 128 + 127)
+                                       *bpout++ = ch - 128;
+                               else {
+                                       *bpout++ = '^';
+                                       *bpout++ = '?';
+                               }
+                       } else {
+                               *bpout++ = '^';
+                               *bpout++ = ch - 128 + 64;
+                       }
+               }
+       } else {
+               *bpout++ = '^';
+               *bpout++ = ch + 64;
+       }
+       *bpout = '\0';
+       return (const char *) buf;
+}
+
+#ifdef TEST
+
+const char *applet_name = "stty";
+
+#endif
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/swaponoff.c b/swaponoff.c
new file mode 100644 (file)
index 0000000..a57dfe4
--- /dev/null
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini swapon/swapoff implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <mntent.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+
+#if __GNU_LIBRARY__ < 5
+/* libc5 doesn't have sys/swap.h, define these here. */ 
+extern int swapon (__const char *__path, int __flags);
+extern int swapoff (__const char *__path);
+#else
+#include <sys/swap.h>
+#endif
+
+#include "busybox.h"
+
+static int whichApp;    /* default SWAPON_APP */
+
+static const int SWAPON_APP = 0;
+static const int SWAPOFF_APP = 1;
+
+
+static int swap_enable_disable(const char *device)
+{
+       int status;
+
+       if (whichApp == SWAPON_APP)
+               status = swapon(device, 0);
+       else
+               status = swapoff(device);
+
+       if (status != 0) {
+               perror_msg("%s", device);
+               return EXIT_FAILURE;
+       }
+       return EXIT_SUCCESS;
+}
+
+static int do_em_all(void)
+{
+       struct mntent *m;
+       FILE *f = setmntent("/etc/fstab", "r");
+       int err = 0;
+
+       if (f == NULL)
+               perror_msg_and_die("/etc/fstab");
+       while ((m = getmntent(f)) != NULL) {
+               if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) {
+                       if(swap_enable_disable(m->mnt_fsname) == EXIT_FAILURE)
+                               err++;
+               }
+       }
+       endmntent(f);
+       return err;
+}
+
+
+extern int swap_on_off_main(int argc, char **argv)
+{
+       if (applet_name[5] == 'f') { /* "swapoff" */
+               whichApp = SWAPOFF_APP;
+       }
+
+       if (argc != 2) {
+               goto usage_and_exit;
+       }
+       argc--;
+       argv++;
+
+       /* Parse any options */
+       while (**argv == '-') {
+               while (*++(*argv))
+                       switch (**argv) {
+                       case 'a':
+                               {
+                                       struct stat statBuf;
+
+                                       if (stat("/etc/fstab", &statBuf) < 0)
+                                               error_msg_and_die("/etc/fstab file missing");
+                               }
+                               return do_em_all();
+                               break;
+                       default:
+                               goto usage_and_exit;
+                       }
+       }
+       return swap_enable_disable(*argv);
+
+  usage_and_exit:
+       show_usage();
+}
diff --git a/sync.c b/sync.c
new file mode 100644 (file)
index 0000000..ee22ae1
--- /dev/null
+++ b/sync.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini sync implementation for busybox
+ *
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int sync_main(int argc, char **argv)
+{
+       if (argc > 1 && **(argv + 1) == '-')
+               show_usage();
+       sync();
+       return(EXIT_SUCCESS);
+}
diff --git a/syslogd.c b/syslogd.c
new file mode 100644 (file)
index 0000000..784337b
--- /dev/null
+++ b/syslogd.c
@@ -0,0 +1,638 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini syslogd implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
+ *
+ * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/param.h>
+
+#include "busybox.h"
+
+/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
+#define SYSLOG_NAMES
+#include <sys/syslog.h>
+#include <sys/uio.h>
+
+/* Path for the file where all log messages are written */
+#define __LOG_FILE "/var/log/messages"
+
+/* Path to the unix socket */
+static char lfile[MAXPATHLEN];
+
+static char *logFilePath = __LOG_FILE;
+
+/* interval between marks in seconds */
+static int MarkInterval = 20 * 60;
+
+/* localhost's name */
+static char LocalHostName[64];
+
+#ifdef BB_FEATURE_REMOTE_LOG
+#include <netinet/in.h>
+/* udp socket for logging to remote host */
+static int remotefd = -1;
+/* where do we log? */
+static char *RemoteHost;
+/* what port to log to? */
+static int RemotePort = 514;
+/* To remote log or not to remote log, that is the question. */
+static int doRemoteLog = FALSE;
+static int local_logging = FALSE;
+#endif
+
+
+#define MAXLINE         1024            /* maximum line length */
+
+
+/* circular buffer variables/structures */
+#ifdef BB_FEATURE_IPC_SYSLOG
+#if __GNU_LIBRARY__ < 5
+#error Sorry.  Looks like you are using libc5.
+#error libc5 shm support isnt good enough.
+#error Please disable BB_FEATURE_IPC_SYSLOG
+#endif
+
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+/* our shared key */
+static const long KEY_ID = 0x414e4547; /*"GENA"*/
+
+// Semaphore operation structures
+static struct shbuf_ds {
+       int size;               // size of data written
+       int head;               // start of message list
+       int tail;               // end of message list
+       char data[1];           // data/messages
+} *buf = NULL;                  // shared memory pointer
+
+static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
+static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
+
+static int      shmid = -1;     // ipc shared memory id
+static int      s_semid = -1;   // ipc semaphore id
+int     data_size = 16000; // data size
+int     shm_size = 16000 + sizeof(*buf); // our buffer size
+static int circular_logging = FALSE;
+
+/*
+ * sem_up - up()'s a semaphore.
+ */
+static inline void sem_up(int semid)
+{
+       if ( semop(semid, SMwup, 1) == -1 )
+               perror_msg_and_die("semop[SMwup]");
+}
+
+/*
+ * sem_down - down()'s a semaphore
+ */
+static inline void sem_down(int semid)
+{
+       if ( semop(semid, SMwdn, 3) == -1 )
+               perror_msg_and_die("semop[SMwdn]");
+}
+
+
+void ipcsyslog_cleanup(void){
+       printf("Exiting Syslogd!\n");
+       if (shmid != -1)
+               shmdt(buf);
+
+       if (shmid != -1)
+               shmctl(shmid, IPC_RMID, NULL);
+       if (s_semid != -1)
+               semctl(s_semid, 0, IPC_RMID, 0);
+}
+
+void ipcsyslog_init(void){
+       if (buf == NULL){
+           if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
+                       perror_msg_and_die("shmget");
+
+
+           if ((buf = shmat(shmid, NULL, 0)) == NULL)
+                       perror_msg_and_die("shmat");
+
+
+           buf->size=data_size;
+           buf->head=buf->tail=0;
+
+           // we'll trust the OS to set initial semval to 0 (let's hope)
+           if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
+               if (errno == EEXIST){
+                  if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
+                   perror_msg_and_die("semget");
+               }else
+                       perror_msg_and_die("semget");
+           }
+       }else{
+               printf("Buffer already allocated just grab the semaphore?");
+       }
+}
+
+/* write message to buffer */
+void circ_message(const char *msg){
+       int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
+
+       sem_down(s_semid);
+
+       /*
+        * Circular Buffer Algorithm:
+        * --------------------------
+        *
+        * Start-off w/ empty buffer of specific size SHM_SIZ
+        * Start filling it up w/ messages. I use '\0' as separator to break up messages.
+        * This is also very handy since we can do printf on message.
+        *
+        * Once the buffer is full we need to get rid of the first message in buffer and
+        * insert the new message. (Note: if the message being added is >1 message then
+        * we will need to "remove" >1 old message from the buffer). The way this is done
+        * is the following:
+        *      When we reach the end of the buffer we set a mark and start from the beginning.
+        *      Now what about the beginning and end of the buffer? Well we have the "head"
+        *      index/pointer which is the starting point for the messages and we have "tail"
+        *      index/pointer which is the ending point for the messages. When we "display" the
+        *      messages we start from the beginning and continue until we reach "tail". If we
+        *      reach end of buffer, then we just start from the beginning (offset 0). "head" and
+        *      "tail" are actually offsets from the beginning of the buffer.
+        *
+        * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
+        *       a threasafe way of handling shared memory operations.
+        */
+       if ( (buf->tail + l) < buf->size ){
+               /* before we append the message we need to check the HEAD so that we won't
+                  overwrite any of the message that we still need and adjust HEAD to point
+                  to the next message! */
+               if ( buf->tail < buf->head){
+                       if ( (buf->tail + l) >= buf->head ){
+                         /* we need to move the HEAD to point to the next message
+                          * Theoretically we have enough room to add the whole message to the
+                          * buffer, because of the first outer IF statement, so we don't have
+                          * to worry about overflows here!
+                          */
+                          int k= buf->tail + l - buf->head; /* we need to know how many bytes
+                                                               we are overwriting to make
+                                                               enough room */
+                          char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
+                          if (c != NULL) {/* do a sanity check just in case! */
+                               buf->head = c - buf->data + 1; /* we need to convert pointer to
+                                                                 offset + skip the '\0' since
+                                                                 we need to point to the beginning
+                                                                 of the next message */
+                               /* Note: HEAD is only used to "retrieve" messages, it's not used
+                                       when writing messages into our buffer */
+                          }else{ /* show an error message to know we messed up? */
+                               printf("Weird! Can't find the terminator token??? \n");
+                               buf->head=0;
+                          }
+                       }
+               } /* in other cases no overflows have been done yet, so we don't care! */
+
+               /* we should be ok to append the message now */
+               strncpy(buf->data + buf->tail,msg,l); /* append our message */
+               buf->tail+=l; /* count full message w/ '\0' terminating char */
+       }else{
+               /* we need to break up the message and "circle" it around */
+               char *c;
+               int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
+
+               /* We need to move HEAD! This is always the case since we are going
+                * to "circle" the message.
+                */
+               c=memchr(buf->data + k ,'\0', buf->size - k);
+
+               if (c != NULL) /* if we don't have '\0'??? weird!!! */{
+                       /* move head pointer*/
+                       buf->head=c-buf->data+1;
+
+                       /* now write the first part of the message */
+                       strncpy(buf->data + buf->tail, msg, l - k - 1);
+
+                       /* ALWAYS terminate end of buffer w/ '\0' */
+                       buf->data[buf->size-1]='\0';
+
+                       /* now write out the rest of the string to the beginning of the buffer */
+                       strcpy(buf->data, &msg[l-k-1]);
+
+                       /* we need to place the TAIL at the end of the message */
+                       buf->tail = k + 1;
+               }else{
+                       printf("Weird! Can't find the terminator token from the beginning??? \n");
+                       buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
+               }
+
+       }
+       sem_up(s_semid);
+}
+#endif  /* BB_FEATURE_IPC_SYSLOG */
+
+/* Note: There is also a function called "message()" in init.c */
+/* Print a message to the log file. */
+static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+static void message (char *fmt, ...)
+{
+       int fd;
+       struct flock fl;
+       va_list arguments;
+
+       fl.l_whence = SEEK_SET;
+       fl.l_start  = 0;
+       fl.l_len    = 1;
+
+#ifdef BB_FEATURE_IPC_SYSLOG
+       if ((circular_logging == TRUE) && (buf != NULL)){
+                       char b[1024];
+                       va_start (arguments, fmt);
+                       vsnprintf (b, sizeof(b)-1, fmt, arguments);
+                       va_end (arguments);
+                       circ_message(b);
+
+       }else
+#endif
+       if ((fd = device_open (logFilePath,
+                                                  O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
+                                                  O_NONBLOCK)) >= 0) {
+               fl.l_type = F_WRLCK;
+               fcntl (fd, F_SETLKW, &fl);
+               va_start (arguments, fmt);
+               vdprintf (fd, fmt, arguments);
+               va_end (arguments);
+               fl.l_type = F_UNLCK;
+               fcntl (fd, F_SETLKW, &fl);
+               close (fd);
+       } else {
+               /* Always send console messages to /dev/console so people will see them. */
+               if ((fd = device_open (_PATH_CONSOLE,
+                                                          O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
+                       va_start (arguments, fmt);
+                       vdprintf (fd, fmt, arguments);
+                       va_end (arguments);
+                       close (fd);
+               } else {
+                       fprintf (stderr, "Bummer, can't print: ");
+                       va_start (arguments, fmt);
+                       vfprintf (stderr, fmt, arguments);
+                       fflush (stderr);
+                       va_end (arguments);
+               }
+       }
+}
+
+static void logMessage (int pri, char *msg)
+{
+       time_t now;
+       char *timestamp;
+       static char res[20] = "";
+       CODE *c_pri, *c_fac;
+
+       if (pri != 0) {
+               for (c_fac = facilitynames;
+                               c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
+               for (c_pri = prioritynames;
+                               c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
+               if (c_fac->c_name == NULL || c_pri->c_name == NULL)
+                       snprintf(res, sizeof(res), "<%d>", pri);
+               else
+                       snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
+       }
+
+       if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
+                       msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
+               time(&now);
+               timestamp = ctime(&now) + 4;
+               timestamp[15] = '\0';
+       } else {
+               timestamp = msg;
+               timestamp[15] = '\0';
+               msg += 16;
+       }
+
+       /* todo: supress duplicates */
+
+#ifdef BB_FEATURE_REMOTE_LOG
+       /* send message to remote logger */
+       if ( -1 != remotefd){
+static const int IOV_COUNT = 2;
+               struct iovec iov[IOV_COUNT];
+               struct iovec *v = iov;
+
+               memset(&res, 0, sizeof(res));
+               snprintf(res, sizeof(res), "<%d>", pri);
+               v->iov_base = res ;
+               v->iov_len = strlen(res);
+               v++;
+
+               v->iov_base = msg;
+               v->iov_len = strlen(msg);
+writev_retry:
+               if ( -1 == writev(remotefd,iov, IOV_COUNT)){
+                       if (errno == EINTR) goto writev_retry;
+                       error_msg_and_die("cannot write to remote file handle on"
+                                       "%s:%d",RemoteHost,RemotePort);
+               }
+       }
+       if (local_logging == TRUE)
+#endif
+               /* now spew out the message to wherever it is supposed to go */
+               message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
+
+
+}
+
+static void quit_signal(int sig)
+{
+       logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
+       unlink(lfile);
+#ifdef BB_FEATURE_IPC_SYSLOG
+       ipcsyslog_cleanup();
+#endif
+
+       exit(TRUE);
+}
+
+static void domark(int sig)
+{
+       if (MarkInterval > 0) {
+               logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
+               alarm(MarkInterval);
+       }
+}
+
+/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
+ * enabled, we otherwise get a "storage size isn't constant error. */
+static int serveConnection (char* tmpbuf, int n_read)
+{
+       char *p = tmpbuf;
+
+       while (p < tmpbuf + n_read) {
+
+               int           pri = (LOG_USER | LOG_NOTICE);
+               int           num_lt = 0;
+               char          line[ MAXLINE + 1 ];
+               unsigned char c;
+
+               char *q = line;
+
+               while ( (c = *p) && q < &line[ sizeof (line) - 1 ]) {
+                       if (c == '<' && num_lt == 0) {
+                       /* Parse the magic priority number. */
+                               num_lt++;
+                               pri = 0;
+                               while (isdigit (*(++p))) {
+                                       pri = 10 * pri + (*p - '0');
+                               }
+                               if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
+                                       pri = (LOG_USER | LOG_NOTICE);
+                               }
+                       } else if (c == '\n') {
+                               *q++ = ' ';
+                       } else if (iscntrl (c) && (c < 0177)) {
+                               *q++ = '^';
+                               *q++ = c ^ 0100;
+                       } else {
+                               *q++ = c;
+                       }
+                       p++;
+               }
+               *q = '\0';
+               p++;
+               /* Now log it */
+               logMessage (pri, line);
+       }
+       return n_read;
+}
+
+
+#ifdef BB_FEATURE_REMOTE_LOG
+static void init_RemoteLog (void)
+{
+
+  struct sockaddr_in remoteaddr;
+  struct hostent *hostinfo;
+  int len = sizeof(remoteaddr);
+
+  memset(&remoteaddr, 0, len);
+
+  remotefd = socket(AF_INET, SOCK_DGRAM, 0);
+
+  if (remotefd < 0) {
+    error_msg_and_die("cannot create socket");
+  }
+
+  hostinfo = xgethostbyname(RemoteHost);
+
+  remoteaddr.sin_family = AF_INET;
+  remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
+  remoteaddr.sin_port = htons(RemotePort);
+
+  /*
+     Since we are using UDP sockets, connect just sets the default host and port
+     for future operations
+  */
+  if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
+    error_msg_and_die("cannot connect to remote host %s:%d", RemoteHost, RemotePort);
+  }
+
+}
+#endif
+
+static void doSyslogd (void) __attribute__ ((noreturn));
+static void doSyslogd (void)
+{
+       struct sockaddr_un sunx;
+       socklen_t addrLength;
+
+       int sock_fd;
+       fd_set fds;
+
+       /* Set up signal handlers. */
+       signal (SIGINT,  quit_signal);
+       signal (SIGTERM, quit_signal);
+       signal (SIGQUIT, quit_signal);
+       signal (SIGHUP,  SIG_IGN);
+       signal (SIGCHLD,  SIG_IGN);
+#ifdef SIGCLD
+       signal (SIGCLD,  SIG_IGN);
+#endif
+       signal (SIGALRM, domark);
+       alarm (MarkInterval);
+
+       /* Create the syslog file so realpath() can work. */
+       if (realpath (_PATH_LOG, lfile) != NULL)
+               unlink (lfile);
+
+       memset (&sunx, 0, sizeof (sunx));
+       sunx.sun_family = AF_UNIX;
+       strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
+       if ((sock_fd = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0)
+               perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
+
+       addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
+       if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0)
+               perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
+
+       if (chmod (lfile, 0666) < 0)
+               perror_msg_and_die ("Could not set permission on " _PATH_LOG);
+
+
+#ifdef BB_FEATURE_IPC_SYSLOG
+       if (circular_logging == TRUE ){
+          ipcsyslog_init();
+       }
+#endif
+
+#ifdef BB_FEATURE_REMOTE_LOG
+       if (doRemoteLog == TRUE){
+         init_RemoteLog();
+       }
+#endif
+
+       logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
+
+       for (;;) {
+
+               FD_ZERO (&fds);
+               FD_SET (sock_fd, &fds);
+
+               if (select (sock_fd+1, &fds, NULL, NULL, NULL) < 0) {
+                       if (errno == EINTR) {
+                               /* alarm may have happened. */
+                               continue;
+                       }
+                       perror_msg_and_die ("select error");
+               }
+
+               if (FD_ISSET (sock_fd, &fds)) {
+                      int   i;
+                      RESERVE_BB_BUFFER(tmpbuf, MAXLINE + 1);
+
+                      memset(tmpbuf, '\0', MAXLINE+1);
+                      if ( (i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) {
+                              serveConnection(tmpbuf, i);
+                      } else {
+                              perror_msg_and_die ("UNIX socket error");
+                      }
+                      RELEASE_BB_BUFFER (tmpbuf);
+               }/* FD_ISSET() */
+       } /* for main loop */
+}
+
+extern int syslogd_main(int argc, char **argv)
+{
+       int opt;
+#if ! defined(__uClinux__)
+       int doFork = TRUE;
+#endif
+
+       char *p;
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
+               switch (opt) {
+                       case 'm':
+                               MarkInterval = atoi(optarg) * 60;
+                               break;
+#if ! defined(__uClinux__)
+                       case 'n':
+                               doFork = FALSE;
+                               break;
+#endif
+                       case 'O':
+                               logFilePath = xstrdup(optarg);
+                               break;
+#ifdef BB_FEATURE_REMOTE_LOG
+                       case 'R':
+                               RemoteHost = xstrdup(optarg);
+                               if ( (p = strchr(RemoteHost, ':'))){
+                                       RemotePort = atoi(p+1);
+                                       *p = '\0';
+                               }
+                               doRemoteLog = TRUE;
+                               break;
+                       case 'L':
+                               local_logging = TRUE;
+                               break;
+#endif
+#ifdef BB_FEATURE_IPC_SYSLOG
+                       case 'C':
+                               circular_logging = TRUE;
+                               break;
+#endif
+                       default:
+                               show_usage();
+               }
+       }
+
+#ifdef BB_FEATURE_REMOTE_LOG
+       /* If they have not specified remote logging, then log locally */
+       if (doRemoteLog == FALSE)
+               local_logging = TRUE;
+#endif
+
+
+       /* Store away localhost's name before the fork */
+       gethostname(LocalHostName, sizeof(LocalHostName));
+       if ((p = strchr(LocalHostName, '.'))) {
+               *p++ = '\0';
+       }
+
+       umask(0);
+
+#if ! defined(__uClinux__)
+       if (doFork == TRUE) {
+               if (daemon(0, 1) < 0)
+                       perror_msg_and_die("daemon");
+       }
+#endif
+       doSyslogd();
+
+       return EXIT_SUCCESS;
+}
+
+/*
+Local Variables
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/tail.c b/tail.c
new file mode 100644 (file)
index 0000000..5e572c5
--- /dev/null
+++ b/tail.c
@@ -0,0 +1,257 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tail implementation for busybox
+ *
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+static const struct suffix_mult tail_suffixes[] = {
+       { "b", 512 },
+       { "k", 1024 },
+       { "m", 1048576 },
+       { NULL, 0 }
+};
+
+static const int BYTES = 0;
+static const int LINES = 1;
+
+static char *tailbuf;
+static int taillen;
+static int newline;
+
+static void tailbuf_append(char *buf, int len)
+{
+       tailbuf = xrealloc(tailbuf, taillen + len);
+       memcpy(tailbuf + taillen, buf, len);
+       taillen += len;
+}
+
+static void tailbuf_trunc(void)
+{
+       char *s;
+       s = memchr(tailbuf, '\n', taillen);
+       memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf));
+       taillen -= (s + 1) - tailbuf;
+       newline = 0;
+}
+
+int tail_main(int argc, char **argv)
+{
+       int from_top = 0, units = LINES, count = 10, sleep_period = 1;
+       int show_headers = 0, hide_headers = 0, follow = 0;
+       int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0;
+       char *s, *start, *end, buf[BUFSIZ];
+       int i, opt;
+
+       if (( argc >= 2 ) && ( argv [1][0] == '-' ) && isdigit ( argv [1][1] )) {
+               count = atoi ( &argv [1][1] );
+               optind = 2;
+       }
+
+       while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) {
+               switch (opt) {
+                       case 'f':
+                               follow = 1;
+                               break;
+#ifdef BB_FEATURE_FANCY_TAIL
+                       case 'c':
+                               units = BYTES;
+                               /* FALLS THROUGH */
+#endif
+                       case 'n':
+                               count = parse_number(optarg, tail_suffixes);
+                               if (count < 0)
+                                       count = -count;
+                               if (optarg[0] == '+')
+                                       from_top = 1;
+                               break;
+#ifdef BB_FEATURE_FANCY_TAIL
+                       case 'q':
+                               hide_headers = 1;
+                               break;
+                       case 's':
+                               sleep_period = parse_number(optarg, 0);
+                               break;
+                       case 'v':
+                               show_headers = 1;
+                               break;
+#endif
+                       default:
+                               show_usage();
+               }
+       }
+
+       /* open all the files */
+       fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1));
+       if (argc == optind) {
+               fds[nfiles++] = STDIN_FILENO;
+               argv[optind] = "standard input";
+       } else {
+               for (i = optind; i < argc; i++) {
+                       if (strcmp(argv[i], "-") == 0) {
+                               fds[nfiles++] = STDIN_FILENO;
+                               argv[i] = "standard input";
+                       } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) {
+                               perror_msg("%s", argv[i]);
+                               status = EXIT_FAILURE;
+                       }
+               }
+       }
+       
+#ifdef BB_FEATURE_FANCY_TAIL
+       /* tail the files */
+       if (!from_top && units == BYTES)
+               tailbuf = xmalloc(count);
+#endif
+
+       for (i = 0; i < nfiles; i++) {
+               if (fds[i] == -1)
+                       continue;
+               if (!count) {
+                       lseek(fds[i], 0, SEEK_END);
+                       continue;
+               }
+               seen = 0;
+               if (show_headers || (!hide_headers && nfiles > 1))
+                       printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]);
+               while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
+                       if (from_top) {
+#ifdef BB_FEATURE_FANCY_TAIL
+                               if (units == BYTES) {
+                                       if (count - 1 <= seen)
+                                               nwrite = nread;
+                                       else if (count - 1 <= seen + nread)
+                                               nwrite = nread + seen - (count - 1);
+                                       else
+                                               nwrite = 0;
+                                       seen += nread;
+                               } else {
+#else
+                               {
+#endif
+                                       if (count - 1 <= seen)
+                                               nwrite = nread;
+                                       else {
+                                               nwrite = 0;
+                                               for (s = memchr(buf, '\n', nread); s != NULL;
+                                                               s = memchr(s+1, '\n', nread - (s + 1 - buf))) {
+                                                       if (count - 1 <= ++seen) {
+                                                               nwrite = nread - (s + 1 - buf);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (full_write(STDOUT_FILENO, buf + nread - nwrite,
+                                                       nwrite) < 0) {
+                                       perror_msg("write");
+                                       status = EXIT_FAILURE;
+                                       break;
+                               }
+                       } else {
+#ifdef BB_FEATURE_FANCY_TAIL
+                               if (units == BYTES) {
+                                       if (nread < count) {
+                                               memmove(tailbuf, tailbuf + nread, count - nread);
+                                               memcpy(tailbuf + count - nread, buf, nread);
+                                       } else {
+                                               memcpy(tailbuf, buf + nread - count, count);
+                                       }
+                                       seen += nread;
+                               } else {
+#else
+                               {
+#endif
+                                       for (start = buf, end = memchr(buf, '\n', nread);
+                                                       end != NULL; start = end+1,
+                                                       end = memchr(start, '\n', nread - (start - buf))) {
+                                               if (newline && count <= seen)
+                                                       tailbuf_trunc();
+                                               tailbuf_append(start, end - start + 1);
+                                               seen++;
+                                               newline = 1;
+                                       }
+                                       if (newline && count <= seen && nread - (start - buf) > 0)
+                                               tailbuf_trunc();
+                                       tailbuf_append(start, nread - (start - buf));
+                               }
+                       }
+               }
+
+               if (nread < 0) {
+                       perror_msg("read");
+                       status = EXIT_FAILURE;
+               }
+
+#ifdef BB_FEATURE_FANCY_TAIL
+               if (!from_top && units == BYTES) {
+                       if (count < seen)
+                               seen = count;
+                       if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) {
+                               perror_msg("write");
+                               status = EXIT_FAILURE;
+                       }
+               }
+#endif
+
+               if (!from_top && units == LINES) {
+                       if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) {
+                               perror_msg("write");
+                               status = EXIT_FAILURE;
+                       }
+               }
+
+               taillen = 0;
+       }
+
+       while (follow) {
+               sleep(sleep_period);
+
+               for (i = 0; i < nfiles; i++) {
+                       if (fds[i] == -1)
+                               continue;
+
+                       if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) {
+                               if (show_headers || (!hide_headers && nfiles > 1))
+                                       printf("\n==> %s <==\n", argv[optind + i]);
+
+                               do {
+                                       full_write(STDOUT_FILENO, buf, nread);
+                               } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0);
+                       }
+
+                       if (nread < 0) {
+                               perror_msg("read");
+                               status = EXIT_FAILURE;
+                       }
+               }
+       }
+
+       return status;
+}
diff --git a/tar.c b/tar.c
new file mode 100644 (file)
index 0000000..60d9cf9
--- /dev/null
+++ b/tar.c
@@ -0,0 +1,1154 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tar implementation for busybox 
+ *
+ * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
+ * ground up.  It still has remnents of the old code lying about, but it is
+ * very different now (i.e., cleaner, less global variables, etc.)
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org>
+ *
+ * Based in part in the tar implementation in sash
+ *  Copyright (c) 1999 by David I. Bell
+ *  Permission is granted to use, distribute, or modify this source,
+ *  provided that this copyright notice remains intact.
+ *  Permission to distribute sash derived code under the GPL has been granted.
+ *
+ * Based in part on the tar implementation from busybox-0.28
+ *  Copyright (C) 1995 Bruce Perens
+ *  This is free software under the GNU General Public License.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <utime.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <getopt.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+/* Tar file constants  */
+#ifndef MAJOR
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
+
+enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */
+
+/* POSIX tar Header Block, from POSIX 1003.1-1990  */
+struct TarHeader
+{
+                                /* byte offset */
+       char name[NAME_SIZE];         /*   0-99 */
+       char mode[8];                 /* 100-107 */
+       char uid[8];                  /* 108-115 */
+       char gid[8];                  /* 116-123 */
+       char size[12];                /* 124-135 */
+       char mtime[12];               /* 136-147 */
+       char chksum[8];               /* 148-155 */
+       char typeflag;                /* 156-156 */
+       char linkname[NAME_SIZE];     /* 157-256 */
+       char magic[6];                /* 257-262 */
+       char version[2];              /* 263-264 */
+       char uname[32];               /* 265-296 */
+       char gname[32];               /* 297-328 */
+       char devmajor[8];             /* 329-336 */
+       char devminor[8];             /* 337-344 */
+       char prefix[155];             /* 345-499 */
+       char padding[12];             /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
+};
+typedef struct TarHeader TarHeader;
+
+
+/* A few useful constants */
+#define TAR_MAGIC          "ustar"        /* ustar and a null */
+#define TAR_VERSION        "  "           /* Be compatable with GNU tar format */
+static const int TAR_MAGIC_LEN = 6;
+static const int TAR_VERSION_LEN = 2;
+static const int TAR_BLOCK_SIZE = 512;
+
+/* A nice enum with all the possible tar file content types */
+enum TarFileType 
+{
+       REGTYPE  = '0',            /* regular file */
+       REGTYPE0 = '\0',           /* regular file (ancient bug compat)*/
+       LNKTYPE  = '1',            /* hard link */
+       SYMTYPE  = '2',            /* symbolic link */
+       CHRTYPE  = '3',            /* character special */
+       BLKTYPE  = '4',            /* block special */
+       DIRTYPE  = '5',            /* directory */
+       FIFOTYPE = '6',            /* FIFO special */
+       CONTTYPE = '7',            /* reserved */
+       GNULONGLINK = 'K',         /* GNU long (>100 chars) link name */
+       GNULONGNAME = 'L',         /* GNU long (>100 chars) file name */
+};
+typedef enum TarFileType TarFileType;
+
+/* This struct ignores magic, non-numeric user name, 
+ * non-numeric group name, and the checksum, since
+ * these are all ignored by BusyBox tar. */ 
+struct TarInfo
+{
+       int              tarFd;          /* An open file descriptor for reading from the tarball */
+       char *           name;           /* File name */
+       mode_t           mode;           /* Unix mode, including device bits. */
+       uid_t            uid;            /* Numeric UID */
+       gid_t            gid;            /* Numeric GID */
+       size_t           size;           /* Size of file */
+       time_t           mtime;          /* Last-modified time */
+       enum TarFileType type;           /* Regular, directory, link, etc. */
+       char *           linkname;       /* Name for symbolic and hard links */
+       long             devmajor;       /* Major number for special device */
+       long             devminor;       /* Minor number for special device */
+};
+typedef struct TarInfo TarInfo;
+
+/* Local procedures to restore files from a tar file.  */
+static int readTarFile(int tarFd, int extractFlag, int listFlag, 
+               int tostdoutFlag, int verboseFlag, char** extractList,
+               char** excludeList);
+
+#ifdef BB_FEATURE_TAR_CREATE
+/* Local procedures to save files into a tar file.  */
+static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
+               char** excludeList);
+#endif
+
+#if defined BB_FEATURE_TAR_EXCLUDE
+static struct option longopts[] = {
+       { "exclude", 1, NULL, 'e' },
+       { NULL, 0, NULL, 0 }
+};
+#endif
+
+extern int tar_main(int argc, char **argv)
+{
+       char** excludeList=NULL;
+       char** extractList=NULL;
+       const char *tarName="-";
+       const char *cwd=NULL;
+#if defined BB_FEATURE_TAR_EXCLUDE
+       int excludeListSize=0;
+       FILE *fileList;
+       char file[256];
+#endif
+#if defined BB_FEATURE_TAR_GZIP
+       FILE *comp_file = NULL;
+       int unzipFlag    = FALSE;
+#endif
+       int listFlag     = FALSE;
+       int extractFlag  = FALSE;
+       int createFlag   = FALSE;
+       int verboseFlag  = FALSE;
+       int tostdoutFlag = FALSE;
+       int status       = FALSE;
+       int opt;
+#if defined BB_FEATURE_TAR_GZIP
+       pid_t pid;
+#endif
+
+       if (argc <= 1)
+               show_usage();
+
+       if (argv[1][0] != '-') {
+               char *tmp = xmalloc(strlen(argv[1]) + 2);
+               tmp[0] = '-';
+               strcpy(tmp + 1, argv[1]);
+               argv[1] = tmp;
+       }
+
+       while (
+#ifndef BB_FEATURE_TAR_EXCLUDE
+                       (opt = getopt(argc, argv, "cxtzvOf:pC:"))
+#else
+                       (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL))
+#endif
+                       > 0) {
+               switch (opt) {
+                       case 'c':
+                               if (extractFlag == TRUE || listFlag == TRUE)
+                                       goto flagError;
+                               createFlag = TRUE;
+                               break;
+                       case 'x':
+                               if (listFlag == TRUE || createFlag == TRUE)
+                                       goto flagError;
+                               extractFlag = TRUE;
+                               break;
+                       case 't':
+                               if (extractFlag == TRUE || createFlag == TRUE)
+                                       goto flagError;
+                               listFlag = TRUE;
+                               break;
+#ifdef BB_FEATURE_TAR_GZIP
+                       case 'z':
+                               unzipFlag = TRUE;
+                               break;
+#endif
+                       case 'v':
+                               verboseFlag = TRUE;
+                               break;
+                       case 'O':
+                               tostdoutFlag = TRUE;
+                               break;
+                       case 'f':
+                               if (*tarName != '-')
+                                       error_msg_and_die( "Only one 'f' option allowed");
+                               tarName = optarg;
+                               break;
+#if defined BB_FEATURE_TAR_EXCLUDE
+                       case 'e':
+                               excludeList=xrealloc( excludeList,
+                                               sizeof(char *) * (excludeListSize+2));
+                               excludeList[excludeListSize] = optarg;
+                               /* Tack a NULL onto the end of the list */
+                               excludeList[++excludeListSize] = NULL;
+                       case 'X':
+                               fileList = xfopen(optarg, "r");
+                               while (fgets(file, sizeof(file), fileList) != NULL) {
+                                       excludeList = xrealloc(excludeList,
+                                                       sizeof(char *) * (excludeListSize+2));
+                                       chomp(file);
+                                       excludeList[excludeListSize] = xstrdup(file);
+                                       /* Tack a NULL onto the end of the list */
+                                       excludeList[++excludeListSize] = NULL;
+                               }
+                               fclose(fileList);
+                               break;
+#endif
+                       case 'p':
+                               break;
+                       case 'C':
+                               cwd = xgetcwd((char *)cwd);
+                               if (chdir(optarg)) {
+                                       printf("cd: %s: %s\n", optarg, strerror(errno));
+                                       return EXIT_FAILURE;
+                               }
+                               break;
+                       default:
+                                       show_usage();
+               }
+       }
+
+       /*
+        * Do the correct type of action supplying the rest of the
+        * command line arguments as the list of files to process.
+        */
+       if (createFlag == TRUE) {
+#ifndef BB_FEATURE_TAR_CREATE
+               error_msg_and_die( "This version of tar was not compiled with tar creation support.");
+#else
+#ifdef BB_FEATURE_TAR_GZIP
+               if (unzipFlag==TRUE)
+                       error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip");
+#endif
+               status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList);
+#endif
+       }
+       if (listFlag == TRUE || extractFlag == TRUE) {
+               int tarFd;
+               if (argv[optind])
+                       extractList = argv + optind;
+               /* Open the tar file for reading.  */
+               if (!strcmp(tarName, "-"))
+                       tarFd = fileno(stdin);
+               else
+                       tarFd = open(tarName, O_RDONLY);
+               if (tarFd < 0)
+                       perror_msg_and_die("Error opening '%s'", tarName);
+
+#ifdef BB_FEATURE_TAR_GZIP     
+               /* unzip tarFd in a seperate process */
+               if (unzipFlag == TRUE) {
+                       comp_file = fdopen(tarFd, "r");
+
+                       /* set the buffer size */
+                       setvbuf(comp_file, NULL, _IOFBF, 0x8000);
+
+                       if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) {
+                               error_msg_and_die("Couldnt unzip file");
+                       }
+               }
+#endif                 
+               status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag,
+                                       verboseFlag, extractList, excludeList);
+               close(tarFd);
+#ifdef BB_FEATURE_TAR_GZIP     
+               if (unzipFlag == TRUE) {
+                       gz_close(pid);
+                       fclose(comp_file);
+               }
+#endif                 
+       }
+
+       if (cwd)
+               chdir(cwd);
+       if (status == TRUE)
+               return EXIT_SUCCESS;
+       else
+               return EXIT_FAILURE;
+
+  flagError:
+       error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified");
+}
+                                       
+static void
+fixUpPermissions(TarInfo *header)
+{
+       struct utimbuf t;
+       /* Now set permissions etc. for the new file */
+       chown(header->name, header->uid, header->gid);
+       chmod(header->name, header->mode);
+       /* Reset the time */
+       t.actime = time(0);
+       t.modtime = header->mtime;
+       utime(header->name, &t);
+}
+                               
+static int
+tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag)
+{
+       size_t  writeSize;
+       size_t  readSize;
+       size_t  actualWriteSz;
+       char    buffer[20 * TAR_BLOCK_SIZE];
+       size_t  size = header->size;
+       int outFd=fileno(stdout);
+
+       /* Open the file to be written, if a file is supposed to be written */
+       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
+               /* Create the path to the file, just in case it isn't there...
+                * This should not screw up path permissions or anything. */
+               char *buf, *dir;
+               buf = xstrdup (header->name);
+               dir = dirname (buf);
+               make_directory (dir, -1, FILEUTILS_RECUR);
+               free (buf);
+               if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, 
+                                               header->mode & ~S_IFMT)) < 0) {
+                       error_msg(io_error, header->name, strerror(errno)); 
+                       return( FALSE);
+               }
+       }
+
+       /* Write out the file, if we are supposed to be doing that */
+       while ( size > 0 ) {
+               actualWriteSz=0;
+               if ( size > sizeof(buffer) )
+                       writeSize = readSize = sizeof(buffer);
+               else {
+                       int mod = size % TAR_BLOCK_SIZE;
+                       if ( mod != 0 )
+                               readSize = size + (TAR_BLOCK_SIZE - mod);
+                       else
+                               readSize = size;
+                       writeSize = size;
+               }
+               if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) {
+                       /* Tarball seems to have a problem */
+                       error_msg("Unexpected EOF in archive"); 
+                       return( FALSE);
+               }
+               if ( readSize < writeSize )
+                       writeSize = readSize;
+
+               /* Write out the file, if we are supposed to be doing that */
+               if (extractFlag==TRUE) {
+
+                       if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) {
+                               /* Output file seems to have a problem */
+                               error_msg(io_error, header->name, strerror(errno)); 
+                               return( FALSE);
+                       }
+               } else {
+                       actualWriteSz=writeSize;
+               }
+
+               size -= actualWriteSz;
+       }
+
+       /* Now we are done writing the file out, so try 
+        * and fix up the permissions and whatnot */
+       if (extractFlag==TRUE && tostdoutFlag==FALSE) {
+               close(outFd);
+               fixUpPermissions(header);
+       }
+       return( TRUE);
+}
+
+static int
+tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag)
+{
+       if (extractFlag==FALSE || tostdoutFlag==TRUE)
+               return( TRUE);
+
+       if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0)
+               return( FALSE);
+
+       fixUpPermissions(header);
+       return( TRUE);
+}
+
+static int
+tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag)
+{
+       if (extractFlag==FALSE || tostdoutFlag==TRUE)
+               return( TRUE);
+
+       if (link(header->linkname, header->name) < 0) {
+               perror_msg("%s: Cannot create hard link to '%s'", header->name,
+                               header->linkname); 
+               return( FALSE);
+       }
+
+       /* Now set permissions etc. for the new directory */
+       fixUpPermissions(header);
+       return( TRUE);
+}
+
+static int
+tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag)
+{
+       if (extractFlag==FALSE || tostdoutFlag==TRUE)
+               return( TRUE);
+
+#ifdef S_ISLNK
+       if (symlink(header->linkname, header->name) < 0) {
+               perror_msg("%s: Cannot create symlink to '%s'", header->name,
+                               header->linkname); 
+               return( FALSE);
+       }
+       /* Try to change ownership of the symlink.
+        * If libs doesn't support that, don't bother.
+        * Changing the pointed-to-file is the Wrong Thing(tm).
+        */
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+       lchown(header->name, header->uid, header->gid);
+#endif
+
+       /* Do not change permissions or date on symlink,
+        * since it changes the pointed to file instead.  duh. */
+#else
+       error_msg("%s: Cannot create symlink to '%s': %s", 
+                       header->name, header->linkname, 
+                       "symlinks not supported"); 
+#endif
+       return( TRUE);
+}
+
+static int
+tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag)
+{
+       if (extractFlag==FALSE || tostdoutFlag==TRUE)
+               return( TRUE);
+
+       if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) {
+               if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) {
+                       perror_msg("%s: Cannot mknod", header->name); 
+                       return( FALSE);
+               }
+       } else if (S_ISFIFO(header->mode)) {
+               if (mkfifo(header->name, header->mode) < 0) {
+                       perror_msg("%s: Cannot mkfifo", header->name); 
+                       return( FALSE);
+               }
+       }
+
+       /* Now set permissions etc. for the new directory */
+       fixUpPermissions(header);
+       return( TRUE);
+}
+
+/* Parse the tar header and fill in the nice struct with the details */
+static int
+readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
+{
+       int i;
+       long chksum, sum=0;
+       unsigned char *s = (unsigned char *)rawHeader;
+
+       header->name  = rawHeader->name;
+       /* Check for and relativify any absolute paths */
+       if ( *(header->name) == '/' ) {
+               static int alreadyWarned=FALSE;
+
+               while (*(header->name) == '/')
+                       header->name++;
+
+               if (alreadyWarned == FALSE) {
+                       error_msg("Removing leading '/' from member names");
+                       alreadyWarned = TRUE;
+               }
+       }
+
+       header->mode  = strtol(rawHeader->mode, NULL, 8);
+       header->uid   = strtol(rawHeader->uid, NULL, 8);
+       header->gid   = strtol(rawHeader->gid, NULL, 8);
+       header->size  = strtol(rawHeader->size, NULL, 8);
+       header->mtime = strtol(rawHeader->mtime, NULL, 8);
+       chksum = strtol(rawHeader->chksum, NULL, 8);
+       header->type  = rawHeader->typeflag;
+       header->linkname  = rawHeader->linkname;
+       header->devmajor  = strtol(rawHeader->devmajor, NULL, 8);
+       header->devminor  = strtol(rawHeader->devminor, NULL, 8);
+
+       /* Check the checksum */
+       for (i = sizeof(*rawHeader); i-- != 0;) {
+               sum += *s++;
+       }
+       /* Remove the effects of the checksum field (replace 
+        * with blanks for the purposes of the checksum) */
+       s = rawHeader->chksum;
+       for (i = sizeof(rawHeader->chksum) ; i-- != 0;) {
+               sum -= *s++;
+       }
+       sum += ' ' * sizeof(rawHeader->chksum);
+       if (sum == chksum )
+               return ( TRUE);
+       return( FALSE);
+}
+
+#if defined BB_FEATURE_TAR_EXCLUDE
+static int exclude_file(char **excluded_files, const char *file)
+{
+       int i;
+
+       if (excluded_files == NULL)
+               return 0;
+
+       for (i = 0; excluded_files[i] != NULL; i++) {
+               if (excluded_files[i][0] == '/') {
+                       if (fnmatch(excluded_files[i], file,
+                                               FNM_PATHNAME | FNM_LEADING_DIR) == 0)
+                               return 1;
+               } else {
+                       const char *p;
+
+                       for (p = file; p[0] != '\0'; p++) {
+                               if ((p == file || p[-1] == '/') && p[0] != '/' &&
+                                               fnmatch(excluded_files[i], p,
+                                                       FNM_PATHNAME | FNM_LEADING_DIR) == 0)
+                                       return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int extract_file(char **extract_files, const char *file)
+{
+       int i;
+
+       if (extract_files == NULL)
+               return 1;
+
+       for (i = 0; extract_files[i] != NULL; i++) {
+               if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Read a tar file and extract or list the specified files within it.
+ * If the list is empty than all files are extracted or listed.
+ */
+static int readTarFile(int tarFd, int extractFlag, int listFlag, 
+               int tostdoutFlag, int verboseFlag, char** extractList,
+               char** excludeList)
+{
+       int status;
+       int errorFlag=FALSE;
+       int skipNextHeaderFlag=FALSE;
+       TarHeader rawHeader;
+       TarInfo header;
+
+       /* Read the tar file, and iterate over it one file at a time */
+       while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) {
+
+               /* Try to read the header */
+               if ( readTarHeader(&rawHeader, &header) == FALSE ) {
+                       if ( *(header.name) == '\0' ) {
+                               goto endgame;
+                       } else {
+                               errorFlag=TRUE;
+                               error_msg("Bad tar header, skipping");
+                               continue;
+                       }
+               }
+               if ( *(header.name) == '\0' )
+                       continue;
+               header.tarFd = tarFd;
+
+               /* Skip funky extra GNU headers that precede long files */
+               if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) {
+                       skipNextHeaderFlag=TRUE;
+                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
+                               errorFlag = TRUE;
+                       continue;
+               }
+               if ( skipNextHeaderFlag == TRUE ) { 
+                       skipNextHeaderFlag=FALSE;
+                       error_msg(name_longer_than_foo, NAME_SIZE); 
+                       if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
+                               errorFlag = TRUE;
+                       continue;
+               }
+
+#if defined BB_FEATURE_TAR_EXCLUDE
+               if (exclude_file(excludeList, header.name)) {
+                       /* There are not the droids you're looking for, move along */
+                       /* If it is a regular file, pretend to extract it with
+                        * the extractFlag set to FALSE, so the junk in the tarball
+                        * is properly skipped over */
+                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
+                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
+                                       errorFlag = TRUE;
+                       }
+                       continue;
+               }
+#endif
+
+               if (!extract_file(extractList, header.name)) {
+                       /* There are not the droids you're looking for, move along */
+                       /* If it is a regular file, pretend to extract it with
+                        * the extractFlag set to FALSE, so the junk in the tarball
+                        * is properly skipped over */
+                       if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
+                               if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE)
+                                       errorFlag = TRUE;
+                       }
+                       continue;
+               }
+
+               if (listFlag == TRUE) {
+                       /* Special treatment if the list (-t) flag is on */
+                       if (verboseFlag == TRUE) {
+                               int len, len1;
+                               char buf[35];
+                               struct tm *tm = localtime (&(header.mtime));
+
+                               len=printf("%s ", mode_string(header.mode));
+                               my_getpwuid(buf, header.uid);
+                               if (! *buf)
+                                       len+=printf("%d", header.uid);
+                               else
+                                       len+=printf("%s", buf);
+                               my_getgrgid(buf, header.gid);
+                               if (! *buf)
+                                       len+=printf("/%-d ", header.gid);
+                               else
+                                       len+=printf("/%-s ", buf);
+
+                               if (header.type==CHRTYPE || header.type==BLKTYPE) {
+                                       len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", 
+                                                       header.devmajor, header.devminor);
+                               } else {
+                                       len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size);
+                               }
+                               /* Jump through some hoops to make the columns match up */
+                               for(;(len+len1)<31;len++)
+                                       printf(" ");
+                               printf(buf);
+
+                               /* Use ISO 8610 time format */
+                               if (tm) { 
+                                       printf ("%04d-%02d-%02d %02d:%02d:%02d ", 
+                                                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
+                                                       tm->tm_hour, tm->tm_min, tm->tm_sec);
+                               }
+                       }
+                       printf("%s", header.name);
+                       if (verboseFlag == TRUE) {
+                               if (header.type==LNKTYPE)       /* If this is a link, say so */
+                                       printf(" link to %s", header.linkname);
+                               else if (header.type==SYMTYPE)
+                                       printf(" -> %s", header.linkname);
+                       }
+                       printf("\n");
+               }
+
+               /* List contents if we are supposed to do that */
+               if (verboseFlag == TRUE && extractFlag == TRUE) {
+                       /* Now the normal listing */
+                       FILE *vbFd = stdout;
+                       if (tostdoutFlag == TRUE)       // If the archive goes to stdout, verbose to stderr
+                               vbFd = stderr;
+                       fprintf(vbFd, "%s\n", header.name);
+               }
+                       
+               /* Remove files if we would overwrite them */
+               if (extractFlag == TRUE && tostdoutFlag == FALSE)
+                       unlink(header.name);
+
+               /* If we got here, we can be certain we have a legitimate 
+                * header to work with.  So work with it.  */
+               switch ( header.type ) {
+                       case REGTYPE:
+                       case REGTYPE0:
+                               /* If the name ends in a '/' then assume it is
+                                * supposed to be a directory, and fall through */
+                               if (!last_char_is(header.name,'/')) {
+                                       if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE)
+                                               errorFlag=TRUE;
+                                       break;
+                               }
+                       case DIRTYPE:
+                               if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE)
+                                       errorFlag=TRUE;
+                               break;
+                       case LNKTYPE:
+                               if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE)
+                                       errorFlag=TRUE;
+                               break;
+                       case SYMTYPE:
+                               if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE)
+                                       errorFlag=TRUE;
+                               break;
+                       case CHRTYPE:
+                       case BLKTYPE:
+                       case FIFOTYPE:
+                               if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE)
+                                       errorFlag=TRUE;
+                               break;
+#if 0
+                       /* Handled earlier */
+                       case GNULONGNAME:
+                       case GNULONGLINK:
+                               skipNextHeaderFlag=TRUE;
+                               break;
+#endif
+                       default:
+                               error_msg("Unknown file type '%c' in tar file", header.type);
+                               close( tarFd);
+                               return( FALSE);
+               }
+       }
+       close(tarFd);
+       if (status > 0) {
+               /* Bummer - we read a partial header */
+               perror_msg("Error reading tar file");
+               return ( FALSE);
+       }
+       else if (errorFlag==TRUE) {
+               error_msg( "Error exit delayed from previous errors");
+               return( FALSE);
+       } else 
+               return( status);
+
+       /* Stuff to do when we are done */
+endgame:
+       close( tarFd);
+       if ( *(header.name) == '\0' ) {
+               if (errorFlag==TRUE)
+                       error_msg( "Error exit delayed from previous errors");
+               else
+                       return( TRUE);
+       } 
+       return( FALSE);
+}
+
+
+#ifdef BB_FEATURE_TAR_CREATE
+
+/*
+** writeTarFile(),  writeFileToTarball(), and writeTarHeader() are
+** the only functions that deal with the HardLinkInfo structure.
+** Even these functions use the xxxHardLinkInfo() functions.
+*/
+typedef struct HardLinkInfo HardLinkInfo;
+struct HardLinkInfo
+{
+       HardLinkInfo *next;           /* Next entry in list */
+       dev_t dev;                    /* Device number */
+       ino_t ino;                    /* Inode number */
+       short linkCount;              /* (Hard) Link Count */
+       char name[1];                 /* Start of filename (must be last) */
+};
+
+/* Some info to be carried along when creating a new tarball */
+struct TarBallInfo
+{
+       char* fileName;               /* File name of the tarball */
+       int tarFd;                    /* Open-for-write file descriptor
+                                                                        for the tarball */
+       struct stat statBuf;          /* Stat info for the tarball, letting
+                                                                        us know the inode and device that the
+                                                                        tarball lives, so we can avoid trying 
+                                                                        to include the tarball into itself */
+       int verboseFlag;              /* Whether to print extra stuff or not */
+       char** excludeList;           /* List of files to not include */
+       HardLinkInfo *hlInfoHead;     /* Hard Link Tracking Information */
+       HardLinkInfo *hlInfo;         /* Hard Link Info for the current file */
+};
+typedef struct TarBallInfo TarBallInfo;
+
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
+static void
+addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino,
+               short linkCount, const char *name)
+{
+       /* Note: hlInfoHeadPtr can never be NULL! */
+       HardLinkInfo *hlInfo;
+
+       hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1);
+       if (hlInfo) {
+               hlInfo->next = *hlInfoHeadPtr;
+               *hlInfoHeadPtr = hlInfo;
+               hlInfo->dev = dev;
+               hlInfo->ino = ino;
+               hlInfo->linkCount = linkCount;
+               strcpy(hlInfo->name, name);
+       }
+       return;
+}
+
+static void
+freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr)
+{
+       HardLinkInfo *hlInfo = NULL;
+       HardLinkInfo *hlInfoNext = NULL;
+
+       if (hlInfoHeadPtr) {
+               hlInfo = *hlInfoHeadPtr;
+               while (hlInfo) {
+                       hlInfoNext = hlInfo->next;
+                       free(hlInfo);
+                       hlInfo = hlInfoNext;
+               }
+               *hlInfoHeadPtr = NULL;
+       }
+       return;
+}
+
+/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
+static HardLinkInfo *
+findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino)
+{
+       while(hlInfo) {
+               if ((ino == hlInfo->ino) && (dev == hlInfo->dev))
+                       break;
+               hlInfo = hlInfo->next;
+       }
+       return(hlInfo);
+}
+
+/* Put an octal string into the specified buffer.
+ * The number is zero and space padded and possibly null padded.
+ * Returns TRUE if successful.  */ 
+static int putOctal (char *cp, int len, long value)
+{
+       int tempLength;
+       char tempBuffer[32];
+       char *tempString = tempBuffer;
+
+       /* Create a string of the specified length with an initial space,
+        * leading zeroes and the octal number, and a trailing null.  */
+       sprintf (tempString, "%0*lo", len - 1, value);
+
+       /* If the string is too large, suppress the leading space.  */
+       tempLength = strlen (tempString) + 1;
+       if (tempLength > len) {
+               tempLength--;
+               tempString++;
+       }
+
+       /* If the string is still too large, suppress the trailing null.  */
+       if (tempLength > len)
+               tempLength--;
+
+       /* If the string is still too large, fail.  */
+       if (tempLength > len)
+               return FALSE;
+
+       /* Copy the string to the field.  */
+       memcpy (cp, tempString, len);
+
+       return TRUE;
+}
+
+/* Write out a tar header for the specified file/directory/whatever */
+static int
+writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name,
+               const char *real_name, struct stat *statbuf)
+{
+       long chksum=0;
+       struct TarHeader header;
+       const unsigned char *cp = (const unsigned char *) &header;
+       ssize_t size = sizeof(struct TarHeader);
+               
+       memset( &header, 0, size);
+
+       strncpy(header.name, header_name, sizeof(header.name)); 
+
+       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
+       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
+       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
+       putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
+       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
+       strncpy(header.magic, TAR_MAGIC TAR_VERSION, 
+                       TAR_MAGIC_LEN + TAR_VERSION_LEN );
+
+       /* Enter the user and group names (default to root if it fails) */
+       my_getpwuid(header.uname, statbuf->st_uid);
+       if (! *header.uname)
+               strcpy(header.uname, "root");
+       my_getgrgid(header.gname, statbuf->st_gid);
+       if (! *header.uname)
+               strcpy(header.uname, "root");
+
+       if (tbInfo->hlInfo) {
+               /* This is a hard link */
+               header.typeflag = LNKTYPE;
+               strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
+       } else if (S_ISLNK(statbuf->st_mode)) {
+               char *lpath = xreadlink(real_name);
+               if (!lpath) /* Already printed err msg inside xreadlink() */
+                       return ( FALSE);
+               header.typeflag  = SYMTYPE;
+               strncpy(header.linkname, lpath, sizeof(header.linkname)); 
+               free(lpath);
+       } else if (S_ISDIR(statbuf->st_mode)) {
+               header.typeflag  = DIRTYPE;
+               strncat(header.name, "/", sizeof(header.name)); 
+       } else if (S_ISCHR(statbuf->st_mode)) {
+               header.typeflag  = CHRTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
+       } else if (S_ISBLK(statbuf->st_mode)) {
+               header.typeflag  = BLKTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
+       } else if (S_ISFIFO(statbuf->st_mode)) {
+               header.typeflag  = FIFOTYPE;
+       } else if (S_ISREG(statbuf->st_mode)) {
+               header.typeflag  = REGTYPE;
+               putOctal(header.size, sizeof(header.size), statbuf->st_size);
+       } else {
+               error_msg("%s: Unknown file type", real_name);
+               return ( FALSE);
+       }
+
+       /* Calculate and store the checksum (i.e., the sum of all of the bytes of
+        * the header).  The checksum field must be filled with blanks for the
+        * calculation.  The checksum field is formatted differently from the
+        * other fields: it has [6] digits, a null, then a space -- rather than
+        * digits, followed by a null like the other fields... */
+       memset(header.chksum, ' ', sizeof(header.chksum));
+       cp = (const unsigned char *) &header;
+       while (size-- > 0)
+               chksum += *cp++;
+       putOctal(header.chksum, 7, chksum);
+       
+       /* Now write the header out to disk */
+       if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
+               error_msg(io_error, real_name, strerror(errno)); 
+               return ( FALSE);
+       }
+       /* Pad the header up to the tar block size */
+       for (; size<TAR_BLOCK_SIZE; size++) {
+               write(tbInfo->tarFd, "\0", 1);
+       }
+       /* Now do the verbose thing (or not) */
+       if (tbInfo->verboseFlag==TRUE) {
+               FILE *vbFd = stdout;
+               if (tbInfo->tarFd == fileno(stdout))    // If the archive goes to stdout, verbose to stderr
+                       vbFd = stderr;
+               fprintf(vbFd, "%s\n", header.name);
+       }
+
+       return ( TRUE);
+}
+
+
+static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
+{
+       struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
+       const char *header_name;
+
+       /*
+       ** Check to see if we are dealing with a hard link.
+       ** If so -
+       ** Treat the first occurance of a given dev/inode as a file while
+       ** treating any additional occurances as hard links.  This is done
+       ** by adding the file information to the HardLinkInfo linked list.
+       */
+       tbInfo->hlInfo = NULL;
+       if (statbuf->st_nlink > 1) {
+               tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, 
+                               statbuf->st_ino);
+               if (tbInfo->hlInfo == NULL)
+                       addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev,
+                                       statbuf->st_ino, statbuf->st_nlink, fileName);
+       }
+
+       /* It is against the rules to archive a socket */
+       if (S_ISSOCK(statbuf->st_mode)) {
+               error_msg("%s: socket ignored", fileName);
+               return( TRUE);
+       }
+
+       /* It is a bad idea to store the archive we are in the process of creating,
+        * so check the device and inode to be sure that this particular file isn't
+        * the new tarball */
+       if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
+                       tbInfo->statBuf.st_ino == statbuf->st_ino) {
+               error_msg("%s: file is the archive; skipping", fileName);
+               return( TRUE);
+       }
+
+       header_name = fileName;
+       while (header_name[0] == '/') {
+               static int alreadyWarned=FALSE;
+               if (alreadyWarned==FALSE) {
+                       error_msg("Removing leading '/' from member names");
+                       alreadyWarned=TRUE;
+               }
+               header_name++;
+       }
+
+       if (strlen(fileName) >= NAME_SIZE) {
+               error_msg(name_longer_than_foo, NAME_SIZE);
+               return ( TRUE);
+       }
+
+       if (header_name[0] == '\0')
+               return TRUE;
+
+#if defined BB_FEATURE_TAR_EXCLUDE
+       if (exclude_file(tbInfo->excludeList, header_name)) {
+               return SKIP;
+       }
+#endif
+
+       if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) {
+               return( FALSE);
+       } 
+
+       /* Now, if the file is a regular file, copy it out to the tarball */
+       if ((tbInfo->hlInfo == NULL)
+       &&  (S_ISREG(statbuf->st_mode))) {
+               int  inputFileFd;
+               char buffer[BUFSIZ];
+               ssize_t size=0, readSize=0;
+
+               /* open the file we want to archive, and make sure all is well */
+               if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
+                       error_msg("%s: Cannot open: %s", fileName, strerror(errno));
+                       return( FALSE);
+               }
+               
+               /* write the file to the archive */
+               while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
+                       if (full_write(tbInfo->tarFd, buffer, size) != size ) {
+                               /* Output file seems to have a problem */
+                               error_msg(io_error, fileName, strerror(errno)); 
+                               return( FALSE);
+                       }
+                       readSize+=size;
+               }
+               if (size == -1) {
+                       error_msg(io_error, fileName, strerror(errno)); 
+                       return( FALSE);
+               }
+               /* Pad the file up to the tar block size */
+               for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
+                       write(tbInfo->tarFd, "\0", 1);
+               }
+               close( inputFileFd);
+       }
+
+       return( TRUE);
+}
+
+static int writeTarFile(const char* tarName, int verboseFlag, char **argv,
+               char** excludeList)
+{
+       int tarFd=-1;
+       int errorFlag=FALSE;
+       ssize_t size;
+       struct TarBallInfo tbInfo;
+       tbInfo.verboseFlag = verboseFlag;
+       tbInfo.hlInfoHead = NULL;
+
+       /* Make sure there is at least one file to tar up.  */
+       if (*argv == NULL)
+               error_msg_and_die("Cowardly refusing to create an empty archive");
+
+       /* Open the tar file for writing.  */
+       if (!strcmp(tarName, "-"))
+               tbInfo.tarFd = fileno(stdout);
+       else
+               tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (tbInfo.tarFd < 0) {
+               perror_msg( "Error opening '%s'", tarName);
+               freeHardLinkInfo(&tbInfo.hlInfoHead);
+               return ( FALSE);
+       }
+       tbInfo.excludeList=excludeList;
+       /* Store the stat info for the tarball's file, so
+        * can avoid including the tarball into itself....  */
+       if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
+               error_msg_and_die(io_error, tarName, strerror(errno)); 
+
+       /* Read the directory/files and iterate over them one at a time */
+       while (*argv != NULL) {
+               if (recursive_action(*argv++, TRUE, FALSE, FALSE,
+                                       writeFileToTarball, writeFileToTarball, 
+                                       (void*) &tbInfo) == FALSE) {
+                       errorFlag = TRUE;
+               }
+       }
+       /* Write two empty blocks to the end of the archive */
+       for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
+               write(tbInfo.tarFd, "\0", 1);
+       }
+
+       /* To be pedantically correct, we would check if the tarball
+        * is smaller than 20 tar blocks, and pad it if it was smaller,
+        * but that isn't necessary for GNU tar interoperability, and
+        * so is considered a waste of space */
+
+       /* Hang up the tools, close up shop, head home */
+       close(tarFd);
+       if (errorFlag == TRUE) {
+               error_msg("Error exit delayed from previous errors");
+               freeHardLinkInfo(&tbInfo.hlInfoHead);
+               return(FALSE);
+       }
+       freeHardLinkInfo(&tbInfo.hlInfoHead);
+       return( TRUE);
+}
+
+
+#endif
+
diff --git a/tee.c b/tee.c
new file mode 100644 (file)
index 0000000..0533dbd
--- /dev/null
+++ b/tee.c
@@ -0,0 +1,67 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tee implementation for busybox
+ *
+ * Copyright (C) 1999,2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include <getopt.h>
+#include <stdio.h>
+
+int
+tee_main(int argc, char **argv)
+{
+       char *mode = "w";
+       int c, i, status = 0, nfiles = 0;
+       FILE **files;
+
+       while ((c = getopt(argc, argv, "a")) != EOF) {
+               switch (c) {
+               case 'a': 
+                       mode = "a";
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1));
+       files[nfiles++] = stdout;
+       while (optind < argc) {
+               if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) {
+                       nfiles--;
+                       perror_msg("%s", argv[optind-1]);
+                       status = 1;
+               }
+       }
+
+       while ((c = getchar()) != EOF)
+               for (i = 0; i < nfiles; i++)
+                       putc(c, files[i]);
+
+       return status;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/telnet.c b/telnet.c
new file mode 100644 (file)
index 0000000..cacb91f
--- /dev/null
+++ b/telnet.c
@@ -0,0 +1,755 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * telnet implementation for busybox
+ *
+ * Author: Tomi Ollila <too@iki.fi>
+ * Copyright (C) 1994-2000 by Tomi Ollila
+ *
+ * Created: Thu Apr  7 13:29:41 1994 too
+ * Last modified: Fri Jun  9 14:34:24 2000 too
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * HISTORY
+ * Revision 3.1  1994/04/17  11:31:54  too
+ * initial revision
+ * Modified 2000/06/13 for inclusion in BusyBox by Erik Andersen <andersee@debian.org> 
+ * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
+ * <jam@ltsp.org>
+ *
+ */
+
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <arpa/telnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "busybox.h"
+
+#ifdef BB_FEATURE_AUTOWIDTH
+#   include <sys/ioctl.h>
+#endif
+
+#if 0
+static const int DOTRACE = 1;
+#endif
+
+#ifdef DOTRACE
+#include <arpa/inet.h> /* for inet_ntoa()... */
+#define TRACE(x, y) do { if (x) printf y; } while (0)
+#else
+#define TRACE(x, y) 
+#endif
+
+#if 0
+#define USE_POLL
+#include <sys/poll.h>
+#else
+#include <sys/time.h>
+#endif
+
+#define DATABUFSIZE  128
+#define IACBUFSIZE   128
+
+static const int CHM_TRY = 0;
+static const int CHM_ON = 1;
+static const int CHM_OFF = 2;
+
+static const int UF_ECHO = 0x01;
+static const int UF_SGA = 0x02;
+
+enum {
+       TS_0 = 1,
+       TS_IAC = 2,
+       TS_OPT = 3,
+       TS_SUB1 = 4,
+       TS_SUB2 = 5,
+};
+
+#define WriteCS(fd, str) write(fd, str, sizeof str -1)
+
+typedef unsigned char byte;
+
+/* use globals to reduce size ??? */ /* test this hypothesis later */
+static struct Globalvars {
+       int             netfd; /* console fd:s are 0 and 1 (and 2) */
+    /* same buffer used both for network and console read/write */
+       char    buf[DATABUFSIZE]; /* allocating so static size is smaller */
+       byte    telstate; /* telnet negotiation state from network input */
+       byte    telwish;  /* DO, DONT, WILL, WONT */
+       byte    charmode;
+       byte    telflags;
+       byte    gotsig;
+       /* buffer to handle telnet negotiations */
+       char    iacbuf[IACBUFSIZE];
+       short   iaclen; /* could even use byte */
+       struct termios termios_def;     
+       struct termios termios_raw;     
+} G;
+
+#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
+
+#ifdef USE_GLOBALVAR_PTR
+struct Globalvars * Gptr;
+#define G (*Gptr)
+#else
+static struct Globalvars G;
+#endif
+
+static inline void iacflush()
+{
+       write(G.netfd, G.iacbuf, G.iaclen);
+       G.iaclen = 0;
+}
+
+/* Function prototypes */
+static int getport(char * p);
+static struct in_addr getserver(char * p);
+static int create_socket();
+static void setup_sockaddr_in(struct sockaddr_in * addr, int port);
+static int remote_connect(struct in_addr addr, int port);
+static void rawmode();
+static void cookmode();
+static void do_linemode();
+static void will_charmode();
+static void telopt(byte c);
+static int subneg(byte c);
+#if 0
+static int local_bind(int port);
+#endif
+
+/* Some globals */
+static int one = 1;
+
+#ifdef BB_FEATURE_TELNET_TTYPE
+static char *ttype;
+#endif
+
+#ifdef BB_FEATURE_AUTOWIDTH
+static int win_width, win_height;
+#endif
+
+static void doexit(int ev)
+{
+       cookmode();
+       exit(ev);
+}      
+
+static void conescape()
+{
+       char b;
+
+       if (G.gotsig)   /* came from line  mode... go raw */
+               rawmode();
+
+       WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
+                       " l     go to line mode\r\n"
+                       " c     go to character mode\r\n"
+                       " z     suspend telnet\r\n"
+                       " e     exit telnet\r\n");
+
+       if (read(0, &b, 1) <= 0)
+               doexit(1);
+
+       switch (b)
+       {
+       case 'l':
+               if (!G.gotsig)
+               {
+                       do_linemode();
+                       goto rrturn;
+               }
+               break;
+       case 'c':
+               if (G.gotsig)
+               {
+                       will_charmode();
+                       goto rrturn;
+               }
+               break;
+       case 'z':
+               cookmode();
+               kill(0, SIGTSTP);
+               rawmode();
+               break;
+       case 'e':
+               doexit(0);
+       }
+
+       WriteCS(1, "continuing...\r\n");
+
+       if (G.gotsig)
+               cookmode();
+       
+ rrturn:
+       G.gotsig = 0;
+       
+}
+static void handlenetoutput(int len)
+{
+       /*      here we could do smart tricks how to handle 0xFF:s in output
+        *      stream  like writing twice every sequence of FF:s (thus doing
+        *      many write()s. But I think interactive telnet application does
+        *      not need to be 100% 8-bit clean, so changing every 0xff:s to
+        *      0x7f:s
+        *
+        *      2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
+        *      I don't agree.
+        *      first - I cannot use programs like sz/rz
+        *      second - the 0x0D is sent as one character and if the next
+        *               char is 0x0A then it's eaten by a server side.
+        *      third - whay doy you have to make 'many write()s'?
+        *              I don't understand.
+        *      So I implemented it. It's realy useful for me. I hope that
+        *      others people will find it interesting to.
+        */
+
+       int i, j;
+       byte * p = G.buf;
+       byte outbuf[4*DATABUFSIZE];
+
+       for (i = len, j = 0; i > 0; i--, p++)
+       {
+               if (*p == 0x1d)
+               {
+                       conescape();
+                       return;
+               }
+               outbuf[j++] = *p;
+               if (*p == 0xff)
+                   outbuf[j++] = 0xff;
+               else if (*p == 0x0d)
+                   outbuf[j++] = 0x00;
+       }
+       if (j > 0 )
+           write(G.netfd, outbuf, j);
+}
+
+
+static void handlenetinput(int len)
+{
+       int i;
+       int cstart = 0;
+
+       for (i = 0; i < len; i++)
+       {
+               byte c = G.buf[i];
+
+               if (G.telstate == 0) /* most of the time state == 0 */
+               {
+                       if (c == IAC)
+                       {
+                               cstart = i;
+                               G.telstate = TS_IAC;
+                       }
+               }
+               else
+                       switch (G.telstate)
+                        {
+                        case TS_0:
+                                if (c == IAC)
+                                        G.telstate = TS_IAC;
+                                else
+                                        G.buf[cstart++] = c;
+                                break;
+
+                        case TS_IAC:
+                                if (c == IAC) /* IAC IAC -> 0xFF */
+                                {
+                                        G.buf[cstart++] = c;
+                                        G.telstate = TS_0;
+                                        break;
+                                }
+                                /* else */
+                                switch (c)
+                                {
+                                case SB:
+                                        G.telstate = TS_SUB1;
+                                        break;
+                                case DO:
+                                case DONT:
+                                case WILL:
+                                case WONT:
+                                        G.telwish =  c;
+                                        G.telstate = TS_OPT;
+                                        break;
+                                default:
+                                        G.telstate = TS_0;     /* DATA MARK must be added later */
+                                }
+                                break;
+                        case TS_OPT: /* WILL, WONT, DO, DONT */
+                                telopt(c);
+                                G.telstate = TS_0;
+                                break;
+                        case TS_SUB1: /* Subnegotiation */
+                        case TS_SUB2: /* Subnegotiation */
+                                if (subneg(c) == TRUE)
+                                        G.telstate = TS_0;
+                                break;
+                        }
+       }
+       if (G.telstate)
+       {
+               if (G.iaclen)                   iacflush();
+               if (G.telstate == TS_0) G.telstate = 0;
+
+               len = cstart;
+       }
+
+       if (len)
+               write(1, G.buf, len);
+}
+
+
+/* ******************************* */
+
+static inline void putiac(int c)
+{
+       G.iacbuf[G.iaclen++] = c;
+}
+
+
+static void putiac2(byte wwdd, byte c)
+{
+       if (G.iaclen + 3 > IACBUFSIZE)
+               iacflush();
+
+       putiac(IAC);
+       putiac(wwdd);
+       putiac(c);
+}
+
+#if 0
+static void putiac1(byte c)
+{
+       if (G.iaclen + 2 > IACBUFSIZE)
+               iacflush();
+
+       putiac(IAC);
+       putiac(c);
+}
+#endif
+
+#ifdef BB_FEATURE_TELNET_TTYPE
+static void putiac_subopt(byte c, char *str)
+{
+       int     len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
+
+       if (G.iaclen + len > IACBUFSIZE)
+               iacflush();
+
+       putiac(IAC);
+       putiac(SB);
+       putiac(c);
+       putiac(0);
+
+       while(*str)
+               putiac(*str++);
+
+       putiac(IAC);
+       putiac(SE);
+}
+#endif
+
+#ifdef BB_FEATURE_AUTOWIDTH
+static void putiac_naws(byte c, int x, int y)
+{
+       if (G.iaclen + 9 > IACBUFSIZE)
+               iacflush();
+
+       putiac(IAC);
+       putiac(SB);
+       putiac(c);
+
+       putiac((x >> 8) & 0xff);
+       putiac(x & 0xff);
+       putiac((y >> 8) & 0xff);
+       putiac(y & 0xff);
+
+       putiac(IAC);
+       putiac(SE);
+}
+#endif
+
+/* void putiacstring (subneg strings) */
+
+/* ******************************* */
+
+static char const escapecharis[] = "\r\nEscape character is ";
+
+static void setConMode()
+{
+       if (G.telflags & UF_ECHO)
+       {
+               if (G.charmode == CHM_TRY) {
+                       G.charmode = CHM_ON;
+                       printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
+                       rawmode();
+               }
+       }
+       else
+       {
+               if (G.charmode != CHM_OFF) {
+                       G.charmode = CHM_OFF;
+                       printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
+                       cookmode();
+               }
+       }
+}
+
+/* ******************************* */
+
+static void will_charmode()
+{
+       G.charmode = CHM_TRY;
+       G.telflags |= (UF_ECHO | UF_SGA);
+       setConMode();
+  
+       putiac2(DO, TELOPT_ECHO);
+       putiac2(DO, TELOPT_SGA);
+       iacflush();
+}
+
+static void do_linemode()
+{
+       G.charmode = CHM_TRY;
+       G.telflags &= ~(UF_ECHO | UF_SGA);
+       setConMode();
+
+       putiac2(DONT, TELOPT_ECHO);
+       putiac2(DONT, TELOPT_SGA);
+       iacflush();
+}
+
+/* ******************************* */
+
+static inline void to_notsup(char c)
+{
+       if      (G.telwish == WILL)     putiac2(DONT, c);
+       else if (G.telwish == DO)       putiac2(WONT, c);
+}
+
+static inline void to_echo(void)
+{
+       /* if server requests ECHO, don't agree */
+       if      (G.telwish == DO) {     putiac2(WONT, TELOPT_ECHO);     return; }
+       else if (G.telwish == DONT)     return;
+  
+       if (G.telflags & UF_ECHO)
+       {
+               if (G.telwish == WILL)
+                       return;
+       }
+       else
+               if (G.telwish == WONT)
+                       return;
+
+       if (G.charmode != CHM_OFF)
+               G.telflags ^= UF_ECHO;
+
+       if (G.telflags & UF_ECHO)
+               putiac2(DO, TELOPT_ECHO);
+       else
+               putiac2(DONT, TELOPT_ECHO);
+
+       setConMode();
+       WriteCS(1, "\r\n");  /* sudden modec */
+}
+
+static inline void to_sga(void)
+{
+       /* daemon always sends will/wont, client do/dont */
+
+       if (G.telflags & UF_SGA)
+       {
+               if (G.telwish == WILL)
+                       return;
+       }
+       else
+               if (G.telwish == WONT)
+                       return;
+  
+       if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
+               putiac2(DO, TELOPT_SGA);
+       else
+               putiac2(DONT, TELOPT_SGA);
+
+       return;
+}
+
+#ifdef BB_FEATURE_TELNET_TTYPE
+static inline void to_ttype(void)
+{
+       /* Tell server we will (or won't) do TTYPE */
+
+       if(ttype)
+               putiac2(WILL, TELOPT_TTYPE);
+       else
+               putiac2(WONT, TELOPT_TTYPE);
+
+       return;
+}
+#endif
+
+#ifdef BB_FEATURE_AUTOWIDTH
+static inline void to_naws(void)
+{
+       /* Tell server we will do NAWS */
+       putiac2(WILL, TELOPT_NAWS);
+       return;
+}
+#endif
+
+static void telopt(byte c)
+{
+       switch (c)
+       {
+               case TELOPT_ECHO:               to_echo();      break;
+               case TELOPT_SGA:                to_sga();       break;
+#ifdef BB_FEATURE_TELNET_TTYPE
+               case TELOPT_TTYPE:              to_ttype();     break;
+#endif
+#ifdef BB_FEATURE_AUTOWIDTH
+               case TELOPT_NAWS:               to_naws();
+                                                               putiac_naws(c, win_width, win_height);
+                                                               break;
+#endif
+               default:                                to_notsup(c);
+                                                               break;
+       }
+}
+
+
+/* ******************************* */
+
+/* subnegotiation -- ignore all (except TTYPE,NAWS) */
+
+static int subneg(byte c)
+{
+       switch (G.telstate)
+       {
+       case TS_SUB1:
+               if (c == IAC)
+                       G.telstate = TS_SUB2;
+#ifdef BB_FEATURE_TELNET_TTYPE
+               else
+               if (c == TELOPT_TTYPE)
+                       putiac_subopt(TELOPT_TTYPE,ttype);
+#endif
+               break;
+       case TS_SUB2:
+               if (c == SE)
+                       return TRUE;
+               G.telstate = TS_SUB1;
+               /* break; */
+       }
+       return FALSE;
+}
+
+/* ******************************* */
+
+static void fgotsig(int sig)
+{
+       G.gotsig = sig;
+}
+
+
+static void rawmode()
+{
+       tcsetattr(0, TCSADRAIN, &G.termios_raw);
+}      
+
+static void cookmode()
+{
+       tcsetattr(0, TCSADRAIN, &G.termios_def);
+}
+
+extern int telnet_main(int argc, char** argv)
+{
+       struct in_addr host;
+       int port;
+       int len;
+#ifdef USE_POLL
+       struct pollfd ufds[2];
+#else  
+       fd_set readfds;
+       int maxfd;
+#endif 
+
+#ifdef BB_FEATURE_AUTOWIDTH
+    struct winsize winp;
+    if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) {
+       win_width  = winp.ws_col;
+       win_height = winp.ws_row;
+    }
+#endif
+
+#ifdef BB_FEATURE_TELNET_TTYPE
+    ttype = getenv("TERM");
+#endif
+
+       memset(&G, 0, sizeof G);
+
+       if (tcgetattr(0, &G.termios_def) < 0)
+               exit(1);
+       
+       G.termios_raw = G.termios_def;
+       cfmakeraw(&G.termios_raw);
+       
+       if (argc < 2)   show_usage();
+       port = (argc > 2)? getport(argv[2]): 23;
+       
+       host = getserver(argv[1]);
+
+       G.netfd = remote_connect(host, port);
+
+       signal(SIGINT, fgotsig);
+
+#ifdef USE_POLL
+       ufds[0].fd = 0; ufds[1].fd = G.netfd;
+       ufds[0].events = ufds[1].events = POLLIN;
+#else  
+       FD_ZERO(&readfds);
+       FD_SET(0, &readfds);
+       FD_SET(G.netfd, &readfds);
+       maxfd = G.netfd + 1;
+#endif
+       
+       while (1)
+       {
+#ifndef USE_POLL
+               fd_set rfds = readfds;
+               
+               switch (select(maxfd, &rfds, NULL, NULL, NULL))
+#else
+               switch (poll(ufds, 2, -1))
+#endif                 
+               {
+               case 0:
+                       /* timeout */
+               case -1:
+                       /* error, ignore and/or log something, bay go to loop */
+                       if (G.gotsig)
+                               conescape();
+                       else
+                               sleep(1);
+                       break;
+               default:
+
+#ifdef USE_POLL
+                       if (ufds[0].revents) /* well, should check POLLIN, but ... */
+#else                          
+                       if (FD_ISSET(0, &rfds))
+#endif                         
+                       {
+                               len = read(0, G.buf, DATABUFSIZE);
+
+                               if (len <= 0)
+                                       doexit(0);
+
+                               TRACE(0, ("Read con: %d\n", len));
+                               
+                               handlenetoutput(len);
+                       }
+
+#ifdef USE_POLL
+                       if (ufds[1].revents) /* well, should check POLLIN, but ... */
+#else                          
+                       if (FD_ISSET(G.netfd, &rfds))
+#endif                         
+                       {
+                               len = read(G.netfd, G.buf, DATABUFSIZE);
+
+                               if (len <= 0)
+                               {
+                                       WriteCS(1, "Connection closed by foreign host.\r\n");
+                                       doexit(1);
+                               }
+                               TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
+
+                               handlenetinput(len);
+                       }
+               }
+       }
+}
+
+static int getport(char * p)
+{
+       unsigned int port = atoi(p);
+
+       if ((unsigned)(port - 1 ) > 65534)
+       {
+               error_msg_and_die("%s: bad port number", p);
+       }
+       return port;
+}
+
+static struct in_addr getserver(char * host)
+{
+       struct in_addr addr;
+
+       struct hostent * he;
+       he = xgethostbyname(host);
+       memcpy(&addr, he->h_addr, sizeof addr);
+
+       TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
+
+       return addr;
+}
+
+static int create_socket()
+{
+       return socket(AF_INET, SOCK_STREAM, 0);
+}
+
+static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
+{
+       memset(addr, 0, sizeof(struct sockaddr_in));
+       addr->sin_family = AF_INET;
+       addr->sin_port = htons(port);
+}
+  
+static int remote_connect(struct in_addr addr, int port)
+{
+       struct sockaddr_in s_addr;
+       int s = create_socket();
+
+       setup_sockaddr_in(&s_addr, port);
+       s_addr.sin_addr = addr;
+
+       setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
+
+       if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
+       {
+               perror_msg_and_die("Unable to connect to remote host");
+       }
+       return s;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
diff --git a/test.c b/test.c
new file mode 100644 (file)
index 0000000..9c66cbb
--- /dev/null
+++ b/test.c
@@ -0,0 +1,579 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * test implementation for busybox
+ *
+ * Copyright (c) by a whole pile of folks: 
+ *
+ *     test(1); version 7-like  --  author Erik Baalbergen
+ *     modified by Eric Gisin to be used as built-in.
+ *     modified by Arnold Robbins to add SVR3 compatibility
+ *     (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ *     modified by J.T. Conklin for NetBSD.
+ *     modified by Herbert Xu to be used as built-in in ash.
+ *     modified by Erik Andersen <andersee@debian.org> to be used 
+ *     in busybox.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original copyright notice states:
+ *     "This program is in the Public Domain."
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "busybox.h"
+
+/* test(1) accepts the following grammar:
+       oexpr   ::= aexpr | aexpr "-o" oexpr ;
+       aexpr   ::= nexpr | nexpr "-a" aexpr ;
+       nexpr   ::= primary | "!" primary
+       primary ::= unary-operator operand
+               | operand binary-operator operand
+               | operand
+               | "(" oexpr ")"
+               ;
+       unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+               "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+       binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+                       "-nt"|"-ot"|"-ef";
+       operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+       EOI,
+       FILRD,
+       FILWR,
+       FILEX,
+       FILEXIST,
+       FILREG,
+       FILDIR,
+       FILCDEV,
+       FILBDEV,
+       FILFIFO,
+       FILSOCK,
+       FILSYM,
+       FILGZ,
+       FILTT,
+       FILSUID,
+       FILSGID,
+       FILSTCK,
+       FILNT,
+       FILOT,
+       FILEQ,
+       FILUID,
+       FILGID,
+       STREZ,
+       STRNZ,
+       STREQ,
+       STRNE,
+       STRLT,
+       STRGT,
+       INTEQ,
+       INTNE,
+       INTGE,
+       INTGT,
+       INTLE,
+       INTLT,
+       UNOT,
+       BAND,
+       BOR,
+       LPAREN,
+       RPAREN,
+       OPERAND
+};
+
+enum token_types {
+       UNOP,
+       BINOP,
+       BUNOP,
+       BBINOP,
+       PAREN
+};
+
+static const struct t_op {
+       const char *op_text;
+       short op_num, op_type;
+} ops [] = {
+       {"-r",  FILRD,  UNOP},
+       {"-w",  FILWR,  UNOP},
+       {"-x",  FILEX,  UNOP},
+       {"-e",  FILEXIST,UNOP},
+       {"-f",  FILREG, UNOP},
+       {"-d",  FILDIR, UNOP},
+       {"-c",  FILCDEV,UNOP},
+       {"-b",  FILBDEV,UNOP},
+       {"-p",  FILFIFO,UNOP},
+       {"-u",  FILSUID,UNOP},
+       {"-g",  FILSGID,UNOP},
+       {"-k",  FILSTCK,UNOP},
+       {"-s",  FILGZ,  UNOP},
+       {"-t",  FILTT,  UNOP},
+       {"-z",  STREZ,  UNOP},
+       {"-n",  STRNZ,  UNOP},
+       {"-h",  FILSYM, UNOP},          /* for backwards compat */
+       {"-O",  FILUID, UNOP},
+       {"-G",  FILGID, UNOP},
+       {"-L",  FILSYM, UNOP},
+       {"-S",  FILSOCK,UNOP},
+       {"=",   STREQ,  BINOP},
+       {"!=",  STRNE,  BINOP},
+       {"<",   STRLT,  BINOP},
+       {">",   STRGT,  BINOP},
+       {"-eq", INTEQ,  BINOP},
+       {"-ne", INTNE,  BINOP},
+       {"-ge", INTGE,  BINOP},
+       {"-gt", INTGT,  BINOP},
+       {"-le", INTLE,  BINOP},
+       {"-lt", INTLT,  BINOP},
+       {"-nt", FILNT,  BINOP},
+       {"-ot", FILOT,  BINOP},
+       {"-ef", FILEQ,  BINOP},
+       {"!",   UNOT,   BUNOP},
+       {"-a",  BAND,   BBINOP},
+       {"-o",  BOR,    BBINOP},
+       {"(",   LPAREN, PAREN},
+       {")",   RPAREN, PAREN},
+       {0,     0,      0}
+};
+
+static char **t_wp;
+static struct t_op const *t_wp_op;
+static gid_t *group_array = NULL;
+static int ngroups;
+
+static enum token t_lex();
+static int oexpr();
+static int aexpr();
+static int nexpr();
+static int binop();
+static int primary();
+static int filstat();
+static int getn();
+static int newerf();
+static int olderf();
+static int equalf();
+static void syntax();
+static int test_eaccess();
+static int is_a_group_member();
+static void initialize_group_array();
+
+extern int
+test_main(int argc, char** argv)
+{
+       int     res;
+
+       if (strcmp(applet_name, "[") == 0) {
+               if (strcmp(argv[--argc], "]"))
+                       error_msg_and_die("missing ]");
+               argv[argc] = NULL;
+       }
+       /* Implement special cases from POSIX.2, section 4.62.4 */
+       switch (argc) {
+       case 1:
+               exit( 1);
+       case 2:
+               exit (*argv[1] == '\0');
+       case 3:
+               if (argv[1][0] == '!' && argv[1][1] == '\0') {
+                       exit (!(*argv[2] == '\0'));
+               }
+               break;
+       case 4:
+               if (argv[1][0] != '!' || argv[1][1] != '\0') {
+                       if (t_lex(argv[2]), 
+                           t_wp_op && t_wp_op->op_type == BINOP) {
+                               t_wp = &argv[1];
+                               exit (binop() == 0);
+                       }
+               }
+               break;
+       case 5:
+               if (argv[1][0] == '!' && argv[1][1] == '\0') {
+                       if (t_lex(argv[3]), 
+                           t_wp_op && t_wp_op->op_type == BINOP) {
+                               t_wp = &argv[2];
+                               exit (!(binop() == 0));
+                       }
+               }
+               break;
+       }
+
+       t_wp = &argv[1];
+       res = !oexpr(t_lex(*t_wp));
+
+       if (*t_wp != NULL && *++t_wp != NULL)
+               syntax(*t_wp, "unknown operand");
+
+       return( res);
+}
+
+static void
+syntax(op, msg)
+       char    *op;
+       char    *msg;
+{
+       if (op && *op)
+               error_msg_and_die("%s: %s", op, msg);
+       else
+               error_msg_and_die("%s", msg);
+}
+
+static int
+oexpr(n)
+       enum token n;
+{
+       int res;
+
+       res = aexpr(n);
+       if (t_lex(*++t_wp) == BOR)
+               return oexpr(t_lex(*++t_wp)) || res;
+       t_wp--;
+       return res;
+}
+
+static int
+aexpr(n)
+       enum token n;
+{
+       int res;
+
+       res = nexpr(n);
+       if (t_lex(*++t_wp) == BAND)
+               return aexpr(t_lex(*++t_wp)) && res;
+       t_wp--;
+       return res;
+}
+
+static int
+nexpr(n)
+       enum token n;                   /* token */
+{
+       if (n == UNOT)
+               return !nexpr(t_lex(*++t_wp));
+       return primary(n);
+}
+
+static int
+primary(n)
+       enum token n;
+{
+       int res;
+
+       if (n == EOI)
+               syntax(NULL, "argument expected");
+       if (n == LPAREN) {
+               res = oexpr(t_lex(*++t_wp));
+               if (t_lex(*++t_wp) != RPAREN)
+                       syntax(NULL, "closing paren expected");
+               return res;
+       }
+       if (t_wp_op && t_wp_op->op_type == UNOP) {
+               /* unary expression */
+               if (*++t_wp == NULL)
+                       syntax(t_wp_op->op_text, "argument expected");
+               switch (n) {
+               case STREZ:
+                       return strlen(*t_wp) == 0;
+               case STRNZ:
+                       return strlen(*t_wp) != 0;
+               case FILTT:
+                       return isatty(getn(*t_wp));
+               default:
+                       return filstat(*t_wp, n);
+               }
+       }
+
+       if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
+               return binop();
+       }         
+
+       return strlen(*t_wp) > 0;
+}
+
+static int
+binop()
+{
+       const char *opnd1, *opnd2;
+       struct t_op const *op;
+
+       opnd1 = *t_wp;
+       (void) t_lex(*++t_wp);
+       op = t_wp_op;
+
+       if ((opnd2 = *++t_wp) == (char *)0)
+               syntax(op->op_text, "argument expected");
+               
+       switch (op->op_num) {
+       case STREQ:
+               return strcmp(opnd1, opnd2) == 0;
+       case STRNE:
+               return strcmp(opnd1, opnd2) != 0;
+       case STRLT:
+               return strcmp(opnd1, opnd2) < 0;
+       case STRGT:
+               return strcmp(opnd1, opnd2) > 0;
+       case INTEQ:
+               return getn(opnd1) == getn(opnd2);
+       case INTNE:
+               return getn(opnd1) != getn(opnd2);
+       case INTGE:
+               return getn(opnd1) >= getn(opnd2);
+       case INTGT:
+               return getn(opnd1) > getn(opnd2);
+       case INTLE:
+               return getn(opnd1) <= getn(opnd2);
+       case INTLT:
+               return getn(opnd1) < getn(opnd2);
+       case FILNT:
+               return newerf (opnd1, opnd2);
+       case FILOT:
+               return olderf (opnd1, opnd2);
+       case FILEQ:
+               return equalf (opnd1, opnd2);
+       }
+       /* NOTREACHED */
+       return 1;
+}
+
+static int
+filstat(nm, mode)
+       char *nm;
+       enum token mode;
+{
+       struct stat s;
+       unsigned int i;
+
+       if (mode == FILSYM) {
+#ifdef S_IFLNK
+               if (lstat(nm, &s) == 0) {
+                       i = S_IFLNK;
+                       goto filetype;
+               }
+#endif
+               return 0;
+       }
+
+       if (stat(nm, &s) != 0) 
+               return 0;
+
+       switch (mode) {
+       case FILRD:
+               return test_eaccess(nm, R_OK) == 0;
+       case FILWR:
+               return test_eaccess(nm, W_OK) == 0;
+       case FILEX:
+               return test_eaccess(nm, X_OK) == 0;
+       case FILEXIST:
+               return 1;
+       case FILREG:
+               i = S_IFREG;
+               goto filetype;
+       case FILDIR:
+               i = S_IFDIR;
+               goto filetype;
+       case FILCDEV:
+               i = S_IFCHR;
+               goto filetype;
+       case FILBDEV:
+               i = S_IFBLK;
+               goto filetype;
+       case FILFIFO:
+#ifdef S_IFIFO
+               i = S_IFIFO;
+               goto filetype;
+#else
+               return 0;
+#endif
+       case FILSOCK:
+#ifdef S_IFSOCK
+               i = S_IFSOCK;
+               goto filetype;
+#else
+               return 0;
+#endif
+       case FILSUID:
+               i = S_ISUID;
+               goto filebit;
+       case FILSGID:
+               i = S_ISGID;
+               goto filebit;
+       case FILSTCK:
+               i = S_ISVTX;
+               goto filebit;
+       case FILGZ:
+               return s.st_size > 0L;
+       case FILUID:
+               return s.st_uid == geteuid();
+       case FILGID:
+               return s.st_gid == getegid();
+       default:
+               return 1;
+       }
+
+filetype:
+       return ((s.st_mode & S_IFMT) == i);
+
+filebit:
+       return ((s.st_mode & i) != 0);
+}
+
+static enum token
+t_lex(s)
+       char *s;
+{
+       struct t_op const *op = ops;
+
+       if (s == 0) {
+               t_wp_op = (struct t_op *)0;
+               return EOI;
+       }
+       while (op->op_text) {
+               if (strcmp(s, op->op_text) == 0) {
+                       t_wp_op = op;
+                       return op->op_num;
+               }
+               op++;
+       }
+       t_wp_op = (struct t_op *)0;
+       return OPERAND;
+}
+
+/* atoi with error detection */
+static int
+getn(s)
+       char *s;
+{
+       char *p;
+       long r;
+
+       errno = 0;
+       r = strtol(s, &p, 10);
+
+       if (errno != 0)
+         error_msg_and_die("%s: out of range", s);
+
+       while (isspace(*p))
+         p++;
+       
+       if (*p)
+         error_msg_and_die("%s: bad number", s);
+
+       return (int) r;
+}
+
+static int
+newerf (f1, f2)
+char *f1, *f2;
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_mtime > b2.st_mtime);
+}
+
+static int
+olderf (f1, f2)
+char *f1, *f2;
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_mtime < b2.st_mtime);
+}
+
+static int
+equalf (f1, f2)
+char *f1, *f2;
+{
+       struct stat b1, b2;
+
+       return (stat (f1, &b1) == 0 &&
+               stat (f2, &b2) == 0 &&
+               b1.st_dev == b2.st_dev &&
+               b1.st_ino == b2.st_ino);
+}
+
+/* Do the same thing access(2) does, but use the effective uid and gid,
+   and don't make the mistake of telling root that any file is
+   executable. */
+static int
+test_eaccess (path, mode)
+char *path;
+int mode;
+{
+       struct stat st;
+       unsigned int euid = geteuid();
+
+       if (stat (path, &st) < 0)
+               return (-1);
+
+       if (euid == 0) {
+               /* Root can read or write any file. */
+               if (mode != X_OK)
+               return (0);
+
+               /* Root can execute any file that has any one of the execute
+                  bits set. */
+               if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+                       return (0);
+       }
+
+       if (st.st_uid == euid)          /* owner */
+               mode <<= 6;
+       else if (is_a_group_member (st.st_gid))
+               mode <<= 3;
+
+       if (st.st_mode & mode)
+               return (0);
+
+       return (-1);
+}
+
+static void
+initialize_group_array ()
+{
+       ngroups = getgroups(0, NULL);
+       group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
+       getgroups(ngroups, group_array);
+}
+
+/* Return non-zero if GID is one that we have in our groups list. */
+static int
+is_a_group_member (gid)
+gid_t gid;
+{
+       register int i;
+
+       /* Short-circuit if possible, maybe saving a call to getgroups(). */
+       if (gid == getgid() || gid == getegid())
+               return (1);
+
+       if (ngroups == 0)
+               initialize_group_array ();
+
+       /* Search through the list looking for GID. */
+       for (i = 0; i < ngroups; i++)
+               if (gid == group_array[i])
+                       return (1);
+
+       return (0);
+}
diff --git a/tests/.cvsignore b/tests/.cvsignore
new file mode 100644 (file)
index 0000000..3645cf9
--- /dev/null
@@ -0,0 +1,16 @@
+cp
+cp_*.bb
+cp_*.gnu
+cp_tests
+date
+df
+du
+ln
+ln_*.bb
+ln_*.gnu
+ln_tests
+mv
+mv_*.bb
+mv_*.gnu
+mv_tests
+syslog_test
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..8ad304d
--- /dev/null
@@ -0,0 +1,34 @@
+# busybox/tests/Makefile - Run through all defined tests.
+# ------------------------
+# Copyright (C) 2000  Karl M. Hegbloom <karlheg@debian.org>  GPL
+
+all:: message_header
+
+message_header:
+       @echo
+       @echo BusyBox Test Suite.
+       @echo
+       (cd ..; tests/busybox.REGRESS.sh)
+
+clean::
+
+distclean: clean
+
+.PHONY: all clean distclean message_header
+
+include $(wildcard *_tests.mk)
+
+BBL := $(shell pushd .. >/dev/null &&          \
+                ${MAKE} busybox.links >/dev/null && \
+              popd >/dev/null &&               \
+              cat ../busybox.links |           \
+                sed -e 's,.*/\(.*\)$$,\1,')
+
+../busybox:
+       cd .. && ${MAKE} busybox
+
+${BBL}: ../busybox
+       rm -f $@
+       ln ../busybox $@
+
+syslog_test: syslog_test.c
diff --git a/tests/cp_tests.mk b/tests/cp_tests.mk
new file mode 100644 (file)
index 0000000..b96c5ce
--- /dev/null
@@ -0,0 +1,360 @@
+# cp_tests.mk - Set of test cases for busybox cp
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
+
+# GNU `cp'
+GCP = /bin/cp
+# BusyBox `cp'
+BCP = $(shell pwd)/cp
+
+all:: cp_tests
+clean:: cp_clean
+
+cp_clean:
+       - rm -rf cp_tests cp_*.{gnu,bb} cp
+
+# check_cp_dir_to_dir_wo_a removed from this list; see below
+cp_tests: cp_clean cp check_exists check_simple_cp check_cp_symlnk \
+       check_cp_symlink_w_a check_cp_files_to_dir check_cp_files_to_dir_w_d \
+       check_cp_files_to_dir_w_p check_cp_files_to_dir_w_p_and_d \
+       check_cp_dir_to_dir_w_a \
+       check_cp_dir_to_dir_w_a_take_two
+
+check_exists:
+       @echo;
+       @echo "No output from diff means busybox cp is functioning properly.";
+       @echo "Some tests might show timestamp differences that are Ok.";
+
+       @echo;
+       @echo Verify that busybox cp exists;
+       @echo ------------------------------;
+       [ -x ${BCP} ] || exit 0
+
+       @echo;
+       mkdir cp_tests;
+
+check_simple_cp:
+       @echo Copy a file to a copy of the file;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../cp_afile_afilecopy.gnu; \
+        ${GCP} afile afilecopy;                \
+        ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu;
+
+       @echo;
+       rm -rf cp_tests/*;
+
+       @echo;
+       cd cp_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../cp_afile_afilecopy.bb; \
+        ${BCP} afile afilecopy;                \
+        ls -l afile afilecopy >> ../cp_afile_afilecopy.bb;
+
+       @echo;
+       @echo Might show timestamp differences.
+       -diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb;
+
+       @echo;
+       rm -rf cp_tests/*;
+
+check_cp_symlnk:
+       @echo; echo Copy a file pointed to by a symlink;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        mkdir here there;                      \
+        echo A file > afile;                   \
+        cd here;                               \
+         ln -s ../afile .;                     \
+
+       @echo;
+       cd cp_tests;                            \
+        ls -lR . > ../cp_symlink.gnu;          \
+        ${GCP} here/afile there;               \
+        ls -lR . >> ../cp_symlink.gnu;
+
+       @echo;
+       rm -rf cp_tests/there/*;
+
+       sleep 1;
+
+       @echo;
+       cd cp_tests;                            \
+        ls -lR . > ../cp_symlink.bb;           \
+        ${BCP} here/afile there;               \
+        ls -lR . >> ../cp_symlink.bb;
+
+       @echo;
+       @echo Will show timestamp difference.
+       -diff -u cp_symlink.gnu cp_symlink.bb;
+
+       @echo;
+       rm -rf cp_tests/*
+
+check_cp_symlink_w_a:
+       @echo; echo Copy a symlink, useing the -a switch.;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file > afile;                   \
+        mkdir here there;                      \
+        cd here;                               \
+         ln -s ../afile .
+
+       cd cp_tests;                            \
+        ls -lR . > ../cp_a_symlink.gnu;        \
+        ${GCP} -a here/afile there;            \
+        ls -lR . >> ../cp_a_symlink.gnu;
+
+       @echo;
+       rm -rf cp_tests/there/*;
+
+       sleep 1;
+
+       @echo;
+       cd cp_tests;                            \
+        echo A file > afile;                   \
+        ls -lR . > ../cp_a_symlink.bb;         \
+        ${BCP} -a here/afile there;            \
+        ls -lR . >> ../cp_a_symlink.bb;
+
+       @echo;
+       diff -u cp_a_symlink.gnu cp_a_symlink.bb;
+
+       @echo;
+       rm -rf cp_tests/*;
+
+
+check_cp_files_to_dir:
+       # Copy a set of files to a directory.
+       @echo; echo Copy a set of files to a directory.;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        ln -s afile1 symlink1;                 \
+        mkdir there;
+
+       cd cp_tests;                            \
+        ${GCP} afile1 afile2 symlink1 there/;  \
+        ls -lR > ../cp_files_dir.gnu;
+
+       @echo;
+       rm -rf cp_tests/there/*;
+
+       @echo;
+       cd cp_tests;                            \
+        ${BCP} afile1 afile2 symlink1 there/;  \
+        ls -lR > ../cp_files_dir.bb;
+
+       @echo;
+       diff -u cp_files_dir.gnu cp_files_dir.bb;
+
+       @echo;
+       rm -rf cp_tests/*;
+
+check_cp_files_to_dir_w_d:
+       # Copy a set of files to a directory with the -d switch.
+       @echo; echo Copy a set of files to a directory with the -d switch.;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${GCP} -d afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_d_files_dir.gnu;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+       @echo;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${BCP} -d afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_d_files_dir.bb;
+
+       @echo;
+       diff -u cp_d_files_dir.gnu cp_d_files_dir.bb;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+check_cp_files_to_dir_w_p:
+       # Copy a set of files to a directory with the -p switch.
+       @echo; echo Copy a set of files to a directory with the -p switch.;
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${GCP} -p afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_p_files_dir.gnu;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+       @echo;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${BCP} -p afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_p_files_dir.bb;
+
+       @echo;
+       diff -u cp_p_files_dir.gnu cp_p_files_dir.bb;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+
+check_cp_files_to_dir_w_p_and_d:
+       @echo; echo Copy a set of files to a directory with -p and -d switches.
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${GCP} -p -d afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_pd_files_dir.gnu;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+       @echo;
+       cd cp_tests;                            \
+        echo A file number one > afile1;       \
+        echo A file number two, blah. > afile2; \
+        touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+        ln -s afile1 symlink1;                 \
+        mkdir there1;                          \
+        ${BCP} -p -d afile1 afile2 symlink1 there1/; \
+        ls -lR > ../cp_pd_files_dir.bb;
+
+       @echo;
+       diff -u cp_pd_files_dir.gnu cp_pd_files_dir.bb;
+
+       @echo;
+       rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+# This test doesn't work any more; gnu cp now _does_ copy a directory
+# to a subdirectory of itself.  What's worse, that "feature" has no
+# (documented) way to be disabled with command line switches.
+# It's not obvious that busybox cp should mimic this behavior.
+# For now, this test is removed from the cp_tests list, above.
+check_cp_dir_to_dir_wo_a:
+       # Copy a directory to another directory, without the -a switch.
+       @echo; echo Copy a directory to another directory, without the -a switch.
+       @echo ------------------------------;
+       @echo There should be an error message about cannot cp a dir to a subdir of itself.
+       cd cp_tests;                            \
+        touch a b c;                           \
+        mkdir adir;                            \
+        ls -lR . > ../cp_a_star_adir.gnu;      \
+        ${GCP} -a * adir;                      \
+        ls -lR . >> ../cp_a_star_adir.gnu;
+
+       @echo
+       @echo There should be an error message about cannot cp a dir to a subdir of itself.
+       cd cp_tests;                            \
+        rm -rf adir;                           \
+        mkdir adir;                            \
+        ls -lR . > ../cp_a_star_adir.bb;       \
+        ${BCP} -a * adir;                      \
+        ls -lR . >> ../cp_a_star_adir.bb;
+
+       @echo;
+       diff -u cp_a_star_adir.gnu cp_a_star_adir.bb;
+
+       # Done
+       @echo;
+       rm -rf cp_tests;
+       @echo; echo Done.
+
+
+check_cp_dir_to_dir_w_a:
+       @echo; echo Copy a directory into another directory with the -a switch.
+       @echo ------------------------------;
+       cd cp_tests;                            \
+        mkdir dir{a,b};                        \
+        echo A file > dira/afile;              \
+        echo A file in dirb > dirb/afileindirb; \
+        ln -s dira/afile dira/alinktoafile;    \
+        mkdir dira/subdir1;                    \
+        echo Another file > dira/subdir1/anotherfile; \
+        ls -lR . > ../cp_a_dira_dirb.gnu;      \
+        ${GCP} -a dira dirb;                   \
+        ls -lR . >> ../cp_a_dira_dirb.gnu;
+
+       @echo;
+       rm -rf cp_tests/dir{a,b};
+
+       @echo;
+       cd cp_tests;                            \
+        mkdir dir{a,b};                        \
+        echo A file > dira/afile;              \
+        echo A file in dirb > dirb/afileindirb; \
+        ln -s dira/afile dira/alinktoafile;    \
+        mkdir dira/subdir1;                    \
+        echo Another file > dira/subdir1/anotherfile; \
+        ls -lR . > ../cp_a_dira_dirb.bb;       \
+        ${BCP} -a dira dirb;                   \
+        ls -lR . >> ../cp_a_dira_dirb.bb;
+
+       @echo;
+       diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb;
+
+       @echo;
+       rm -rf cp_tests/dir{a,b};
+
+
+check_cp_dir_to_dir_w_a_take_two:
+       @echo; echo Copy a directory into another directory with the -a switch;
+       @echo ------------------------------;
+       mkdir -p cp_tests/gnu;                  \
+        mkdir -p cp_tests/bb;                  \
+        cd cp_tests;                           \
+        mkdir here there;                      \
+        echo A file > here/afile;              \
+        mkdir here/adir;                       \
+        touch here/adir/afileinadir;           \
+        ln -s $$(pwd) here/alink;
+
+       @echo;
+       cd cp_tests/gnu;                        \
+        ls -lR . > ../../cp_a_dir_dir.gnu;     \
+        ${GCP} -a here/ there/;                \
+        ls -lR . >> ../../cp_a_dir_dir.gnu;
+
+       @echo;
+       rm -rf cp_tests/there/*;
+
+       sleep 1;
+
+       @echo;
+       cd cp_tests/bb;                         \
+        ls -lR . > ../../cp_a_dir_dir.bb;              \
+        ${BCP} -a here/ there/;                \
+        ls -lR . >> ../../cp_a_dir_dir.bb;
+
+       @echo;
+       echo "Erik 1"
+       diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb;
+       echo "Erik 2"
+
+       @echo;
+       echo "Erik 3"
+       rm -rf cp_tests/*;
+
+
diff --git a/tests/ln_tests.mk b/tests/ln_tests.mk
new file mode 100644 (file)
index 0000000..3110f81
--- /dev/null
@@ -0,0 +1,71 @@
+# ln_tests.mk - Set of tests for busybox ln
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
+
+# GNU `ln'
+GLN = /bin/ln
+# BusyBox `ln'
+BLN = $(shell pwd)/ln
+
+all:: ln_tests
+clean:: ln_clean
+
+ln_clean:
+       rm -rf ln_tests ln_*.{gnu,bb} ln
+
+ln_tests: ln_clean ln
+       @echo;
+       @echo "No output from diff means busybox ln is functioning properly.";
+
+       @echo;
+       ${BLN} || true;
+
+       @echo;
+       mkdir ln_tests;
+
+       @echo;
+       cd ln_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../ln_afile_newname.gnu; \
+        ${GLN} afile newname;                  \
+        ls -l afile newname >> ../ln_afile_newname.gnu;
+
+       @echo;
+       rm -f ln_tests/{afile,newname};
+
+       @echo;
+       cd ln_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../ln_afile_newname.bb;  \
+        ${BLN} afile newname;                  \
+        ls -l afile newname >> ../ln_afile_newname.bb;
+
+       @echo;
+       diff -u ln_afile_newname.gnu ln_afile_newname.bb
+
+       @echo;
+       rm -f ln_tests/{afile,newname};
+
+       @echo;
+       cd ln_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../ln_s_afile_newname.gnu;       \
+        ${GLN} -s afile newname;               \
+        ls -l afile newname >> ../ln_s_afile_newname.gnu;
+
+       @echo;
+       rm -f ln_tests/{afile,newname};
+
+       @echo;
+       cd ln_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../ln_s_afile_newname.bb;        \
+        ${BLN} -s afile newname;               \
+        ls -l afile newname >> ../ln_s_afile_newname.bb;
+
+       @echo;
+       diff -u ln_s_afile_newname.gnu ln_s_afile_newname.bb
+
+       @echo;
+       rm -f ln_tests/{afile,newname};
diff --git a/tests/multibuild.pl b/tests/multibuild.pl
new file mode 100755 (executable)
index 0000000..94930bd
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/perl
+
+# multibuild.pl
+# Tests BusyBox-0.48 (at least) to see if each applet builds
+# properly on its own.  The most likely problems this will
+# flush out are those involving preprocessor instructions in
+# utility.c.
+#
+# TODO: some time it might be nice to list absolute and 
+# differential object sizes for each option...
+#
+
+$logfile = "multibuild.log";
+
+# How to handle all the BB_FEATURE_FOO lines
+if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
+if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
+# neither means, leave that part of Config.h alone
+
+# Support building from pristine source
+$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
+
+# Move the config file to a safe place
+-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
+
+# Clear previous log file, if any
+unlink($logfile);
+
+# Parse the config file
+open(C,"<Config.h.orig") || die;
+while (<C>) {
+       if ($in_trailer) {
+               if (!$in_olympus) {
+                       s/^\/\/#/#/ if ($choice eq "all" && !/USE_DEVPS_PATCH/);
+                       s/^#/\/\/#/ if ($choice eq "none");
+               }
+               $in_olympus=1 if /End of Features List/;
+               $trailer .= $_;
+       } else {
+               $in_trailer=1 if /End of Applications List/;
+               if (/^\/*#define BB_([A-Z0-9_]*)/) {
+                       push @apps, $1;
+               }
+       }
+}
+close C;
+
+# Do the real work ...
+$failed_tests=0;
+for $a (@apps) {
+       # print "Testing build of applet $a ...\n";
+       open (O, ">Config.h") || die;
+       print O "#define BB_$a\n", $trailer;
+       close O;
+       system("echo -e '\n***\n$a\n***' >>$logfile");
+       # With a fast computer and 1-second resolution on file timestamps, this
+       # process pushes beyond the limits of what unix make can understand.
+       # That's why need to weed out obsolete files before restarting make.
+       $result{$a} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1");
+       $flag = $result{$a} ? "FAILED!!!" : "ok";
+       printf("Applet %-20s: %s\n", $a, $flag);
+       $total_tests++;
+       $failed_tests++ if $flag eq "FAILED!!!";
+       # pause long enough to let user stop us with a ^C
+       select(undef, undef, undef, 0.03);
+}
+
+# Clean up our mess
+system("mv -f Config.h.orig Config.h");
+
+print "$total_tests applets tested, $failed_tests failures\n";
+print "See $logfile for details.\n";
+
diff --git a/tests/multifeat.pl b/tests/multifeat.pl
new file mode 100755 (executable)
index 0000000..adcb30b
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+#
+# multifeat.pl
+#
+# Turns on all applets, then tests turning on one feature at a time through
+# iterative compilations. Tests if any features depend on each other in any
+# weird ways or such-like problems.
+#
+# Hacked by Mark Whitley, but based *heavily* on multibuild.pl which was
+# written by Larry Doolittle.
+
+$logfile = "multifeat.log";
+
+# How to handle all the BB_APPLET lines
+# (most thorough testing occurs when you call it with the -all switch)
+if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; }
+if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; }
+# neither means, leave that part of Config.h alone
+
+# Support building from pristine source
+$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne "");
+
+# Move the config file to a safe place
+-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die;
+
+# Clear previous log file, if any
+unlink($logfile);
+
+# Parse the config file
+open(C,"<Config.h.orig") || die;
+$in_applist=1;
+$in_features=0;
+$in_olympus=0;
+while (<C>) {
+       if ($in_applist) {
+               s/^\/\/#/#/ if ($choice eq "all");
+               s/^#/\/\/#/ if ($choice eq "none");
+               $header .= $_;
+               if (/End of Applications List/) {
+                       $in_applist=0;
+                       $in_features=1
+               }
+       }
+       elsif ($in_features) {
+               if (/^\/*#define BB_FEATURE_([A-Z0-9_]*)/) {
+                       push @features, $1;
+               }
+               if (/End of Features List/) {
+                       $in_features=0;
+                       $in_olympus=1
+               }
+       } elsif ($in_olympus) {
+               $trailer .= $_;
+       }
+}
+close C;
+
+# Do the real work ...
+$failed_tests=0;
+for $f (@features) {
+       # print "Testing build with feature $f ...\n";
+       open (O, ">Config.h") || die;
+       print O $header, "#define BB_FEATURE_$f\n", $trailer;
+       close O;
+       system("echo -e '\n***\n$f\n***' >>$logfile");
+       # With a fast computer and 1-second resolution on file timestamps, this
+       # process pushes beyond the limits of what unix make can understand.
+       # That's why need to weed out obsolete files before restarting make.
+       $result{$f} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1");
+       $flag = $result{$f} ? "FAILED!!!" : "ok";
+       printf("Feature %-20s: %s\n", $f, $flag);
+       $total_tests++;
+       $failed_tests++ if $flag eq "FAILED!!!";
+       # pause long enough to let user stop us with a ^C
+       select(undef, undef, undef, 0.03);
+}
+
+# Clean up our mess
+system("mv -f Config.h.orig Config.h");
+
+print "$total_tests applets tested, $failed_tests failures\n";
+print "See $logfile for details.\n";
+
diff --git a/tests/mv_tests.mk b/tests/mv_tests.mk
new file mode 100644 (file)
index 0000000..f03e08a
--- /dev/null
@@ -0,0 +1,167 @@
+# mv_tests.mk - Set of tests cases for busybox mv
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
+
+# GNU `mv'
+GMV = /bin/mv
+# BusyBox `mv'
+BMV = $(shell pwd)/mv
+
+all:: mv_tests
+clean:: mv_clean
+
+mv_clean:
+       rm -rf mv_tests mv_*.{gnu,bb} mv
+
+mv_tests: mv_clean mv
+       @echo;
+       @echo "No output from diff means busybox mv is functioning properly.";
+       @echo;
+       @echo "No such file or directory is good; it means the old file got removed.";
+       @echo;
+       ${BMV} || true;
+
+       @echo;
+       mkdir mv_tests;
+
+       @echo;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../mv_afile_newname.gnu; \
+        ${GMV} afile newname;                  \
+        ls -l newname >> ../mv_afile_newname.gnu;
+       -ls -l mv_tests/afile;
+
+       @echo;
+       rm -f mv_tests/{afile,newname};
+
+       @echo;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ls -l afile > ../mv_afile_newname.bb;  \
+        ${BMV} afile newname;                  \
+        ls -l newname >> ../mv_afile_newname.bb;
+       -ls -l mv_tests/afile;
+
+       @echo;
+       diff -u mv_afile_newname.gnu mv_afile_newname.bb;
+
+       @echo;
+       rm -f mv_tests/{afile,newname};
+
+       @echo; echo ------------------------------;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ln -s afile symlink;                   \
+        ls -l afile symlink > ../mv_symlink_newname.gnu; \
+        ${GMV} symlink newname;                \
+        ls -l afile newname >> ../mv_symlink_newname.gnu;
+       -ls -l mv_tests/symlink;
+
+       @echo;
+       rm -f mv_tests/{afile,newname};
+
+       @echo;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ln -s afile symlink;                   \
+        ls -l afile symlink > ../mv_symlink_newname.bb;\
+        ${BMV} symlink newname;                \
+        ls -l afile newname >> ../mv_symlink_newname.bb;
+       -ls -l mv_tests/symlink;
+
+       @echo;
+       diff -u mv_symlink_newname.gnu mv_symlink_newname.bb;
+
+       @echo;
+       rm -rf mv_tests/*;
+
+       @echo; echo ------------------------------;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ln -s afile symlink;                   \
+        mkdir newdir;                          \
+        ls -lR > ../mv_file_symlink_dir.gnu;   \
+        ${GMV} symlink afile newdir;           \
+        ls -lR >> ../mv_file_symlink_dir.gnu;
+       -ls -l mv_tests/{symlink,afile};
+
+       @echo;
+       rm -rf mv_tests/*
+
+       @echo; echo ------------------------------;
+       cd mv_tests;                            \
+        echo A file > afile;                   \
+        ln -s afile symlink;                   \
+        mkdir newdir;                          \
+        ls -lR > ../mv_file_symlink_dir.bb;    \
+        ${BMV} symlink afile newdir;           \
+        ls -lR >> ../mv_file_symlink_dir.bb;
+       -ls -l mv_tests/{symlink,afile};
+
+       @echo;
+       diff -u mv_file_symlink_dir.gnu mv_file_symlink_dir.bb;
+
+       @echo;
+       rm -rf mv_tests/*;
+
+       @echo; echo ------------------------------;
+       cd mv_tests;                            \
+        mkdir dir{a,b};                        \
+        echo A file > dira/afile;              \
+        echo A file in dirb > dirb/afileindirb; \
+        ln -s dira/afile dira/alinktoafile;    \
+        mkdir dira/subdir1;                    \
+        echo Another file > dira/subdir1/anotherfile; \
+        ls -lR . > ../mv_dira_dirb.gnu;        \
+        ${GMV} dira dirb;                      \
+        ls -lR . >> ../mv_dira_dirb.gnu;
+
+       # false;
+       @echo;
+       rm -rf mv_tests/dir{a,b};
+
+       @echo;
+       cd mv_tests;                            \
+        mkdir dir{a,b};                        \
+        echo A file > dira/afile;              \
+        echo A file in dirb > dirb/afileindirb; \
+        ln -s dira/afile dira/alinktoafile;    \
+        mkdir dira/subdir1;                    \
+        echo Another file > dira/subdir1/anotherfile; \
+        ls -lR . > ../mv_dira_dirb.bb;         \
+        ${BMV} dira dirb;                      \
+        ls -lR . >> ../mv_dira_dirb.bb;
+
+       @echo;
+       diff -u mv_dira_dirb.gnu mv_dira_dirb.bb;
+
+       # false;
+       @echo;
+       rm -rf mv_tests/dir{a,b};
+
+       @echo; echo ------------------------------;
+       @echo There should be an error message about cannot mv a dir to a subdir of itself.
+       cd mv_tests;                            \
+        mkdir adir;                            \
+        touch -r . a b c adir;                 \
+        ls -lR . > ../mv_a_star_adir.gnu;      \
+        ${GMV} * adir;                         \
+        ls -lR . >> ../mv_a_star_adir.gnu;
+
+       @echo
+       @echo There should be an error message about cannot mv a dir to a subdir of itself.
+       cd mv_tests;                            \
+        rm -rf a b c adir;                     \
+        mkdir adir;                            \
+        touch -r . a b c adir;                 \
+        ls -lR . > ../mv_a_star_adir.bb;       \
+        ${BMV} * adir;                 \
+        ls -lR . >> ../mv_a_star_adir.bb;
+
+       @echo;
+       diff -u mv_a_star_adir.gnu mv_a_star_adir.bb;
+
+       @echo;
+       rm -rf mv_test/*;
diff --git a/tests/sh.testcases b/tests/sh.testcases
new file mode 100644 (file)
index 0000000..aa834d4
--- /dev/null
@@ -0,0 +1,89 @@
+# try running this with bash, ksh, ash, and hush.
+
+# simple quoting rules.
+echo a  b
+echo "a  b"
+echo a "" b
+echo a '' b
+echo hello?
+echo "hello?"
+echo t* hello
+echo t\* hello
+
+# quick and painless exit for lash
+if false; then true; exit; fi
+
+# fairly simple command substitution
+echo `echo -e foo\\\necho bar`
+
+echo THIS IS A TEST >foo
+cat $(echo FOO | tr 'A-Z' 'a-z')
+cat foo | tr 'A-Z' 'a-z'
+cat $(echo FOO | tr 'A-Z' 'a-z') | tr 'A-Z' 'a-z'
+
+cat foo | if true;  then tr 'A-Z' 'a-z'; else echo bar1; fi
+cat foo | if false; then tr 'A-Z' 'a-z'; else echo bar2; fi
+if true;  then tr 'A-Z' 'a-z'; else echo bar3; fi <foo
+if false; then tr 'A-Z' 'a-z'; else echo bar4; fi <foo
+if true || false; then echo foo; else echo bar5; fi
+if true && false; then echo bar6; else echo foo; fi
+
+# basic distinction between local and env variables
+unset FOO
+FOO=bar env | grep FOO
+echo "but not here: $FOO"
+FOO=bar
+env | grep FOO
+echo "yes, here: $FOO"
+FOO=
+echo a $FOO b
+echo "a $FOO b"
+
+# not quite so basic variables.  Credit to Matt Kraai.
+unset FOO
+FOO=bar
+export FOO
+env | grep FOO
+unset FOO
+export FOO=bar
+FOO=baz
+env | grep FOO
+
+# interaction between environment variables and if/then and subshells
+FOO=default
+if true; then FOO=new; fi
+echo $FOO
+FOO=default
+(FOO=bogus)
+echo $FOO
+
+# make sure we can duplicate file descriptors properly
+echo replacement >foo 2>&1
+cat foo
+cat doesnt_exist >foo 2>&1
+tr 'a-z' 'A-Z' <foo
+
+# fairly simple example of hush expanding variables too early
+unset TMP
+rm -f fish
+TMP=fish && >$TMP
+ls fish
+
+# ash, lash, and hush do not create wish; bash and ksh do.
+# Thanks to Tapani Tarvainen <tt@mit.jyu.fi> for this stress test.
+unset TMP
+rm -f wish
+TMP=wish >$TMP
+ls wish
+
+# The following example shows that hush's parser is
+# not _really_ Bourne compatible
+echo "echo Hello World" >"a=b"
+unset a
+chmod a+x "a=b"
+PATH=$PATH:.
+"a=b"
+echo $a
+
+# assuming the shell wasn't too buggy, clean up the mess
+rm -f a=b wish fish foo
diff --git a/tests/syslog_test.c b/tests/syslog_test.c
new file mode 100644 (file)
index 0000000..fb4c691
--- /dev/null
@@ -0,0 +1,19 @@
+#include <syslog.h>
+
+int do_log(char* msg, int delay)
+{
+  openlog("testlog", LOG_PID, LOG_DAEMON);
+  while(1) {
+    syslog(LOG_ERR, "%s: testing one, two, three\n", msg);
+    sleep(delay);
+  }
+  closelog();
+  return(0);
+};
+
+int main(void)
+{
+  if (fork()==0)
+    do_log("A", 2);
+  do_log("B", 3);
+}
diff --git a/tests/testcases b/tests/testcases
new file mode 100644 (file)
index 0000000..2aad9b6
--- /dev/null
@@ -0,0 +1,404 @@
+# testcases
+#
+# This file should be filled with test cases to test applets that:
+#
+#  - can somehow produce output (we can't test sync or sleep)
+#  - have a GNU (or other) counterpart
+#  - are not interactive (don't require a ^C or anything)
+#  - don't require extensive setup or cleanup (a litte setup is fine)
+#  - don't have huge and possibly damaging effects (fsck, swapoff)
+#
+# If possible, a test case should be made that tests each option the applet
+# supports. When a new option is added, a new test case should be written for
+# it. When somebody reports a bug with a testcase, that testcase should be
+# added here as well.
+#
+# Some other guidelines to follow:
+#
+#  - please try to keep applets alphabetized, it will make life easier
+#  - use the file tester.sh or testcases when you need to do a non-destructive
+#    test on a file (i.e., cat, md5sum)
+#  - try to make the applet you're testing the first thing on the line (this
+#    not always possible)
+#  - (???) if you have to create a temporary file, call it TMPFILE
+#  - pipe symbols that represent real pipes need a space in front of them
+#     (so the test script can find them and add the "../busybox" after it).
+#  - pipe symbols that are not used for pipes need to be shell-escaped,
+#     with a double \.  See the expr test cases.
+
+
+# ar
+
+# basename
+basename `pwd`
+
+# cat
+cat tester.sh
+echo hello there | cat tester.sh -
+
+# chmod
+# chown
+# chgrp
+# chroot
+# chvt - can't be tested here
+# clear - can't be tested here
+# cmp
+# cp
+
+# cut
+echo "1234" | cut -c1
+echo "1234" | cut -c 1
+echo "1234567890" | cut -c2-7
+echo "1234567890" | cut -c 2-7
+echo "f1       f2" | cut -f2
+echo "f1       f2" | cut -f 2
+echo "f1       f2      f3      f4      f5" | cut -f2-4
+echo "f1       f2      f3      f4      f5" | cut -f 2-4
+
+# date
+date
+date -R
+date -u
+date +%d/%m/%y
+
+# dc - needs an input file
+
+# dd
+# BUG: record count line goes to stdout instead of stderr
+dd if=/dev/urandom of=O bs=1k count=1 ; ls -l O ; rm O
+
+# deallocvt
+
+# df
+# XXX: minor formatting differences
+df
+df .
+df -k
+df -h
+df -m
+
+# dirname
+dirname `pwd`
+
+# dmesg (XXX: change the silly cmd business in the source)
+dmesg
+dmesg -n 8
+dmesg -s 512
+# I really don't want to do this next one
+#dmesg -c
+
+# dos2unix - needs an input file
+# dpkg
+# dpkg_deb
+
+# du
+# BUG: rounding behavior differs from GNU du
+du
+du -s
+du -l
+du -k
+du -h
+du -m
+
+# dumpkmap - no counterprt?
+# dutmp - no counterprt?
+
+# echo
+echo "foo bar baz"
+echo -n "no newline"
+
+
+# expr
+expr 1 \\| 1
+expr 1 \\| 0
+expr 0 \\| 1
+expr 0 \\| 0
+
+expr 1 \\& 1
+expr 1 \\& 0
+expr 0 \\& 1
+expr 0 \\& 0
+
+expr 0 \\< 1
+expr 1 \\< 0
+
+expr 1 \\> 0
+expr 0 \\> 1
+
+expr 0 \\<= 1
+expr 1 \\<= 0
+expr 1 \\<= 1
+
+expr 1 \\>= 0
+expr 0 \\>= 1
+expr 1 \\>= 1
+
+expr 1 + 2
+expr 2 - 1
+expr 2 \\* 3
+expr 12 / 2
+expr 12 % 5
+
+# somebody else can do all the string stuff
+
+
+# fbset - can't be tested here
+# fdflush
+# find
+find .
+
+# free
+# XXX: minor formatting differences
+free
+
+# freeramdisk
+# fsck.minix - won't test
+# getopt
+
+# grep
+grep -l strdup ../*.c
+grep -c strdup ../*.c
+grep -lc strdup ../*.c
+grep -cv strdup ../*.c
+grep -i null ../grep.c
+grep -e strdup -e regcomp -e atexit ../grep.c
+
+# gunzip
+
+# gzip
+# XXX: compressed output differs from gzip-1.2.4, but decompresses fine
+echo testing 1 2 3 >tmpfile1; gzip tmpfile1; echo tmpfile*; md5sum tmpfile1.gz; rm tmpfile1.gz
+echo testing 1 2 3 | gzip >tmpfile1.gz; md5sum tmpfile1.gz; rm tmpfile1.gz
+
+
+# halt - won't test, dangerous
+
+# head
+head tester.sh
+head -n 2 tester.sh
+
+# hostid
+hostid
+
+# hostname
+# XXX: minor formatting differences
+hostname
+hostname -s
+hostname -i
+hostname -d
+# not going to do this next one
+#hostname -F
+
+# id
+# BUG: Busybox id doesn't print supplemental groups
+id
+id -u
+id -g
+id -ur
+id -un
+
+
+# ifconfig
+# requires BB_FEATURE_IFCONFIG_STATUS
+ifconfig
+#ifconfig -a
+#ifconfig eth0
+#ifconfig lo
+
+# init - won't test
+# insmod - won't test
+
+# kill
+#kill -l
+# not going to do any more
+
+# length
+# ln - see ln_tests.mk
+# loadacm
+# loadfont
+# loadkmap
+# logger
+# logname
+
+# ls
+# XXX: minor formatting differences
+ls ../e*
+ls -l ../e*
+ls -s ../e*
+ls -h ../e*
+ls -1 ../e*
+
+# lsmod
+lsmod
+
+# makedevs
+
+# md5sum
+md5sum tester.sh
+
+# mkdir
+mkdir D ; ls -ld D ; rmdir D
+
+# mkfifo
+#
+# we will test making one. actually testing pushing data through it requires
+# more interaction than we can manage here.
+# (these lines turn up an existing ls bug)
+mkfifo F ; ls -l F ; rm F
+mkfifo -m 0600 F ; ls -l F ; rm F
+
+# mkfs.minix - won't test
+# mknod
+# mkswap - won't test
+# mktemp
+# more - can't test: interactive
+
+# mount
+# BUG: proc line starts with /proc instead of proc
+mount
+# not going to test mount with any args, can't be done safely or sanely
+
+# mt
+# mv - see mv_tests.mk
+# nc
+# nfsmount
+# nslookup
+# ping
+ping -c 3 yahoo.com
+# pivot_root
+# poweroff - won't test
+# printf
+# ps - there's lotsa differences between busybox ps and any other ps
+
+# pwd
+pwd
+
+# rdate - won't test
+
+# readlink
+ln -sf tester.sh L ; readlink L ; rm -f L
+
+# reboot - won't test
+# renice - won't test
+# reset - can't test: no output
+
+# rm
+touch F ; rm F
+
+# rmdir
+# rmmod - won't test: dangerous
+
+# route
+# XXX: doesn't DNS resolve
+route
+
+# rpm2cpio
+
+# sed - we can do some one-liners here, some testing is a little
+# difficult to do in just this space (like a,i,c cmds).
+
+# test ^$ matching
+echo foo | sed -ne '/^$/p'
+echo -e "foo\\n\\nbar" | sed -ne '/^$/p'
+
+sed -e '/test$/d' testcases
+sed -e '/^echo/d' testcases
+sed -e '/test/s/dangerous/PELIGROSO/' testcases
+sed -ne '1,/getopt/p' ../pwd.c
+sed -e '/getopt/r ../pwd.c' ../sed.c
+
+
+# setkeycodes
+
+# sh - note that we cannot test the shell interactively here
+sh -c "echo a b c"
+sh -c ">"
+sh -c "a"
+sh sh.testcases
+
+
+# sleep - can't test: produces no output
+
+# sort
+sort tester.sh
+sort -n tester.sh
+sort -r tester.sh
+
+# stty
+# swapon - won't test: dangerous
+# swapoff - won't test: dangerous
+# sync - can't test: no output
+# syslogd - won't test: too involved
+
+# tail
+tail tester.sh
+tail -n 2  tester.sh
+
+# tar
+
+# tee
+echo "please tee me!" | tee A B C ; cat A B C
+echo "please tee me!" | tee A B C ; echo "tee me too!" | tee -a A B C ; cat A B C ; rm A B C
+
+# telnet - can't test: interactive
+
+# test
+# tftp
+
+# touch
+touch tmpfile1; ls tmpfile1; rm -f tmpfile1
+touch -c tmpfile1; ls tmpfile1; rm -f tmpfile1
+
+# tr
+# BUG: Busybox tr range handling minix style [a-z] instead of GNU # style a-z
+echo "cbaab" | tr abc zyx
+echo "TESTING A B C" | tr [A-Z] [a-z]
+# not GNU compatible
+echo fdhrnzvfu bffvsentr | tr [a-z] [n-z][a-m]
+echo abc[] | tr a[b AXB
+echo testing | tr -d aeiou
+
+# true
+true ; echo $?
+
+# false
+false ; echo $?
+
+# tty
+# umount
+# uname
+# uniq
+# unix2dos
+# update
+
+# uptime
+# BUG: doesn't print number of users
+uptime
+
+# usleep
+# uudecode
+# uuencode
+# watchdog
+
+# wc
+wc tester.sh
+wc -c tester.sh
+wc -w tester.sh
+wc -l tester.sh
+wc -L tester.sh
+
+# wget
+
+# which
+which ls
+
+# whoami
+whoami
+
+# xargs
+# XXX: Busygox xargs divides filenames with '\n' instead of ' '
+ls -1 ../e* | xargs
+ls -1 ../e* | xargs md5sum
+
+# yes - can't test: interactive (needs ^C)
+
diff --git a/tests/tester.sh b/tests/tester.sh
new file mode 100755 (executable)
index 0000000..a767c6c
--- /dev/null
@@ -0,0 +1,158 @@
+#!/bin/bash
+#
+# tester.sh - reads testcases from file and tests busybox applets vs GNU
+# counterparts
+#
+# This should be run from within the tests/ directory. Before you run it, you
+# should compile up a busybox that has all applets and all features turned on.
+
+# set up defaults (can be changed with cmd-line options)
+BUSYBOX=../busybox
+TESTCASES=testcases
+LOGFILE=tester.log
+BB_OUT=bb.out
+GNU_OUT=gnu.out
+SETUP=""
+CLEANUP=""
+KEEPTMPFILES="no"
+DEBUG=2
+
+
+#while getopts 'p:t:l:b:g:s:c:kd:' opt
+while getopts 'p:t:l:s:c:kd:' opt
+do
+       case $opt in
+               p) BUSYBOX=$OPTARG; ;;
+               t) TESTCASES=$OPTARG; ;;
+               l) LOGFILE=$OPTARG; ;;
+#              b) BB_OUT=$OPTARG; ;;
+#              g) GNU_OUT=$OPTARG; ;;
+               s) SETUP=$OPTARG; ;;
+               c) CLEANUP=$OPTARG; ;;
+               k) KEEPTMPFILES="yes"; ;;
+               d) DEBUG=$OPTARG; ;;
+               *)
+                       echo "usage: $0 [-ptlbgsc]"
+                       echo "  -p PATH  path to busybox executable (default=$BUSYBOX)"
+                       echo "  -t FILE  run testcases in FILE (default=$TESTCASES)"
+                       echo "  -l FILE  log test results in FILE (default=$LOGFILE)"
+#                      echo "  -b FILE  store temporary busybox output in FILE"
+#                      echo "  -g FILE  store temporary GNU output in FILE"
+                       echo "  -s FILE  (setup) run commands in FILE before testcases"
+                       echo "  -c FILE  (cleanup) run commands in FILE after testcases"
+                       echo "  -k       keep temporary output files (don't delete them)"
+                       echo "  -d NUM   set level of debugging output"
+                       echo "           0 = no output"
+                       echo "           1 = output failures / whoops lines only"
+                       echo "           2 = (default) output setup / cleanup msgs and testcase lines"
+                       echo "           3+= other debug noise (internal stuff)"
+                       exit 1
+                       ;;
+       esac
+done
+#shift `expr $OPTIND - 1`
+
+
+# maybe print some debug output
+if [ $DEBUG -ge 3 ]
+then
+       echo "BUSYBOX=$BUSYBOX"
+       echo "TESTCASES=$TESTCASES"
+       echo "LOGFILE=$LOGFILE"
+       echo "BB_OUT=$BB_OUT"
+       echo "GNU_OUT=$GNU_OUT"
+       echo "SETUP=$SETUP"
+       echo "CLEANUP=$CLEANUP"
+       echo "DEBUG=$DEBUG"
+fi
+
+
+# do sanity checks
+if [ ! -e $BUSYBOX ]
+then
+       echo "Busybox executable: $BUSYBOX not found!"
+       exit 1
+fi
+
+if [ ! -e $TESTCASES ]
+then
+       echo "Testcases file: $TESTCASES not found!"
+       exit 1
+fi
+
+
+# do normal setup
+[ -e $LOGFILE ] && rm $LOGFILE
+unalias -a     # gets rid of aliases that might create different output
+
+
+# do extra setup (if any)
+if [ ! -z "$SETUP" ] 
+then
+       [ $DEBUG -ge 2 ] && echo "running setup commands in $SETUP"
+       source $SETUP
+fi
+
+
+# go through each line in the testcase file
+cat $TESTCASES | while read line
+do
+       #echo $line
+       # only process non-blank lines and non-comment lines
+       if [ "$line" ]
+       then
+               if [ `echo "$line" | cut -c1` != "#" ]
+               then
+
+                       # test if the applet was compiled into busybox
+                       # (this only tests the applet at the beginning of the line)
+                       #applet=`echo $line | cut -d' ' -f1`
+                       applet=`echo $line | sed 's/\(^[^ ;]*\)[ ;].*/\1/'`
+                       $BUSYBOX 2>&1 | grep -qw $applet
+                       if [ $? -eq 1 ]
+                       then
+                               echo "WHOOPS: $applet not compiled into busybox" | tee -a $LOGFILE
+                       else
+
+                               # execute line using gnu / system programs
+                               [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE
+                               sh -c "$line" > $GNU_OUT
+
+                               # change line to include "busybox" before every statement
+                               line="$BUSYBOX $line"
+                               # is this a bash-2-ism?
+                               # line=${line//;/; $BUSYBOX }
+                               # line=${line//|/| $BUSYBOX }
+                               # assume $BUSYBOX has no commas
+                               line=`echo "$line" | sed -e 's,;,; '$BUSYBOX, \
+                                                      -e 's, |, | '$BUSYBOX,`
+
+                               # execute line using busybox programs
+                               [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE
+                               sh -c "$line" > $BB_OUT
+
+                               # see if they match
+                               diff -q $BB_OUT $GNU_OUT > /dev/null
+                               if [ $? -eq 1 ]
+                               then
+                                       [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE
+                                       diff -u $BB_OUT $GNU_OUT >> $LOGFILE 
+                               fi
+                       fi
+               fi
+       fi
+done
+
+[ $DEBUG -gt 0 ] && echo "Finished. Results are in $LOGFILE"
+
+
+# do normal cleanup
+[ "$KEEPTMPFILES" = "no" ] && rm -f $BB_OUT $GNU_OUT
+
+
+# do extra cleanup (if any)
+if [ ! -z "$CLEANUP" ] 
+then
+       [ $DEBUG -ge 2 ] && echo "running cleanup commands in $CLEANUP"
+       source $CLEANUP
+fi
diff --git a/tests/tst-syslogd.c b/tests/tst-syslogd.c
new file mode 100644 (file)
index 0000000..bae10af
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  tst-syslogd.c - tests concurrent threads calling syslog
+ *
+ *  build with: gcc -Wall tst-syslogd.c -lpthread
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <unistd.h>
+
+void *log_func(void *arg)
+{
+       int i;
+       int thrid = (int)arg;
+
+       openlog(NULL, LOG_PERROR | LOG_PID, LOG_USER);
+       for (i = 0; i < 10; i++) {
+               syslog(LOG_DEBUG, "thread %i iter %i\n", thrid, i);
+               sleep(thrid); /* this mixes things up a bit */
+       }
+       closelog();
+
+       return NULL;
+}
+
+int main(int argc, char **argv)
+{
+       pthread_t thr1, thr2, thr3;
+       int id1 = 1;
+       int id2 = 2;
+       int id3 = 3;
+
+       pthread_create(&thr1, NULL, log_func, (void *)id1);
+       pthread_create(&thr2, NULL, log_func, (void *)id2);
+       pthread_create(&thr3, NULL, log_func, (void *)id3);
+
+       pthread_join(thr1, NULL);
+       pthread_join(thr2, NULL);
+       pthread_join(thr3, NULL);
+
+       return 0;
+}
+
diff --git a/tftp.c b/tftp.c
new file mode 100644 (file)
index 0000000..08535a9
--- /dev/null
+++ b/tftp.c
@@ -0,0 +1,589 @@
+/* ------------------------------------------------------------------------- */
+/* tftp.c                                                                    */
+/*                                                                           */
+/* A simple tftp client for busybox.                                         */
+/* Tries to follow RFC1350.                                                  */
+/* Only "octet" mode supported.                                              */
+/* Optional blocksize negotiation (RFC2347 + RFC2348)                        */
+/*                                                                           */
+/* Copyright (C) 2001 Magnus Damm <damm@opensource.se>                       */
+/*                                                                           */
+/* Parts of the code based on:                                               */
+/*                                                                           */
+/* atftp:  Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>   */
+/*                        and Remi Lefebvre <remi@debian.org>                */
+/*                                                                           */
+/* utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>                         */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "busybox.h"
+
+//#define BB_FEATURE_TFTP_GET
+//#define BB_FEATURE_TFTP_PUT
+//#define BB_FEATURE_TFTP_BLOCKSIZE
+//#define BB_FEATURE_TFTP_DEBUG
+
+#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
+#define TFTP_TIMEOUT 5             /* seconds */
+
+/* opcodes we support */
+
+#define TFTP_RRQ   1
+#define TFTP_WRQ   2
+#define TFTP_DATA  3
+#define TFTP_ACK   4
+#define TFTP_ERROR 5
+#define TFTP_OACK  6
+
+static const char *tftp_error_msg[] = {
+       "Undefined error",
+       "File not found",
+       "Access violation",
+       "Disk full or allocation error",
+       "Illegal TFTP operation",
+       "Unknown transfer ID",
+       "File already exists",
+       "No such user"
+};
+
+const int tftp_cmd_get = 1;
+const int tftp_cmd_put = 2;
+
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+
+static int tftp_blocksize_check(int blocksize, int bufsize)  
+{
+        /* Check if the blocksize is valid: 
+        * RFC2348 says between 8 and 65464,
+        * but our implementation makes it impossible
+        * to use blocksizes smaller than 22 octets.
+        */
+
+        if ((bufsize && (blocksize > bufsize)) || 
+           (blocksize < 8) || (blocksize > 65464)) {
+               error_msg("bad blocksize");
+               return 0;
+       }
+
+       return blocksize;
+}
+
+static char *tftp_option_get(char *buf, int len, char *option)  
+{
+        int opt_val = 0;
+       int opt_found = 0;
+       int k;
+  
+       while (len > 0) {
+
+               /* Make sure the options are terminated correctly */
+
+               for (k = 0; k < len; k++) {
+                       if (buf[k] == '\0') {
+                               break;
+                       }
+               }
+
+               if (k >= len) {
+                       break;
+               }
+
+               if (opt_val == 0) {
+                       if (strcasecmp(buf, option) == 0) {
+                               opt_found = 1;
+                       }
+               }      
+               else {
+                       if (opt_found) {
+                               return buf;
+                       }
+               }
+    
+               k++;
+               
+               buf += k;
+               len -= k;
+               
+               opt_val ^= 1;
+       }
+       
+       return NULL;
+}
+
+#endif
+
+static inline int tftp(const int cmd, const struct hostent *host,
+       const char *remotefile, int localfd, const int port, int tftp_bufsize)
+{
+       const int cmd_get = cmd & tftp_cmd_get;
+       const int cmd_put = cmd & tftp_cmd_put;
+       const int bb_tftp_num_retries = 5;
+
+       struct sockaddr_in sa;
+       struct sockaddr_in from;
+       struct timeval tv;
+       socklen_t fromlen;
+       fd_set rfds;
+       char *cp;
+       unsigned short tmp;
+       int socketfd;
+       int len;
+       int opcode = 0;
+       int finished = 0;
+       int timeout = bb_tftp_num_retries;
+       int block_nr = 1;
+
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+       int want_option_ack = 0;
+#endif
+
+       /* Can't use RESERVE_BB_BUFFER here since the allocation
+        * size varies meaning BUFFERS_GO_ON_STACK would fail */
+       char *buf=xmalloc(tftp_bufsize + 4);
+
+       tftp_bufsize += 4;
+
+       if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+               perror_msg("socket");
+               return EXIT_FAILURE;
+       }
+
+       len = sizeof(sa);
+
+       memset(&sa, 0, len);
+       bind(socketfd, (struct sockaddr *)&sa, len);
+
+       sa.sin_family = host->h_addrtype;
+       sa.sin_port = htons(port);
+       memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
+                  sizeof(sa.sin_addr));
+
+       /* build opcode */
+
+       if (cmd_get) {
+               opcode = TFTP_RRQ;
+       }
+
+       if (cmd_put) {
+               opcode = TFTP_WRQ;
+       }
+
+       while (1) {
+
+               cp = buf;
+
+               /* first create the opcode part */
+
+               *((unsigned short *) cp) = htons(opcode);
+
+               cp += 2;
+
+               /* add filename and mode */
+
+               if ((cmd_get && (opcode == TFTP_RRQ)) ||
+                       (cmd_put && (opcode == TFTP_WRQ))) {
+                        int too_long = 0; 
+
+                       /* see if the filename fits into buf */
+                       /* and fill in packet                */
+
+                       len = strlen(remotefile) + 1;
+
+                       if ((cp + len) >= &buf[tftp_bufsize - 1]) {
+                               too_long = 1;
+                       }
+                       else {
+                               safe_strncpy(cp, remotefile, len);
+                               cp += len;
+                       }
+
+                       if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
+                               error_msg("too long remote-filename");
+                               break;
+                       }
+
+                       /* add "mode" part of the package */
+
+                       memcpy(cp, "octet", 6);
+                       cp += 6;
+
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+
+                       len = tftp_bufsize - 4; /* data block size */
+
+                       if (len != TFTP_BLOCKSIZE_DEFAULT) {
+
+                               if ((&buf[tftp_bufsize - 1] - cp) < 15) {
+                                       error_msg("too long remote-filename");
+                                       break;
+                               }
+
+                               /* add "blksize" + number of blocks  */
+
+                               memcpy(cp, "blksize", 8);
+                               cp += 8;
+
+                               cp += snprintf(cp, 6, "%d", len) + 1;
+
+                               want_option_ack = 1;
+                       }
+#endif
+               }
+
+               /* add ack and data */
+
+               if ((cmd_get && (opcode == TFTP_ACK)) ||
+                       (cmd_put && (opcode == TFTP_DATA))) {
+
+                       *((unsigned short *) cp) = htons(block_nr);
+
+                       cp += 2;
+
+                       block_nr++;
+
+                       if (cmd_put && (opcode == TFTP_DATA)) {
+                               len = read(localfd, cp, tftp_bufsize - 4);
+
+                               if (len < 0) {
+                                       perror_msg("read");
+                                       break;
+                               }
+
+                               if (len != (tftp_bufsize - 4)) {
+                                       finished++;
+                               }
+
+                               cp += len;
+                       } else if (finished) {
+                               break;
+                       }
+               }
+
+
+               /* send packet */
+
+
+               do {
+
+                       len = cp - buf;
+
+#ifdef BB_FEATURE_TFTP_DEBUG
+                       printf("sending %u bytes\n", len);
+                       for (cp = buf; cp < &buf[len]; cp++)
+                               printf("%02x ", *cp);
+                       printf("\n");
+#endif
+                       if (sendto(socketfd, buf, len, 0,
+                                       (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+                               perror_msg("send");
+                               len = -1;
+                               break;
+                       }
+
+
+                       /* receive packet */
+
+
+                       memset(&from, 0, sizeof(from));
+                       fromlen = sizeof(from);
+
+                       tv.tv_sec = TFTP_TIMEOUT;
+                       tv.tv_usec = 0;
+
+                       FD_ZERO(&rfds);
+                       FD_SET(socketfd, &rfds);
+
+                       switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
+                       case 1:
+                               len = recvfrom(socketfd, buf, tftp_bufsize, 0,
+                                               (struct sockaddr *) &from, &fromlen);
+
+                               if (len < 0) {
+                                       perror_msg("recvfrom");
+                                       break;
+                               }
+
+                               timeout = 0;
+
+                               if (sa.sin_port == htons(port)) {
+                                       sa.sin_port = from.sin_port;
+                               }
+                               if (sa.sin_port == from.sin_port) {
+                                       break;
+                               }
+
+                               /* fall-through for bad packets! */
+                               /* discard the packet - treat as timeout */
+                               timeout = bb_tftp_num_retries;
+
+                       case 0:
+                               error_msg("timeout");
+
+                               if (timeout == 0) {
+                                       len = -1;
+                                       error_msg("last timeout");
+                               } else {
+                                       timeout--;
+                               }
+                               break;
+
+                       default:
+                               perror_msg("select");
+                               len = -1;
+                       }
+
+               } while (timeout && (len >= 0));
+
+               if (len < 0) {
+                       break;
+               }
+
+               /* process received packet */
+
+
+               opcode = ntohs(*((unsigned short *) buf));
+               tmp = ntohs(*((unsigned short *) &buf[2]));
+
+#ifdef BB_FEATURE_TFTP_DEBUG
+               printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
+#endif
+
+               if (opcode == TFTP_ERROR) {
+                       char *msg = NULL;
+
+                       if (buf[4] != '\0') {
+                               msg = &buf[4];
+                               buf[tftp_bufsize - 1] = '\0';
+                       } else if (tmp < (sizeof(tftp_error_msg) 
+                                         / sizeof(char *))) {
+
+                               msg = (char *) tftp_error_msg[tmp];
+                       }
+
+                       if (msg) {
+                               error_msg("server says: %s", msg);
+                       }
+
+                       break;
+               }
+
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+               if (want_option_ack) {
+
+                        want_option_ack = 0;
+
+                        if (opcode == TFTP_OACK) {
+
+                                /* server seems to support options */
+
+                                char *res;
+
+                                res = tftp_option_get(&buf[2], len-2, 
+                                                      "blksize");
+
+                                if (res) {
+                                        int foo = atoi(res);
+                            
+                                        if (tftp_blocksize_check(foo,
+                                                          tftp_bufsize - 4)) {
+
+                                                if (cmd_put) {
+                                                        opcode = TFTP_DATA;
+                                                }
+                                                else {
+                                                        opcode = TFTP_ACK;
+                                                }
+#ifdef BB_FEATURE_TFTP_DEBUG
+                                                printf("using blksize %u\n");
+#endif
+                                                tftp_bufsize = foo + 4;
+                                                block_nr = 0;
+                                                continue;
+                                        }
+                                }
+                                /* FIXME:
+                                 * we should send ERROR 8 */
+                                error_msg("bad server option");
+                                break;
+                        }
+
+                        error_msg("warning: blksize not supported by server"
+                                  " - reverting to 512");
+
+                        tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
+               }
+#endif
+
+               if (cmd_get && (opcode == TFTP_DATA)) {
+
+                       if (tmp == block_nr) {
+                           
+                               len = write(localfd, &buf[4], len - 4);
+
+                               if (len < 0) {
+                                       perror_msg("write");
+                                       break;
+                               }
+
+                               if (len != (tftp_bufsize - 4)) {
+                                       finished++;
+                               }
+
+                               opcode = TFTP_ACK;
+                               continue;
+                       }
+               }
+
+               if (cmd_put && (opcode == TFTP_ACK)) {
+
+                       if (tmp == (block_nr - 1)) {
+                               if (finished) {
+                                       break;
+                               }
+
+                               opcode = TFTP_DATA;
+                               continue;
+                       }
+               }
+       }
+
+#ifdef BB_FEATURE_CLEAN_UP
+       close(socketfd);
+
+        free(buf);
+#endif
+
+       return finished ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+int tftp_main(int argc, char **argv)
+{
+       struct hostent *host = NULL;
+       char *localfile = NULL;
+       char *remotefile = NULL;
+       int port = 69;
+       int cmd = 0;
+       int fd = -1;
+       int flags = 0;
+       int opt;
+       int result;
+       int blocksize = TFTP_BLOCKSIZE_DEFAULT;
+
+       /* figure out what to pass to getopt */
+
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+#define BS "b:"
+#else
+#define BS
+#endif
+
+#ifdef BB_FEATURE_TFTP_GET
+#define GET "g"
+#else
+#define GET 
+#endif
+
+#ifdef BB_FEATURE_TFTP_PUT
+#define PUT "p"
+#else
+#define PUT 
+#endif
+
+       while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
+               switch (opt) {
+#ifdef BB_FEATURE_TFTP_BLOCKSIZE
+               case 'b':
+                       blocksize = atoi(optarg);
+                       if (!tftp_blocksize_check(blocksize, 0)) {
+                                return EXIT_FAILURE;
+                       }
+                       break;
+#endif
+#ifdef BB_FEATURE_TFTP_GET
+               case 'g':
+                       cmd = tftp_cmd_get;
+                       flags = O_WRONLY | O_CREAT;
+                       break;
+#endif
+#ifdef BB_FEATURE_TFTP_PUT
+               case 'p':
+                       cmd = tftp_cmd_put;
+                       flags = O_RDONLY;
+                       break;
+#endif
+               case 'l': 
+                       localfile = xstrdup(optarg);
+                       break;
+               case 'r':
+                       remotefile = xstrdup(optarg);
+                       break;
+               }
+       }
+
+       if ((cmd == 0) || (optind == argc)) {
+               show_usage();
+       }
+       if(localfile && strcmp(localfile, "-") == 0) {
+           fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
+       }
+       if(localfile == NULL)
+           localfile = remotefile;
+       if(remotefile == NULL)
+           remotefile = localfile;
+       if (fd==-1) {
+           fd = open(localfile, flags, 0644);
+       }
+       if (fd < 0) {
+               perror_msg_and_die("local file");
+       }
+
+       host = xgethostbyname(argv[optind]);
+
+       if (optind + 2 == argc) {
+               port = atoi(argv[optind + 1]);
+       }
+
+#ifdef BB_FEATURE_TFTP_DEBUG
+       printf("using server \"%s\", remotefile \"%s\", "
+               "localfile \"%s\".\n",
+               inet_ntoa(*((struct in_addr *) host->h_addr)),
+               remotefile, localfile);
+#endif
+
+       result = tftp(cmd, host, remotefile, fd, port, blocksize);
+
+#ifdef BB_FEATURE_CLEAN_UP
+       if (!(fd == fileno(stdout) || fd == fileno(stdin))) {
+           close(fd);
+       }
+#endif
+       return(result);
+}
diff --git a/time.c b/time.c
new file mode 100644 (file)
index 0000000..fa352a8
--- /dev/null
+++ b/time.c
@@ -0,0 +1,502 @@
+/* `time' utility to display resource usage of processes.
+   Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* Originally written by David Keppel <pardo@cs.washington.edu>.
+   Heavily modified by David MacKenzie <djm@gnu.ai.mit.edu>.  
+   Heavily modified for busybox by Erik Andersen <andersen@codepoet.org>
+   */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>         /* For pid_t. */
+#include <sys/wait.h>
+#include <sys/param.h>         /* For getpagesize, maybe.  */
+
+#define TV_MSEC tv_usec / 1000
+#include <sys/resource.h>
+#include "busybox.h"
+
+/* Information on the resources used by a child process.  */
+typedef struct
+{
+  int waitstatus;
+  struct rusage ru;
+  struct timeval start, elapsed; /* Wallclock time of process.  */
+} resource_t;
+
+/* msec = milliseconds = 1/1,000 (1*10e-3) second.
+   usec = microseconds = 1/1,000,000 (1*10e-6) second.  */
+
+#ifndef TICKS_PER_SEC
+#define TICKS_PER_SEC 100
+#endif
+
+/* The number of milliseconds in one `tick' used by the `rusage' structure.  */
+#define MSEC_PER_TICK (1000 / TICKS_PER_SEC)
+
+/* Return the number of clock ticks that occur in M milliseconds.  */
+#define MSEC_TO_TICKS(m) ((m) / MSEC_PER_TICK)
+
+#define UL unsigned long
+
+static const char *const default_format = "real\t%E\nuser\t%u\nsys\t%T";
+
+/* The output format for the -p option .*/
+static const char *const posix_format = "real %e\nuser %U\nsys %S";
+
+
+/* Format string for printing all statistics verbosely.
+   Keep this output to 24 lines so users on terminals can see it all.*/
+static const char *const long_format =
+  "\tCommand being timed: \"%C\"\n"
+  "\tUser time (seconds): %U\n"
+  "\tSystem time (seconds): %S\n"
+  "\tPercent of CPU this job got: %P\n"
+  "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n"
+  "\tAverage shared text size (kbytes): %X\n"
+  "\tAverage unshared data size (kbytes): %D\n"
+  "\tAverage stack size (kbytes): %p\n"
+  "\tAverage total size (kbytes): %K\n"
+  "\tMaximum resident set size (kbytes): %M\n"
+  "\tAverage resident set size (kbytes): %t\n"
+  "\tMajor (requiring I/O) page faults: %F\n"
+  "\tMinor (reclaiming a frame) page faults: %R\n"
+  "\tVoluntary context switches: %w\n"
+  "\tInvoluntary context switches: %c\n"
+  "\tSwaps: %W\n"
+  "\tFile system inputs: %I\n"
+  "\tFile system outputs: %O\n"
+  "\tSocket messages sent: %s\n"
+  "\tSocket messages received: %r\n"
+  "\tSignals delivered: %k\n"
+  "\tPage size (bytes): %Z\n"
+  "\tExit status: %x";
+
+
+  /* Wait for and fill in data on child process PID.
+   Return 0 on error, 1 if ok.  */
+
+/* pid_t is short on BSDI, so don't try to promote it.  */
+static int resuse_end (pid_t pid, resource_t *resp)
+{
+    int status;
+
+    pid_t caught;
+
+    /* Ignore signals, but don't ignore the children.  When wait3
+       returns the child process, set the time the command finished. */
+    while ((caught = wait3 (&status, 0, &resp->ru)) != pid)
+    {
+       if (caught == -1)
+           return 0;
+    }
+
+    gettimeofday (&resp->elapsed, (struct timezone *) 0);
+    resp->elapsed.tv_sec -= resp->start.tv_sec;
+    if (resp->elapsed.tv_usec < resp->start.tv_usec)
+    {
+       /* Manually carry a one from the seconds field.  */
+       resp->elapsed.tv_usec += 1000000;
+       --resp->elapsed.tv_sec;
+    }
+    resp->elapsed.tv_usec -= resp->start.tv_usec;
+
+    resp->waitstatus = status;
+
+    return 1;
+}
+
+/* Print ARGV to FP, with each entry in ARGV separated by FILLER.  */
+static void fprintargv (FILE *fp, char *const *argv, const char *filler)
+{
+    char *const *av;
+
+    av = argv;
+    fputs (*av, fp);
+    while (*++av)
+    {
+       fputs (filler, fp);
+       fputs (*av, fp);
+    }
+    if (ferror (fp))
+       error_msg_and_die("write error");
+}
+
+/* Return the number of kilobytes corresponding to a number of pages PAGES.
+   (Actually, we use it to convert pages*ticks into kilobytes*ticks.)
+
+   Try to do arithmetic so that the risk of overflow errors is minimized.
+   This is funky since the pagesize could be less than 1K.
+   Note: Some machines express getrusage statistics in terms of K,
+   others in terms of pages.  */
+
+static unsigned long ptok (unsigned long pages)
+{
+    static unsigned long ps = 0;
+    unsigned long tmp;
+    static long size = LONG_MAX;
+
+    /* Initialization.  */
+    if (ps == 0)
+       ps = (long) getpagesize ();
+
+    /* Conversion.  */
+    if (pages > (LONG_MAX / ps))
+    {                          /* Could overflow.  */
+       tmp = pages / 1024;     /* Smaller first, */
+       size = tmp * ps;                /* then larger.  */
+    }
+    else
+    {                          /* Could underflow.  */
+       tmp = pages * ps;               /* Larger first, */
+       size = tmp / 1024;      /* then smaller.  */
+    }
+    return size;
+}
+
+/* summarize: Report on the system use of a command.
+
+   Copy the FMT argument to FP except that `%' sequences
+   have special meaning, and `\n' and `\t' are translated into
+   newline and tab, respectively, and `\\' is translated into `\'.
+
+   The character following a `%' can be:
+   (* means the tcsh time builtin also recognizes it)
+   % == a literal `%'
+   C == command name and arguments
+*  D == average unshared data size in K (ru_idrss+ru_isrss)
+*  E == elapsed real (wall clock) time in [hour:]min:sec
+*  F == major page faults (required physical I/O) (ru_majflt)
+*  I == file system inputs (ru_inblock)
+*  K == average total mem usage (ru_idrss+ru_isrss+ru_ixrss)
+*  M == maximum resident set size in K (ru_maxrss)
+*  O == file system outputs (ru_oublock)
+*  P == percent of CPU this job got (total cpu time / elapsed time)
+*  R == minor page faults (reclaims; no physical I/O involved) (ru_minflt)
+*  S == system (kernel) time (seconds) (ru_stime)
+*  T == system time in [hour:]min:sec
+*  U == user time (seconds) (ru_utime)
+*  u == user time in [hour:]min:sec
+*  W == times swapped out (ru_nswap)
+*  X == average amount of shared text in K (ru_ixrss)
+   Z == page size
+*  c == involuntary context switches (ru_nivcsw)
+   e == elapsed real time in seconds
+*  k == signals delivered (ru_nsignals)
+   p == average unshared stack size in K (ru_isrss)
+*  r == socket messages received (ru_msgrcv)
+*  s == socket messages sent (ru_msgsnd)
+   t == average resident set size in K (ru_idrss)
+*  w == voluntary context switches (ru_nvcsw)
+   x == exit status of command
+
+   Various memory usages are found by converting from page-seconds
+   to kbytes by multiplying by the page size, dividing by 1024,
+   and dividing by elapsed real time.
+
+   FP is the stream to print to.
+   FMT is the format string, interpreted as described above.
+   COMMAND is the command and args that are being summarized.
+   RESP is resource information on the command.  */
+
+static void summarize (FILE *fp, const char *fmt, char **command, resource_t *resp)
+{
+    unsigned long r;           /* Elapsed real milliseconds.  */
+    unsigned long v;           /* Elapsed virtual (CPU) milliseconds.  */
+
+    if (WIFSTOPPED (resp->waitstatus))
+       fprintf (fp, "Command stopped by signal %d\n", WSTOPSIG (resp->waitstatus));
+    else if (WIFSIGNALED (resp->waitstatus))
+       fprintf (fp, "Command terminated by signal %d\n", WTERMSIG (resp->waitstatus));
+    else if (WIFEXITED (resp->waitstatus) && WEXITSTATUS (resp->waitstatus))
+       fprintf (fp, "Command exited with non-zero status %d\n", WEXITSTATUS (resp->waitstatus));
+
+    /* Convert all times to milliseconds.  Occasionally, one of these values
+       comes out as zero.  Dividing by zero causes problems, so we first
+       check the time value.  If it is zero, then we take `evasive action'
+       instead of calculating a value.  */
+
+    r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;
+
+    v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
+       resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
+
+    while (*fmt)
+    {
+       switch (*fmt)
+       {
+           case '%':
+               switch (*++fmt)
+               {
+                   case '%':           /* Literal '%'.  */
+                       putc ('%', fp);
+                       break;
+                   case 'C':           /* The command that got timed.  */
+                       fprintargv (fp, command, " ");
+                       break;
+                   case 'D':           /* Average unshared data size.  */
+                       fprintf (fp, "%lu",
+                               MSEC_TO_TICKS (v) == 0 ? 0 :
+                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
+                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
+                       break;
+                   case 'E':           /* Elapsed real (wall clock) time.  */
+                       if (resp->elapsed.tv_sec >= 3600)       /* One hour -> h:m:s.  */
+                           fprintf (fp, "%ldh %ldm %02lds",
+                                   resp->elapsed.tv_sec / 3600,
+                                   (resp->elapsed.tv_sec % 3600) / 60,
+                                   resp->elapsed.tv_sec % 60);
+                       else
+                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
+                                   resp->elapsed.tv_sec / 60,
+                                   resp->elapsed.tv_sec % 60,
+                                   resp->elapsed.tv_usec / 10000);
+                       break;
+                   case 'F':           /* Major page faults.  */
+                       fprintf (fp, "%ld", resp->ru.ru_majflt);
+                       break;
+                   case 'I':           /* Inputs.  */
+                       fprintf (fp, "%ld", resp->ru.ru_inblock);
+                       break;
+                   case 'K':           /* Average mem usage == data+stack+text.  */
+                       fprintf (fp, "%lu",
+                               MSEC_TO_TICKS (v) == 0 ? 0 :
+                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) +
+                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v) +
+                               ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
+                       break;
+                   case 'M':           /* Maximum resident set size.  */
+                       fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss));
+                       break;
+                   case 'O':           /* Outputs.  */
+                       fprintf (fp, "%ld", resp->ru.ru_oublock);
+                       break;
+                   case 'P':           /* Percent of CPU this job got.  */
+                       /* % cpu is (total cpu time)/(elapsed time).  */
+                       if (r > 0)
+                           fprintf (fp, "%lu%%", (v * 100 / r));
+                       else
+                           fprintf (fp, "?%%");
+                       break;
+                   case 'R':           /* Minor page faults (reclaims).  */
+                       fprintf (fp, "%ld", resp->ru.ru_minflt);
+                       break;
+                   case 'S':           /* System time.  */
+                       fprintf (fp, "%ld.%02ld",
+                               resp->ru.ru_stime.tv_sec,
+                               resp->ru.ru_stime.TV_MSEC / 10);
+                       break;
+                   case 'T':           /* System time.  */
+                       if (resp->ru.ru_stime.tv_sec >= 3600)   /* One hour -> h:m:s.  */
+                           fprintf (fp, "%ldh %ldm %02lds",
+                                   resp->ru.ru_stime.tv_sec / 3600,
+                                   (resp->ru.ru_stime.tv_sec % 3600) / 60,
+                                   resp->ru.ru_stime.tv_sec % 60);
+                       else
+                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
+                                   resp->ru.ru_stime.tv_sec / 60,
+                                   resp->ru.ru_stime.tv_sec % 60,
+                                   resp->ru.ru_stime.tv_usec / 10000);
+                       break;
+                   case 'U':           /* User time.  */
+                       fprintf (fp, "%ld.%02ld",
+                               resp->ru.ru_utime.tv_sec,
+                               resp->ru.ru_utime.TV_MSEC / 10);
+                       break;
+                   case 'u':           /* User time.  */
+                       if (resp->ru.ru_utime.tv_sec >= 3600)   /* One hour -> h:m:s.  */
+                           fprintf (fp, "%ldh %ldm %02lds",
+                                   resp->ru.ru_utime.tv_sec / 3600,
+                                   (resp->ru.ru_utime.tv_sec % 3600) / 60,
+                                   resp->ru.ru_utime.tv_sec % 60);
+                       else
+                           fprintf (fp, "%ldm %ld.%02lds",     /* -> m:s.  */
+                                   resp->ru.ru_utime.tv_sec / 60,
+                                   resp->ru.ru_utime.tv_sec % 60,
+                                   resp->ru.ru_utime.tv_usec / 10000);
+                       break;
+                   case 'W':           /* Times swapped out.  */
+                       fprintf (fp, "%ld", resp->ru.ru_nswap);
+                       break;
+                   case 'X':           /* Average shared text size.  */
+                       fprintf (fp, "%lu",
+                               MSEC_TO_TICKS (v) == 0 ? 0 :
+                               ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v));
+                       break;
+                   case 'Z':           /* Page size.  */
+                       fprintf (fp, "%d", getpagesize ());
+                       break;
+                   case 'c':           /* Involuntary context switches.  */
+                       fprintf (fp, "%ld", resp->ru.ru_nivcsw);
+                       break;
+                   case 'e':           /* Elapsed real time in seconds.  */
+                       fprintf (fp, "%ld.%02ld",
+                               resp->elapsed.tv_sec,
+                               resp->elapsed.tv_usec / 10000);
+                       break;
+                   case 'k':           /* Signals delivered.  */
+                       fprintf (fp, "%ld", resp->ru.ru_nsignals);
+                       break;
+                   case 'p':           /* Average stack segment.  */
+                       fprintf (fp, "%lu",
+                               MSEC_TO_TICKS (v) == 0 ? 0 :
+                               ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v));
+                       break;
+                   case 'r':           /* Incoming socket messages received.  */
+                       fprintf (fp, "%ld", resp->ru.ru_msgrcv);
+                       break;
+                   case 's':           /* Outgoing socket messages sent.  */
+                       fprintf (fp, "%ld", resp->ru.ru_msgsnd);
+                       break;
+                   case 't':           /* Average resident set size.  */
+                       fprintf (fp, "%lu",
+                               MSEC_TO_TICKS (v) == 0 ? 0 :
+                               ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v));
+                       break;
+                   case 'w':           /* Voluntary context switches.  */
+                       fprintf (fp, "%ld", resp->ru.ru_nvcsw);
+                       break;
+                   case 'x':           /* Exit status.  */
+                       fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus));
+                       break;
+                   case '\0':
+                       putc ('?', fp);
+                       return;
+                   default:
+                       putc ('?', fp);
+                       putc (*fmt, fp);
+               }
+               ++fmt;
+               break;
+
+           case '\\':          /* Format escape.  */
+               switch (*++fmt)
+               {
+                   case 't':
+                       putc ('\t', fp);
+                       break;
+                   case 'n':
+                       putc ('\n', fp);
+                       break;
+                   case '\\':
+                       putc ('\\', fp);
+                       break;
+                   default:
+                       putc ('?', fp);
+                       putc ('\\', fp);
+                       putc (*fmt, fp);
+               }
+               ++fmt;
+               break;
+
+           default:
+               putc (*fmt++, fp);
+       }
+
+       if (ferror (fp))
+           error_msg_and_die("write error");
+    }
+    putc ('\n', fp);
+
+    if (ferror (fp))
+       error_msg_and_die("write error");
+}
+
+/* Run command CMD and return statistics on it.
+   Put the statistics in *RESP.  */
+static void run_command (char *const *cmd, resource_t *resp)
+{
+    pid_t pid;                 /* Pid of child.  */
+    __sighandler_t interrupt_signal, quit_signal;
+
+    gettimeofday (&resp->start, (struct timezone *) 0);
+    pid = fork ();             /* Run CMD as child process.  */
+    if (pid < 0)
+       error_msg_and_die("cannot fork");
+    else if (pid == 0)
+    {                          /* If child.  */
+       /* Don't cast execvp arguments; that causes errors on some systems,
+          versus merely warnings if the cast is left off.  */
+       execvp (cmd[0], cmd);
+       error_msg("cannot run %s", cmd[0]);
+       _exit (errno == ENOENT ? 127 : 126);
+    }
+
+    /* Have signals kill the child but not self (if possible).  */
+    interrupt_signal = signal (SIGINT, SIG_IGN);
+    quit_signal = signal (SIGQUIT, SIG_IGN);
+
+    if (resuse_end (pid, resp) == 0)
+       error_msg("error waiting for child process");
+
+    /* Re-enable signals.  */
+    signal (SIGINT, interrupt_signal);
+    signal (SIGQUIT, quit_signal);
+}
+
+extern int time_main (int argc, char **argv)
+{
+    int gotone;
+    resource_t res;
+    const char *output_format = default_format;
+
+    argc--;
+    argv++;
+    /* Parse any options  -- don't use getopt() here so we don't
+     * consume the args of our client application... */
+    while (argc > 0 && **argv == '-') {
+       gotone = 0;
+       while (gotone==0 && *++(*argv)) {
+           switch (**argv) {
+               case 'v':
+                   output_format = long_format;
+                   break;
+               case 'p':
+                   output_format = posix_format;
+                   break;
+               default:
+                   show_usage();
+           }
+           argc--;
+           argv++;
+           gotone = 1;
+       }
+    }
+
+    if (argv == NULL || *argv == NULL)
+       show_usage();
+
+    run_command (argv, &res);
+    summarize (stdout, output_format, argv, &res);
+    fflush (stdout);
+
+    if (WIFSTOPPED (res.waitstatus))
+       exit (WSTOPSIG (res.waitstatus));
+    else if (WIFSIGNALED (res.waitstatus))
+       exit (WTERMSIG (res.waitstatus));
+    else if (WIFEXITED (res.waitstatus))
+       exit (WEXITSTATUS (res.waitstatus));
+    return 0;
+}
diff --git a/top.c b/top.c
new file mode 100644 (file)
index 0000000..e992d23
--- /dev/null
+++ b/top.c
@@ -0,0 +1,739 @@
+/*
+ * A tiny 'top' utility.
+ *
+ * This is written specifically for the linux /proc/<PID>/stat(m)
+ * files format.
+
+ * This reads the PIDs of all processes and their status and shows
+ * the status of processes (first ones that fit to screen) at given
+ * intervals.
+ * 
+ * NOTES:
+ * - At startup this changes to /proc, all the reads are then
+ *   relative to that.
+ * 
+ * (C) Eero Tamminen <oak at welho dot com>
+ *
+ * Rewroted by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
+ */
+
+/* Original code Copyrights */
+/*
+ * Copyright (c) 1992 Branko Lankester
+ * Copyright (c) 1992 Roger Binns
+ * Copyright (C) 1994-1996 Charles L. Blake.
+ * Copyright (C) 1992-1998 Michael K. Johnson
+ * May be distributed under the conditions of the
+ * GNU Library General Public License
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+/* get page info */
+#include <asm/page.h>
+#include "busybox.h"
+
+#define FEATURE_CPU_USAGE_PERCENTAGE  /* + 2k */
+
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+#include <time.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <netinet/in.h>  /* htons */
+#endif
+
+
+typedef struct {
+       int pid;
+       char user[9];
+       char state[4];
+       unsigned long rss;
+       int ppid;
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       unsigned pcpu;
+       unsigned long stime, utime;
+#endif
+       char *cmd;
+
+       /* basename of executable file in call to exec(2),
+               size from kernel headers */
+       char short_cmd[16];
+} status_t;
+
+typedef int (*cmp_t)(status_t *P, status_t *Q);
+
+static status_t *top;   /* Hehe */
+static int ntop;
+
+
+static int pid_sort (status_t *P, status_t *Q)
+{
+    int p = P->pid;
+    int q = Q->pid;
+
+    if( p < q ) return -1;
+    if( p > q ) return  1;
+    return 0;
+}
+
+static int mem_sort (status_t *P, status_t *Q)
+{
+    long p = P->rss;
+    long q = Q->rss;
+
+    if( p > q ) return -1;
+    if( p < q ) return  1;
+    return 0;
+}
+
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+
+#define sort_depth 3
+static cmp_t sort_function[sort_depth];
+
+static int pcpu_sort (status_t *P, status_t *Q)
+{
+    int p = P->pcpu;
+    int q = Q->pcpu;
+
+    if( p > q ) return -1;
+    if( p < q ) return  1;
+    return 0;
+}
+
+static int time_sort (status_t *P, status_t *Q)
+{
+    long p = P->stime;
+    long q = Q->stime;
+
+    p += P->utime;
+    q += Q->utime;
+    if( p > q ) return -1;
+    if( p < q ) return  1;
+    return 0;
+}
+
+int mult_lvl_cmp(void* a, void* b) {
+    int i, cmp_val;
+
+    for(i = 0; i < sort_depth; i++) {
+       cmp_val = (*sort_function[i])(a, b);
+       if (cmp_val != 0)
+           return cmp_val;
+    }
+    return 0;
+}
+
+/* This structure stores some critical information from one frame to
+   the next. mostly used for sorting. Added cumulative and resident fields. */
+struct save_hist {
+    int ticks;
+    int pid;
+    int utime;
+    int stime;
+};
+
+/*
+ * Calculates percent cpu usage for each task.
+ */
+
+static struct save_hist *save_history;
+
+static unsigned long Hertz;
+
+/***********************************************************************
+ * Some values in /proc are expressed in units of 1/HZ seconds, where HZ
+ * is the kernel clock tick rate. One of these units is called a jiffy.
+ * The HZ value used in the kernel may vary according to hacker desire.
+ * According to Linus Torvalds, this is not true. He considers the values
+ * in /proc as being in architecture-dependant units that have no relation
+ * to the kernel clock tick rate. Examination of the kernel source code
+ * reveals that opinion as wishful thinking.
+ *
+ * In any case, we need the HZ constant as used in /proc. (the real HZ value
+ * may differ, but we don't care) There are several ways we could get HZ:
+ *
+ * 1. Include the kernel header file. If it changes, recompile this library.
+ * 2. Use the sysconf() function. When HZ changes, recompile the C library!
+ * 3. Ask the kernel. This is obviously correct...
+ *
+ * Linus Torvalds won't let us ask the kernel, because he thinks we should
+ * not know the HZ value. Oh well, we don't have to listen to him.
+ * Someone smuggled out the HZ value. :-)
+ *
+ * This code should work fine, even if Linus fixes the kernel to match his
+ * stated behavior. The code only fails in case of a partial conversion.
+ *
+ */
+
+#define FILE_TO_BUF(filename, fd) do{                           \
+    if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) {    \
+       perror_msg_and_die("/proc not be mounted?");            \
+    }                                                           \
+    lseek(fd, 0L, SEEK_SET);                                    \
+    if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) {        \
+       perror_msg_and_die("%s", filename);                     \
+    }                                                           \
+    buf[local_n] = '\0';                                        \
+}while(0)
+
+#define FILE_TO_BUF2(filename, fd) do{                          \
+    lseek(fd, 0L, SEEK_SET);                                    \
+    if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) {        \
+       perror_msg_and_die("%s", filename);                     \
+    }                                                           \
+    buf[local_n] = '\0';                                        \
+}while(0)
+
+static void init_Hertz_value(void) {
+  unsigned long user_j, nice_j, sys_j, other_j;  /* jiffies (clock ticks) */
+  double up_1, up_2, seconds;
+  unsigned long jiffies, h;
+  char buf[80];
+  int uptime_fd = -1;
+  int stat_fd = -1;
+
+  long smp_num_cpus = sysconf(_SC_NPROCESSORS_CONF);
+
+  if(smp_num_cpus<1) smp_num_cpus=1;
+  do {
+    int local_n;
+
+    FILE_TO_BUF("uptime", uptime_fd);
+    up_1 = strtod(buf, 0);
+    FILE_TO_BUF("stat", stat_fd);
+    sscanf(buf, "cpu %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &other_j);
+    FILE_TO_BUF2("uptime", uptime_fd);
+    up_2 = strtod(buf, 0);
+  } while((long)( (up_2-up_1)*1000.0/up_1 )); /* want under 0.1% error */
+
+  close(uptime_fd);
+  close(stat_fd);
+
+  jiffies = user_j + nice_j + sys_j + other_j;
+  seconds = (up_1 + up_2) / 2;
+  h = (unsigned long)( (double)jiffies/seconds/smp_num_cpus );
+  /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
+  switch(h){
+  case   30 ...   34 :  Hertz =   32; break; /* ia64 emulator */
+  case   48 ...   52 :  Hertz =   50; break;
+  case   58 ...   62 :  Hertz =   60; break;
+  case   63 ...   65 :  Hertz =   64; break; /* StrongARM /Shark */
+  case   95 ...  105 :  Hertz =  100; break; /* normal Linux */
+  case  124 ...  132 :  Hertz =  128; break; /* MIPS, ARM */
+  case  195 ...  204 :  Hertz =  200; break; /* normal << 1 */
+  case  253 ...  260 :  Hertz =  256; break;
+  case  295 ...  304 :  Hertz =  300; break; /* 3 cpus */
+  case  393 ...  408 :  Hertz =  400; break; /* normal << 2 */
+  case  495 ...  504 :  Hertz =  500; break; /* 5 cpus */
+  case  595 ...  604 :  Hertz =  600; break; /* 6 cpus */
+  case  695 ...  704 :  Hertz =  700; break; /* 7 cpus */
+  case  790 ...  808 :  Hertz =  800; break; /* normal << 3 */
+  case  895 ...  904 :  Hertz =  900; break; /* 9 cpus */
+  case  990 ... 1010 :  Hertz = 1000; break; /* ARM */
+  case 1015 ... 1035 :  Hertz = 1024; break; /* Alpha, ia64 */
+  case 1095 ... 1104 :  Hertz = 1100; break; /* 11 cpus */
+  case 1180 ... 1220 :  Hertz = 1200; break; /* Alpha */
+  default:
+    /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
+    Hertz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
+  }
+}
+
+static void do_stats(void)
+{
+    struct timeval t;
+    static struct timeval oldtime;
+    struct timezone timez;
+    float elapsed_time;
+
+    status_t *cur;
+    int total_time, i, n;
+    static int prev_count;
+    int systime, usrtime, pid;
+
+    struct save_hist *New_save_hist;
+
+    /*
+     * Finds the current time (in microseconds) and calculates the time
+     * elapsed since the last update.
+     */
+    gettimeofday(&t, &timez);
+    elapsed_time = (t.tv_sec - oldtime.tv_sec)
+       + (float) (t.tv_usec - oldtime.tv_usec) / 1000000.0;
+    oldtime.tv_sec  = t.tv_sec;
+    oldtime.tv_usec = t.tv_usec;
+
+    New_save_hist  = alloca(sizeof(struct save_hist)*ntop);
+    /*
+     * Make a pass through the data to get stats.
+     */
+    for(n = 0; n < ntop; n++) {
+       cur = top + n;
+
+       /*
+        * Calculate time in cur process.  Time is sum of user time
+        * (usrtime) plus system time (systime).
+        */
+       systime = cur->stime;
+       usrtime = cur->utime;
+       pid = cur->pid;
+       total_time = systime + usrtime;
+       New_save_hist[n].ticks = total_time;
+       New_save_hist[n].pid = pid;
+       New_save_hist[n].stime = systime;
+       New_save_hist[n].utime = usrtime;
+
+       /* find matching entry from previous pass */
+       for (i = 0; i < prev_count; i++) {
+           if (save_history[i].pid == pid) {
+               total_time -= save_history[i].ticks;
+               systime -= save_history[i].stime;
+               usrtime -= save_history[i].utime;
+               break;
+           }
+       }
+
+       /*
+        * Calculate percent cpu time for cur task.
+        */
+       i = (total_time * 10 * 100/Hertz) / elapsed_time;
+       if (i > 999)
+           i = 999;
+       cur->pcpu = i;
+
+    }
+
+    /*
+     * Save cur frame's information.
+     */
+    free(save_history);
+    save_history = memcpy(xmalloc(sizeof(struct save_hist)*n), New_save_hist,
+                                               sizeof(struct save_hist)*n);
+    prev_count = n;
+    qsort(top, n, sizeof(status_t), (void*)mult_lvl_cmp);
+}
+#else
+static cmp_t sort_function;
+#endif /* FEATURE_CPU_USAGE_PERCENTAGE */
+
+/* display generic info (meminfo / loadavg) */
+static unsigned long display_generic(void)
+{
+       FILE *fp;
+       char buf[80];
+       float avg1, avg2, avg3;
+       unsigned long total, used, mfree, shared, buffers, cached;
+       unsigned int needs_conversion = 1;
+
+       /* read memory info */
+       fp = xfopen("meminfo", "r");
+
+       /*
+        * Old kernels (such as 2.4.x) had a nice summary of memory info that
+        * we could parse, however this is gone entirely in 2.6. Try parsing
+        * the old way first, and if that fails, parse each field manually.
+        *
+        * First, we read in the first line. Old kernels will have bogus
+        * strings we don't care about, whereas new kernels will start right
+        * out with MemTotal:
+        *                              -- PFM.
+        */
+       if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
+               fgets(buf, sizeof(buf), fp);    /* skip first line */
+
+               fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
+                  &total, &used, &mfree, &shared, &buffers, &cached);
+       } else {
+               /* 
+                * Revert to manual parsing, which incidentally already has the
+                * sizes in kilobytes. This should be safe for both 2.4 and
+                * 2.6.
+                */
+               needs_conversion = 0;
+
+               fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
+
+               /* 
+                * MemShared: is no longer present in 2.6. Report this as 0,
+                * to maintain consistent behavior with normal procps.
+                */
+               if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
+                       shared = 0;
+
+               fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
+               fscanf(fp, "Cached: %lu %s\n", &cached, buf);
+
+               used = total - mfree;
+       }
+       fclose(fp);
+       
+       /* read load average */
+       fp = xfopen("loadavg", "r");
+       if (fscanf(fp, "%f %f %f", &avg1, &avg2, &avg3) != 3) {
+               error_msg_and_die("failed to read '%s'", "loadavg");
+       }
+       fclose(fp);
+
+       if (needs_conversion) {
+               /* convert to kilobytes */
+               used /= 1024;
+               mfree /= 1024;
+               shared /= 1024;
+               buffers /= 1024;
+               cached /= 1024;
+               total /= 1024;
+       }
+               
+       /* output memory info and load average */
+       /* clear screen & go to top */
+       printf("\e[H\e[J" "Mem: "
+              "%ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached\n",
+              used, mfree, shared, buffers, cached);
+       printf("Load average: %.2f, %.2f, %.2f    "
+                       "(State: S=sleeping R=running, W=waiting)\n",
+              avg1, avg2, avg3);
+       return total;
+}
+
+
+/* display process statuses */
+static void display_status(int count, int col)
+{
+       status_t *s = top;
+       char rss_str_buf[8];
+       unsigned long total_memory = display_generic();
+       
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       /* what info of the processes is shown */
+       printf("\n\e[7m  PID USER     STATUS   RSS  PPID %%CPU %%MEM COMMAND\e[0m\n");
+#else
+       printf("\n\e[7m  PID USER     STATUS   RSS  PPID %%MEM COMMAND\e[0m\n");
+#endif
+
+       while (count--) {
+               char *namecmd = s->cmd;
+               int pmem;
+
+               pmem = 1000.0 * s->rss / total_memory;
+               if (pmem > 999) pmem = 999;
+       
+               if(s->rss > 10*1024)
+                       sprintf(rss_str_buf, "%6ldM", s->rss/1024);
+               else
+                       sprintf(rss_str_buf, "%7ld", s->rss);
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+               printf("%5d %-8s %s  %s %5d %2d.%d %2u.%u ",
+#else
+               printf("%5d %-8s %s  %s %5d %2u.%u ",
+#endif
+                       s->pid, s->user, s->state, rss_str_buf, s->ppid,
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+                       s->pcpu/10, s->pcpu%10,
+#endif
+                       pmem/10, pmem%10);
+               if(namecmd != 0 && namecmd[0] != 0) {
+                       if(strlen(namecmd) > col)
+                               namecmd[col] = 0;
+                       printf("%s\n", namecmd);
+                       } else {
+                       namecmd = s->short_cmd;
+                       if(strlen(namecmd) > (col-2))
+                               namecmd[col-2] = 0;
+                       printf("[%s]\n", namecmd);
+                       }
+               s++;
+               }
+}
+
+/* returns true for file names which are PID dirs
+ * (i.e. start with number)
+ */
+static int filter_pids(const struct dirent *dir)
+{
+       char *name = dir->d_name;
+       int n;
+       char status[20];
+       char buf[1024];
+       FILE *fp;
+       status_t curstatus;
+       int pid;
+       long tasknice;
+       struct stat sb;
+
+       if (!(*name >= '0' && *name <= '9'))
+               return 0;
+       if(stat(name, &sb))
+               return 0;
+
+       memset(&curstatus, 0, sizeof(status_t));
+       pid = atoi(name);
+       curstatus.pid = pid;
+       
+       my_getpwuid(curstatus.user, sb.st_uid);
+
+       sprintf(status, "%d/stat", pid);
+       if((fp = fopen(status, "r")) == NULL)
+               return 0;
+       name = fgets(buf, sizeof(buf), fp);
+                       fclose(fp);
+       if(name == NULL)
+               return 0;
+       name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+       if(name == 0 || name[1] != ' ')
+               return 0;
+       *name = 0;
+       sscanf(buf, "%*s (%15c", curstatus.short_cmd);
+       n = sscanf(name+2,
+        "%c %d "
+        "%*s %*s %*s %*s "     /* pgrp, session, tty, tpgid */
+        "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+        "%lu %lu "
+#else
+        "%*s %*s "
+#endif
+        "%*s %*s %*s "         /* cutime, cstime, priority */
+        "%ld "
+        "%*s %*s %*s "         /* timeout, it_real_value, start_time */
+        "%*s "                 /* vsize */
+        "%ld",
+        curstatus.state, &curstatus.ppid,
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       &curstatus.utime, &curstatus.stime,
+#endif
+       &tasknice,
+       &curstatus.rss);
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       if(n != 6)
+#else
+       if(n != 4)
+#endif
+               return 0;
+
+       if (curstatus.rss == 0 && curstatus.state[0] != 'Z')
+               curstatus.state[1] = 'W';
+        else
+               curstatus.state[1] = ' ';
+       if (tasknice < 0)
+               curstatus.state[2] = '<';
+        else if (tasknice > 0)
+               curstatus.state[2] = 'N';
+        else
+               curstatus.state[2] = ' ';
+
+       curstatus.rss <<= (PAGE_SHIFT - 10);     /* 2**10 = 1kb */
+
+       sprintf(status, "%d/cmdline", pid);
+       if((fp = fopen(status, "r")) == NULL)
+               return 0;
+       if(fgets(buf, sizeof(buf), fp) != NULL) {
+            name = strchr(buf, '\n');
+            if(name != NULL)
+               *name = 0;
+            if(buf[0])
+               curstatus.cmd = strdup(buf); /* if NULL it work true also */
+               }
+               fclose(fp);
+               
+       n = ntop;
+       top = xrealloc(top, (++ntop)*sizeof(status_t));
+       memcpy(top + n, &curstatus, sizeof(status_t));
+       return 1;
+}
+
+
+static struct dirent **namelist;
+
+static void clearmems(void) {
+       int i;
+
+       for(i = 0; i < ntop; i++) {
+               free(top[i].cmd);
+               free(namelist[i]);
+       }
+       free(top);
+       free(namelist);
+       top = 0;
+       namelist = 0;
+       ntop = 0;
+}
+
+#if defined BB_FEATURE_USE_TERMIOS
+#include <termios.h>
+#include <sys/time.h>
+#include <signal.h>
+
+
+static struct termios initial_settings;
+
+static void reset_term(void)
+{
+       tcsetattr(0, TCSANOW, (void *) &initial_settings);
+#ifdef CONFIG_FEATURE_CLEAN_UP
+       clearmems();
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       free(save_history);
+#endif
+#endif /* CONFIG_FEATURE_CLEAN_UP */
+}
+       
+static void sig_catcher (int sig)
+{
+       reset_term();
+}
+#endif /* BB_FEATURE_USE_TERMIOS */
+
+
+int top_main(int argc, char **argv)
+{
+       int opt, interval, lines, col;
+#if defined BB_FEATURE_USE_TERMIOS
+       struct termios new_settings;
+       struct timeval tv;
+       fd_set readfds;
+       unsigned char c;
+       struct sigaction sa;
+#if defined BB_FEATURE_AUTOWIDTH
+       struct winsize win = { 0, 0, 0, 0 };
+#endif
+#endif /* BB_FEATURE_USE_TERMIOS */
+
+       /* Default update rate is 5 seconds */
+       interval = 5;
+
+       /* do normal option parsing */
+       while ((opt = getopt(argc, argv, "d:")) > 0) {
+           switch (opt) {
+               case 'd':
+                   interval = atoi(optarg);
+                   break;
+               default:
+                   show_usage();
+           }
+       }
+
+       /* Default to 25 lines - 5 lines for status */
+       lines = 25 - 5;
+       /* Default CMD format size */
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       col = 35 - 6;
+#else
+       col = 35;
+#endif
+       /* change to proc */
+       if (chdir("/proc") < 0) {
+               perror_msg_and_die("chdir('/proc')");
+       }
+#if defined BB_FEATURE_USE_TERMIOS
+       tcgetattr(0, (void *) &initial_settings);
+       memcpy(&new_settings, &initial_settings, sizeof(struct termios));
+       new_settings.c_lflag &= ~(ISIG | ICANON); /* unbuffered input */
+       /* Turn off echoing */
+       new_settings.c_lflag &= ~(ECHO | ECHONL);
+
+       signal (SIGTERM, sig_catcher);
+       sigaction (SIGTERM, (struct sigaction *) 0, &sa);
+       sa.sa_flags |= SA_RESTART;
+       sa.sa_flags &= ~SA_INTERRUPT;
+       sigaction (SIGTERM, &sa, (struct sigaction *) 0);
+       sigaction (SIGINT, &sa, (struct sigaction *) 0);
+       tcsetattr(0, TCSANOW, (void *) &new_settings);
+       atexit(reset_term);
+#if defined BB_FEATURE_AUTOWIDTH
+       ioctl(0, TIOCGWINSZ, &win);
+       if (win.ws_row > 4) {
+           lines = win.ws_row - 5;
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+           col = win.ws_col - 80 + 35 - 6;
+#else
+           col = win.ws_col - 80 + 35;
+#endif
+       }
+#endif
+#endif /* BB_FEATURE_USE_TERMIOS */
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+       sort_function[0] = pcpu_sort;
+       sort_function[1] = mem_sort;
+       sort_function[2] = time_sort;
+#else
+       sort_function = mem_sort;
+#endif
+       while (1) {
+               /* read process IDs & status for all the processes */
+               if (scandir(".", &namelist, filter_pids, 0) < 0) {
+               perror_msg_and_die("scandir('/proc')");
+       }
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+               if(!Hertz) {
+                       init_Hertz_value();
+                       do_stats();
+                       sleep(1);
+                       clearmems();
+                       continue;
+       }
+               do_stats();
+#else
+               qsort(top, ntop, sizeof(status_t), (void*)sort_function);
+#endif
+               opt = lines;
+               if (opt > ntop) {
+                       opt = ntop;
+               }
+               /* show status for each of the processes */
+               display_status(opt, col);
+#if defined BB_FEATURE_USE_TERMIOS
+               tv.tv_sec = interval;
+               tv.tv_usec = 0;
+               FD_ZERO (&readfds);
+               FD_SET (0, &readfds);
+               select (1, &readfds, NULL, NULL, &tv);
+               if (FD_ISSET (0, &readfds)) {
+                       if (read (0, &c, 1) <= 0) {   /* signal */
+               return EXIT_FAILURE;
+       }
+                       if(c == 'q' || c == initial_settings.c_cc[VINTR])
+                               return EXIT_SUCCESS;
+                       if(c == 'M') {
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+                               sort_function[0] = mem_sort;
+                               sort_function[1] = pcpu_sort;
+                               sort_function[2] = time_sort;
+#else
+                               sort_function = mem_sort;
+#endif
+                       }
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+                       if(c == 'P') {
+                               sort_function[0] = pcpu_sort;
+                               sort_function[1] = mem_sort;
+                               sort_function[2] = time_sort;
+                       }
+                       if(c == 'T') {
+                               sort_function[0] = time_sort;
+                               sort_function[1] = mem_sort;
+                               sort_function[2] = pcpu_sort;
+                       }
+#endif
+                       if(c == 'N') {
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+                               sort_function[0] = pid_sort;
+#else
+                               sort_function = pid_sort;
+#endif
+                       }
+               }
+#else
+               sleep(interval);
+#endif                                  /* BB_FEATURE_USE_TERMIOS */
+               clearmems();
+       }
+       
+       return EXIT_SUCCESS;
+}
diff --git a/touch.c b/touch.c
new file mode 100644 (file)
index 0000000..036b5c3
--- /dev/null
+++ b/touch.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini touch implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int touch_main(int argc, char **argv)
+{
+       int fd;
+       int create = TRUE;
+
+       /* Parse options */
+       while (--argc > 0 && **(++argv) == '-') {
+               while (*(++(*argv))) {
+                       switch (**argv) {
+                       case 'c':
+                               create = FALSE;
+                               break;
+                       default:
+                               show_usage();
+                       }
+               }
+       }
+
+       if (argc < 1) {
+               show_usage();
+       }
+
+       while (argc > 0) {
+               fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT,
+                               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+               if (fd < 0) {
+                       if (create == FALSE && errno == ENOENT)
+                               return EXIT_SUCCESS;
+                       else {
+                               perror_msg_and_die("%s", *argv);
+                       }
+               }
+               close(fd);
+               if (utime(*argv, NULL)) {
+                       perror_msg_and_die("%s", *argv);
+               }
+               argc--;
+               argv++;
+       }
+
+       return EXIT_SUCCESS;
+}
diff --git a/tr.c b/tr.c
new file mode 100644 (file)
index 0000000..5b7b8d0
--- /dev/null
+++ b/tr.c
@@ -0,0 +1,248 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tr implementation for busybox
+ *
+ * Copyright (c) Michiel Huisjes
+ *
+ * This version of tr is adapted from Minix tr and was modified 
+ * by Erik Andersen <andersee@debian.org> to be used in busybox.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
+ * enabled, we otherwise get a "storage size isn't constant error. */
+#define ASCII 0377
+
+/* some "globals" shared across this file */
+static char com_fl, del_fl, sq_fl;
+static short in_index, out_index;
+/* these last are pointers to static buffers declared in tr_main */
+static unsigned char *poutput, *pinput;
+static unsigned char *pvector;
+static char *pinvec, *poutvec;
+
+
+static void convert()
+{
+       short read_chars = 0;
+       short c, coded;
+       short last = -1;
+
+       for (;;) {
+               if (in_index == read_chars) {
+                       if ((read_chars = read(0, (char *) pinput, BUFSIZ)) <= 0) {
+                               if (write(1, (char *) poutput, out_index) != out_index)
+                                       error_msg("%s", write_error);
+                               exit(0);
+                       }
+                       in_index = 0;
+               }
+               c = pinput[in_index++];
+               coded = pvector[c];
+               if (del_fl && pinvec[c])
+                       continue;
+               if (sq_fl && last == coded && (pinvec[c] || poutvec[coded]))
+                       continue;
+               poutput[out_index++] = last = coded;
+               if (out_index == BUFSIZ) {
+                       if (write(1, (char *) poutput, out_index) != out_index)
+                               error_msg_and_die("%s", write_error);
+                       out_index = 0;
+               }
+       }
+
+       /* NOTREACHED */
+}
+
+static void map(register unsigned char *string1, unsigned int string1_len,
+               register unsigned char *string2, unsigned int string2_len)
+{
+       unsigned char last = '0';
+       unsigned int i, j;
+
+       for (j = 0, i = 0; i < string1_len; i++) {
+               if (string2_len <= j)
+                       pvector[string1[i]] = last;
+               else
+                       pvector[string1[i]] = last = string2[j++];
+       }
+}
+
+/* supported constructs:
+ *   Ranges,  e.g.,  [0-9]  ==>  0123456789
+ *   Escapes, e.g.,  \a     ==>  Control-G
+ */
+static unsigned int expand(const char *arg, register unsigned char *buffer)
+{
+       unsigned char *buffer_start = buffer;
+       int i, ac;
+
+       while (*arg) {
+               if (*arg == '\\') {
+                       arg++;
+                       *buffer++ = process_escape_sequence(&arg);
+               } else if (*(arg+1) == '-') {
+                       ac = *(arg+2);
+                       if(ac == 0) {
+                               *buffer++ = *arg++;
+                               continue;
+                       }
+                       i = *arg;
+                       while (i <= ac)
+                               *buffer++ = i++;
+                       arg += 3; /* Skip the assumed a-z */
+               } else if (*arg == '[') {
+                       arg++;
+                       i = *arg++;
+                       if (*arg++ != '-') {
+                               *buffer++ = '[';
+                               arg -= 2;
+                               continue;
+                       }
+                       ac = *arg++;
+                       while (i <= ac)
+                               *buffer++ = i++;
+                       arg++;                          /* Skip the assumed ']' */
+               } else
+                       *buffer++ = *arg++;
+       }
+
+       return (buffer - buffer_start);
+}
+
+static int complement(unsigned char *buffer, int buffer_len)
+{
+       register short i, j, ix;
+       char conv[ASCII + 2];
+
+       ix = 0;
+       for (i = 0; i <= ASCII; i++) {
+               for (j = 0; j < buffer_len; j++)
+                       if (buffer[j] == i)
+                               break;
+               if (j == buffer_len)
+                       conv[ix++] = i & ASCII;
+       }
+       memcpy(buffer, conv, ix);
+       return ix;
+}
+
+extern int tr_main(int argc, char **argv)
+{
+       register unsigned char *ptr;
+       int output_length=0, input_length;
+       int idx = 1;
+       int i;
+       RESERVE_BB_BUFFER(output, BUFSIZ);
+       RESERVE_BB_BUFFER(input,  BUFSIZ);
+       RESERVE_BB_UBUFFER(vector, ASCII+1);
+       RESERVE_BB_BUFFER(invec,  ASCII+1);
+       RESERVE_BB_BUFFER(outvec, ASCII+1);
+
+       /* ... but make them available globally */
+       poutput = output;
+       pinput  = input;
+       pvector = vector;
+       pinvec  = invec;
+       poutvec = outvec;
+
+       if (argc > 1 && argv[idx][0] == '-') {
+               for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
+                       switch (*ptr) {
+                       case 'c':
+                               com_fl = TRUE;
+                               break;
+                       case 'd':
+                               del_fl = TRUE;
+                               break;
+                       case 's':
+                               sq_fl = TRUE;
+                               break;
+                       default:
+                               show_usage();
+                       }
+               }
+               idx++;
+       }
+       for (i = 0; i <= ASCII; i++) {
+               vector[i] = i;
+               invec[i] = outvec[i] = FALSE;
+       }
+
+       if (argv[idx] != NULL) {
+               input_length = expand(argv[idx++], input);
+               if (com_fl)
+                       input_length = complement(input, input_length);
+               if (argv[idx] != NULL) {
+                       if (*argv[idx] == '\0')
+                               error_msg_and_die("STRING2 cannot be empty");
+                       output_length = expand(argv[idx], output);
+                       map(input, input_length, output, output_length);
+               }
+               for (i = 0; i < input_length; i++)
+                       invec[(int)input[i]] = TRUE;
+               for (i = 0; i < output_length; i++)
+                       outvec[(int)output[i]] = TRUE;
+       }
+       convert();
+       return (0);
+}
+
+/*
+ * Copyright (c) 1987,1997, Prentice Hall
+ * All rights reserved.
+ * 
+ * Redistribution and use of the MINIX operating system in source and
+ * binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * 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.
+ * 
+ * Neither the name of Prentice Hall nor the names of the software
+ * authors or contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, 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 PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
diff --git a/traceroute.c b/traceroute.c
new file mode 100644 (file)
index 0000000..c0c2165
--- /dev/null
@@ -0,0 +1,647 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ *
+ * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * traceroute host  - trace the route ip packets follow going to "host".
+ * Notes
+ * -----
+ * This program must be run by root or be setuid.  (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * I stole the idea for this program from Steve Deering.  Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis.  I don't know (or care) who came up with
+ * the idea first.  I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself.  Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless.  Maybe one day...
+ *
+ *  -- Van Jacobson (van@helios.ee.lbl.gov)
+ *     Tue Dec 20 03:50:13 PST 1988
+ */
+
+#undef BB_FEATURE_TRACEROUTE_VERBOSE
+//#define BB_FEATURE_TRACEROUTE_VERBOSE
+#undef BB_FEATURE_TRACEROUTE_SO_DEBUG   /* not in documentation man */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <endian.h>
+#include <arpa/inet.h>
+#include <netinet/udp.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+ /* It turns out that libc5 doesn't have proper icmp support
+ * built into it header files, so we have to supplement it */
+#if __GNU_LIBRARY__ < 5
+static const int ICMP_MINLEN = 8;                              /* abs minimum */
+
+struct icmp_ra_addr
+{
+  u_int32_t ira_addr;
+  u_int32_t ira_preference;
+};
+
+
+struct icmp
+{
+  u_int8_t  icmp_type; /* type of message, see below */
+  u_int8_t  icmp_code; /* type sub code */
+  u_int16_t icmp_cksum;        /* ones complement checksum of struct */
+  union
+  {
+    u_char ih_pptr;            /* ICMP_PARAMPROB */
+    struct in_addr ih_gwaddr;  /* gateway address */
+    struct ih_idseq            /* echo datagram */
+    {
+      u_int16_t icd_id;
+      u_int16_t icd_seq;
+    } ih_idseq;
+    u_int32_t ih_void;
+
+    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+    struct ih_pmtu
+    {
+      u_int16_t ipm_void;
+      u_int16_t ipm_nextmtu;
+    } ih_pmtu;
+
+    struct ih_rtradv
+    {
+      u_int8_t irt_num_addrs;
+      u_int8_t irt_wpa;
+      u_int16_t irt_lifetime;
+    } ih_rtradv;
+  } icmp_hun;
+#define        icmp_pptr       icmp_hun.ih_pptr
+#define        icmp_gwaddr     icmp_hun.ih_gwaddr
+#define        icmp_id         icmp_hun.ih_idseq.icd_id
+#define        icmp_seq        icmp_hun.ih_idseq.icd_seq
+#define        icmp_void       icmp_hun.ih_void
+#define        icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
+#define        icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
+#define        icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
+#define        icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
+#define        icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
+  union
+  {
+    struct
+    {
+      u_int32_t its_otime;
+      u_int32_t its_rtime;
+      u_int32_t its_ttime;
+    } id_ts;
+    struct
+    {
+      struct ip idi_ip;
+      /* options and then 64 bits of data */
+    } id_ip;
+    struct icmp_ra_addr id_radv;
+    u_int32_t   id_mask;
+    u_int8_t    id_data[1];
+  } icmp_dun;
+#define        icmp_otime      icmp_dun.id_ts.its_otime
+#define        icmp_rtime      icmp_dun.id_ts.its_rtime
+#define        icmp_ttime      icmp_dun.id_ts.its_ttime
+#define        icmp_ip         icmp_dun.id_ip.idi_ip
+#define        icmp_radv       icmp_dun.id_radv
+#define        icmp_mask       icmp_dun.id_mask
+#define        icmp_data       icmp_dun.id_data
+};
+
+#define        ICMP_MINLEN     8                               /* abs minimum */
+#define        ICMP_UNREACH            3               /* dest unreachable, codes: */
+#define        ICMP_TIMXCEED           11              /* time exceeded, code: */
+#define        ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
+#define        ICMP_UNREACH_NET                0       /* bad net */
+#define        ICMP_UNREACH_HOST               1       /* bad host */
+#define        ICMP_UNREACH_PROTOCOL           2       /* bad protocol */
+#define        ICMP_UNREACH_PORT               3       /* bad port */
+#define        ICMP_UNREACH_NEEDFRAG           4       /* IP_DF caused drop */
+#define        ICMP_UNREACH_SRCFAIL            5       /* src route failed */
+#endif
+
+
+#define MAXPACKET       65535   /* max ip packet size */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN  64
+#endif
+
+/*
+ * format of a (udp) probe packet.
+ */
+struct opacket {
+       struct ip ip;
+       struct udphdr udp;
+       u_char seq;             /* sequence number of this packet */
+       u_char ttl;             /* ttl packet left with */
+       struct timeval tv;      /* time packet left */
+};
+
+/*
+ * Definitions for internet protocol version 4.
+ * Per RFC 791, September 1981.
+ */
+#define IPVERSION       4
+
+
+#include "busybox.h"
+
+static u_char  packet[512];            /* last inbound (icmp) packet */
+static struct opacket  *outpacket;     /* last output (udp) packet */
+
+static int s;                          /* receive (icmp) socket file descriptor */
+static int sndsock;                    /* send (udp) socket file descriptor */
+
+static struct sockaddr whereto;        /* Who to try to reach */
+static int datalen;                    /* How much data */
+
+static char *hostname;
+
+static int max_ttl = 30;
+static u_short ident;
+static u_short port = 32768+666;       /* start udp dest port # for probe packets */
+
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+static int verbose;
+#endif
+static int waittime = 5;               /* time to wait for response (in seconds) */
+static int nflag;                      /* print addresses numerically */
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+static inline void
+inetname(struct sockaddr_in *from)
+{
+       char *cp;
+       struct hostent *hp;
+       static char domain[MAXHOSTNAMELEN + 1];
+       static int first = 1;
+       const char *ina;
+
+       if (first && !nflag) {
+               first = 0;
+               if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
+                   domain[0] = 0;
+       }
+       cp = 0;
+       if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
+               hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
+               if (hp) {
+                       if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain))
+                               *cp = 0;
+                       cp = (char *)hp->h_name;
+               }
+       }
+       ina = inet_ntoa(from->sin_addr);
+       if (nflag)
+               printf(" %s", ina);
+       else
+               printf(" %s (%s)", (cp ? cp : ina), ina);
+}
+
+static inline void
+print(u_char *buf, int cc, struct sockaddr_in *from)
+{
+       struct ip *ip;
+       int hlen;
+
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       cc -= hlen;
+
+       inetname(from);
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+       if (verbose)
+               printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+#endif
+}
+
+static inline double
+deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+       double dt;
+
+       dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+            (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+       return (dt);
+}
+
+static inline int
+wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
+{
+       fd_set fds;
+       static struct timeval wait;
+       int cc = 0;
+       int fromlen = sizeof (*from);
+
+       FD_ZERO(&fds);
+       FD_SET(sock, &fds);
+       if (reset_timer) {
+               /*
+                * traceroute could hang if someone else has a ping
+                * running and our ICMP reply gets dropped but we don't
+                * realize it because we keep waking up to handle those
+                * other ICMP packets that keep coming in.  To fix this,
+                * "reset_timer" will only be true if the last packet that
+                * came in was for us or if this is the first time we're
+                * waiting for a reply since sending out a probe.  Note
+                * that this takes advantage of the select() feature on
+                * Linux where the remaining timeout is written to the
+                * struct timeval area.
+                */
+               wait.tv_sec = waittime;
+               wait.tv_usec = 0;
+       }
+
+       if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
+               cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
+                           (struct sockaddr *)from, &fromlen);
+
+       return(cc);
+}
+
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+static inline const char *
+pr_type(u_char t)
+{
+       static const char * const ttab[] = {
+       "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
+       "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
+       "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
+       "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
+       "Info Reply"
+       };
+
+       if(t > 16)
+               return("OUT-OF-RANGE");
+
+       return(ttab[t]);
+}
+#endif
+
+static inline int
+packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
+{
+       struct icmp *icp;
+       u_char type, code;
+       int hlen;
+       struct ip *ip;
+
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       if (cc < hlen + ICMP_MINLEN) {
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+               if (verbose)
+                       printf("packet too short (%d bytes) from %s\n", cc,
+                               inet_ntoa(from->sin_addr));
+#endif
+               return (0);
+       }
+       cc -= hlen;
+       icp = (struct icmp *)(buf + hlen);
+       type = icp->icmp_type; code = icp->icmp_code;
+       if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+           type == ICMP_UNREACH) {
+               struct ip *hip;
+               struct udphdr *up;
+
+               hip = &icp->icmp_ip;
+               hlen = hip->ip_hl << 2;
+               up = (struct udphdr *)((u_char *)hip + hlen);
+               if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
+                   up->source == htons(ident) &&
+                   up->dest == htons(port+seq))
+                       return (type == ICMP_TIMXCEED? -1 : code+1);
+       }
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+       if (verbose) {
+               int i;
+               u_long *lp = (u_long *)&icp->icmp_ip;
+
+               printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
+                       cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
+                       type, pr_type(type), icp->icmp_code);
+               for (i = 4; i < cc ; i += sizeof(long))
+                       printf("%2d: x%8.8lx\n", i, *lp++);
+       }
+#endif
+       return(0);
+}
+
+static void             /* not inline */
+send_probe(int seq, int ttl)
+{
+       struct opacket *op = outpacket;
+       struct ip *ip = &op->ip;
+       struct udphdr *up = &op->udp;
+       int i;
+       struct timezone tz;
+
+       ip->ip_off = 0;
+       ip->ip_hl = sizeof(*ip) >> 2;
+       ip->ip_p = IPPROTO_UDP;
+       ip->ip_len = datalen;
+       ip->ip_ttl = ttl;
+       ip->ip_v = IPVERSION;
+       ip->ip_id = htons(ident+seq);
+
+       up->source = htons(ident);
+       up->dest = htons(port+seq);
+       up->len = htons((u_short)(datalen - sizeof(struct ip)));
+       up->check = 0;
+
+       op->seq = seq;
+       op->ttl = ttl;
+       (void) gettimeofday(&op->tv, &tz);
+
+       i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
+                  sizeof(struct sockaddr));
+       if (i < 0 || i != datalen)  {
+               if (i<0)
+                       perror("sendto");
+               printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
+                       datalen, i);
+               (void) fflush(stdout);
+       }
+}
+
+
+int
+#ifndef BB_TRACEROUTE
+main(argc, argv)
+#else
+traceroute_main(argc, argv)
+#endif
+       int argc;
+       char *argv[];
+{
+       extern char *optarg;
+       extern int optind;
+       struct hostent *hp;
+       struct sockaddr_in from, *to;
+       int ch, i, on, probe, seq, tos, ttl;
+
+       int options = 0;                /* socket options */
+       char *source = 0;
+       int nprobes = 3;
+
+       on = 1;
+       seq = tos = 0;
+       to = (struct sockaddr_in *)&whereto;
+       while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
+               switch(ch) {
+               case 'd':
+#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
+                       options |= SO_DEBUG;
+#endif
+                       break;
+               case 'm':
+                       max_ttl = atoi(optarg);
+                       if (max_ttl <= 1)
+                               error_msg_and_die("max ttl must be >1.");
+                       break;
+               case 'n':
+                       nflag++;
+                       break;
+               case 'p':
+                       port = atoi(optarg);
+                       if (port < 1)
+                               error_msg_and_die("port must be >0.");
+                       break;
+               case 'q':
+                       nprobes = atoi(optarg);
+                       if (nprobes < 1)
+                               error_msg_and_die("nprobes must be >0.");
+                       break;
+               case 'r':
+                       options |= SO_DONTROUTE;
+                       break;
+               case 's':
+                       /*
+                        * set the ip source address of the outbound
+                        * probe (e.g., on a multi-homed host).
+                        */
+                       source = optarg;
+                       break;
+               case 't':
+                       tos = atoi(optarg);
+                       if (tos < 0 || tos > 255)
+                               error_msg_and_die("tos must be 0 to 255.");
+                       break;
+               case 'v':
+#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
+                       verbose++;
+#endif
+                       break;
+               case 'w':
+                       waittime = atoi(optarg);
+                       if (waittime <= 1)
+                               error_msg_and_die("wait must be >1 sec.");
+                       break;
+               default:
+                       show_usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1)
+               show_usage();
+
+       setlinebuf (stdout);
+
+       memset(&whereto, 0, sizeof(struct sockaddr));
+       hp = xgethostbyname(*argv);
+                       to->sin_family = hp->h_addrtype;
+       memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
+                       hostname = (char *)hp->h_name;
+       if (*++argv)
+               datalen = atoi(*argv);
+       if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
+               error_msg_and_die("packet size must be 0 <= s < %d.",
+                   MAXPACKET - sizeof(struct opacket));
+       datalen += sizeof(struct opacket);
+       outpacket = (struct opacket *)xmalloc((unsigned)datalen);
+       memset(outpacket, 0, datalen);
+       outpacket->ip.ip_dst = to->sin_addr;
+       outpacket->ip.ip_tos = tos;
+       outpacket->ip.ip_v = IPVERSION;
+       outpacket->ip.ip_id = 0;
+
+       ident = (getpid() & 0xffff) | 0x8000;
+
+       if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+               perror_msg_and_die(can_not_create_raw_socket);
+
+       s = create_icmp_socket();
+
+#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
+       if (options & SO_DEBUG)
+               (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
+                                 (char *)&on, sizeof(on));
+#endif
+       if (options & SO_DONTROUTE)
+               (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
+                                 (char *)&on, sizeof(on));
+#ifdef SO_SNDBUF
+       if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
+                      sizeof(datalen)) < 0)
+               perror_msg_and_die("SO_SNDBUF");
+#endif /* SO_SNDBUF */
+#ifdef IP_HDRINCL
+       if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+                      sizeof(on)) < 0)
+               perror_msg_and_die("IP_HDRINCL");
+#endif /* IP_HDRINCL */
+#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
+       if (options & SO_DEBUG)
+               (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
+                                 (char *)&on, sizeof(on));
+#endif
+       if (options & SO_DONTROUTE)
+               (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
+                                 (char *)&on, sizeof(on));
+
+       if (source) {
+               memset(&from, 0, sizeof(struct sockaddr));
+               from.sin_family = AF_INET;
+               from.sin_addr.s_addr = inet_addr(source);
+               if (from.sin_addr.s_addr == -1)
+                       error_msg_and_die("unknown host %s", source);
+               outpacket->ip.ip_src = from.sin_addr;
+#ifndef IP_HDRINCL
+               if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
+                       perror_msg_and_die("bind");
+#endif /* IP_HDRINCL */
+       }
+
+       fprintf(stderr, "traceroute to %s (%s)", hostname,
+               inet_ntoa(to->sin_addr));
+       if (source)
+               fprintf(stderr, " from %s", source);
+       fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
+
+       for (ttl = 1; ttl <= max_ttl; ++ttl) {
+               u_long lastaddr = 0;
+               int got_there = 0;
+               int unreachable = 0;
+
+               printf("%2d ", ttl);
+               for (probe = 0; probe < nprobes; ++probe) {
+                       int cc, reset_timer;
+                       struct timeval t1, t2;
+                       struct timezone tz;
+                       struct ip *ip;
+
+                       (void) gettimeofday(&t1, &tz);
+                       send_probe(++seq, ttl);
+                       reset_timer = 1;
+                       while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
+                               (void) gettimeofday(&t2, &tz);
+                               if ((i = packet_ok(packet, cc, &from, seq))) {
+                                       reset_timer = 1;
+                                       if (from.sin_addr.s_addr != lastaddr) {
+                                               print(packet, cc, &from);
+                                               lastaddr = from.sin_addr.s_addr;
+                                       }
+                                       printf("  %g ms", deltaT(&t1, &t2));
+                                       switch(i - 1) {
+                                       case ICMP_UNREACH_PORT:
+                                               ip = (struct ip *)packet;
+                                               if (ip->ip_ttl <= 1)
+                                                       printf(" !");
+                                               ++got_there;
+                                               break;
+                                       case ICMP_UNREACH_NET:
+                                               ++unreachable;
+                                               printf(" !N");
+                                               break;
+                                       case ICMP_UNREACH_HOST:
+                                               ++unreachable;
+                                               printf(" !H");
+                                               break;
+                                       case ICMP_UNREACH_PROTOCOL:
+                                               ++got_there;
+                                               printf(" !P");
+                                               break;
+                                       case ICMP_UNREACH_NEEDFRAG:
+                                               ++unreachable;
+                                               printf(" !F");
+                                               break;
+                                       case ICMP_UNREACH_SRCFAIL:
+                                               ++unreachable;
+                                               printf(" !S");
+                                               break;
+                                       }
+                                       break;
+                               } else
+                                       reset_timer = 0;
+                       }
+                       if (cc == 0)
+                               printf(" *");
+                       (void) fflush(stdout);
+               }
+               putchar('\n');
+               if (got_there || unreachable >= nprobes-1)
+                       exit(0);
+       }
+
+       return 0;
+}
diff --git a/true_false.c b/true_false.c
new file mode 100644 (file)
index 0000000..b00e298
--- /dev/null
@@ -0,0 +1,39 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini true/false implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdlib.h>
+#include "busybox.h"
+
+
+extern int true_main(int argc, char **argv)
+{
+       return EXIT_SUCCESS;
+}
+
+extern int false_main(int argc, char **argv)
+{
+       return EXIT_FAILURE;
+}
diff --git a/tty.c b/tty.c
new file mode 100644 (file)
index 0000000..4510c29
--- /dev/null
+++ b/tty.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini tty implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "busybox.h"
+
+extern int tty_main(int argc, char **argv)
+{
+       char *tty;
+
+       if (argc > 1) {
+               if (argv[1][0] != '-' || argv[1][1] != 's')
+                       show_usage();
+       } else {
+               tty = ttyname(0);
+               if (tty)
+                       puts(tty);
+               else
+                       puts("not a tty");
+       }
+       return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/umount.c b/umount.c
new file mode 100644 (file)
index 0000000..2a06a3b
--- /dev/null
+++ b/umount.c
@@ -0,0 +1,298 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini umount implementation for busybox
+ *
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+/* Teach libc5 about realpath -- it includes it but the 
+ * prototype is missing... */
+#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
+extern char *realpath(const char *path, char *resolved_path);
+#endif
+
+static const int MNT_FORCE = 1;
+static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
+static const int MS_REMOUNT = 32;      /* Alter flags of a mounted FS.  */
+static const int MS_RDONLY = 1;        /* Mount read-only.  */
+
+extern int mount (__const char *__special_file, __const char *__dir,
+                       __const char *__fstype, unsigned long int __rwflag,
+                       __const void *__data);
+extern int umount (__const char *__special_file);
+extern int umount2 (__const char *__special_file, int __flags);
+
+struct _mtab_entry_t {
+       char *device;
+       char *mountpt;
+       struct _mtab_entry_t *next;
+};
+
+static struct _mtab_entry_t *mtab_cache = NULL;
+
+
+
+#if defined BB_FEATURE_MOUNT_FORCE
+static int doForce = FALSE;
+#endif
+#if defined BB_FEATURE_MOUNT_LOOP
+static int freeLoop = TRUE;
+#endif
+#if defined BB_FEATURE_MTAB_SUPPORT
+static int useMtab = TRUE;
+#endif
+static int umountAll = FALSE;
+static int doRemount = FALSE;
+extern const char mtab_file[]; /* Defined in utility.c */
+
+
+
+/* These functions are here because the getmntent functions do not appear
+ * to be re-entrant, which leads to all sorts of problems when we try to
+ * use them recursively - randolph
+ *
+ * TODO: Perhaps switch to using Glibc's getmntent_r
+ *        -Erik
+ */
+static void mtab_read(void)
+{
+       struct _mtab_entry_t *entry = NULL;
+       struct mntent *e;
+       FILE *fp;
+
+       if (mtab_cache != NULL)
+               return;
+
+       if ((fp = setmntent(mtab_file, "r")) == NULL) {
+               error_msg("Cannot open %s", mtab_file);
+               return;
+       }
+       while ((e = getmntent(fp))) {
+               entry = xmalloc(sizeof(struct _mtab_entry_t));
+               entry->device = strdup(e->mnt_fsname);
+               entry->mountpt = strdup(e->mnt_dir);
+               entry->next = mtab_cache;
+               mtab_cache = entry;
+       }
+       endmntent(fp);
+}
+
+static char *mtab_getinfo(const char *match, const char which)
+{
+       struct _mtab_entry_t *cur = mtab_cache;
+
+       while (cur) {
+               if (strcmp(cur->mountpt, match) == 0 ||
+                       strcmp(cur->device, match) == 0) {
+                       if (which == MTAB_GETMOUNTPT) {
+                               return cur->mountpt;
+                       } else {
+#if !defined BB_FEATURE_MTAB_SUPPORT
+                               if (strcmp(cur->device, "/dev/root") == 0) {
+                                       /* Adjusts device to be the real root device,
+                                        * or leaves device alone if it can't find it */
+                                       cur->device = find_real_root_device_name(cur->device);
+                               }
+#endif
+                               return cur->device;
+                       }
+               }
+               cur = cur->next;
+       }
+       return NULL;
+}
+
+static char *mtab_next(void **iter)
+{
+       char *mp;
+
+       if (iter == NULL || *iter == NULL)
+               return NULL;
+       mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
+       *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
+       return mp;
+}
+
+static char *mtab_first(void **iter)
+{
+       struct _mtab_entry_t *mtab_iter;
+
+       if (!iter)
+               return NULL;
+       mtab_iter = mtab_cache;
+       *iter = (void *) mtab_iter;
+       return mtab_next(iter);
+}
+
+/* Don't bother to clean up, since exit() does that 
+ * automagically, so we can save a few bytes */
+#ifdef BB_FEATURE_CLEAN_UP
+static void mtab_free(void)
+{
+       struct _mtab_entry_t *this, *next;
+
+       this = mtab_cache;
+       while (this) {
+               next = this->next;
+               if (this->device)
+                       free(this->device);
+               if (this->mountpt)
+                       free(this->mountpt);
+               free(this);
+               this = next;
+       }
+}
+#endif
+
+static int do_umount(const char *name)
+{
+       int status;
+       char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
+
+       if (blockDevice && strcmp(blockDevice, name) == 0)
+               name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
+
+       status = umount(name);
+
+#if defined BB_FEATURE_MOUNT_LOOP
+       if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
+               /* this was a loop device, delete it */
+               del_loop(blockDevice);
+#endif
+#if defined BB_FEATURE_MOUNT_FORCE
+       if (status != 0 && doForce == TRUE) {
+               status = umount2(blockDevice, MNT_FORCE);
+               if (status != 0) {
+                       error_msg_and_die("forced umount of %s failed!", blockDevice);
+               }
+       }
+#endif
+       if (status != 0 && doRemount == TRUE && errno == EBUSY) {
+               status = mount(blockDevice, name, NULL,
+                                          MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
+               if (status == 0) {
+                       error_msg("%s busy - remounted read-only", blockDevice);
+               } else {
+                       error_msg("Cannot remount %s read-only", blockDevice);
+               }
+       }
+       if (status == 0) {
+#if defined BB_FEATURE_MTAB_SUPPORT
+               if (useMtab == TRUE)
+                       erase_mtab(name);
+#endif
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+static int umount_all(void)
+{
+       int status = TRUE;
+       char *mountpt;
+       void *iter;
+
+       for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
+               /* Never umount /proc on a umount -a */
+               if (strstr(mountpt, "proc")!= NULL)
+                       continue;
+               if (!do_umount(mountpt)) {
+                       /* Don't bother retrying the umount on busy devices */
+                       if (errno == EBUSY) {
+                               perror_msg("%s", mountpt);
+                               status = FALSE;
+                               continue;
+                       }
+                       if (!do_umount(mountpt)) {
+                               printf("Couldn't umount %s on %s: %s\n",
+                                          mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
+                                          strerror(errno));
+                               status = FALSE;
+                       }
+               }
+       }
+       return (status);
+}
+
+extern int umount_main(int argc, char **argv)
+{
+       char path[PATH_MAX];
+
+       if (argc < 2) {
+               show_usage();
+       }
+#ifdef BB_FEATURE_CLEAN_UP
+       atexit(mtab_free);
+#endif
+
+       /* Parse any options */
+       while (--argc > 0 && **(++argv) == '-') {
+               while (*++(*argv))
+                       switch (**argv) {
+                       case 'a':
+                               umountAll = TRUE;
+                               break;
+#if defined BB_FEATURE_MOUNT_LOOP
+                       case 'l':
+                               freeLoop = FALSE;
+                               break;
+#endif
+#ifdef BB_FEATURE_MTAB_SUPPORT
+                       case 'n':
+                               useMtab = FALSE;
+                               break;
+#endif
+#ifdef BB_FEATURE_MOUNT_FORCE
+                       case 'f':
+                               doForce = TRUE;
+                               break;
+#endif
+                       case 'r':
+                               doRemount = TRUE;
+                               break;
+                       case 'v':
+                               break; /* ignore -v */
+                       default:
+                               show_usage();
+                       }
+       }
+
+       mtab_read();
+       if (umountAll == TRUE) {
+               if (umount_all() == TRUE)
+                       return EXIT_SUCCESS;
+               else
+                       return EXIT_FAILURE;
+       }
+       if (realpath(*argv, path) == NULL)
+               perror_msg_and_die("%s", path);
+       if (do_umount(path) == TRUE)
+               return EXIT_SUCCESS;
+       perror_msg_and_die("%s", *argv);
+}
+
diff --git a/uname.c b/uname.c
new file mode 100644 (file)
index 0000000..f7e2291
--- /dev/null
+++ b/uname.c
@@ -0,0 +1,156 @@
+/* vi: set sw=4 ts=4: */
+/* uname -- print system information
+   Copyright (C) 1989-1999 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Option              Example
+
+   -s, --sysname       SunOS
+   -n, --nodename      rocky8
+   -r, --release       4.0
+   -v, --version
+   -m, --machine       sun
+   -a, --all           SunOS rocky8 4.0  sun
+
+   The default behavior is equivalent to `-s'.
+
+   David MacKenzie <djm@gnu.ai.mit.edu> */
+
+/* Busyboxed by Erik Andersen */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H)
+# include <sys/systeminfo.h>
+#endif
+#include "busybox.h"
+
+static void print_element(unsigned int mask, char *element);
+
+/* Values that are bitwise or'd into `toprint'. */
+/* Operating system name. */
+static const int PRINT_SYSNAME = 1;
+
+/* Node name on a communications network. */
+static const int PRINT_NODENAME = 2;
+
+/* Operating system release. */
+static const int PRINT_RELEASE = 4;
+
+/* Operating system version. */
+static const int PRINT_VERSION = 8;
+
+/* Machine hardware name. */
+static const int PRINT_MACHINE = 16;
+
+ /* Host processor type. */
+static const int PRINT_PROCESSOR = 32;
+
+/* Mask indicating which elements of the name to print. */
+static unsigned char toprint;
+
+
+int uname_main(int argc, char **argv)
+{
+       struct utsname name;
+       char processor[256];
+
+#if defined(__sparc__) && defined(__linux__)
+       char *fake_sparc = getenv("FAKE_SPARC");
+#endif
+
+       toprint = 0;
+
+       /* Parse any options */
+       //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
+       while (--argc > 0 && **(++argv) == '-') {
+               while (*(++(*argv))) {
+                       switch (**argv) {
+                       case 's':
+                               toprint |= PRINT_SYSNAME;
+                               break;
+                       case 'n':
+                               toprint |= PRINT_NODENAME;
+                               break;
+                       case 'r':
+                               toprint |= PRINT_RELEASE;
+                               break;
+                       case 'v':
+                               toprint |= PRINT_VERSION;
+                               break;
+                       case 'm':
+                               toprint |= PRINT_MACHINE;
+                               break;
+                       case 'p':
+                               toprint |= PRINT_PROCESSOR;
+                               break;
+                       case 'a':
+                               toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
+                                                  PRINT_PROCESSOR | PRINT_VERSION |
+                                                  PRINT_MACHINE);
+                               break;
+                       default:
+                               show_usage();
+                       }
+               }
+       }
+
+       if (toprint == 0)
+               toprint = PRINT_SYSNAME;
+
+       if (uname(&name) == -1)
+               perror_msg("cannot get system name");
+
+#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE)
+       if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1)
+               perror_msg("cannot get processor type");
+}
+
+#else
+       strcpy(processor, "unknown");
+#endif
+
+#if defined(__sparc__) && defined(__linux__)
+       if (fake_sparc != NULL
+               && (fake_sparc[0] == 'y'
+                       || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc");
+#endif
+
+       print_element(PRINT_SYSNAME, name.sysname);
+       print_element(PRINT_NODENAME, name.nodename);
+       print_element(PRINT_RELEASE, name.release);
+       print_element(PRINT_VERSION, name.version);
+       print_element(PRINT_MACHINE, name.machine);
+       print_element(PRINT_PROCESSOR, processor);
+
+       return EXIT_SUCCESS;
+}
+
+/* If the name element set in MASK is selected for printing in `toprint',
+   print ELEMENT; then print a space unless it is the last element to
+   be printed, in which case print a newline. */
+
+static void print_element(unsigned int mask, char *element)
+{
+       if (toprint & mask) {
+               toprint &= ~mask;
+               printf("%s%c", element, toprint ? ' ' : '\n');
+       }
+}
diff --git a/uniq.c b/uniq.c
new file mode 100644 (file)
index 0000000..e46fc44
--- /dev/null
+++ b/uniq.c
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini uniq implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
+ * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
+ * Written by John Beppu <beppu@codepoet.org>
+ * Rewritten by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+static int print_count;
+static int print_uniq = 1;
+static int print_duplicates = 1;
+
+static void print_line(char *line, int count, FILE *fp)
+{
+       if ((print_duplicates && count > 1) || (print_uniq && count == 1)) {
+               if (print_count)
+                       fprintf(fp, "%7d\t%s", count, line);
+               else
+                       fputs(line, fp);
+       }
+}
+
+int uniq_main(int argc, char **argv)
+{
+       FILE *in = stdin, *out = stdout;
+       char *lastline = NULL, *input;
+       int opt, count = 0;
+
+       /* parse argv[] */
+       while ((opt = getopt(argc, argv, "cdu")) > 0) {
+               switch (opt) {
+                       case 'c':
+                               print_count = 1;
+                               break;
+                       case 'd':
+                               print_duplicates = 1;
+                               print_uniq = 0;
+                               break;
+                       case 'u':
+                               print_duplicates = 0;
+                               print_uniq = 1;
+                               break;
+               }
+       }
+
+       if (argv[optind] != NULL) {
+               in = xfopen(argv[optind], "r");
+               if (argv[optind+1] != NULL)
+                       out = xfopen(argv[optind+1], "w");
+       }
+
+       while ((input = get_line_from_file(in)) != NULL) {
+               if (lastline == NULL || strcmp(input, lastline) != 0) {
+                       print_line(lastline, count, out);
+                       free(lastline);
+                       lastline = input;
+                       count = 0;
+               }
+               count++;
+       }
+       print_line(lastline, count, out);
+       free(lastline);
+
+       return EXIT_SUCCESS;
+}
diff --git a/update.c b/update.c
new file mode 100644 (file)
index 0000000..27a04dd
--- /dev/null
+++ b/update.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini update implementation for busybox; much pasted from update-2.11
+ *
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
+ * Copyright (c) 2000 by Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Note: This program is only necessary if you are running a 2.0.x (or
+ * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically.
+ */
+
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <unistd.h> /* for getopt() */
+#include <stdlib.h>
+
+#if __GNU_LIBRARY__ > 5
+       #include <sys/kdaemon.h>
+#else
+       extern int bdflush (int func, long int data);
+#endif
+
+#include "busybox.h"
+
+static unsigned int sync_duration = 30;
+static unsigned int flush_duration = 5;
+static int use_sync = 0;
+
+extern int update_main(int argc, char **argv)
+{
+       int pid;
+       int opt;
+
+       while ((opt = getopt(argc, argv, "Ss:f:")) > 0) {
+               switch (opt) {
+                       case 'S':
+                               use_sync = 1;
+                               break;
+                       case 's':
+                               sync_duration = atoi(optarg);
+                               break;
+                       case 'f':
+                               flush_duration = atoi(optarg);
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+       
+       if (daemon(0, 1) < 0)
+               perror_msg_and_die("daemon");
+
+#ifdef OPEN_MAX
+       for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
+#else
+       /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */
+       for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid);
+#endif
+
+       /* This is no longer necessary since 1.3.5x, but it will harmlessly
+        * exit if that is the case.
+        */
+
+       /* set the program name that will show up in a 'ps' listing */
+       argv[0] = "bdflush (update)";
+       argv[1] = NULL;
+       argv[2] = NULL;
+       for (;;) {
+               if (use_sync) {
+                       sleep(sync_duration);
+                       sync();
+               } else {
+                       sleep(flush_duration);
+                       if (bdflush(1, 0) < 0) {
+                               openlog("update", LOG_CONS, LOG_DAEMON);
+                               syslog(LOG_INFO,
+                                               "This kernel does not need update(8). Exiting.");
+                               closelog();
+                               return EXIT_SUCCESS;
+                       }
+               }
+       }
+
+       return EXIT_SUCCESS;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/uptime.c b/uptime.c
new file mode 100644 (file)
index 0000000..5460ac8
--- /dev/null
+++ b/uptime.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini uptime implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* This version of uptime doesn't display the number of users on the system,
+ * since busybox init doesn't mess with utmp.  For folks using utmp that are
+ * just dying to have # of users reported, feel free to write it as some type
+ * of BB_FEATURE_UTMP_SUPPORT #define
+ */
+
+/* getopt not needed */
+
+
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+static const int FSHIFT = 16;              /* nr of bits of precision */
+#define FIXED_1         (1<<FSHIFT)     /* 1.0 as fixed-point */
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+
+extern int uptime_main(int argc, char **argv)
+{
+       int updays, uphours, upminutes;
+       struct sysinfo info;
+       struct tm *current_time;
+       time_t current_secs;
+
+       time(&current_secs);
+       current_time = localtime(&current_secs);
+
+       sysinfo(&info);
+
+       printf(" %2d:%02d%s  up ", 
+                       current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, 
+                       current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am");
+       updays = (int) info.uptime / (60*60*24);
+       if (updays)
+               printf("%d day%s, ", updays, (updays != 1) ? "s" : "");
+       upminutes = (int) info.uptime / 60;
+       uphours = (upminutes / 60) % 24;
+       upminutes %= 60;
+       if(uphours)
+               printf("%2d:%02d, ", uphours, upminutes);
+       else
+               printf("%d min, ", upminutes);
+
+       printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", 
+                       LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), 
+                       LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), 
+                       LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2]));
+
+       return EXIT_SUCCESS;
+}
diff --git a/usage.c b/usage.c
new file mode 100644 (file)
index 0000000..dfea1f9
--- /dev/null
+++ b/usage.c
@@ -0,0 +1,10 @@
+#include "busybox.h"
+
+const char usage_messages[] =
+
+#define MAKE_USAGE
+#include "usage.h"
+
+#include "applets.h"
+
+;
diff --git a/usage.h b/usage.h
new file mode 100644 (file)
index 0000000..2cf5919
--- /dev/null
+++ b/usage.h
@@ -0,0 +1,1951 @@
+#define adjtimex_trivial_usage \
+       "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
+#define adjtimex_full_usage \
+       "Reads and optionally sets system timebase parameters.\n" \
+       "See adjtimex(2).\n\n" \
+       "Options:\n" \
+       "\t-q\t\tquiet mode - do not print\n" \
+       "\t-o offset\ttime offset, microseconds\n" \
+       "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \
+       "\t\t\t(positive values make the system clock run fast)\n" \
+       "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \
+       "\t-p timeconstant\n"
+
+#define ar_trivial_usage \
+       "-[ov][ptx] ARCHIVE FILES"
+#define ar_full_usage \
+       "Extract or list FILES from an ar archive.\n\n" \
+       "Options:\n" \
+       "\t-o\t\tpreserve original dates\n" \
+       "\t-p\t\textract to stdout\n" \
+       "\t-t\t\tlist\n" \
+       "\t-x\t\textract\n" \
+       "\t-v\t\tverbosely list files processed\n"
+
+#define basename_trivial_usage \
+       "FILE [SUFFIX]"
+#define basename_full_usage \
+       "Strips directory path and suffixes from FILE.\n" \
+       "If specified, also removes any trailing SUFFIX."
+#define basename_example_usage \
+       "$ basename /usr/local/bin/foo\n" \
+       "foo\n" \
+       "$ basename /usr/local/bin/\n" \
+       "bin\n" \
+       "$ basename /foo/bar.txt .txt\n" \
+       "bar"
+
+#define cat_trivial_usage \
+       "[FILE]..."
+#define cat_full_usage \
+       "Concatenates FILE(s) and prints them to stdout."
+#define cat_example_usage \
+       "$ cat /proc/uptime\n" \
+       "110716.72 17.67"
+
+#define chgrp_trivial_usage \
+       "[OPTION]... GROUP FILE..."
+#define chgrp_full_usage \
+       "Change the group membership of each FILE to GROUP.\n" \
+       "\nOptions:\n" \
+       "\t-R\tChanges files and directories recursively."
+#define chgrp_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
+       "$ chgrp root /tmp/foo\n" \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo\n"
+
+#define chmod_trivial_usage \
+       "[-R] MODE[,MODE]... FILE..."
+#define chmod_full_usage \
+       "Each MODE is one or more of the letters ugoa, one of the\n" \
+       "symbols +-= and one or more of the letters rwxst.\n\n" \
+       "Options:\n" \
+       "\t-R\tChanges files and directories recursively."
+#define chmod_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n" \
+       "$ chmod u+x /tmp/foo\n" \
+       "$ ls -l /tmp/foo\n" \
+       "-rwxrw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo*\n" \
+       "$ chmod 444 /tmp/foo\n" \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
+
+#define chown_trivial_usage \
+       "[ -Rh ]...  OWNER[<.|:>[GROUP]] FILE..."
+#define chown_full_usage \
+       "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
+       "\nOptions:\n" \
+       "\t-R\tChanges files and directories recursively.\n" \
+       "\t-h\tDo not dereference symbolic links."
+#define chown_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
+       "$ chown root /tmp/foo\n" \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 root     andersen        0 Apr 12 18:25 /tmp/foo\n" \
+       "$ chown root.root /tmp/foo\n" \
+       "ls -l /tmp/foo\n" \
+       "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
+
+#define chroot_trivial_usage \
+       "NEWROOT [COMMAND...]"
+#define chroot_full_usage \
+       "Run COMMAND with root directory set to NEWROOT."
+#define chroot_example_usage \
+       "$ ls -l /bin/ls\n" \
+       "lrwxrwxrwx    1 root     root          12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \
+       "$ mount /dev/hdc1 /mnt -t minix\n" \
+       "$ chroot /mnt\n" \
+       "$ ls -l /bin/ls\n" \
+       "-rwxr-xr-x    1 root     root        40816 Feb  5 07:45 /bin/ls*\n"
+
+#define chvt_trivial_usage \
+       "N"
+#define chvt_full_usage \
+       "Changes the foreground virtual terminal to /dev/ttyN"
+
+#define clear_trivial_usage \
+       ""
+#define clear_full_usage \
+       "Clear screen."
+
+#define cmp_trivial_usage \
+       "FILE1 [FILE2]"
+#define cmp_full_usage \
+       "\t-s\tquiet mode - do not print\n" \
+       "Compare files."
+
+#define cp_trivial_usage \
+       "[OPTION]... SOURCE DEST"
+#define cp_full_usage \
+       "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
+       "\n" \
+       "\t-a\tSame as -dpR\n" \
+       "\t-d\tPreserves links\n" \
+       "\t-p\tPreserves file attributes if possible\n" \
+       "\t-f\tforce (implied; ignored) - always set\n" \
+       "\t-R\tCopies directories recursively"
+
+#define cpio_trivial_usage \
+       "-[dimtuv][F cpiofile]"
+#define cpio_full_usage \
+       "Extract or list files from a cpio archive\n" \
+       "Main operation mode:\n" \
+       "\td\t\tmake leading directories\n" \
+       "\ti\t\textract\n" \
+       "\tm\t\tpreserve mtime\n" \
+       "\tt\t\tlist\n" \
+       "\tu\t\tunconditional overwrite\t" \
+       "\tF\t\tinput from file\t"
+       
+#define cut_trivial_usage \
+       "[OPTION]... [FILE]..."
+#define cut_full_usage \
+       "Prints selected fields from each input FILE to standard output.\n\n" \
+       "Options:\n" \
+       "\t-b LIST\t\tOutput only bytes from LIST\n" \
+       "\t-c LIST\t\tOutput only characters from LIST\n" \
+       "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \
+       "\t-s\t\tOutput only the lines containing delimiter\n" \
+       "\t-f N\t\tPrint only these fields\n" \
+       "\t-n\t\tIgnored"
+#define cut_example_usage \
+       "$ echo "Hello world" | cut -f 1 -d ' '\n" \
+       "Hello\n" \
+       "$ echo "Hello world" | cut -f 2 -d ' '\n" \
+       "world\n"
+
+#define date_trivial_usage \
+       "[OPTION]... [+FORMAT]"
+#define date_full_usage \
+       "Displays the current time in the given FORMAT, or sets the system date.\n" \
+       "\nOptions:\n" \
+       "\t-R\t\tOutputs RFC-822 compliant date string\n" \
+       "\t-d STRING\tdisplay time described by STRING, not `now'\n" \
+       "\t-s\t\tSets time described by STRING\n" \
+       "\t-u\t\tPrints or sets Coordinated Universal Time"
+#define date_example_usage \
+       "$ date\n" \
+       "Wed Apr 12 18:52:41 MDT 2000\n"
+
+#define dc_trivial_usage \
+       "expression ..."
+#define dc_full_usage \
+       "This is a Tiny RPN calculator that understands the\n" \
+       "following operations: +, -, /, *, and, or, not, eor.\n" \
+       "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16"
+#define dc_example_usage \
+       "$ dc 2 2 +\n" \
+       "4\n" \
+       "$ dc 8 8 \* 2 2 + /\n" \
+       "16\n" \
+       "$ dc 0 1 and\n" \
+       "0\n" \
+       "$ dc 0 1 or\n" \
+       "1\n" \
+       "$ echo 72 9 div 8 mul | dc\n" \
+       "64\n"
+
+#define dd_trivial_usage \
+       "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \
+       "\t  [seek=N] [conv=notrunc|noerror|sync]"
+#define dd_full_usage \
+       "Copy a file, converting and formatting according to options\n\n" \
+       "\tif=FILE\t\tread from FILE instead of stdin\n" \
+       "\tof=FILE\t\twrite to FILE instead of stdout\n" \
+       "\tbs=N\t\tread and write N bytes at a time\n" \
+       "\tcount=N\t\tcopy only N input blocks\n" \
+       "\tskip=N\t\tskip N input blocks\n" \
+       "\tseek=N\t\tskip N output blocks\n" \
+       "\tconv=notrunc\tdon't truncate output file\n" \
+       "\tconv=noerror\tcontinue after read errors\n" \
+       "\tconv=sync\tpad blocks with zeros\n" \
+       "\n" \
+       "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
+       "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
+#define dd_example_usage \
+       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
+       "4+0 records in\n" \
+       "4+0 records out\n"
+
+#define deallocvt_trivial_usage \
+       "N"
+#define deallocvt_full_usage \
+        "Deallocate unused virtual terminal /dev/ttyN"
+
+
+#ifdef BB_FEATURE_HUMAN_READABLE
+  #define USAGE_HUMAN_READABLE(a) a
+  #define USAGE_NOT_HUMAN_READABLE(a)
+#else
+  #define USAGE_HUMAN_READABLE(a) 
+  #define USAGE_NOT_HUMAN_READABLE(a) a
+#endif
+#define df_trivial_usage \
+       "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
+#define df_full_usage \
+       "Print the filesystem space used and space available.\n\n" \
+       "Options:\n" \
+       USAGE_HUMAN_READABLE( \
+       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
+       "\t-m\tprint sizes in megabytes\n" \
+       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
+       "\n\t-k\tprint sizes in kilobytes(compatibility)")
+#define df_example_usage \
+       "$ df\n" \
+       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
+       "/dev/sda3              8690864   8553540    137324  98% /\n" \
+       "/dev/sda1                64216     36364     27852  57% /boot\n" \
+       "$ df /dev/sda3\n" \
+       "Filesystem           1k-blocks      Used Available Use% Mounted on\n" \
+       "/dev/sda3              8690864   8553540    137324  98% /\n"
+
+#define dirname_trivial_usage \
+       "[FILENAME ...]"
+#define dirname_full_usage \
+       "Strips non-directory suffix from FILENAME"
+#define dirname_example_usage \
+       "$ dirname /tmp/foo\n" \
+       "/tmp\n" \
+       "$ dirname /tmp/foo/\n" \
+       "/tmp\n"
+
+#define dmesg_trivial_usage \
+       "[-c] [-n LEVEL] [-s SIZE]"
+#define dmesg_full_usage \
+       "Prints or controls the kernel ring buffer\n\n" \
+       "Options:\n" \
+       "\t-c\t\tClears the ring buffer's contents after printing\n" \
+       "\t-n LEVEL\tSets console logging level\n" \
+       "\t-s SIZE\t\tUse a buffer of size SIZE"
+
+#define dos2unix_trivial_usage \
+       "[option] [FILE]"
+#define dos2unix_full_usage \
+       "Converts FILE from dos format to unix format.  When no option\n" \
+       "is given, the input is converted to the opposite output format.\n" \
+       "When no file is given, uses stdin for input and stdout for output.\n\n" \
+       "Options:\n" \
+       "\t-u\toutput will be in UNIX format\n" \
+       "\t-d\toutput will be in DOS format"
+
+#define dpkg_trivial_usage \
+       "-i package_file\n" \
+       "[-CPru] package_name"
+#define dpkg_full_usage \
+       "\t-i\tInstall the package\n" \
+       "\t-C\tConfigure an unpackaged package\n" \
+       "\t-P\tPurge all files of a package\n" \
+       "\t-r\tRemove all but the configuration files for a package\n" \
+       "\t-u\tUnpack a package, but dont configure it\n"
+
+#define dpkg_deb_trivial_usage \
+       "[-cefItxX] FILE [argument]"
+#define dpkg_deb_full_usage \
+       "Perform actions on debian packages (.debs)\n\n" \
+       "Options:\n" \
+       "\t-c\tList contents of filesystem tree\n" \
+       "\t-e\tExtract control files to [argument] directory\n" \
+       "\t-f\tDisplay control field name starting with [argument]\n" \
+       "\t-I\tDisplay the control filenamed [argument]\n" \
+       "\t-t\tExtract filesystem tree to stdout in tar format\n" \
+       "\t-x\tExtract packages filesystem tree to directory\n" \
+       "\t-X\tVerbose extract"
+#define dpkg_deb_example_usage \
+       "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
+
+#define du_trivial_usage \
+       "[-lsx" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..."
+#define du_full_usage \
+       "Summarizes disk space used for each FILE and/or directory.\n" \
+       "Disk space is printed in units of 1024 bytes.\n\n" \
+       "Options:\n" \
+       "\t-l\tcount sizes many times if hard linked\n" \
+       "\t-s\tdisplay only a total for each argument" \
+       USAGE_HUMAN_READABLE( \
+       "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
+       "\t-m\tprint sizes in megabytes\n" \
+       "\t-x\tskip directories on different filesystems\n" \
+       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
+       "\n\t-k\tprint sizes in kilobytes(compatibility)")
+#define du_example_usage \
+       "$ du\n" \
+       "16      ./CVS\n" \
+       "12      ./kernel-patches/CVS\n" \
+       "80      ./kernel-patches\n" \
+       "12      ./tests/CVS\n" \
+       "36      ./tests\n" \
+       "12      ./scripts/CVS\n" \
+       "16      ./scripts\n" \
+       "12      ./docs/CVS\n" \
+       "104     ./docs\n" \
+       "2417    .\n"
+
+#define dumpkmap_trivial_usage \
+       "> keymap"
+#define dumpkmap_full_usage \
+       "Prints out a binary keyboard translation table to standard output."
+#define dumpkmap_example_usage \
+       "$ dumpkmap > keymap\n"
+
+#define dutmp_trivial_usage \
+       "[FILE]"
+#define dutmp_full_usage \
+       "Dump utmp file format (pipe delimited) from FILE\n" \
+       "or stdin to stdout.  (i.e., 'dutmp /var/run/utmp')"
+#define dutmp_example_usage \
+       "$ dutmp /var/run/utmp\n" \
+       "8|7||si|||0|0|0|955637625|760097|0\n" \
+       "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \
+       "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \
+       "8|125||l4|||0|0|0|955637629|998367|0\n" \
+       "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \
+       "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \
+       "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n"
+
+#define echo_trivial_usage \
+       "[-neE] [ARG ...]"
+#define echo_full_usage \
+       "Prints the specified ARGs to stdout\n\n" \
+       "Options:\n" \
+       "\t-n\tsuppress trailing newline\n" \
+       "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
+       "\t-E\tdisable interpretation of backslash-escaped characters"
+#define echo_example_usage \
+       "$ echo "Erik is cool"\n" \
+       "Erik is cool\n" \
+       "$  echo -e "Erik\\nis\\ncool"\n" \
+       "Erik\n" \
+       "is\n" \
+       "cool\n" \
+       "$ echo "Erik\\nis\\ncool"\n" \
+       "Erik\\nis\\ncool\n"
+
+#define env_trivial_usage \
+       "[-iu] [-] [name=value]... [command]"
+#define env_full_usage \
+       "Prints the current environment or runs a program after setting\n" \
+       "up the specified environment.\n\n" \
+       "Options:\n" \
+       "\t-, -i\tstart with an empty environment\n" \
+       "\t-u\tremove variable from the environment\n"
+
+#define expr_trivial_usage \
+       "EXPRESSION"
+#define expr_full_usage \
+       "Prints the value of EXPRESSION to standard output.\n\n" \
+       "EXPRESSION may be:\n" \
+       "\tARG1 |  ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \
+       "\tARG1 &  ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \
+       "\tARG1 <  ARG2 ARG1 is less than ARG2\n" \
+       "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \
+       "\tARG1 =  ARG2 ARG1 is equal to ARG2\n" \
+       "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \
+       "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \
+       "\tARG1 >  ARG2 ARG1 is greater than ARG2\n" \
+       "\tARG1 +  ARG2 arithmetic sum of ARG1 and ARG2\n" \
+       "\tARG1 -  ARG2 arithmetic difference of ARG1 and ARG2\n" \
+       "\tARG1 *  ARG2 arithmetic product of ARG1 and ARG2\n" \
+       "\tARG1 /  ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \
+       "\tARG1 %  ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \
+       "\tSTRING : REGEXP             anchored pattern match of REGEXP in STRING\n" \
+       "\tmatch STRING REGEXP         same as STRING : REGEXP\n" \
+       "\tsubstr STRING POS LENGTH    substring of STRING, POS counted from 1\n" \
+       "\tindex STRING CHARS          index in STRING where any CHARS is found,\n" \
+       "\t                            or 0\n" \
+       "\tlength STRING               length of STRING\n" \
+       "\tquote TOKEN                 interpret TOKEN as a string, even if\n" \
+       "\t                            it is a keyword like `match' or an\n" \
+       "\t                            operator like `/'\n" \
+       "\t( EXPRESSION )              value of EXPRESSION\n\n" \
+       "Beware that many operators need to be escaped or quoted for shells.\n" \
+       "Comparisons are arithmetic if both ARGs are numbers, else\n" \
+       "lexicographical.  Pattern matches return the string matched between \n" \
+       "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
+       "of characters matched or 0."
+
+#define false_trivial_usage \
+       ""
+#define false_full_usage \
+       "Return an exit code of FALSE (1)."
+#define false_example_usage \
+       "$ false\n" \
+       "$ echo $?\n" \
+       "1\n"
+
+#define fbset_trivial_usage \
+       "[options] [mode]"
+#define fbset_full_usage \
+       "Show and modify frame buffer settings"
+#define fbset_example_usage \
+       "$ fbset\n" \
+       "mode "1024x768-76"\n" \
+       "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
+       "\tgeometry 1024 768 1024 768 16\n" \
+       "\ttimings 12714 128 32 16 4 128 4\n" \
+       "\taccel false\n" \
+       "\trgba 5/11,6/5,5/0,0/0\n" \
+       "endmode\n"
+
+#define fdflush_trivial_usage \
+       "DEVICE"
+#define fdflush_full_usage \
+       "Forces floppy disk drive to detect disk change"
+
+#ifdef BB_FEATURE_FIND_TYPE
+  #define USAGE_FIND_TYPE(a) a
+#else
+  #define USAGE_FIND_TYPE(a)
+#endif
+#ifdef BB_FEATURE_FIND_PERM
+  #define USAGE_FIND_PERM(a) a
+#else
+  #define USAGE_FIND_PERM(a)
+#endif
+#ifdef BB_FEATURE_FIND_MTIME
+  #define USAGE_FIND_MTIME(a) a
+#else
+  #define USAGE_FIND_MTIME(a)
+#endif
+#ifdef BB_FEATURE_FIND_NEWER
+  #define USAGE_FIND_NEWER(a) a
+#else
+  #define USAGE_FIND_NEWER(a)
+#endif
+
+#define find_trivial_usage \
+       "[PATH...] [EXPRESSION]"
+#define find_full_usage \
+       "Search for files in a directory hierarchy.  The default PATH is\n" \
+       "the current directory; default EXPRESSION is '-print'\n" \
+       "\nEXPRESSION may consist of:\n" \
+       "\t-follow\t\tDereference symbolic links.\n" \
+       "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
+       "\t-print\t\tPrint (default and assumed).\n" \
+       USAGE_FIND_TYPE( \
+       "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
+) USAGE_FIND_PERM( \
+       "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \
+) USAGE_FIND_MTIME( \
+       "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days"\
+) USAGE_FIND_NEWER( \
+       "\n\t-newer FILE\tModified time is more recent than FILE's")
+#define find_example_usage \
+       "$ find / -name /etc/passwd\n" \
+       "/etc/passwd\n"
+
+#define free_trivial_usage \
+       ""
+#define free_full_usage \
+       "Displays the amount of free and used system memory"
+#define free_example_usage \
+       "$ free\n" \
+       "              total         used         free       shared      buffers\n" \
+       "  Mem:       257628       248724         8904        59644        93124\n" \
+       " Swap:       128516         8404       120112\n" \
+       "Total:       386144       257128       129016\n" \
+
+#define freeramdisk_trivial_usage \
+       "DEVICE"
+#define freeramdisk_full_usage \
+       "Frees all memory used by the specified ramdisk."
+#define freeramdisk_example_usage \
+       "$ freeramdisk /dev/ram2\n"
+
+#define fsck_minix_trivial_usage \
+       "[-larvsmf] /dev/name"
+#define fsck_minix_full_usage \
+       "Performs a consistency check for MINIX filesystems.\n\n" \
+       "Options:\n" \
+       "\t-l\tLists all filenames\n" \
+       "\t-r\tPerform interactive repairs\n" \
+       "\t-a\tPerform automatic repairs\n" \
+       "\t-v\tverbose\n" \
+       "\t-s\tOutputs super-block information\n" \
+       "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
+       "\t-f\tForce file system check."
+
+#define getopt_trivial_usage \
+       "[OPTIONS]..."
+#define getopt_full_usage \
+       "Parse command options\n" \
+       "\t-a, --alternative            Allow long options starting with single -\n" \
+       "\t-l, --longoptions=longopts   Long options to be recognized\n" \
+       "\t-n, --name=progname          The name under which errors are reported\n" \
+       "\t-o, --options=optstring      Short options to be recognized\n" \
+       "\t-q, --quiet                  Disable error reporting by getopt(3)\n" \
+       "\t-Q, --quiet-output           No normal output\n" \
+       "\t-s, --shell=shell            Set shell quoting conventions\n" \
+       "\t-T, --test                   Test for getopt(1) version\n" \
+       "\t-u, --unqote                 Do not quote the output"
+#define getopt_example_usage \
+        "$ cat getopt.test\n" \
+        "#!/bin/sh\n" \
+        "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
+        "       -n 'example.busybox' -- "$@"`\n" \
+        "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
+        "eval set -- "$GETOPT"\n" \
+        "while true ; do\n" \
+        " case $1 in\n" \
+        "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
+        "   -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \
+        "   -c|--c-long)\n" \
+        "     case "$2" in\n" \
+        "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
+        "       *)  echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \
+        "     esac ;;\n" \
+        "   --) shift ; break ;;\n" \
+        "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
+        " esac\n" \
+        "done\n"
+
+#define grep_trivial_usage \
+       "[-ihHnqvs] PATTERN [FILEs...]"
+#define grep_full_usage \
+       "Search for PATTERN in each FILE or standard input.\n\n" \
+       "Options:\n" \
+       "\t-H\tprefix output lines with filename where match was found\n" \
+       "\t-h\tsuppress the prefixing filename on output\n" \
+       "\t-i\tignore case distinctions\n" \
+       "\t-l\tlist names of files that match\n" \
+       "\t-n\tprint line number with output lines\n" \
+       "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \
+       "\t-v\tselect non-matching lines\n" \
+       "\t-s\tsuppress file open/read error messages"
+#define grep_example_usage \
+       "$ grep root /etc/passwd\n" \
+       "root:x:0:0:root:/root:/bin/bash\n" \
+       "$ grep ^[rR]oo. /etc/passwd\n" \
+       "root:x:0:0:root:/root:/bin/bash\n"
+
+#define gunzip_trivial_usage \
+       "[OPTION]... FILE"
+#define gunzip_full_usage \
+       "Uncompress FILE (or standard input if FILE is '-').\n\n" \
+       "Options:\n" \
+       "\t-c\tWrite output to standard output\n" \
+       "\t-t\tTest compressed file integrity"
+#define gunzip_example_usage \
+       "$ ls -la /tmp/BusyBox*\n" \
+       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \
+       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \
+       "$ ls -la /tmp/BusyBox*\n" \
+       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
+
+#define gzip_trivial_usage \
+       "[OPTION]... FILE"
+#define gzip_full_usage \
+       "Compress FILE with maximum compression.\n" \
+       "When FILE is '-', reads standard input.  Implies -c.\n\n" \
+       "Options:\n" \
+       "\t-c\tWrite output to standard output instead of FILE.gz\n" \
+       "\t-d\tdecompress"
+#define gzip_example_usage \
+       "$ ls -la /tmp/busybox*\n" \
+       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n" \
+       "$ gzip /tmp/busybox.tar\n" \
+       "$ ls -la /tmp/busybox*\n" \
+       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
+
+#define halt_trivial_usage \
+       ""
+#define halt_full_usage \
+       "Halt the system."
+
+#define head_trivial_usage \
+       "[OPTION] [FILE]..."
+#define head_full_usage \
+       "Print first 10 lines of each FILE to standard output.\n" \
+       "With more than one FILE, precede each with a header giving the\n" \
+       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
+       "Options:\n" \
+       "\t-n NUM\t\tPrint first NUM lines instead of first 10"
+#define head_example_usage \
+       "$ head -n 2 /etc/passwd\n" \
+       "root:x:0:0:root:/root:/bin/bash\n" \
+       "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
+
+#define hostid_trivial_usage \
+       ""
+#define hostid_full_usage \
+       "Print out a unique 32-bit identifier for the machine."
+
+#define hostname_trivial_usage \
+       "[OPTION] {hostname | -F FILE}"
+#define hostname_full_usage \
+       "Get or set the hostname or DNS domain name. If a hostname is given\n" \
+       "(or FILE with the -F parameter), the host name will be set.\n\n" \
+       "Options:\n" \
+       "\t-s\t\tShort\n" \
+       "\t-i\t\tAddresses for the hostname\n" \
+       "\t-d\t\tDNS domain name\n" \
+       "\t-F, --file FILE\tUse the contents of FILE to specify the hostname"
+#define hostname_example_usage \
+       "$ hostname\n" \
+       "sage \n"
+
+#define id_trivial_usage \
+       "[OPTIONS]... [USERNAME]"
+#define id_full_usage \
+       "Print information for USERNAME or the current user\n\n" \
+       "Options:\n" \
+       "\t-g\tprints only the group ID\n" \
+       "\t-u\tprints only the user ID\n" \
+       "\t-n\tprint a name instead of a number (with for -ug)\n" \
+       "\t-r\tprints the real user ID instead of the effective ID (with -ug)"
+#define id_example_usage \
+       "$ id\n" \
+       "uid=1000(andersen) gid=1000(andersen)\n"
+
+#ifdef BB_FEATURE_IFCONFIG_SLIP
+  #define USAGE_SIOCSKEEPALIVE(a) a
+#else
+  #define USAGE_SIOCSKEEPALIVE(a)
+#endif
+#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+  #define USAGE_IFCONFIG_MII(a) a
+#else
+  #define USAGE_IFCONFIG_MII(a)
+#endif
+#ifdef BB_FEATURE_IFCONFIG_HW
+  #define USAGE_IFCONFIG_HW(a) a
+#else
+  #define USAGE_IFCONFIG_HW(a)
+#endif
+#ifdef BB_FEATURE_IFCONFIG_STATUS
+  #define USAGE_IFCONFIG_OPT_A(a) a
+#else
+  #define USAGE_IFCONFIG_OPT_A(a)
+#endif
+
+#define ifconfig_trivial_usage \
+       USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
+#define ifconfig_full_usage \
+       "configure a network interface\n\n" \
+       "Options:\n" \
+       "\t[[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n" \
+       "\t[netmask <address>]  [dstaddr <address>]\n" \
+       USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
+       "\t" USAGE_IFCONFIG_HW("[hw ether <address>]  ") \
+    "[metric <NN>]  [mtu <NN>]\n" \
+       "\t[[-]trailers]  [[-]arp]  [[-]allmulti]\n" \
+       "\t[multicast]  [[-]promisc]  [txqueuelen <NN>]  [[-]dynamic]\n" \
+       USAGE_IFCONFIG_MII("\t[mem_start <NN>]  [io_addr <NN>]  [irq <NN>]\n") \
+       "\t[up|down] ..."
+
+#define init_trivial_usage \
+       ""
+#define init_full_usage \
+       "Init is the parent of all processes."
+#define init_notes_usage \
+"This version of init is designed to be run only by the kernel.\n" \
+"\n" \
+"BusyBox init doesn't support multiple runlevels.  The runlevels field of\n" \
+"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \
+"runlevels, use sysvinit.\n" \
+"\n" \
+"BusyBox init works just fine without an inittab.  If no inittab is found, \n" \
+"it has the following default behavior:\n" \
+"\n" \
+"      ::sysinit:/etc/init.d/rcS\n" \
+"      ::askfirst:/bin/sh\n" \
+"      ::ctrlaltdel:/sbin/reboot\n" \
+"      ::shutdown:/sbin/swapoff -a\n" \
+"      ::shutdown:/bin/umount -a -r\n" \
+"      ::restart:/sbin/init\n" \
+"\n" \
+"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
+"\n" \
+"      tty2::askfirst:/bin/sh\n" \
+"      tty3::askfirst:/bin/sh\n" \
+"      tty4::askfirst:/bin/sh\n" \
+"\n" \
+"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
+"\n" \
+"      <id>:<runlevels>:<action>:<process>\n" \
+"\n" \
+"      <id>: \n" \
+"\n" \
+"              WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
+"              The id field is used by BusyBox init to specify the controlling tty for\n" \
+"              the specified process to run on.  The contents of this field are\n" \
+"              appended to "/dev/" and used as-is.  There is no need for this field to\n" \
+"              be unique, although if it isn't you may have strange results.  If this\n" \
+"              field is left blank, the controlling tty is set to the console.  Also\n" \
+"              note that if BusyBox detects that a serial console is in use, then only\n" \
+"              entries whose controlling tty is either the serial console or /dev/null\n" \
+"              will be run.  BusyBox init does nothing with utmp.  We don't need no\n" \
+"              stinkin' utmp.\n" \
+"\n" \
+"      <runlevels>: \n" \
+"\n" \
+"              The runlevels field is completely ignored.\n" \
+"\n" \
+"      <action>: \n" \
+"\n" \
+"              Valid actions include: sysinit, respawn, askfirst, wait, \n" \
+"              once, restart, ctrlaltdel, and shutdown.\n" \
+"\n" \
+"              The available actions can be classified into two groups: actions\n" \
+"              that are run only once, and actions that are re-run when the specified\n" \
+"              process exits.\n" \
+"\n" \
+"              Run only-once actions:\n" \
+"\n" \
+"                      'sysinit' is the first item run on boot.  init waits until all\n" \
+"                      sysinit actions are completed before continuing.  Following the\n" \
+"                      completion of all sysinit actions, all 'wait' actions are run.\n" \
+"                      'wait' actions, like  'sysinit' actions, cause init to wait until\n" \
+"                      the specified task completes.  'once' actions are asynchronous,\n" \
+"                      therefore, init does not wait for them to complete.  'restart' is\n" \
+"                      the action taken to restart the init process.  By default this should\n" \
+"                      simply run /sbin/init, but can be a script which runs pivot_root or it\n" \
+"                      can do all sorts of other interesting things.  The 'ctrlaltdel' init\n" \
+"                      actions are run when the system detects that someone on the system\n" \
+"                       console has pressed the CTRL-ALT-DEL key combination.  Typically one\n" \
+"                       wants to run 'reboot' at this point to cause the system to reboot.\n" \
+"                      Finally the 'shutdown' action specifies the actions to taken when\n" \
+"                       init is told to reboot.  Unmounting filesystems and disabling swap\n" \
+"                       is a very good here\n" \
+"\n" \
+"              Run repeatedly actions:\n" \
+"\n" \
+"                      'respawn' actions are run after the 'once' actions.  When a process\n" \
+"                      started with a 'respawn' action exits, init automatically restarts\n" \
+"                      it.  Unlike sysvinit, BusyBox init does not stop processes from\n" \
+"                      respawning out of control.  The 'askfirst' actions acts just like\n" \
+"                      respawn, except that before running the specified process it\n" \
+"                      displays the line "Please press Enter to activate this console."\n" \
+"                      and then waits for the user to press enter before starting the\n" \
+"                      specified process.  \n" \
+"\n" \
+"              Unrecognized actions (like initdefault) will cause init to emit an\n" \
+"              error message, and then go along with its business.  All actions are\n" \
+"              run in the order they appear in /etc/inittab.\n" \
+"\n" \
+"      <process>: \n" \
+"\n" \
+"              Specifies the process to be executed and it's command line.\n" \
+"\n" \
+"Example /etc/inittab file:\n" \
+"\n" \
+"      # This is run first except when booting in single-user mode.\n" \
+"      #\n" \
+"      ::sysinit:/etc/init.d/rcS\n" \
+"      \n" \
+"      # /bin/sh invocations on selected ttys\n" \
+"      #\n" \
+"      # Start an "askfirst" shell on the console (whatever that may be)\n" \
+"      ::askfirst:-/bin/sh\n" \
+"      # Start an "askfirst" shell on /dev/tty2-4\n" \
+"      tty2::askfirst:-/bin/sh\n" \
+"      tty3::askfirst:-/bin/sh\n" \
+"      tty4::askfirst:-/bin/sh\n" \
+"      \n" \
+"      # /sbin/getty invocations for selected ttys\n" \
+"      #\n" \
+"      tty4::respawn:/sbin/getty 38400 tty4\n" \
+"      tty5::respawn:/sbin/getty 38400 tty5\n" \
+"      \n" \
+"      \n" \
+"      # Example of how to put a getty on a serial line (for a terminal)\n" \
+"      #\n" \
+"      #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
+"      #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
+"      #\n" \
+"      # Example how to put a getty on a modem line.\n" \
+"      #::respawn:/sbin/getty 57600 ttyS2\n" \
+"      \n" \
+"      # Stuff to do when restarting the init process\n" \
+"      ::restart:/sbin/init\n" \
+"      \n" \
+"      # Stuff to do before rebooting\n" \
+"      ::ctrlaltdel:/sbin/reboot\n" \
+"      ::shutdown:/bin/umount -a -r\n" \
+"      ::shutdown:/sbin/swapoff -a\n"
+
+#define insmod_trivial_usage \
+       "[OPTION]... MODULE [symbol=value]..."
+#define insmod_full_usage \
+       "Loads the specified kernel modules into the kernel.\n\n" \
+       "Options:\n" \
+       "\t-f\tForce module to load into the wrong kernel version.\n" \
+       "\t-k\tMake module autoclean-able.\n" \
+       "\t-v\tverbose output\n"  \
+       "\t-L\tLock to prevent simultaneous loads of a module\n" \
+       "\t-x\tdo not export externs"
+
+#define kill_trivial_usage \
+       "[-signal] process-id [process-id ...]"
+#define kill_full_usage \
+       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
+       "Options:\n" \
+       "\t-l\tList all signal names and numbers."
+#define kill_example_usage \
+       "$ ps | grep apache\n" \
+       "252 root     root     S [apache]\n" \
+       "263 www-data www-data S [apache]\n" \
+       "264 www-data www-data S [apache]\n" \
+       "265 www-data www-data S [apache]\n" \
+       "266 www-data www-data S [apache]\n" \
+       "267 www-data www-data S [apache]\n" \
+       "$ kill 252\n"
+
+#define killall_trivial_usage \
+       "[-signal] process-name [process-name ...]"
+#define killall_full_usage \
+       "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
+       "Options:\n" \
+       "\t-l\tList all signal names and numbers."
+#define killall_example_usage \
+       "$ killall apache\n" 
+
+#define klogd_trivial_usage \
+       "-n"
+#define klogd_full_usage \
+       "Kernel logger.\n"\
+       "Options:\n"\
+       "\t-n\tRun as a foreground process."
+
+#define length_trivial_usage \
+       "STRING"
+#define length_full_usage \
+       "Prints out the length of the specified STRING."
+#define length_example_usage \
+       "$ length Hello\n" \
+       "5\n"
+
+#define ln_trivial_usage \
+       "[OPTION] TARGET... LINK_NAME|DIRECTORY"
+#define ln_full_usage \
+       "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
+       "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
+       "Options:\n" \
+       "\t-s\tmake symbolic links instead of hard links\n" \
+       "\t-f\tremove existing destination files\n" \
+       "\t-n\tno dereference symlinks - treat like normal file"
+#define ln_example_usage \
+       "$ ln -s BusyBox /tmp/ls\n" \
+       "$ ls -l /tmp/ls\n" \
+       "lrwxrwxrwx    1 root     root            7 Apr 12 18:39 ls -> BusyBox*\n" 
+
+#define loadacm_trivial_usage \
+       "< mapfile"
+#define loadacm_full_usage \
+       "Loads an acm from standard input."
+#define loadacm_example_usage \
+       "$ loadacm < /etc/i18n/acmname\n" 
+
+#define loadfont_trivial_usage \
+       "< font"
+#define loadfont_full_usage \
+       "Loads a console font from standard input."
+#define loadfont_example_usage \
+       "$ loadfont < /etc/i18n/fontname\n" 
+
+#define loadkmap_trivial_usage \
+       "< keymap"
+#define loadkmap_full_usage \
+       "Loads a binary keyboard translation table from standard input."
+#define loadkmap_example_usage \
+       "$ loadkmap < /etc/i18n/lang-keymap\n" 
+
+#define logger_trivial_usage \
+       "[OPTION]... [MESSAGE]"
+#define logger_full_usage \
+       "Write MESSAGE to the system log.  If MESSAGE is omitted, log stdin.\n\n" \
+       "Options:\n" \
+       "\t-s\tLog to stderr as well as the system log.\n" \
+       "\t-t\tLog using the specified tag (defaults to user name).\n" \
+       "\t-p\tEnter the message with the specified priority.\n" \
+       "\t\tThis may be numerical or a ``facility.level'' pair."
+#define logger_example_usage \
+       "$ logger "hello"\n" 
+
+#define logname_trivial_usage \
+       ""
+#define logname_full_usage \
+       "Print the name of the current user."
+#define logname_example_usage \
+       "$ logname\n" \
+       "root\n" 
+
+#define logread_trivial_usage \
+        ""
+
+#define logread_full_usage \
+        "Shows the messages from syslogd (using circular buffer)."
+
+#define losetup_trivial_usage \
+       "[OPTION]... LOOPDEVICE [FILE]"
+#define losetup_full_usage \
+       "Associate LOOPDEVICE with FILE.\n\n" \
+       "Options:\n" \
+       "\t-d\t\tDisassociate LOOPDEVICE.\n" \
+       "\t-o OFFSET\tStart OFFSET bytes into FILE.\n"
+
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+  #define USAGE_LS_TIMESTAMPS(a) a
+#else
+  #define USAGE_LS_TIMESTAMPS(a)
+#endif
+#ifdef BB_FEATURE_LS_FILETYPES
+  #define USAGE_LS_FILETYPES(a) a
+#else
+  #define USAGE_LS_FILETYPES(a)
+#endif
+#ifdef BB_FEATURE_LS_FOLLOWLINKS
+  #define USAGE_LS_FOLLOWLINKS(a) a
+#else
+  #define USAGE_LS_FOLLOWLINKS(a)
+#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+  #define USAGE_LS_RECURSIVE(a) a
+#else
+  #define USAGE_LS_RECURSIVE(a)
+#endif
+#ifdef BB_FEATURE_LS_SORTFILES
+  #define USAGE_LS_SORTFILES(a) a
+#else
+  #define USAGE_LS_SORTFILES(a)
+#endif
+#ifdef BB_FEATURE_AUTOWIDTH
+  #define USAGE_AUTOWIDTH(a) a
+#else
+  #define USAGE_AUTOWIDTH(a)
+#endif
+#define ls_trivial_usage \
+       "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]"
+#define ls_full_usage \
+       "List directory contents\n\n" \
+       "Options:\n" \
+       "\t-1\tlist files in a single column\n" \
+       "\t-A\tdo not list implied . and ..\n" \
+       "\t-a\tdo not hide entries starting with .\n" \
+       "\t-C\tlist entries by columns\n" \
+       USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \
+       "\t-d\tlist directory entries instead of contents\n" \
+       USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \
+       USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \
+       "\t-i\tlist the i-node for each file\n" \
+       "\t-l\tuse a long listing format\n" \
+       "\t-n\tlist numeric UIDs and GIDs instead of names\n" \
+       USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \
+       USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \
+       USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \
+       USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \
+       USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \
+       "\t-s\tlist the size of each file, in blocks\n" \
+       USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \
+       USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \
+       USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \
+       USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \
+       USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \
+       "\t-x\tlist entries by lines instead of by columns\n" \
+       USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \
+       USAGE_HUMAN_READABLE( \
+       "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \
+       "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \
+       "\t-k\tprint sizes in kilobytes(compatibility)") 
+
+#define lsmod_trivial_usage \
+       ""
+#define lsmod_full_usage \
+       "List the currently loaded kernel modules."
+
+#define makedevs_trivial_usage \
+       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
+#define makedevs_full_usage \
+       "Creates a range of block or character special files\n\n" \
+       "TYPEs include:\n" \
+       "\tb:\tMake a block (buffered) device.\n" \
+       "\tc or u:\tMake a character (un-buffered) device.\n" \
+       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
+       "FIRST specifies the number appended to NAME to create the first device.\n" \
+       "LAST specifies the number of the last item that should be created.\n" \
+       "If 's' is the last argument, the base device is created as well.\n\n" \
+       "For example:\n" \
+       "\tmakedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63\n" \
+       "\tmakedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8"
+#define makedevs_example_usage \
+       "$ makedevs /dev/ttyS c 4 66 2 63\n" \
+       "[creates ttyS2-ttyS63]\n" \
+       "$ makedevs /dev/hda b 3 0 0 8 s\n" \
+       "[creates hda,hda1-hda8]\n" 
+
+#define md5sum_trivial_usage \
+       "[OPTION] [FILE]...\n" \
+       "or: md5sum [OPTION] -c [FILE]"
+#define md5sum_full_usage \
+       "Print or check MD5 checksums.\n\n" \
+       "Options:\n" \
+       "With no FILE, or when FILE is -, read standard input.\n\n" \
+       "\t-b\tread files in binary mode\n" \
+       "\t-c\tcheck MD5 sums against given list\n" \
+       "\t-t\tread files in text mode (default)\n" \
+       "\t-g\tread a string\n" \
+       "\nThe following two options are useful only when verifying checksums:\n" \
+       "\t-s\tdon't output anything, status code shows success\n" \
+       "\t-w\twarn about improperly formated MD5 checksum lines"
+#define md5sum_example_usage \
+       "$ md5sum < busybox\n" \
+       "6fd11e98b98a58f64ff3398d7b324003\n" \
+       "$ md5sum busybox\n" \
+       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
+       "$ md5sum -c -\n" \
+       "6fd11e98b98a58f64ff3398d7b324003  busybox\n" \
+       "busybox: OK\n" \
+       "^D\n"
+
+#define mkdir_trivial_usage \
+       "[OPTION] DIRECTORY..."
+#define mkdir_full_usage \
+       "Create the DIRECTORY(ies) if they do not already exist\n\n" \
+       "Options:\n" \
+       "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \
+       "\t-p\tno error if existing, make parent directories as needed"
+#define mkdir_example_usage \
+       "$ mkdir /tmp/foo\n" \
+       "$ mkdir /tmp/foo\n" \
+       "/tmp/foo: File exists\n" \
+       "$ mkdir /tmp/foo/bar/baz\n" \
+       "/tmp/foo/bar/baz: No such file or directory\n" \
+       "$ mkdir -p /tmp/foo/bar/baz\n" 
+
+#define mkfifo_trivial_usage \
+       "[OPTIONS] name"
+#define mkfifo_full_usage \
+       "Creates a named pipe (identical to 'mknod name p')\n\n" \
+       "Options:\n" \
+       "\t-m\tcreate the pipe using the specified mode (default a=rw)"
+
+#define mkfs_minix_trivial_usage \
+       "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]"
+#define mkfs_minix_full_usage \
+       "Make a MINIX filesystem.\n\n" \
+       "Options:\n" \
+       "\t-c\t\tCheck the device for bad blocks\n" \
+       "\t-n [14|30]\tSpecify the maximum length of filenames\n" \
+       "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \
+       "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \
+       "\t-v\t\tMake a Minix version 2 filesystem"
+
+#define mknod_trivial_usage \
+       "[OPTIONS] NAME TYPE MAJOR MINOR"
+#define mknod_full_usage \
+       "Create a special file (block, character, or pipe).\n\n" \
+       "Options:\n" \
+       "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
+       "TYPEs include:\n" \
+       "\tb:\tMake a block (buffered) device.\n" \
+       "\tc or u:\tMake a character (un-buffered) device.\n" \
+       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
+#define mknod_example_usage \
+       "$ mknod /dev/fd0 b 2 0 \n" \
+       "$ mknod -m 644 /tmp/pipe p\n" 
+
+#define mkswap_trivial_usage \
+       "[-c] [-v0|-v1] device [block-count]"
+#define mkswap_full_usage \
+       "Prepare a disk partition to be used as a swap partition.\n\n" \
+       "Options:\n" \
+       "\t-c\t\tCheck for read-ability.\n" \
+       "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
+       "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
+       "\tblock-count\tNumber of block to use (default is entire partition)."
+
+#define mktemp_trivial_usage \
+       "[-q] TEMPLATE"
+#define mktemp_full_usage \
+       "Creates a temporary file with its name based on TEMPLATE.\n" \
+       "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)."
+#define mktemp_example_usage \
+       "$ mktemp /tmp/temp.XXXXXX\n" \
+       "/tmp/temp.mWiLjM\n" \
+       "$ ls -la /tmp/temp.mWiLjM\n" \
+       "-rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM\n" 
+
+#define modprobe_trivial_usage \
+       "modprobe        [  -adnqv  ] [ -C config ] module [ symbol=value ... ]\n" \
+       "modprobe [ -adnqv ] [ -C config ] [ -t type ] pattern\n" \
+       "modprobe -l [ -C config ] [ -t type ] pattern\n" \
+       "modprobe -c [ -C config ]\n" \
+       "modprobe -r [ -dnv ] [ -C config ] [ module ...]\n" \
+       "modprobe -V\n"
+#define modprobe_full_usage \
+       "Used to load kernel modules and automatically load their dependancies." \
+       "USAGE:\n" \
+       "\tmodprobe      [  -adnqv  ] [ -C config ] module [ symbol=value ... ]\n" \
+       "\tmodprobe [ -adnqv ] [ -C config ] [ -t type ] pattern\n" \
+       "\tmodprobe -l [ -C config ] [ -t type ] pattern\n" \
+       "\tmodprobe -c [ -C config ]\n" \
+       "\tmodprobe -r [ -dnv ] [ -C config ] [ module ...]\n" \
+       "\tmodprobe -V\n" \
+       "\n" \
+       "OPTIONS\n" \
+       "\t-a (*** not supported ***)\n" \
+       "\t   Load all matching modules instead of stopping after\n" \
+       "\t   the first successful loading.\n" \
+       "\n" \
+       "\t-c (*** not supported ***)\n" \
+       "\t   Show the currently used configuration.\n" \
+       "\n" \
+       "\t-d\n" \
+       "\t   Show  information about the internal representation\n" \
+       "\t   of the stack of modules.\n" \
+       "\n" \
+       "\t-k\n" \
+       "\t   Set 'autoclean' on loaded  modules.   Used  by  the\n" \
+       "\t   kernel  when it calls on modprobe to satify a miss­\n" \
+       "\t   ing feature (supplied as a module).  The -q  option\n" \
+       "\t   is implied by -k.  These options will automatically\n" \
+       "\t   be sent to insmod.\n" \
+       "\n" \
+       "\t-l (*** not supported ***)\n" \
+       "\t   List matching modules.\n" \
+       "\n" \
+       "\t-n\n" \
+       "\t   Don't actually perform the action, just  show  what\n" \
+       "\t   would be done.\n" \
+       "\n" \
+       "\t-q\n" \
+       "\t   Do  not  complain about insmod failing to install a\n" \
+       "\t   module.  Continue as  normal,  but  silently,  with\n" \
+       "\t   other  possibilities  for  modprobe  to test.  This\n" \
+       "\t   option will automatically be sent to insmod.\n" \
+       "\n" \
+       "\t-r\n" \
+       "\t   Remove module (stacks) or do  autoclean,  depending\n" \
+       "\t   on  whether  there are any modules mentioned on the\n" \
+       "\t   command line.\n" \
+       "\n" \
+       "\t-s\n" \
+       "\t   Report via syslog instead of stderr.  This  options\n" \
+       "\t   will automatically be sent to insmod.\n" \
+       "\n" \
+       "\t-t type (*** not supported ***)\n" \
+       "\t   Only consider modules of this type (tag).\n" \
+       "\n" \
+       "\t-v\n" \
+       "\t   Print all commands as they are executed.\n" \
+       "\n" \
+       "\t-V\n" \
+       "\t   Show the release version of modprobe.\n" \
+       "\n" \
+       "\t-C configfile (*** not supported ***)\n" \
+       "\t   Use  the  file configfile instead of (the optional)\n" \
+       "\t   /etc/modules.conf  to  specify  the  configuration.\n" \
+       "\t   The  environment  variable  MODULECONF  can also be\n" \
+       "\t   used to select (and override) a different  configu­\n" \
+       "\t   ration  file from the default /etc/modules.conf (or\n" \
+       "\t   /etc/conf.modules (depreciated)).\n"
+#define modprobe_example_usage \
+       "$ modprobe pcnet_cs\n" \
+       "$ modprobe -r pcnet_cs\n"
+
+#define more_trivial_usage \
+       "[FILE ...]"
+#define more_full_usage \
+       "More is a filter for viewing FILE one screenful at a time."
+#define more_example_usage \
+       "$ dmesg | more\n" 
+
+#ifdef BB_FEATURE_MOUNT_LOOP
+  #define USAGE_MOUNT_LOOP(a) a
+#else
+  #define USAGE_MOUNT_LOOP(a)
+#endif
+#ifdef BB_FEATURE_MTAB_SUPPORT
+  #define USAGE_MTAB(a) a
+#else
+  #define USAGE_MTAB(a)
+#endif
+#define mount_trivial_usage \
+       "[flags] DEVICE NODE [-o options,more-options]"
+#define mount_full_usage \
+       "Mount a filesystem\n\n" \
+       "Flags:\n"  \
+       "\t-a:\t\tMount all filesystems in fstab.\n" \
+       USAGE_MTAB( \
+       "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
+       "\t-n:\t\tDon't write a mount table entry.\n" \
+       ) \
+       "\t-o option:\tOne of many filesystem options, listed below.\n" \
+       "\t-r:\t\tMount the filesystem read-only.\n" \
+       "\t-t fs-type:\tSpecify the filesystem type.\n" \
+       "\t-w:\t\tMount for reading and writing (default).\n" \
+       "\n" \
+       "Options for use with the \"-o\" flag:\n" \
+       "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
+       "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
+       "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
+       "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
+       USAGE_MOUNT_LOOP( \
+       "\tloop:\t\tMounts a file via loop device.\n" \
+       ) \
+       "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
+       "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
+       "\tro/rw:\t\tMount for read-only / read-write.\n" \
+       "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
+       "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
+       "You'll have to see the written documentation for those filesystems."
+#define mount_example_usage \
+       "$ mount\n" \
+       "/dev/hda3 on / type minix (rw)\n" \
+       "proc on /proc type proc (rw)\n" \
+       "devpts on /dev/pts type devpts (rw)\n" \
+       "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
+       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" 
+
+#define mt_trivial_usage \
+       "[-f device] opcode value"
+#define mt_full_usage \
+       "Control magnetic tape drive operation\n" \
+       "\nAvailable Opcodes:\n\n" \
+       "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \
+       "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \
+       "ras3 reset retension rew rewoffline seek setblk setdensity\n" \
+       "setpart tell unload unlock weof wset"
+
+#define mv_trivial_usage \
+       "SOURCE DEST\n" \
+       "or: mv SOURCE... DIRECTORY"
+#define mv_full_usage \
+       "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY."
+#define mv_example_usage \
+       "$ mv /tmp/foo /bin/bar\n" 
+
+#define nc_trivial_usage \
+       "[OPTIONS] [IP] [port]" 
+#define nc_full_usage \
+       "Netcat opens a pipe to IP:port\n\n" \
+       "Options:\n" \
+       "\t-l\t\tlisten mode, for inbound connects\n" \
+       "\t-p PORT\t\tlocal port number\n" \
+       "\t-e PROG\t\tprogram to exec after connect (dangerous!)"
+#define nc_example_usage \
+       "$ nc foobar.somedomain.com 25\n" \
+       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
+       "help\n" \
+       "214-Commands supported:\n" \
+       "214-    HELO EHLO MAIL RCPT DATA AUTH\n" \
+       "214     NOOP QUIT RSET HELP\n" \
+       "quit\n" \
+       "221 foobar closing connection\n" 
+
+#define nslookup_trivial_usage \
+       "[HOST] [SERVER]"
+#define nslookup_full_usage \
+       "Queries the nameserver for the IP address of the given HOST\n" \
+       "optionally using a specified DNS server"
+#define nslookup_example_usage \
+       "$ nslookup localhost\n" \
+       "Server:     default\n" \
+       "Address:    default\n" \
+       "\n" \
+       "Name:       debian\n" \
+       "Address:    127.0.0.1\n" 
+
+#define pidof_trivial_usage \
+       "process-name [process-name ...]"
+#define pidof_full_usage \
+       "Lists the PIDs of all processes with names that match the names on the command line"
+#define pidof_example_usage \
+       "$ pidof init\n" \
+       "1\n"
+
+#ifndef BB_FEATURE_FANCY_PING
+#define ping_trivial_usage "host"
+#define ping_full_usage    "Send ICMP ECHO_REQUEST packets to network hosts"
+#else
+#define ping_trivial_usage \
+       "[OPTION]... host"
+#define ping_full_usage \
+       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
+       "Options:\n" \
+       "\t-c COUNT\tSend only COUNT pings.\n" \
+       "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
+       "\t-q\t\tQuiet mode, only displays output at start\n" \
+       "\t\t\tand when finished."
+#endif
+#define ping_example_usage \
+       "$ ping localhost\n" \
+       "PING slag (127.0.0.1): 56 data bytes\n" \
+       "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
+       "\n" \
+       "--- debian ping statistics ---\n" \
+       "1 packets transmitted, 1 packets received, 0% packet loss\n" \
+       "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 
+
+#define pivot_root_trivial_usage \
+       "NEW_ROOT PUT_OLD"
+#define pivot_root_full_usage \
+       "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
+       "the new root file system."
+
+#define poweroff_trivial_usage \
+       ""
+#define poweroff_full_usage \
+       "Halt the system and request that the kernel shut off the power."
+
+#define printf_trivial_usage \
+       "FORMAT [ARGUMENT...]"
+#define printf_full_usage \
+       "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
+       "Where FORMAT controls the output exactly as in C printf."
+#define printf_example_usage \
+       "$ printf "Val=%d\\n" 5\n" \
+       "Val=5\n" 
+
+#define ps_trivial_usage \
+       ""
+#define ps_full_usage \
+       "Report process status\n" \
+       "\nThis version of ps accepts no options."
+#define ps_example_usage \
+       "$ ps\n" \
+       "  PID  Uid      Gid State Command\n" \
+       "    1 root     root     S init\n" \
+       "    2 root     root     S [kflushd]\n" \
+       "    3 root     root     S [kupdate]\n" \
+       "    4 root     root     S [kpiod]\n" \
+       "    5 root     root     S [kswapd]\n" \
+       "  742 andersen andersen S [bash]\n" \
+       "  743 andersen andersen S -bash\n" \
+       "  745 root     root     S [getty]\n" \
+       " 2990 andersen andersen R ps\n"
+
+#define pwd_trivial_usage \
+       ""
+#define pwd_full_usage \
+       "Print the full filename of the current working directory."
+#define pwd_example_usage \
+       "$ pwd\n" \
+       "/root\n"
+
+#define rdate_trivial_usage \
+       "[OPTION] HOST"
+#define rdate_full_usage \
+       "Get and possibly set the system date and time from a remote HOST.\n\n" \
+       "Options:\n" \
+       "\t-s\tSet the system date and time (default).\n" \
+       "\t-p\tPrint the date and time."
+
+#define readlink_trivial_usage \
+       ""
+#define readlink_full_usage \
+       "Read a symbolic link."
+
+#define reboot_trivial_usage \
+       ""
+#define reboot_full_usage \
+       "Reboot the system."
+
+#define renice_trivial_usage \
+       "priority pid [pid ...]"
+#define renice_full_usage \
+       "Changes priority of running processes. Allowed priorities range\n" \
+       "from 20 (the process runs only when nothing else is running) to 0\n" \
+       "(default priority) to -20 (almost nothing else ever gets to run)."
+
+#define reset_trivial_usage \
+       ""
+#define reset_full_usage \
+       "Resets the screen."
+
+#define rm_trivial_usage \
+       "[OPTION]... FILE..."
+#define rm_full_usage \
+       "Remove (unlink) the FILE(s).  You may use '--' to\n" \
+       "indicate that all following arguments are non-options.\n\n" \
+       "Options:\n" \
+       "\t-i\t\talways prompt before removing each destination" \
+       "\t-f\t\tremove existing destinations, never prompt\n" \
+       "\t-r or -R\tremove the contents of directories recursively"
+#define rm_example_usage \
+       "$ rm -rf /tmp/foo\n"
+
+#define rmdir_trivial_usage \
+       "[OPTION]... DIRECTORY..."
+#define rmdir_full_usage \
+       "Remove the DIRECTORY(ies), if they are empty."
+#define rmdir_example_usage \
+       "# rmdir /tmp/foo\n"
+
+#define rmmod_trivial_usage \
+       "[OPTION]... [MODULE]..."
+#define rmmod_full_usage \
+       "Unloads the specified kernel modules from the kernel.\n\n" \
+       "Options:\n" \
+       "\t-a\tTry to remove all unused kernel modules."
+#define rmmod_example_usage \
+       "$ rmmod tulip\n"
+
+#define route_trivial_usage \
+       "[{add|del|flush}]"
+#define route_full_usage \
+       "Edit the kernel's routing tables"
+
+#define rpm2cpio_trivial_usage \
+       "package.rpm"
+#define rpm2cpio_full_usage \
+       "Outputs a cpio archive of the rpm file."
+
+#define sed_trivial_usage \
+       "[-nef] pattern [files...]"
+#define sed_full_usage \
+       "Options:\n" \
+       "\t-n\t\tsuppress automatic printing of pattern space\n" \
+       "\t-e script\tadd the script to the commands to be executed\n" \
+       "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \
+       "\n" \
+       "If no -e or -f is given, the first non-option argument is taken as the\n" \
+       "sed script to interpret. All remaining arguments are names of input\n" \
+       "files; if no input files are specified, then the standard input is read."
+#define sed_example_usage \
+       "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
+       "bar\n"
+
+#define setkeycodes_trivial_usage \
+       "SCANCODE KEYCODE ..."
+#define setkeycodes_full_usage \
+       "Set entries into the kernel's scancode-to-keycode map,\n" \
+       "allowing unusual keyboards to generate usable keycodes.\n\n" \
+       "SCANCODE may be either xx or e0xx (hexadecimal),\n" \
+       "and KEYCODE is given in decimal"
+#define setkeycodes_example_usage \
+       "$ setkeycodes e030 127\n"
+
+#define lash_trivial_usage \
+       "[FILE]...\n" \
+       "or: sh -c command [args]..."
+#define lash_full_usage \
+       "lash: The BusyBox LAme SHell (command interpreter)"
+#define lash_notes_usage \
+"This command does not yet have proper documentation.\n" \
+"\n" \
+"Use lash just as you would use any other shell.  It properly handles pipes,\n" \
+"redirects, job control, can be used as the shell for scripts, and has a\n" \
+"sufficient set of builtins to do what is needed.  It does not (yet) support\n" \
+"Bourne Shell syntax.  If you need things like "if-then-else", "while", and such\n" \
+"use ash or bash.  If you just need a very simple and extremely small shell,\n" \
+"this will do the job."
+
+#define sleep_trivial_usage \
+       "N"
+#define sleep_full_usage \
+       "Pause for N seconds."
+#define sleep_example_usage \
+       "$ sleep 2\n" \
+       "[2 second delay results]\n"
+
+
+#ifdef BB_FEATURE_SORT_UNIQUE
+  #define USAGE_SORT_UNIQUE(a) a
+#else
+  #define USAGE_SORT_UNIQUE(a)
+#endif
+#ifdef BB_FEATURE_SORT_REVERSE
+  #define USAGE_SORT_REVERSE(a) a
+#else
+  #define USAGE_SORT_REVERSE(a)
+#endif
+#define sort_trivial_usage \
+       "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
+#define sort_full_usage \
+       "Sorts lines of text in the specified files\n\n"\
+       "Options:\n" \
+       USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
+       USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
+       "\t-n\tsort numerics"
+#define sort_example_usage \
+       "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
+       "a\n" \
+       "b\n" \
+       "c\n" \
+       "d\n" \
+       "e\n" \
+       "f\n"
+
+#define strings_trivial_usage \
+    "[-afo] [-n length] [file ... ]"
+#define strings_full_usage \
+    "Display printable strings in a binary file." \
+    "\n\nOptions:" \
+    "\n\t-f\tPrecede each string with the name of the file where it was found." \
+    "\n\t-n N\tSpecifies that at least N characters forms a sequence (default 4)" \
+    "\n\t-o\tEach string is preceded by its decimal offset in the file."
+
+#define stty_trivial_usage \
+       "[-a|g] [-F DEVICE] [SETTING]..."
+#define stty_full_usage \
+       "Without arguments, prints baud rate, line discipline," \
+       "\nand deviations from stty sane." \
+       "\n\nOptions:" \
+       "\n\t-F DEVICE\topen device instead of stdin" \
+       "\n\t-a\t\tprint all current settings in human-readable form" \
+       "\n\t-g\t\tprint in stty-readable form" \
+       "\n\t[SETTING]\tsee manpage"
+
+#define swapoff_trivial_usage \
+       "[OPTION] [DEVICE]"
+#define swapoff_full_usage \
+       "Stop swapping virtual memory pages on DEVICE.\n\n" \
+       "Options:\n" \
+       "\t-a\tStop swapping on all swap devices"
+
+#define swapon_trivial_usage \
+       "[OPTION] [DEVICE]"
+#define swapon_full_usage \
+       "Start swapping virtual memory pages on DEVICE.\n\n" \
+       "Options:\n" \
+       "\t-a\tStart swapping on all swap devices"
+
+#define sync_trivial_usage \
+       ""
+#define sync_full_usage \
+       "Write all buffered filesystem blocks to disk."
+
+
+#ifdef BB_FEATURE_REMOTE_LOG
+  #define USAGE_REMOTE_LOG(a) a
+#else
+  #define USAGE_REMOTE_LOG(a)
+#endif
+#define syslogd_trivial_usage \
+       "[OPTION]..."
+#define syslogd_full_usage \
+       "Linux system and kernel logging utility.\n" \
+       "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \
+       "Options:\n" \
+       "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \
+       "\t-n\t\tRun as a foreground process\n" \
+       "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \
+       USAGE_REMOTE_LOG( \
+       "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \
+       "\t-L\t\tLog locally and via network logging (default is network only)")
+#define syslogd_example_usage \
+       "$ syslogd -R masterlog:514\n" \
+       "$ syslogd -R 192.168.1.1:601\n"
+
+
+#ifndef BB_FEATURE_FANCY_TAIL
+  #define USAGE_UNSIMPLE_TAIL(a)
+#else
+  #define USAGE_UNSIMPLE_TAIL(a) a
+#endif
+#define tail_trivial_usage \
+       "[OPTION]... [FILE]..."
+#define tail_full_usage \
+       "Print last 10 lines of each FILE to standard output.\n" \
+       "With more than one FILE, precede each with a header giving the\n" \
+       "file name. With no FILE, or when FILE is -, read standard input.\n\n" \
+       "Options:\n" \
+       USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \
+       "\t-n N[kbm]\tprint last N lines instead of last 10\n" \
+       "\t-f\t\toutput data as the file grows" \
+       USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \
+       "\t-s SEC\t\twait SEC seconds between reads with -f\n" \
+       "\t-v\t\talways output headers giving file names\n\n" \
+       "If the first character of N (bytes or lines) is a '+', output begins with \n" \
+       "the Nth item from the start of each file, otherwise, print the last N items\n" \
+       "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." )
+#define tail_example_usage \
+       "$ tail -n 1 /etc/resolv.conf\n" \
+       "nameserver 10.0.0.1\n"
+
+#ifdef BB_FEATURE_TAR_CREATE
+  #define USAGE_TAR_CREATE(a) a
+#else
+  #define USAGE_TAR_CREATE(a)
+#endif
+#ifdef BB_FEATURE_TAR_EXCLUDE
+  #define USAGE_TAR_EXCLUDE(a) a
+#else
+  #define USAGE_TAR_EXCLUDE(a)
+#endif
+#define tar_trivial_usage \
+       "-[" USAGE_TAR_CREATE("c") "xtvO] " \
+       USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \
+       "[-f TARFILE] [-C DIR] [FILE(s)] ..."
+#define tar_full_usage \
+       "Create, extract, or list files from a tar file.\n\n" \
+       "Options:\n" \
+       USAGE_TAR_CREATE("\tc\t\tcreate\n") \
+       "\tx\t\textract\n" \
+       "\tt\t\tlist\n" \
+       "\nFile selection:\n" \
+       "\tf\t\tname of TARFILE or \"-\" for stdin\n" \
+       "\tO\t\textract to stdout\n" \
+       USAGE_TAR_EXCLUDE( \
+       "\texclude\t\tfile to exclude\n" \
+        "\tX\t\tfile with names to exclude\n" \
+       ) \
+       "\tC\t\tchange to directory DIR before operation\n" \
+       "\tv\t\tverbosely list files processed"
+#define tar_example_usage \
+       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
+       "$ tar -cf /tmp/tarball.tar /usr/local\n"
+
+#define tee_trivial_usage \
+       "[OPTION]... [FILE]..."
+#define tee_full_usage \
+       "Copy standard input to each FILE, and also to standard output.\n\n" \
+       "Options:\n" \
+       "\t-a\tappend to the given FILEs, do not overwrite"
+#define tee_example_usage \
+       "$ echo "Hello" | tee /tmp/foo\n" \
+       "$ cat /tmp/foo\n" \
+       "Hello\n"
+
+#define telnet_trivial_usage \
+       "HOST [PORT]"
+#define telnet_full_usage \
+       "Telnet is used to establish interactive communication with another\n"\
+       "computer over a network using the TELNET protocol."
+
+#define test_trivial_usage \
+       "EXPRESSION\n  or   [ EXPRESSION ]"
+#define test_full_usage \
+       "Checks file types and compares values returning an exit\n" \
+       "code determined by the value of EXPRESSION."
+#define test_example_usage \
+       "$ test 1 -eq 2\n" \
+       "$ echo $?\n" \
+       "1\n" \
+       "$ test 1 -eq 1\n" \
+       "$ echo $? \n" \
+       "0\n" \
+       "$ [ -d /etc ]\n" \
+       "$ echo $?\n" \
+       "0\n" \
+       "$ [ -d /junk ]\n" \
+       "$ echo $?\n" \
+       "1\n"
+
+#ifdef BB_FEATURE_TFTP_GET
+  #define USAGE_TFTP_GET(a) a
+#else
+  #define USAGE_TFTP_GET(a)
+#endif
+#ifdef BB_FEATURE_TFTP_PUT
+  #define USAGE_TFTP_PUT(a) a
+#else
+  #define USAGE_TFTP_PUT(a)
+#endif
+
+#define time_trivial_usage \
+       "[OPTION]... COMMAND [ARGS...]"
+#define time_full_usage \
+       "Runs the program COMMAND with arguments ARGS.  When COMMAND finishes,\n"
+       "COMMAND's resource usage information is displayed\n\n"
+       "Options:\n" \
+       "\t-v\tDisplays verbose resource usage information."
+
+#define tftp_trivial_usage \
+       "[OPTION]... HOST [PORT]"
+#define tftp_full_usage \
+       "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
+       "Options:\n" \
+       "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
+        USAGE_TFTP_GET(        \
+        "\t-g\tGet file.\n" \
+        ) \
+       "\t-l FILE\tTransfer local FILE.\n" \
+        USAGE_TFTP_PUT(        \
+       "\t-p\tPut file.\n" \
+       ) \
+       "\t-r FILE\tTransfer remote FILE.\n"
+
+#define top_trivial_usage \
+       "[-d <seconds>]"
+#define top_full_usage \
+       "top provides an view of processor activity in real time.\n" \
+       "This utility reads the status for all processes in /proc each <seconds>\n" \
+       "and shows the status for however many processes will fit on the screen.\n" \
+       "This utility will not show processes that are started after program startup,\n" \
+       "but it will show the EXIT status for and PIDs that exit while it is running."
+
+#define touch_trivial_usage \
+       "[-c] FILE [FILE ...]"
+#define touch_full_usage \
+       "Update the last-modified date on the given FILE[s].\n\n" \
+       "Options:\n" \
+       "\t-c\tDo not create any files"
+#define touch_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "/bin/ls: /tmp/foo: No such file or directory\n" \
+       "$ touch /tmp/foo\n" \
+       "$ ls -l /tmp/foo\n" \
+       "-rw-rw-r--    1 andersen andersen        0 Apr 15 01:11 /tmp/foo\n" 
+
+#define tr_trivial_usage \
+       "[-cds] STRING1 [STRING2]"
+#define tr_full_usage \
+       "Translate, squeeze, and/or delete characters from\n" \
+       "standard input, writing to standard output.\n\n" \
+       "Options:\n" \
+       "\t-c\ttake complement of STRING1\n" \
+       "\t-d\tdelete input characters coded STRING1\n" \
+       "\t-s\tsqueeze multiple output characters of STRING2 into one character"
+#define tr_example_usage \
+       "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
+       "hello world\n" 
+
+#define traceroute_trivial_usage \
+       "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\
+       [-s src_addr] [-t tos] [-w wait] host [data size]"
+#define traceroute_full_usage \
+       "trace the route ip packets follow going to \"host\"\n" \
+       "Options:\n" \
+       "\t-d\tset SO_DEBUG options to socket\n" \
+       "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
+       "\t-r\tBypass the normal routing tables and send directly to a host\n" \
+       "\t-v\tVerbose output\n" \
+       "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \
+       "\t-p port#\tSet the base UDP port number used in probes\n" \
+       "\t\t(default is 33434)\n" \
+       "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \
+       "\t\t(default is 3)\n" \
+       "\t-s src_addr\tUse the following IP address as the source address\n" \
+       "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
+       "\t\t(default 0)\n" \
+       "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
+       "\t\t(default 3 sec.)."
+
+
+#define true_trivial_usage \
+       ""
+#define true_full_usage \
+       "Return an exit code of TRUE (0)."
+#define true_example_usage \
+       "$ true\n" \
+       "$ echo $?\n" \
+       "0\n"
+
+#define tty_trivial_usage \
+       ""
+#define tty_full_usage \
+       "Print the file name of the terminal connected to standard input.\n\n"\
+       "Options:\n" \
+       "\t-s\tprint nothing, only return an exit status"
+#define tty_example_usage \
+       "$ tty\n" \
+       "/dev/tty2\n"
+
+#ifdef BB_FEATURE_MOUNT_FORCE
+  #define USAGE_MOUNT_FORCE(a) a
+#else
+  #define USAGE_MOUNT_FORCE(a)
+#endif
+#define umount_trivial_usage \
+       "[flags] FILESYSTEM|DIRECTORY"
+#define umount_full_usage \
+       "Unmount file systems\n" \
+       "\nFlags:\n" "\t-a\tUnmount all file systems" \
+       USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \
+       "\n\t-r\tTry to remount devices as read-only if mount is busy" \
+       USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \
+       USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)")
+#define umount_example_usage \
+       "$ umount /dev/hdc1 \n"
+
+#define uname_trivial_usage \
+       "[OPTION]..."
+#define uname_full_usage \
+       "Print certain system information.  With no OPTION, same as -s.\n\n" \
+       "Options:\n" \
+       "\t-a\tprint all information\n" \
+       "\t-m\tthe machine (hardware) type\n" \
+       "\t-n\tprint the machine's network node hostname\n" \
+       "\t-r\tprint the operating system release\n" \
+       "\t-s\tprint the operating system name\n" \
+       "\t-p\tprint the host processor type\n" \
+       "\t-v\tprint the operating system version"
+#define uname_example_usage \
+       "$ uname -a\n" \
+       "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" 
+
+#define uniq_trivial_usage \
+       "[OPTION]... [INPUT [OUTPUT]]"
+#define uniq_full_usage \
+       "Discard all but one of successive identical lines from INPUT\n" \
+       "(or standard input), writing to OUTPUT (or standard output).\n\n" \
+       "Options:\n" \
+       "\t-c\tprefix lines by the number of occurrences\n" \
+       "\t-d\tonly print duplicate lines\n" \
+       "\t-u\tonly print unique lines"
+#define uniq_example_usage \
+       "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \
+       "a\n" \
+       "b\n" \
+       "c\n"
+
+#define unix2dos_trivial_usage \
+       "[option] [FILE]"
+#define unix2dos_full_usage \
+       "Converts FILE from unix format to dos format.  When no option\n" \
+       "is given, the input is converted to the opposite output format.\n" \
+       "When no file is given, uses stdin for input and stdout for output.\n" \
+       "Options:\n" \
+       "\t-u\toutput will be in UNIX format\n" \
+       "\t-d\toutput will be in DOS format"
+
+#define update_trivial_usage \
+       "[options]"
+#define update_full_usage \
+       "Periodically flushes filesystem buffers.\n\n" \
+       "Options:\n" \
+       "\t-S\tforce use of sync(2) instead of flushing\n" \
+       "\t-s SECS\tcall sync this often (default 30)\n" \
+       "\t-f SECS\tflush some buffers this often (default 5)"
+
+#define uptime_trivial_usage \
+       ""
+#define uptime_full_usage \
+       "Display the time since the last boot."
+#define uptime_example_usage \
+       "$ uptime\n" \
+       "  1:55pm  up  2:30, load average: 0.09, 0.04, 0.00\n" 
+
+#define usleep_trivial_usage \
+       "N" 
+#define usleep_full_usage \
+       "Pause for N microseconds."
+#define usleep_example_usage \
+       "$ usleep 1000000\n" \
+       "[pauses for 1 second]\n"
+
+#define uudecode_trivial_usage \
+       "[FILE]..."
+#define uudecode_full_usage \
+       "Uudecode a file that is uuencoded.\n\n" \
+       "Options:\n" \
+       "\t-o FILE\tdirect output to FILE" 
+#define uudecode_example_usage \
+       "$ uudecode -o busybox busybox.uu\n" \
+       "$ ls -l busybox\n" \
+       "-rwxr-xr-x   1 ams      ams        245264 Jun  7 21:35 busybox\n" 
+
+#define uuencode_trivial_usage \
+       "[OPTION] [INFILE] REMOTEFILE"
+#define uuencode_full_usage \
+       "Uuencode a file.\n\n" \
+       "Options:\n" \
+       "\t-m\tuse base64 encoding per RFC1521"
+#define uuencode_example_usage \
+       "$ uuencode busybox busybox\n" \
+       "begin 755 busybox\n" \
+       "<encoded file snipped>\n" \
+       "$ uudecode busybox busybox > busybox.uu\n" \
+       "$\n"
+
+#define vi_trivial_usage \
+       "[OPTION] [FILE]..."
+#define vi_full_usage \
+       "edit FILE.\n\n" \
+       "Options:\n" \
+       "\t-R\tRead-only- do not write to the file." 
+
+#define watchdog_trivial_usage \
+       "DEV"
+#define watchdog_full_usage \
+       "Periodically write to watchdog device DEV"
+
+#define wc_trivial_usage \
+       "[OPTION]... [FILE]..."
+#define wc_full_usage \
+       "Print line, word, and byte counts for each FILE, and a total line if\n" \
+       "more than one FILE is specified.  With no FILE, read standard input.\n\n" \
+       "Options:\n" \
+       "\t-c\tprint the byte counts\n" \
+       "\t-l\tprint the newline counts\n" \
+       "\t-L\tprint the length of the longest line\n" \
+       "\t-w\tprint the word counts"
+#define wc_example_usage \
+       "$ wc /etc/passwd\n" \
+       "     31      46    1365 /etc/passwd\n" 
+
+#define wget_trivial_usage \
+       "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url"
+#define wget_full_usage \
+       "wget retrieves files via HTTP or FTP\n\n" \
+       "Options:\n" \
+       "\t-c\tcontinue retrieval of aborted transfers\n" \
+       "\t-q\tquiet mode - do not print\n" \
+       "\t-P\tSet directory prefix to DIR\n" \
+       "\t-O\tsave to filename ('-' for stdout)"
+
+#define which_trivial_usage \
+       "[COMMAND ...]"
+#define which_full_usage \
+       "Locates a COMMAND."
+#define which_example_usage \
+       "$ which login\n" \
+       "/bin/login\n"
+
+#define whoami_trivial_usage \
+       ""
+#define whoami_full_usage \
+       "Prints the user name associated with the current effective user id."
+
+#define xargs_trivial_usage \
+       "[COMMAND] [ARGS...]"
+#define xargs_full_usage \
+       "Executes COMMAND on every item given by standard input."
+#define xargs_example_usage \
+       "$ ls | xargs gzip\n" \
+       "$ find . -name '*.c' -print | xargs rm\n" 
+
+#define yes_trivial_usage \
+       "[OPTION]... [STRING]..."
+#define yes_full_usage \
+       "Repeatedly outputs a line with all specified STRING(s), or 'y'."
+
+#define zcat_trivial_usage \
+       "FILE"
+#define zcat_full_usage \
+       "Uncompress to stdout."
diff --git a/usleep.c b/usleep.c
new file mode 100644 (file)
index 0000000..6023bf4
--- /dev/null
+++ b/usleep.c
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini usleep implementation for busybox
+ *
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int usleep_main(int argc, char **argv)
+{
+       if ((argc < 2) || (**(argv + 1) == '-')) {
+               show_usage();
+       }
+
+       usleep(atoi(*(++argv)));        /* return void */
+       return EXIT_SUCCESS;
+}
diff --git a/uudecode.c b/uudecode.c
new file mode 100644 (file)
index 0000000..21dc4b2
--- /dev/null
@@ -0,0 +1,353 @@
+/* uudecode.c -- uudecode utility.
+ * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ *
+ * This product is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This product is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this product; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+#include "pwd_grp/pwd.h"
+#include "pwd_grp/grp.h"
+
+/*struct passwd *getpwnam();*/
+
+/* Single character decode.  */
+#define        DEC(Char) (((Char) - ' ') & 077)
+
+static int read_stduu (const char *inname)
+{
+  char buf[2 * BUFSIZ];
+
+  while (1) {
+    int n;
+    char *p;
+
+    if (fgets (buf, sizeof(buf), stdin) == NULL) {
+      error_msg("%s: Short file", inname);
+      return FALSE;
+    }
+    p = buf;
+
+    /* N is used to avoid writing out all the characters at the end of
+       the file.  */
+    n = DEC (*p);
+    if (n <= 0)
+      break;
+    for (++p; n > 0; p += 4, n -= 3) {
+      char ch;
+
+      if (n >= 3) {
+        ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
+        putchar (ch);
+        ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
+        putchar (ch);
+        ch = DEC (p[2]) << 6 | DEC (p[3]);
+        putchar (ch);
+      } else {
+        if (n >= 1) {
+          ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
+          putchar (ch);
+        }
+        if (n >= 2) {
+          ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
+          putchar (ch);
+        }
+      }
+    }
+  }
+
+  if (fgets (buf, sizeof(buf), stdin) == NULL
+      || strcmp (buf, "end\n")) {
+    error_msg("%s: No `end' line", inname);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static int read_base64 (const char *inname)
+{
+  static const char b64_tab[256] = {
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
+    '\177', '\177', '\177', '\76',  '\177', '\177', '\177', '\77',  /*050-057*/
+    '\64',  '\65',  '\66',  '\67',  '\70',  '\71',  '\72',  '\73',  /*060-067*/
+    '\74',  '\75',  '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
+    '\177', '\0',   '\1',   '\2',   '\3',   '\4',   '\5',   '\6',   /*100-107*/
+    '\7',   '\10',  '\11',  '\12',  '\13',  '\14',  '\15',  '\16',  /*110-117*/
+    '\17',  '\20',  '\21',  '\22',  '\23',  '\24',  '\25',  '\26',  /*120-127*/
+    '\27',  '\30',  '\31',  '\177', '\177', '\177', '\177', '\177', /*130-137*/
+    '\177', '\32',  '\33',  '\34',  '\35',  '\36',  '\37',  '\40',  /*140-147*/
+    '\41',  '\42',  '\43',  '\44',  '\45',  '\46',  '\47',  '\50',  /*150-157*/
+    '\51',  '\52',  '\53',  '\54',  '\55',  '\56',  '\57',  '\60',  /*160-167*/
+    '\61',  '\62',  '\63',  '\177', '\177', '\177', '\177', '\177', /*170-177*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
+    '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
+  };
+  unsigned char buf[2 * BUFSIZ];
+
+  while (1) {
+    int last_data = 0;
+    unsigned char *p;
+
+    if (fgets (buf, sizeof(buf), stdin) == NULL) {
+      error_msg("%s: Short file", inname);
+      return FALSE;
+    }
+    p = buf;
+
+    if (memcmp (buf, "====", 4) == 0)
+      break;
+    if (last_data != 0) {
+      error_msg("%s: data following `=' padding character", inname);
+      return FALSE;
+    }
+
+    /* The following implementation of the base64 decoding might look
+       a bit clumsy but I only try to follow the POSIX standard:
+       ``All line breaks or other characters not found in the table
+       [with base64 characters] shall be ignored by decoding
+       software.''  */
+    while (*p != '\n') {
+      char c1, c2, c3;
+
+      while ((b64_tab[*p] & '\100') != 0)
+        if (*p == '\n' || *p++ == '=')
+          break;
+      if (*p == '\n')
+        /* This leaves the loop.  */
+        continue;
+      c1 = b64_tab[*p++];
+
+      while ((b64_tab[*p] & '\100') != 0)
+        if (*p == '\n' || *p++ == '=') {
+          error_msg("%s: illegal line", inname);
+          return FALSE;
+        }
+      c2 = b64_tab[*p++];
+
+      while (b64_tab[*p] == '\177')
+        if (*p++ == '\n') {
+          error_msg("%s: illegal line", inname);
+          return FALSE;
+        }
+      if (*p == '=') {
+        putchar (c1 << 2 | c2 >> 4);
+        last_data = 1;
+        break;
+      }
+      c3 = b64_tab[*p++];
+
+      while (b64_tab[*p] == '\177')
+        if (*p++ == '\n') {
+          error_msg("%s: illegal line", inname);
+          return FALSE;
+        }
+      putchar (c1 << 2 | c2 >> 4);
+      putchar (c2 << 4 | c3 >> 2);
+      if (*p == '=') {
+        last_data = 1;
+        break;
+      }
+      else
+        putchar (c3 << 6 | b64_tab[*p++]);
+    }
+  }
+
+  return TRUE;
+}
+
+static int decode (const char *inname,
+                   const char *forced_outname)
+{
+  struct passwd *pw;
+  register char *p;
+  int mode;
+  char buf[2 * BUFSIZ];
+  char *outname = NULL;
+  int do_base64 = 0;
+  int res;
+  int dofre;
+
+  /* Search for header line.  */
+
+  while (1) {
+    if (fgets (buf, sizeof (buf), stdin) == NULL) {
+      error_msg("%s: No `begin' line", inname);
+      return FALSE;
+    }
+
+    if (strncmp (buf, "begin", 5) == 0) {
+      if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
+        do_base64 = 1;
+        break;
+      } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
+        break;
+    }
+  }
+
+  /* If the output file name is given on the command line this rules.  */
+  dofre = FALSE;
+  if (forced_outname != NULL)
+    outname = (char *) forced_outname;
+  else {
+    /* Handle ~user/file format.  */
+    if (buf[0] != '~')
+      outname = buf;
+    else {
+      p = buf + 1;
+      while (*p != '/')
+        ++p;
+      if (*p == '\0') {
+        error_msg("%s: Illegal ~user", inname);
+        return FALSE;
+      }
+      *p++ = '\0';
+      pw = getpwnam (buf + 1);
+      if (pw == NULL) {
+        error_msg("%s: No user `%s'", inname, buf + 1);
+        return FALSE;
+      }
+      outname = concat_path_file(pw->pw_dir, p);
+      dofre = TRUE;
+    }
+  }
+
+  /* Create output file and set mode.  */
+  if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
+      && (freopen (outname, "w", stdout) == NULL
+         || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
+         )) {
+    perror_msg("%s", outname); /* */
+    if (dofre)
+       free(outname);
+    return FALSE;
+  }
+
+  /* We differenciate decoding standard UU encoding and base64.  A
+     common function would only slow down the program.  */
+
+  /* For each input line:  */
+  if (do_base64)
+      res = read_base64 (inname);
+  else
+       res = read_stduu (inname);
+  if (dofre)
+      free(outname);
+  return res;
+}
+
+int uudecode_main (int argc,
+                   char **argv)
+{
+  int opt;
+  int exit_status;
+  const char *outname;
+  outname = NULL;
+
+  while ((opt = getopt(argc, argv, "o:")) != EOF) {
+    switch (opt) {
+     case 0:
+      break;
+
+     case 'o':
+      outname = optarg;
+      break;
+
+     default:
+      show_usage();
+    }
+  }
+
+  if (optind == argc)
+    exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+  else {
+    exit_status = EXIT_SUCCESS;
+    do {
+      if (freopen (argv[optind], "r", stdin) != NULL) {
+        if (decode (argv[optind], outname) != 0)
+          exit_status = FALSE;
+      } else {
+        perror_msg("%s", argv[optind]);
+        exit_status = EXIT_FAILURE;
+      }
+      optind++;
+    }
+    while (optind < argc);
+  }
+  return(exit_status);
+}
+
+/* Copyright (c) 1983 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. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ */
+
+
diff --git a/uuencode.c b/uuencode.c
new file mode 100644 (file)
index 0000000..fc03740
--- /dev/null
@@ -0,0 +1,180 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *  Copyright (C) 2000 by Glenn McGrath
+ *
+ *  based on the function base64_encode from http.c in wget v1.6
+ *  Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "busybox.h"
+
+/* Conversion table.  for base 64 */
+static char tbl_base64[64] = {
+       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+       'w', 'x', 'y', 'z', '0', '1', '2', '3',
+       '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+static char tbl_std[64] = {
+       '`', '!', '"', '#', '$', '%', '&', '\'',
+       '(', ')', '*', '+', ',', '-', '.', '/',
+       '0', '1', '2', '3', '4', '5', '6', '7',
+       '8', '9', ':', ';', '<', '=', '>', '?',
+       '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+       'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+       'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+       'X', 'Y', 'Z', '[', '\\', ']', '^', '_'
+};
+
+/*
+ * Encode the string S of length LENGTH to base64 format and place it
+ * to STORE.  STORE will be 0-terminated, and must point to a writable
+ * buffer of at least 1+BASE64_LENGTH(length) bytes.
+ * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
+ */
+static void uuencode (const char *s, const char *store, const int length, const char *tbl)
+{
+       int i;
+       unsigned char *p = (unsigned char *)store;
+
+       /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
+       for (i = 0; i < length; i += 3) {
+               *p++ = tbl[s[0] >> 2];
+               *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+               *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+               *p++ = tbl[s[2] & 0x3f];
+               s += 3;
+       }
+       /* Pad the result if necessary...  */
+       if (i == length + 1) {
+               *(p - 1) = '=';
+       }
+       else if (i == length + 2) {
+               *(p - 1) = *(p - 2) = '=';
+       }
+       /* ...and zero-terminate it.  */
+       *p = '\0';
+}
+
+int uuencode_main(int argc, char **argv)
+{
+       const int src_buf_size = 60;    // This *MUST* be a multiple of 3
+       const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
+       RESERVE_BB_BUFFER(src_buf, src_buf_size + 1);
+       RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1);
+       struct stat stat_buf;
+       FILE *src_stream = stdin;
+       char *tbl = tbl_std;
+       size_t size;
+       mode_t mode;
+       int opt;
+       int column = 0;
+       int write_size = 0;
+       int remaining;
+       int buffer_offset = 0;
+
+       while ((opt = getopt(argc, argv, "m")) != -1) {
+               switch (opt) {
+               case 'm':
+                       tbl = tbl_base64;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       switch (argc - optind) {
+               case 2:
+                       src_stream = xfopen(argv[optind], "r");
+                       stat(argv[optind], &stat_buf);
+                       mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+                       if (src_stream == stdout) {
+                               printf("NULL\n");
+                       }
+                       break;
+               case 1:
+                       mode = 0666 & ~umask(0666);
+                       break;
+               default:
+                       show_usage();
+       }
+
+       printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
+
+       while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
+               /* Encode the buffer we just read in */
+               uuencode(src_buf, dst_buf, size, tbl);
+
+               /* Write the buffer to stdout, wrapping at 60 chars.
+                * This looks overly complex, but it gets tricky as
+                * the line has to continue to wrap correctly if we
+                * have to refill the buffer
+                *
+                * Improvments most welcome
+                */
+
+               /* Initialise values for the new buffer */
+               remaining = 4 * ((size + 2) / 3);
+               buffer_offset = 0;
+
+               /* Write the buffer to stdout, wrapping at 60 chars
+                * starting from the column the last buffer ran out
+                */
+               do {
+                       if (remaining > (60 - column)) {
+                               write_size = 60 - column;
+                       }
+                       else if (remaining < 60) {
+                               write_size = remaining;
+                       } else {
+                               write_size = 60;
+                       }
+
+                       /* Setup a new row if required */
+                       if (column == 0) {
+                               putchar('\n');
+                               if (tbl == tbl_std) {
+                                       putchar('M');
+                               }
+                       }
+                       /* Write to the 60th column */
+                       if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) {
+                               perror("Couldnt finish writing");
+                       }
+                       /* Update variables based on last write */
+                       buffer_offset += write_size;
+                       remaining -= write_size;
+                       column += write_size;
+                       if (column % 60 == 0) {
+                               column = 0;
+                       }
+               } while (remaining > 0);
+       }
+       printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
+
+       return(EXIT_SUCCESS);
+}
diff --git a/vi.c b/vi.c
new file mode 100644 (file)
index 0000000..fba5f44
--- /dev/null
+++ b/vi.c
@@ -0,0 +1,3966 @@
+/* vi: set sw=8 ts=8: */
+/*
+ * tiny vi.c: A small 'vi' clone
+ * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static const char vi_Version[] =
+       "$Id: vi.c,v 1.20 2003/12/23 21:26:05 andersen Exp $";
+
+/*
+ * To compile for standalone use:
+ *     gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
+ *       or
+ *     gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c                # include testing features
+ *     strip vi
+ */
+
+/*
+ * Things To Do:
+ *     EXINIT
+ *     $HOME/.exrc  and  ./.exrc
+ *     add magic to search     /foo.*bar
+ *     add :help command
+ *     :map macros
+ *     how about mode lines:   vi: set sw=8 ts=8:
+ *     if mark[] values were line numbers rather than pointers
+ *        it would be easier to change the mark when add/delete lines
+ *     More intelligence in refresh()
+ *     ":r !cmd"  and  "!cmd"  to filter text through an external command
+ *     A true "undo" facility
+ *     An "ex" line oriented mode- maybe using "cmdedit"
+ */
+
+//----  Feature --------------  Bytes to immplement
+#ifdef STANDALONE
+#define vi_main                        main
+#define BB_FEATURE_VI_COLON    // 4288
+#define BB_FEATURE_VI_YANKMARK // 1408
+#define BB_FEATURE_VI_SEARCH   // 1088
+#define BB_FEATURE_VI_USE_SIGNALS      // 1056
+#define BB_FEATURE_VI_DOT_CMD  //  576
+#define BB_FEATURE_VI_READONLY //  128
+#define BB_FEATURE_VI_SETOPTS  //  576
+#define BB_FEATURE_VI_SET      //  224
+#define BB_FEATURE_VI_WIN_RESIZE       //  256  WIN_RESIZE
+// To test editor using CRASHME:
+//    vi -C filename
+// To stop testing, wait until all to text[] is deleted, or
+//    Ctrl-Z and kill -9 %1
+// while in the editor Ctrl-T will toggle the crashme function on and off.
+//#define BB_FEATURE_VI_CRASHME                // randomly pick commands to execute
+#endif                                                 /* STANDALONE */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <regex.h>
+#include <ctype.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#ifndef STANDALONE
+#include "busybox.h"
+#endif                                                 /* STANDALONE */
+
+#ifndef TRUE
+#define TRUE                   ((int)1)
+#define FALSE                  ((int)0)
+#endif                                                 /* TRUE */
+#define MAX_SCR_COLS           BUFSIZ
+
+// Misc. non-Ascii keys that report an escape sequence
+#define VI_K_UP                        128     // cursor key Up
+#define VI_K_DOWN              129     // cursor key Down
+#define VI_K_RIGHT             130     // Cursor Key Right
+#define VI_K_LEFT              131     // cursor key Left
+#define VI_K_HOME              132     // Cursor Key Home
+#define VI_K_END               133     // Cursor Key End
+#define VI_K_INSERT            134     // Cursor Key Insert
+#define VI_K_PAGEUP            135     // Cursor Key Page Up
+#define VI_K_PAGEDOWN          136     // Cursor Key Page Down
+#define VI_K_FUN1              137     // Function Key F1
+#define VI_K_FUN2              138     // Function Key F2
+#define VI_K_FUN3              139     // Function Key F3
+#define VI_K_FUN4              140     // Function Key F4
+#define VI_K_FUN5              141     // Function Key F5
+#define VI_K_FUN6              142     // Function Key F6
+#define VI_K_FUN7              143     // Function Key F7
+#define VI_K_FUN8              144     // Function Key F8
+#define VI_K_FUN9              145     // Function Key F9
+#define VI_K_FUN10             146     // Function Key F10
+#define VI_K_FUN11             147     // Function Key F11
+#define VI_K_FUN12             148     // Function Key F12
+
+static const int YANKONLY = FALSE;
+static const int YANKDEL = TRUE;
+static const int FORWARD = 1;  // code depends on "1"  for array index
+static const int BACK = -1;    // code depends on "-1" for array index
+static const int LIMITED = 0;  // how much of text[] in char_search
+static const int FULL = 1;     // how much of text[] in char_search
+
+static const int S_BEFORE_WS = 1;      // used in skip_thing() for moving "dot"
+static const int S_TO_WS = 2;          // used in skip_thing() for moving "dot"
+static const int S_OVER_WS = 3;                // used in skip_thing() for moving "dot"
+static const int S_END_PUNCT = 4;      // used in skip_thing() for moving "dot"
+static const int S_END_ALNUM = 5;      // used in skip_thing() for moving "dot"
+
+typedef unsigned char Byte;
+
+
+static int editing;            // >0 while we are editing a file
+static int cmd_mode;           // 0=command  1=insert
+static int file_modified;      // buffer contents changed
+static int err_method;         // indicate error with beep or flash
+static int fn_start;           // index of first cmd line file name
+static int save_argc;          // how many file names on cmd line
+static int cmdcnt;             // repetition count
+static fd_set rfds;            // use select() for small sleeps
+static struct timeval tv;      // use select() for small sleeps
+static char erase_char;                // the users erase character
+static int rows, columns;      // the terminal screen is this size
+static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
+static char *SOs, *SOn;                // terminal standout start/normal ESC sequence
+static char *bell;             // terminal bell sequence
+static char *Ceol, *Ceos;      // Clear-end-of-line and Clear-end-of-screen ESC sequence
+static char *CMrc;             // Cursor motion arbitrary destination ESC sequence
+static char *CMup, *CMdown;    // Cursor motion up and down ESC sequence
+static Byte *status_buffer;    // mesages to the user
+static Byte last_input_char;   // last char read from user
+static Byte last_forward_char; // last char searched for with 'f'
+static Byte *cfn;              // previous, current, and next file name
+static Byte *text, *end, *textend;     // pointers to the user data in memory
+static Byte *screen;           // pointer to the virtual screen buffer
+static int screensize;         //            and its size
+static Byte *screenbegin;      // index into text[], of top line on the screen
+static Byte *dot;              // where all the action takes place
+static int tabstop;
+static struct termios term_orig, term_vi;      // remember what the cooked mode was
+
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+static int last_row;           // where the cursor was last moved to
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+static jmp_buf restart;                // catch_sig()
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+static struct winsize winsize; // remember the window size
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+#ifdef BB_FEATURE_VI_DOT_CMD
+static int adding2q;           // are we currently adding user input to q
+static Byte *last_modifying_cmd;       // last modifying cmd for "."
+static Byte *ioq, *ioq_start;  // pointer to string for get_one_char to "read"
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+#if    defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)
+static Byte *modifying_cmds;   // cmds that modify text[]
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_READONLY
+static int vi_readonly, readonly;
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+#ifdef BB_FEATURE_VI_SETOPTS
+static int autoindent;
+static int showmatch;
+static int ignorecase;
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+#ifdef BB_FEATURE_VI_YANKMARK
+static Byte *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
+static int YDreg, Ureg;                // default delete register and orig line for "U"
+static Byte *mark[28];         // user marks points somewhere in text[]-  a-z and previous context ''
+static Byte *context_start, *context_end;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_SEARCH
+static Byte *last_search_pattern;      // last pattern from a '/' or '?' search
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+
+
+static void edit_file(Byte *); // edit one file
+static void do_cmd(Byte);      // execute a command
+static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot
+static Byte *begin_line(Byte *);       // return pointer to cur line B-o-l
+static Byte *end_line(Byte *); // return pointer to cur line E-o-l
+static Byte *dollar_line(Byte *);      // return pointer to just before NL
+static Byte *prev_line(Byte *);        // return pointer to prev line B-o-l
+static Byte *next_line(Byte *);        // return pointer to next line B-o-l
+static Byte *end_screen(void); // get pointer to last char on screen
+static int count_lines(Byte *, Byte *);        // count line from start to stop
+static Byte *find_line(int);   // find begining of line #li
+static Byte *move_to_col(Byte *, int); // move "p" to column l
+static int isblnk(Byte);       // is the char a blank or tab
+static void dot_left(void);    // move dot left- dont leave line
+static void dot_right(void);   // move dot right- dont leave line
+static void dot_begin(void);   // move dot to B-o-l
+static void dot_end(void);     // move dot to E-o-l
+static void dot_next(void);    // move dot to next line B-o-l
+static void dot_prev(void);    // move dot to prev line B-o-l
+static void dot_scroll(int, int);      // move the screen up or down
+static void dot_skip_over_ws(void);    // move dot pat WS
+static void dot_delete(void);  // delete the char at 'dot'
+static Byte *bound_dot(Byte *);        // make sure  text[0] <= P < "end"
+static Byte *new_screen(int, int);     // malloc virtual screen memory
+static Byte *new_text(int);    // malloc memory for text[] buffer
+static Byte *char_insert(Byte *, Byte);        // insert the char c at 'p'
+static Byte *stupid_insert(Byte *, Byte);      // stupidly insert the char c at 'p'
+static Byte find_range(Byte **, Byte **, Byte);        // return pointers for an object
+static int st_test(Byte *, int, int, Byte *);  // helper for skip_thing()
+static Byte *skip_thing(Byte *, int, int, int);        // skip some object
+static Byte *find_pair(Byte *, Byte);  // find matching pair ()  []  {}
+static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole
+static Byte *text_hole_make(Byte *, int);      // at "p", make a 'size' byte hole
+static Byte *yank_delete(Byte *, Byte *, int, int);    // yank text[] into register then delete
+static void show_help(void);   // display some help info
+static void print_literal(Byte *, Byte *);     // copy s to buf, convert unprintable
+static void rawmode(void);     // set "raw" mode on tty
+static void cookmode(void);    // return to "cooked" mode on tty
+static int mysleep(int);       // sleep for 'h' 1/100 seconds
+static Byte readit(void);      // read (maybe cursor) key from stdin
+static Byte get_one_char(void);        // read 1 char from stdin
+static int file_size(Byte *);  // what is the byte size of "fn"
+static int file_insert(Byte *, Byte *, int);
+static int file_write(Byte *, Byte *, Byte *);
+static void place_cursor(int, int, int);
+static void screen_erase();
+static void clear_to_eol(void);
+static void clear_to_eos(void);
+static void standout_start(void);      // send "start reverse video" sequence
+static void standout_end(void);        // send "end reverse video" sequence
+static void flash(int);                // flash the terminal screen
+static void beep(void);                // beep the terminal
+static void indicate_error(char);      // use flash or beep to indicate error
+static void show_status_line(void);    // put a message on the bottom line
+static void psb(char *, ...);  // Print Status Buf
+static void psbs(char *, ...); // Print Status Buf in standout mode
+static void ni(Byte *);                // display messages
+static void edit_status(void); // show file status on status line
+static void redraw(int);       // force a full screen refresh
+static void format_line(Byte*, Byte*, int);
+static void refresh(int);      // update the terminal from screen[]
+
+#ifdef BB_FEATURE_VI_SEARCH
+static Byte *char_search(Byte *, Byte *, int, int);    // search for pattern starting at p
+static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+#ifdef BB_FEATURE_VI_COLON
+static void Hit_Return(void);
+static Byte *get_one_address(Byte *, int *);   // get colon addr, if present
+static Byte *get_address(Byte *, int *, int *);        // get two colon addrs, if present
+static void colon(Byte *);     // execute the "colon" mode cmds
+#endif                                                 /* BB_FEATURE_VI_COLON */
+static Byte *get_input_line(Byte *);   // get input line- use "status line"
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+static void winch_sig(int);    // catch window size changes
+static void suspend_sig(int);  // catch ctrl-Z
+static void alarm_sig(int);    // catch alarm time-outs
+static void catch_sig(int);    // catch ctrl-C
+static void core_sig(int);     // catch a core dump signal
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+#ifdef BB_FEATURE_VI_DOT_CMD
+static void start_new_cmd_q(Byte);     // new queue for command
+static void end_cmd_q();       // stop saving input chars
+#else                                                  /* BB_FEATURE_VI_DOT_CMD */
+#define end_cmd_q()
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+static void window_size_get(int);      // find out what size the window is
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+#ifdef BB_FEATURE_VI_SETOPTS
+static void showmatching(Byte *);      // show the matching pair ()  []  {}
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
+static Byte *string_insert(Byte *, Byte *);    // insert the string at 'p'
+#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
+#ifdef BB_FEATURE_VI_YANKMARK
+static Byte *text_yank(Byte *, Byte *, int);   // save copy of "p" into a register
+static Byte what_reg(void);            // what is letter of current YDreg
+static void check_context(Byte);       // remember context for '' command
+static Byte *swap_context(Byte *);     // goto new context for '' command
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_CRASHME
+static void crash_dummy();
+static void crash_test();
+static int crashme = 0;
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+
+
+extern int vi_main(int argc, char **argv)
+{
+       int c;
+
+#ifdef BB_FEATURE_VI_YANKMARK
+       int i;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+
+       CMrc= "\033[%d;%dH";    // Terminal Crusor motion ESC sequence
+       CMup= "\033[A";         // move cursor up one line, same col
+       CMdown="\n";            // move cursor down one line, same col
+       Ceol= "\033[0K";        // Clear from cursor to end of line
+       Ceos= "\033[0J";        // Clear from cursor to end of screen
+       SOs = "\033[7m";        // Terminal standout mode on
+       SOn = "\033[0m";        // Terminal standout mode off
+       bell= "\007";           // Terminal bell sequence
+#ifdef BB_FEATURE_VI_CRASHME
+       (void) srand((long) getpid());
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+       status_buffer = (Byte *) xmalloc(200);  // hold messages to user
+#ifdef BB_FEATURE_VI_READONLY
+       vi_readonly = readonly = FALSE;
+       if (strncmp(argv[0], "view", 4) == 0) {
+               readonly = TRUE;
+               vi_readonly = TRUE;
+       }
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+#ifdef BB_FEATURE_VI_SETOPTS
+       autoindent = 1;
+       ignorecase = 1;
+       showmatch = 1;
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+#ifdef BB_FEATURE_VI_YANKMARK
+       for (i = 0; i < 28; i++) {
+               reg[i] = 0;
+       }                                       // init the yank regs
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK)
+       modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~";      // cmds modifying text[]
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+
+       //  1-  process $HOME/.exrc file
+       //  2-  process EXINIT variable from environment
+       //  3-  process command line args
+       while ((c = getopt(argc, argv, "hCR")) != -1) {
+               switch (c) {
+#ifdef BB_FEATURE_VI_CRASHME
+               case 'C':
+                       crashme = 1;
+                       break;
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+#ifdef BB_FEATURE_VI_READONLY
+               case 'R':               // Read-only flag
+                       readonly = TRUE;
+                       break;
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       //case 'r':     // recover flag-  ignore- we don't use tmp file
+                       //case 'x':     // encryption flag- ignore
+                       //case 'c':     // execute command first
+                       //case 'h':     // help -- just use default
+               default:
+                       show_help();
+                       return 1;
+               }
+       }
+
+       // The argv array can be used by the ":next"  and ":rewind" commands
+       // save optind.
+       fn_start = optind;      // remember first file name for :next and :rew
+       save_argc = argc;
+
+       //----- This is the main file handling loop --------------
+       if (optind >= argc) {
+               editing = 1;    // 0= exit,  1= one file,  2= multiple files
+               edit_file(0);
+       } else {
+               for (; optind < argc; optind++) {
+                       editing = 1;    // 0=exit, 1=one file, 2+ =many files
+                       if (cfn != 0)
+                               free(cfn);
+                       cfn = (Byte *) strdup(argv[optind]);
+                       edit_file(cfn);
+               }
+       }
+       //-----------------------------------------------------------
+
+       return (0);
+}
+
+static void edit_file(Byte * fn)
+{
+       char c;
+       int cnt, size, ch;
+
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+       char *msg;
+       int sig;
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+#ifdef BB_FEATURE_VI_YANKMARK
+       static Byte *cur_line;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+
+       rawmode();
+       rows = 24;
+       columns = 80;
+       ch= -1;
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+       window_size_get(0);
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+       new_screen(rows, columns);      // get memory for virtual screen
+
+       cnt = file_size(fn);    // file size
+       size = 2 * cnt;         // 200% of file size
+       new_text(size);         // get a text[] buffer
+       screenbegin = dot = end = text;
+       if (fn != 0) {
+               ch= file_insert(fn, text, cnt);
+       }
+       if (ch < 1) {
+               (void) char_insert(text, '\n'); // start empty buf with dummy line
+       }
+       file_modified = FALSE;
+#ifdef BB_FEATURE_VI_YANKMARK
+       YDreg = 26;                     // default Yank/Delete reg
+       Ureg = 27;                      // hold orig line for "U" cmd
+       for (cnt = 0; cnt < 28; cnt++) {
+               mark[cnt] = 0;
+       }                                       // init the marks
+       mark[26] = mark[27] = text;     // init "previous context"
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+
+       err_method = 1;         // flash
+       last_forward_char = last_input_char = '\0';
+       crow = 0;
+       ccol = 0;
+       edit_status();
+
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+       signal(SIGHUP, catch_sig);
+       signal(SIGINT, catch_sig);
+       signal(SIGALRM, alarm_sig);
+       signal(SIGTERM, catch_sig);
+       signal(SIGQUIT, core_sig);
+       signal(SIGILL, core_sig);
+       signal(SIGTRAP, core_sig);
+       signal(SIGIOT, core_sig);
+       signal(SIGABRT, core_sig);
+       signal(SIGFPE, core_sig);
+       signal(SIGBUS, core_sig);
+       signal(SIGSEGV, core_sig);
+#ifdef SIGSYS
+       signal(SIGSYS, core_sig);
+#endif 
+       signal(SIGWINCH, winch_sig);
+       signal(SIGTSTP, suspend_sig);
+       sig = setjmp(restart);
+       if (sig != 0) {
+               msg = "";
+               if (sig == SIGWINCH)
+                       msg = "(window resize)";
+               if (sig == SIGHUP)
+                       msg = "(hangup)";
+               if (sig == SIGINT)
+                       msg = "(interrupt)";
+               if (sig == SIGTERM)
+                       msg = "(terminate)";
+               if (sig == SIGBUS)
+                       msg = "(bus error)";
+               if (sig == SIGSEGV)
+                       msg = "(I tried to touch invalid memory)";
+               if (sig == SIGALRM)
+                       msg = "(alarm)";
+
+               psbs("-- caught signal %d %s--", sig, msg);
+               screenbegin = dot = text;
+       }
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+
+       editing = 1;
+       cmd_mode = 0;           // 0=command  1=insert  2='R'eplace
+       cmdcnt = 0;
+       tabstop = 8;
+       offset = 0;                     // no horizontal offset
+       c = '\0';
+#ifdef BB_FEATURE_VI_DOT_CMD
+       if (last_modifying_cmd != 0)
+               free(last_modifying_cmd);
+       if (ioq_start != NULL)
+               free(ioq_start);
+       ioq = ioq_start = last_modifying_cmd = 0;
+       adding2q = 0;
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+       redraw(FALSE);                  // dont force every col re-draw
+       show_status_line();
+
+       //------This is the main Vi cmd handling loop -----------------------
+       while (editing > 0) {
+#ifdef BB_FEATURE_VI_CRASHME
+               if (crashme > 0) {
+                       if ((end - text) > 1) {
+                               crash_dummy();  // generate a random command
+                       } else {
+                               crashme = 0;
+                               dot =
+                                       string_insert(text, (Byte *) "\n\n#####  Ran out of text to work on.  #####\n\n");      // insert the string
+                               refresh(FALSE);
+                       }
+               }
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+               last_input_char = c = get_one_char();   // get a cmd from user
+#ifdef BB_FEATURE_VI_YANKMARK
+               // save a copy of the current line- for the 'U" command
+               if (begin_line(dot) != cur_line) {
+                       cur_line = begin_line(dot);
+                       text_yank(begin_line(dot), end_line(dot), Ureg);
+               }
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_DOT_CMD
+               // These are commands that change text[].
+               // Remember the input for the "." command
+               if (!adding2q && ioq_start == 0
+                       && strchr((char *) modifying_cmds, c) != NULL) {
+                       start_new_cmd_q(c);
+               }
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+               do_cmd(c);              // execute the user command
+               //
+               // poll to see if there is input already waiting. if we are
+               // not able to display output fast enough to keep up, skip
+               // the display update until we catch up with input.
+               if (mysleep(0) == 0) {
+                       // no input pending- so update output
+                       refresh(FALSE);
+                       show_status_line();
+               }
+#ifdef BB_FEATURE_VI_CRASHME
+               if (crashme > 0)
+                       crash_test();   // test editor variables
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+       }
+       //-------------------------------------------------------------------
+
+       place_cursor(rows, 0, FALSE);   // go to bottom of screen
+       clear_to_eol();         // Erase to end of line
+       cookmode();
+}
+
+static Byte readbuffer[BUFSIZ];
+
+#ifdef BB_FEATURE_VI_CRASHME
+static int totalcmds = 0;
+static int Mp = 85;            // Movement command Probability
+static int Np = 90;            // Non-movement command Probability
+static int Dp = 96;            // Delete command Probability
+static int Ip = 97;            // Insert command Probability
+static int Yp = 98;            // Yank command Probability
+static int Pp = 99;            // Put command Probability
+static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
+char chars[20] = "\t012345 abcdABCD-=.$";
+char *words[20] = { "this", "is", "a", "test",
+       "broadcast", "the", "emergency", "of",
+       "system", "quick", "brown", "fox",
+       "jumped", "over", "lazy", "dogs",
+       "back", "January", "Febuary", "March"
+};
+char *lines[20] = {
+       "You should have received a copy of the GNU General Public License\n",
+       "char c, cm, *cmd, *cmd1;\n",
+       "generate a command by percentages\n",
+       "Numbers may be typed as a prefix to some commands.\n",
+       "Quit, discarding changes!\n",
+       "Forced write, if permission originally not valid.\n",
+       "In general, any ex or ed command (such as substitute or delete).\n",
+       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+       "Please get w/ me and I will go over it with you.\n",
+       "The following is a list of scheduled, committed changes.\n",
+       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+       "Any question about transactions please contact Sterling Huxley.\n",
+       "I will try to get back to you by Friday, December 31.\n",
+       "This Change will be implemented on Friday.\n",
+       "Let me know if you have problems accessing this;\n",
+       "Sterling Huxley recently added you to the access list.\n",
+       "Would you like to go to lunch?\n",
+       "The last command will be automatically run.\n",
+       "This is too much english for a computer geek.\n",
+};
+char *multilines[20] = {
+       "You should have received a copy of the GNU General Public License\n",
+       "char c, cm, *cmd, *cmd1;\n",
+       "generate a command by percentages\n",
+       "Numbers may be typed as a prefix to some commands.\n",
+       "Quit, discarding changes!\n",
+       "Forced write, if permission originally not valid.\n",
+       "In general, any ex or ed command (such as substitute or delete).\n",
+       "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n",
+       "Please get w/ me and I will go over it with you.\n",
+       "The following is a list of scheduled, committed changes.\n",
+       "1.   Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n",
+       "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n",
+       "Any question about transactions please contact Sterling Huxley.\n",
+       "I will try to get back to you by Friday, December 31.\n",
+       "This Change will be implemented on Friday.\n",
+       "Let me know if you have problems accessing this;\n",
+       "Sterling Huxley recently added you to the access list.\n",
+       "Would you like to go to lunch?\n",
+       "The last command will be automatically run.\n",
+       "This is too much english for a computer geek.\n",
+};
+
+// create a random command to execute
+static void crash_dummy()
+{
+       static int sleeptime;   // how long to pause between commands
+       char c, cm, *cmd, *cmd1;
+       int i, cnt, thing, rbi, startrbi, percent;
+
+       // "dot" movement commands
+       cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
+
+       // is there already a command running?
+       if (strlen((char *) readbuffer) > 0)
+               goto cd1;
+  cd0:
+       startrbi = rbi = 0;
+       sleeptime = 0;          // how long to pause between commands
+       memset(readbuffer, '\0', BUFSIZ - 1);   // clear the read buffer
+       // generate a command by percentages
+       percent = (int) lrand48() % 100;        // get a number from 0-99
+       if (percent < Mp) {     //  Movement commands
+               // available commands
+               cmd = cmd1;
+               M++;
+       } else if (percent < Np) {      //  non-movement commands
+               cmd = "mz<>\'\"";       // available commands
+               N++;
+       } else if (percent < Dp) {      //  Delete commands
+               cmd = "dx";             // available commands
+               D++;
+       } else if (percent < Ip) {      //  Inset commands
+               cmd = "iIaAsrJ";        // available commands
+               I++;
+       } else if (percent < Yp) {      //  Yank commands
+               cmd = "yY";             // available commands
+               Y++;
+       } else if (percent < Pp) {      //  Put commands
+               cmd = "pP";             // available commands
+               P++;
+       } else {
+               // We do not know how to handle this command, try again
+               U++;
+               goto cd0;
+       }
+       // randomly pick one of the available cmds from "cmd[]"
+       i = (int) lrand48() % strlen(cmd);
+       cm = cmd[i];
+       if (strchr(":\024", cm))
+               goto cd0;               // dont allow colon or ctrl-T commands
+       readbuffer[rbi++] = cm; // put cmd into input buffer
+
+       // now we have the command-
+       // there are 1, 2, and multi char commands
+       // find out which and generate the rest of command as necessary
+       if (strchr("dmryz<>\'\"", cm)) {        // 2-char commands
+               cmd1 = " \n\r0$^-+wWeEbBhjklHL";
+               if (cm == 'm' || cm == '\'' || cm == '\"') {    // pick a reg[]
+                       cmd1 = "abcdefghijklmnopqrstuvwxyz";
+               }
+               thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+               c = cmd1[thing];
+               readbuffer[rbi++] = c;  // add movement to input buffer
+       }
+       if (strchr("iIaAsc", cm)) {     // multi-char commands
+               if (cm == 'c') {
+                       // change some thing
+                       thing = (int) lrand48() % strlen(cmd1); // pick a movement command
+                       c = cmd1[thing];
+                       readbuffer[rbi++] = c;  // add movement to input buffer
+               }
+               thing = (int) lrand48() % 4;    // what thing to insert
+               cnt = (int) lrand48() % 10;     // how many to insert
+               for (i = 0; i < cnt; i++) {
+                       if (thing == 0) {       // insert chars
+                               readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
+                       } else if (thing == 1) {        // insert words
+                               strcat((char *) readbuffer, words[(int) lrand48() % 20]);
+                               strcat((char *) readbuffer, " ");
+                               sleeptime = 0;  // how fast to type
+                       } else if (thing == 2) {        // insert lines
+                               strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
+                               sleeptime = 0;  // how fast to type
+                       } else {        // insert multi-lines
+                               strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
+                               sleeptime = 0;  // how fast to type
+                       }
+               }
+               strcat((char *) readbuffer, "\033");
+       }
+  cd1:
+       totalcmds++;
+       if (sleeptime > 0)
+               (void) mysleep(sleeptime);      // sleep 1/100 sec
+}
+
+// test to see if there are any errors
+static void crash_test()
+{
+       static time_t oldtim;
+       time_t tim;
+       char d[2], buf[BUFSIZ], msg[BUFSIZ];
+
+       msg[0] = '\0';
+       if (end < text) {
+               strcat((char *) msg, "end<text ");
+       }
+       if (end > textend) {
+               strcat((char *) msg, "end>textend ");
+       }
+       if (dot < text) {
+               strcat((char *) msg, "dot<text ");
+       }
+       if (dot > end) {
+               strcat((char *) msg, "dot>end ");
+       }
+       if (screenbegin < text) {
+               strcat((char *) msg, "screenbegin<text ");
+       }
+       if (screenbegin > end - 1) {
+               strcat((char *) msg, "screenbegin>end-1 ");
+       }
+
+       if (strlen(msg) > 0) {
+               alarm(0);
+               sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
+                       totalcmds, last_input_char, msg, SOs, SOn);
+               write(1, buf, strlen(buf));
+               while (read(0, d, 1) > 0) {
+                       if (d[0] == '\n' || d[0] == '\r')
+                               break;
+               }
+               alarm(3);
+       }
+       tim = (time_t) time((time_t *) 0);
+       if (tim >= (oldtim + 3)) {
+               sprintf((char *) status_buffer,
+                               "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
+                               totalcmds, M, N, I, D, Y, P, U, end - text + 1);
+               oldtim = tim;
+       }
+       return;
+}
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+
+//---------------------------------------------------------------------
+//----- the Ascii Chart -----------------------------------------------
+//
+//  00 nul   01 soh   02 stx   03 etx   04 eot   05 enq   06 ack   07 bel
+//  08 bs    09 ht    0a nl    0b vt    0c np    0d cr    0e so    0f si
+//  10 dle   11 dc1   12 dc2   13 dc3   14 dc4   15 nak   16 syn   17 etb
+//  18 can   19 em    1a sub   1b esc   1c fs    1d gs    1e rs    1f us
+//  20 sp    21 !     22 "     23 #     24 $     25 %     26 &     27 '
+//  28 (     29 )     2a *     2b +     2c ,     2d -     2e .     2f /
+//  30 0     31 1     32 2     33 3     34 4     35 5     36 6     37 7
+//  38 8     39 9     3a :     3b ;     3c <     3d =     3e >     3f ?
+//  40 @     41 A     42 B     43 C     44 D     45 E     46 F     47 G
+//  48 H     49 I     4a J     4b K     4c L     4d M     4e N     4f O
+//  50 P     51 Q     52 R     53 S     54 T     55 U     56 V     57 W
+//  58 X     59 Y     5a Z     5b [     5c \     5d ]     5e ^     5f _
+//  60 `     61 a     62 b     63 c     64 d     65 e     66 f     67 g
+//  68 h     69 i     6a j     6b k     6c l     6d m     6e n     6f o
+//  70 p     71 q     72 r     73 s     74 t     75 u     76 v     77 w
+//  78 x     79 y     7a z     7b {     7c |     7d }     7e ~     7f del
+//---------------------------------------------------------------------
+
+//----- Execute a Vi Command -----------------------------------
+static void do_cmd(Byte c)
+{
+       Byte c1, *p, *q, *msg, buf[9], *save_dot;
+       int cnt, i, j, dir, yf;
+
+       c1 = c;                         // quiet the compiler
+       cnt = yf = dir = 0;     // quiet the compiler
+       p = q = save_dot = msg = buf;   // quiet the compiler
+       memset(buf, '\0', 9);   // clear buf
+       
+       /* if this is a cursor key, skip these checks */
+       switch (c) {
+               case VI_K_UP:
+               case VI_K_DOWN:
+               case VI_K_LEFT:
+               case VI_K_RIGHT:
+               case VI_K_HOME:
+               case VI_K_END:
+               case VI_K_PAGEUP:
+               case VI_K_PAGEDOWN:
+                       goto key_cmd_mode;
+       }
+
+       if (cmd_mode == 2) {
+               // we are 'R'eplacing the current *dot with new char
+               if (*dot == '\n') {
+                       // don't Replace past E-o-l
+                       cmd_mode = 1;   // convert to insert
+               } else {
+                       if (1 <= c && c <= 127) {       // only ASCII chars
+                               if (c != 27)
+                                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
+                               dot = char_insert(dot, c);      // insert new char
+                       }
+                       goto dc1;
+               }
+       }
+       if (cmd_mode == 1) {
+               //  hitting "Insert" twice means "R" replace mode
+               if (c == VI_K_INSERT) goto dc5;
+               // insert the char c at "dot"
+               if (1 <= c && c <= 127) {
+                       dot = char_insert(dot, c);      // only ASCII chars
+               }
+               goto dc1;
+       }
+
+key_cmd_mode:
+       switch (c) {
+               //case 0x01:    // soh
+               //case 0x09:    // ht
+               //case 0x0b:    // vt
+               //case 0x0e:    // so
+               //case 0x0f:    // si
+               //case 0x10:    // dle
+               //case 0x11:    // dc1
+               //case 0x13:    // dc3
+#ifdef BB_FEATURE_VI_CRASHME
+       case 0x14:                      // dc4  ctrl-T
+               crashme = (crashme == 0) ? 1 : 0;
+               break;
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+               //case 0x16:    // syn
+               //case 0x17:    // etb
+               //case 0x18:    // can
+               //case 0x1c:    // fs
+               //case 0x1d:    // gs
+               //case 0x1e:    // rs
+               //case 0x1f:    // us
+               //case '!':     // !- 
+               //case '#':     // #- 
+               //case '&':     // &- 
+               //case '(':     // (- 
+               //case ')':     // )- 
+               //case '*':     // *- 
+               //case ',':     // ,- 
+               //case '=':     // =- 
+               //case '@':     // @- 
+               //case 'F':     // F- 
+               //case 'K':     // K- 
+               //case 'Q':     // Q- 
+               //case 'S':     // S- 
+               //case 'T':     // T- 
+               //case 'V':     // V- 
+               //case '[':     // [- 
+               //case '\\':    // \- 
+               //case ']':     // ]- 
+               //case '_':     // _- 
+               //case '`':     // `- 
+               //case 'g':     // g- 
+               //case 'u':     // u- FIXME- there is no undo
+               //case 'v':     // v- 
+       default:                        // unrecognised command
+               buf[0] = c;
+               buf[1] = '\0';
+               if (c <= ' ') {
+                       buf[0] = '^';
+                       buf[1] = c + '@';
+                       buf[2] = '\0';
+               }
+               ni((Byte *) buf);
+               end_cmd_q();    // stop adding to q
+       case 0x00:                      // nul- ignore
+               break;
+       case 2:                 // ctrl-B  scroll up   full screen
+       case VI_K_PAGEUP:       // Cursor Key Page Up
+               dot_scroll(rows - 2, -1);
+               break;
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+       case 0x03:                      // ctrl-C   interrupt
+               longjmp(restart, 1);
+               break;
+       case 26:                        // ctrl-Z suspend
+               suspend_sig(SIGTSTP);
+               break;
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+       case 4:                 // ctrl-D  scroll down half screen
+               dot_scroll((rows - 2) / 2, 1);
+               break;
+       case 5:                 // ctrl-E  scroll down one line
+               dot_scroll(1, 1);
+               break;
+       case 6:                 // ctrl-F  scroll down full screen
+       case VI_K_PAGEDOWN:     // Cursor Key Page Down
+               dot_scroll(rows - 2, 1);
+               break;
+       case 7:                 // ctrl-G  show current status
+               edit_status();
+               break;
+       case 'h':                       // h- move left
+       case VI_K_LEFT: // cursor key Left
+       case 8:                 // ctrl-H- move left    (This may be ERASE char)
+       case 127:                       // DEL- move left   (This may be ERASE char)
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_left();
+               break;
+       case 10:                        // Newline ^J
+       case 'j':                       // j- goto next line, same col
+       case VI_K_DOWN: // cursor key Down
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_next();             // go to next B-o-l
+               dot = move_to_col(dot, ccol + offset);  // try stay in same col
+               break;
+       case 12:                        // ctrl-L  force redraw whole screen
+       case 18:                        // ctrl-R  force redraw
+               place_cursor(0, 0, FALSE);      // put cursor in correct place
+               clear_to_eos(); // tel terminal to erase display
+               (void) mysleep(10);
+               screen_erase(); // erase the internal screen buffer
+               refresh(TRUE);  // this will redraw the entire display
+               break;
+       case 13:                        // Carriage Return ^M
+       case '+':                       // +- goto next line
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_next();
+               dot_skip_over_ws();
+               break;
+       case 21:                        // ctrl-U  scroll up   half screen
+               dot_scroll((rows - 2) / 2, -1);
+               break;
+       case 25:                        // ctrl-Y  scroll up one line
+               dot_scroll(1, -1);
+               break;
+       case 27:                        // esc
+               if (cmd_mode == 0)
+                       indicate_error(c);
+               cmd_mode = 0;   // stop insrting
+               end_cmd_q();
+               *status_buffer = '\0';  // clear status buffer
+               break;
+       case ' ':                       // move right
+       case 'l':                       // move right
+       case VI_K_RIGHT:        // Cursor Key Right
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_right();
+               break;
+#ifdef BB_FEATURE_VI_YANKMARK
+       case '"':                       // "- name a register to use for Delete/Yank
+               c1 = get_one_char();
+               c1 = tolower(c1);
+               if (islower(c1)) {
+                       YDreg = c1 - 'a';
+               } else {
+                       indicate_error(c);
+               }
+               break;
+       case '\'':                      // '- goto a specific mark
+               c1 = get_one_char();
+               c1 = tolower(c1);
+               if (islower(c1)) {
+                       c1 = c1 - 'a';
+                       // get the b-o-l
+                       q = mark[(int) c1];
+                       if (text <= q && q < end) {
+                               dot = q;
+                               dot_begin();    // go to B-o-l
+                               dot_skip_over_ws();
+                       }
+               } else if (c1 == '\'') {        // goto previous context
+                       dot = swap_context(dot);        // swap current and previous context
+                       dot_begin();    // go to B-o-l
+                       dot_skip_over_ws();
+               } else {
+                       indicate_error(c);
+               }
+               break;
+       case 'm':                       // m- Mark a line
+               // this is really stupid.  If there are any inserts or deletes
+               // between text[0] and dot then this mark will not point to the
+               // correct location! It could be off by many lines!
+               // Well..., at least its quick and dirty.
+               c1 = get_one_char();
+               c1 = tolower(c1);
+               if (islower(c1)) {
+                       c1 = c1 - 'a';
+                       // remember the line
+                       mark[(int) c1] = dot;
+               } else {
+                       indicate_error(c);
+               }
+               break;
+       case 'P':                       // P- Put register before
+       case 'p':                       // p- put register after
+               p = reg[YDreg];
+               if (p == 0) {
+                       psbs("Nothing in register %c", what_reg());
+                       break;
+               }
+               // are we putting whole lines or strings
+               if (strchr((char *) p, '\n') != NULL) {
+                       if (c == 'P') {
+                               dot_begin();    // putting lines- Put above
+                       }
+                       if (c == 'p') {
+                               // are we putting after very last line?
+                               if (end_line(dot) == (end - 1)) {
+                                       dot = end;      // force dot to end of text[]
+                               } else {
+                                       dot_next();     // next line, then put before
+                               }
+                       }
+               } else {
+                       if (c == 'p')
+                               dot_right();    // move to right, can move to NL
+               }
+               dot = string_insert(dot, p);    // insert the string
+               end_cmd_q();    // stop adding to q
+               break;
+       case 'U':                       // U- Undo; replace current line with original version
+               if (reg[Ureg] != 0) {
+                       p = begin_line(dot);
+                       q = end_line(dot);
+                       p = text_hole_delete(p, q);     // delete cur line
+                       p = string_insert(p, reg[Ureg]);        // insert orig line
+                       dot = p;
+                       dot_skip_over_ws();
+               }
+               break;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+       case '$':                       // $- goto end of line
+       case VI_K_END:          // Cursor Key End
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot = end_line(dot + 1);
+               break;
+       case '%':                       // %- find matching char of pair () [] {}
+               for (q = dot; q < end && *q != '\n'; q++) {
+                       if (strchr("()[]{}", *q) != NULL) {
+                               // we found half of a pair
+                               p = find_pair(q, *q);
+                               if (p == NULL) {
+                                       indicate_error(c);
+                               } else {
+                                       dot = p;
+                               }
+                               break;
+                       }
+               }
+               if (*q == '\n')
+                       indicate_error(c);
+               break;
+       case 'f':                       // f- forward to a user specified char
+               last_forward_char = get_one_char();     // get the search char
+               //
+               // dont seperate these two commands. 'f' depends on ';'
+               //
+               //**** fall thru to ... 'i'
+       case ';':                       // ;- look at rest of line for last forward char
+               if (cmdcnt-- > 1) {
+                       do_cmd(';');
+               }                               // repeat cnt
+               if (last_forward_char == 0) break;
+               q = dot + 1;
+               while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
+                       q++;
+               }
+               if (*q == last_forward_char)
+                       dot = q;
+               break;
+       case '-':                       // -- goto prev line
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_prev();
+               dot_skip_over_ws();
+               break;
+#ifdef BB_FEATURE_VI_DOT_CMD
+       case '.':                       // .- repeat the last modifying command
+               // Stuff the last_modifying_cmd back into stdin
+               // and let it be re-executed.
+               if (last_modifying_cmd != 0) {
+                       ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd);
+               }
+               break;
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+#ifdef BB_FEATURE_VI_SEARCH
+       case '?':                       // /- search for a pattern
+       case '/':                       // /- search for a pattern
+               buf[0] = c;
+               buf[1] = '\0';
+               q = get_input_line(buf);        // get input line- use "status line"
+               if (strlen((char *) q) == 1)
+                       goto dc3;       // if no pat re-use old pat
+               if (strlen((char *) q) > 1) {   // new pat- save it and find
+                       // there is a new pat
+                       if (last_search_pattern != 0) {
+                               free(last_search_pattern);
+                       }
+                       last_search_pattern = (Byte *) strdup((char *) q);
+                       goto dc3;       // now find the pattern
+               }
+               // user changed mind and erased the "/"-  do nothing
+               break;
+       case 'N':                       // N- backward search for last pattern
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dir = BACK;             // assume BACKWARD search
+               p = dot - 1;
+               if (last_search_pattern[0] == '?') {
+                       dir = FORWARD;
+                       p = dot + 1;
+               }
+               goto dc4;               // now search for pattern
+               break;
+       case 'n':                       // n- repeat search for last pattern
+               // search rest of text[] starting at next char
+               // if search fails return orignal "p" not the "p+1" address
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+         dc3:
+               if (last_search_pattern == 0) {
+                       msg = (Byte *) "No previous regular expression";
+                       goto dc2;
+               }
+               if (last_search_pattern[0] == '/') {
+                       dir = FORWARD;  // assume FORWARD search
+                       p = dot + 1;
+               }
+               if (last_search_pattern[0] == '?') {
+                       dir = BACK;
+                       p = dot - 1;
+               }
+         dc4:
+               q = char_search(p, last_search_pattern + 1, dir, FULL);
+               if (q != NULL) {
+                       dot = q;        // good search, update "dot"
+                       msg = (Byte *) "";
+                       goto dc2;
+               }
+               // no pattern found between "dot" and "end"- continue at top
+               p = text;
+               if (dir == BACK) {
+                       p = end - 1;
+               }
+               q = char_search(p, last_search_pattern + 1, dir, FULL);
+               if (q != NULL) {        // found something
+                       dot = q;        // found new pattern- goto it
+                       msg = (Byte *) "search hit BOTTOM, continuing at TOP";
+                       if (dir == BACK) {
+                               msg = (Byte *) "search hit TOP, continuing at BOTTOM";
+                       }
+               } else {
+                       msg = (Byte *) "Pattern not found";
+               }
+         dc2:
+               psbs("%s", msg);
+               break;
+       case '{':                       // {- move backward paragraph
+               q = char_search(dot, (Byte *) "\n\n", BACK, FULL);
+               if (q != NULL) {        // found blank line
+                       dot = next_line(q);     // move to next blank line
+               }
+               break;
+       case '}':                       // }- move forward paragraph
+               q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL);
+               if (q != NULL) {        // found blank line
+                       dot = next_line(q);     // move to next blank line
+               }
+               break;
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+       case '0':                       // 0- goto begining of line
+       case '1':                       // 1- 
+       case '2':                       // 2- 
+       case '3':                       // 3- 
+       case '4':                       // 4- 
+       case '5':                       // 5- 
+       case '6':                       // 6- 
+       case '7':                       // 7- 
+       case '8':                       // 8- 
+       case '9':                       // 9- 
+               if (c == '0' && cmdcnt < 1) {
+                       dot_begin();    // this was a standalone zero
+               } else {
+                       cmdcnt = cmdcnt * 10 + (c - '0');       // this 0 is part of a number
+               }
+               break;
+       case ':':                       // :- the colon mode commands
+               p = get_input_line((Byte *) ":");       // get input line- use "status line"
+#ifdef BB_FEATURE_VI_COLON
+               colon(p);               // execute the command
+#else                                                  /* BB_FEATURE_VI_COLON */
+               if (*p == ':')
+                       p++;                            // move past the ':'
+               cnt = strlen((char *) p);
+               if (cnt <= 0)
+                       break;
+               if (strncasecmp((char *) p, "quit", cnt) == 0 ||
+                       strncasecmp((char *) p, "q!", cnt) == 0) {      // delete lines
+                       if (file_modified == TRUE && p[1] != '!') {
+                               psbs("No write since last change (:quit! overrides)");
+                       } else {
+                               editing = 0;
+                       }
+               } else if (strncasecmp((char *) p, "write", cnt) == 0 ||
+                                  strncasecmp((char *) p, "wq", cnt) == 0) {
+                       cnt = file_write(cfn, text, end - 1);
+                       file_modified = FALSE;
+                       psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
+                       if (p[1] == 'q') {
+                               editing = 0;
+                       }
+               } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
+                       edit_status();                  // show current file status
+               } else if (sscanf((char *) p, "%d", &j) > 0) {
+                       dot = find_line(j);             // go to line # j
+                       dot_skip_over_ws();
+               } else {                // unrecognised cmd
+                       ni((Byte *) p);
+               }
+#endif                                                 /* BB_FEATURE_VI_COLON */
+               break;
+       case '<':                       // <- Left  shift something
+       case '>':                       // >- Right shift something
+               cnt = count_lines(text, dot);   // remember what line we are on
+               c1 = get_one_char();    // get the type of thing to delete
+               find_range(&p, &q, c1);
+               (void) yank_delete(p, q, 1, YANKONLY);  // save copy before change
+               p = begin_line(p);
+               q = end_line(q);
+               i = count_lines(p, q);  // # of lines we are shifting
+               for ( ; i > 0; i--, p = next_line(p)) {
+                       if (c == '<') {
+                               // shift left- remove tab or 8 spaces
+                               if (*p == '\t') {
+                                       // shrink buffer 1 char
+                                       (void) text_hole_delete(p, p);
+                               } else if (*p == ' ') {
+                                       // we should be calculating columns, not just SPACE
+                                       for (j = 0; *p == ' ' && j < tabstop; j++) {
+                                               (void) text_hole_delete(p, p);
+                                       }
+                               }
+                       } else if (c == '>') {
+                               // shift right -- add tab or 8 spaces
+                               (void) char_insert(p, '\t');
+                       }
+               }
+               dot = find_line(cnt);   // what line were we on
+               dot_skip_over_ws();
+               end_cmd_q();    // stop adding to q
+               break;
+       case 'A':                       // A- append at e-o-l
+               dot_end();              // go to e-o-l
+               //**** fall thru to ... 'a'
+       case 'a':                       // a- append after current char
+               if (*dot != '\n')
+                       dot++;
+               goto dc_i;
+               break;
+       case 'B':                       // B- back a blank-delimited Word
+       case 'E':                       // E- end of a blank-delimited word
+       case 'W':                       // W- forward a blank-delimited word
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dir = FORWARD;
+               if (c == 'B')
+                       dir = BACK;
+               if (c == 'W' || isspace(dot[dir])) {
+                       dot = skip_thing(dot, 1, dir, S_TO_WS);
+                       dot = skip_thing(dot, 2, dir, S_OVER_WS);
+               }
+               if (c != 'W')
+                       dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
+               break;
+       case 'C':                       // C- Change to e-o-l
+       case 'D':                       // D- delete to e-o-l
+               save_dot = dot;
+               dot = dollar_line(dot); // move to before NL
+               // copy text into a register and delete
+               dot = yank_delete(save_dot, dot, 0, YANKDEL);   // delete to e-o-l
+               if (c == 'C')
+                       goto dc_i;      // start inserting
+#ifdef BB_FEATURE_VI_DOT_CMD
+               if (c == 'D')
+                       end_cmd_q();    // stop adding to q
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+               break;
+       case 'G':               // G- goto to a line number (default= E-O-F)
+               dot = end - 1;                          // assume E-O-F
+               if (cmdcnt > 0) {
+                       dot = find_line(cmdcnt);        // what line is #cmdcnt
+               }
+               dot_skip_over_ws();
+               break;
+       case 'H':                       // H- goto top line on screen
+               dot = screenbegin;
+               if (cmdcnt > (rows - 1)) {
+                       cmdcnt = (rows - 1);
+               }
+               if (cmdcnt-- > 1) {
+                       do_cmd('+');
+               }                               // repeat cnt
+               dot_skip_over_ws();
+               break;
+       case 'I':                       // I- insert before first non-blank
+               dot_begin();    // 0
+               dot_skip_over_ws();
+               //**** fall thru to ... 'i'
+       case 'i':                       // i- insert before current char
+       case VI_K_INSERT:       // Cursor Key Insert
+         dc_i:
+               cmd_mode = 1;   // start insrting
+               psb("-- Insert --");
+               break;
+       case 'J':                       // J- join current and next lines together
+               if (cmdcnt-- > 2) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_end();              // move to NL
+               if (dot < end - 1) {    // make sure not last char in text[]
+                       *dot++ = ' ';   // replace NL with space
+                       while (isblnk(*dot)) {  // delete leading WS
+                               dot_delete();
+                       }
+               }
+               end_cmd_q();    // stop adding to q
+               break;
+       case 'L':                       // L- goto bottom line on screen
+               dot = end_screen();
+               if (cmdcnt > (rows - 1)) {
+                       cmdcnt = (rows - 1);
+               }
+               if (cmdcnt-- > 1) {
+                       do_cmd('-');
+               }                               // repeat cnt
+               dot_begin();
+               dot_skip_over_ws();
+               break;
+       case 'M':                       // M- goto middle line on screen
+               dot = screenbegin;
+               for (cnt = 0; cnt < (rows-1) / 2; cnt++)
+                       dot = next_line(dot);
+               break;
+       case 'O':                       // O- open a empty line above
+               //    0i\n ESC -i
+               p = begin_line(dot);
+               if (p[-1] == '\n') {
+                       dot_prev();
+       case 'o':                       // o- open a empty line below; Yes, I know it is in the middle of the "if (..."
+                       dot_end();
+                       dot = char_insert(dot, '\n');
+               } else {
+                       dot_begin();    // 0
+                       dot = char_insert(dot, '\n');   // i\n ESC
+                       dot_prev();     // -
+               }
+               goto dc_i;
+               break;
+       case 'R':                       // R- continuous Replace char
+         dc5:
+               cmd_mode = 2;
+               psb("-- Replace --");
+               break;
+       case 'X':                       // X- delete char before dot
+       case 'x':                       // x- delete the current char
+       case 's':                       // s- substitute the current char
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dir = 0;
+               if (c == 'X')
+                       dir = -1;
+               if (dot[dir] != '\n') {
+                       if (c == 'X')
+                               dot--;  // delete prev char
+                       dot = yank_delete(dot, dot, 0, YANKDEL);        // delete char
+               }
+               if (c == 's')
+                       goto dc_i;      // start insrting
+               end_cmd_q();    // stop adding to q
+               break;
+       case 'Z':                       // Z- if modified, {write}; exit
+               // ZZ means to save file (if necessary), then exit
+               c1 = get_one_char();
+               if (c1 != 'Z') {
+                       indicate_error(c);
+                       break;
+               }
+               if (file_modified == TRUE
+#ifdef BB_FEATURE_VI_READONLY
+                       && vi_readonly == FALSE
+                       && readonly == FALSE
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       ) {
+                       cnt = file_write(cfn, text, end - 1);
+                       if (cnt == (end - 1 - text + 1)) {
+                               editing = 0;
+                       }
+               } else {
+                       editing = 0;
+               }
+               break;
+       case '^':                       // ^- move to first non-blank on line
+               dot_begin();
+               dot_skip_over_ws();
+               break;
+       case 'b':                       // b- back a word
+       case 'e':                       // e- end of word
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dir = FORWARD;
+               if (c == 'b')
+                       dir = BACK;
+               if ((dot + dir) < text || (dot + dir) > end - 1)
+                       break;
+               dot += dir;
+               if (isspace(*dot)) {
+                       dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
+               }
+               if (isalnum(*dot) || *dot == '_') {
+                       dot = skip_thing(dot, 1, dir, S_END_ALNUM);
+               } else if (ispunct(*dot)) {
+                       dot = skip_thing(dot, 1, dir, S_END_PUNCT);
+               }
+               break;
+       case 'c':                       // c- change something
+       case 'd':                       // d- delete something
+#ifdef BB_FEATURE_VI_YANKMARK
+       case 'y':                       // y- yank   something
+       case 'Y':                       // Y- Yank a line
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+               yf = YANKDEL;   // assume either "c" or "d"
+#ifdef BB_FEATURE_VI_YANKMARK
+               if (c == 'y' || c == 'Y')
+                       yf = YANKONLY;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+               c1 = 'y';
+               if (c != 'Y')
+                       c1 = get_one_char();    // get the type of thing to delete
+               find_range(&p, &q, c1);
+               if (c1 == 27) { // ESC- user changed mind and wants out
+                       c = c1 = 27;    // Escape- do nothing
+               } else if (strchr("wW", c1)) {
+                       if (c == 'c') {
+                               // don't include trailing WS as part of word
+                               while (isblnk(*q)) {
+                                       if (q <= text || q[-1] == '\n')
+                                               break;
+                                       q--;
+                               }
+                       }
+                       dot = yank_delete(p, q, 0, yf); // delete word
+               } else if (strchr("^0bBeEft$", c1)) {
+                       // single line copy text into a register and delete
+                       dot = yank_delete(p, q, 0, yf); // delete word
+               } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
+                       // multiple line copy text into a register and delete
+                       dot = yank_delete(p, q, 1, yf); // delete lines
+                       if (c == 'c') {
+                               dot = char_insert(dot, '\n');
+                               // on the last line of file don't move to prev line
+                               if (dot != (end-1)) {
+                                       dot_prev();
+                               }
+                       } else if (c == 'd') {
+                               dot_begin();
+                               dot_skip_over_ws();
+                       }
+               } else {
+                       // could not recognize object
+                       c = c1 = 27;    // error-
+                       indicate_error(c);
+               }
+               if (c1 != 27) {
+                       // if CHANGING, not deleting, start inserting after the delete
+                       if (c == 'c') {
+                               strcpy((char *) buf, "Change");
+                               goto dc_i;      // start inserting
+                       }
+                       if (c == 'd') {
+                               strcpy((char *) buf, "Delete");
+                       }
+#ifdef BB_FEATURE_VI_YANKMARK
+                       if (c == 'y' || c == 'Y') {
+                               strcpy((char *) buf, "Yank");
+                       }
+                       p = reg[YDreg];
+                       q = p + strlen((char *) p);
+                       for (cnt = 0; p <= q; p++) {
+                               if (*p == '\n')
+                                       cnt++;
+                       }
+                       psb("%s %d lines (%d chars) using [%c]",
+                               buf, cnt, strlen((char *) reg[YDreg]), what_reg());
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+                       end_cmd_q();    // stop adding to q
+               }
+               break;
+       case 'k':                       // k- goto prev line, same col
+       case VI_K_UP:           // cursor key Up
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               dot_prev();
+               dot = move_to_col(dot, ccol + offset);  // try stay in same col
+               break;
+       case 'r':                       // r- replace the current char with user input
+               c1 = get_one_char();    // get the replacement char
+               if (*dot != '\n') {
+                       *dot = c1;
+                       file_modified = TRUE;   // has the file been modified
+               }
+               end_cmd_q();    // stop adding to q
+               break;
+       case 't':                       // t- move to char prior to next x
+                last_forward_char = get_one_char();
+                do_cmd(';');
+                if (*dot == last_forward_char)
+                        dot_left();
+                last_forward_char= 0;
+               break;
+       case 'w':                       // w- forward a word
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               if (isalnum(*dot) || *dot == '_') {     // we are on ALNUM
+                       dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
+               } else if (ispunct(*dot)) {     // we are on PUNCT
+                       dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
+               }
+               if (dot < end - 1)
+                       dot++;          // move over word
+               if (isspace(*dot)) {
+                       dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
+               }
+               break;
+       case 'z':                       // z-
+               c1 = get_one_char();    // get the replacement char
+               cnt = 0;
+               if (c1 == '.')
+                       cnt = (rows - 2) / 2;   // put dot at center
+               if (c1 == '-')
+                       cnt = rows - 2; // put dot at bottom
+               screenbegin = begin_line(dot);  // start dot at top
+               dot_scroll(cnt, -1);
+               break;
+       case '|':                       // |- move to column "cmdcnt"
+               dot = move_to_col(dot, cmdcnt - 1);     // try to move to column
+               break;
+       case '~':                       // ~- flip the case of letters   a-z -> A-Z
+               if (cmdcnt-- > 1) {
+                       do_cmd(c);
+               }                               // repeat cnt
+               if (islower(*dot)) {
+                       *dot = toupper(*dot);
+                       file_modified = TRUE;   // has the file been modified
+               } else if (isupper(*dot)) {
+                       *dot = tolower(*dot);
+                       file_modified = TRUE;   // has the file been modified
+               }
+               dot_right();
+               end_cmd_q();    // stop adding to q
+               break;
+               //----- The Cursor and Function Keys -----------------------------
+       case VI_K_HOME: // Cursor Key Home
+               dot_begin();
+               break;
+               // The Fn keys could point to do_macro which could translate them
+       case VI_K_FUN1: // Function Key F1
+       case VI_K_FUN2: // Function Key F2
+       case VI_K_FUN3: // Function Key F3
+       case VI_K_FUN4: // Function Key F4
+       case VI_K_FUN5: // Function Key F5
+       case VI_K_FUN6: // Function Key F6
+       case VI_K_FUN7: // Function Key F7
+       case VI_K_FUN8: // Function Key F8
+       case VI_K_FUN9: // Function Key F9
+       case VI_K_FUN10:        // Function Key F10
+       case VI_K_FUN11:        // Function Key F11
+       case VI_K_FUN12:        // Function Key F12
+               break;
+       }
+
+  dc1:
+       // if text[] just became empty, add back an empty line
+       if (end == text) {
+               (void) char_insert(text, '\n'); // start empty buf with dummy line
+               dot = text;
+       }
+       // it is OK for dot to exactly equal to end, otherwise check dot validity
+       if (dot != end) {
+               dot = bound_dot(dot);   // make sure "dot" is valid
+       }
+#ifdef BB_FEATURE_VI_YANKMARK
+       check_context(c);       // update the current context
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+
+       if (!isdigit(c))
+               cmdcnt = 0;             // cmd was not a number, reset cmdcnt
+       cnt = dot - begin_line(dot);
+       // Try to stay off of the Newline
+       if (*dot == '\n' && cnt > 0 && cmd_mode == 0)
+               dot--;
+}
+
+//----- The Colon commands -------------------------------------
+#ifdef BB_FEATURE_VI_COLON
+static Byte *get_one_address(Byte * p, int *addr)      // get colon addr, if present
+{
+       int st;
+       Byte *q;
+
+#ifdef BB_FEATURE_VI_YANKMARK
+       Byte c;
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_SEARCH
+       Byte *pat, buf[BUFSIZ];
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+
+       *addr = -1;                     // assume no addr
+       if (*p == '.') {        // the current line
+               p++;
+               q = begin_line(dot);
+               *addr = count_lines(text, q);
+#ifdef BB_FEATURE_VI_YANKMARK
+       } else if (*p == '\'') {        // is this a mark addr
+               p++;
+               c = tolower(*p);
+               p++;
+               if (c >= 'a' && c <= 'z') {
+                       // we have a mark
+                       c = c - 'a';
+                       q = mark[(int) c];
+                       if (q != NULL) {        // is mark valid
+                               *addr = count_lines(text, q);   // count lines
+                       }
+               }
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_SEARCH
+       } else if (*p == '/') { // a search pattern
+               q = buf;
+               for (p++; *p; p++) {
+                       if (*p == '/')
+                               break;
+                       *q++ = *p;
+                       *q = '\0';
+               }
+               pat = (Byte *) strdup((char *) buf);    // save copy of pattern
+               if (*p == '/')
+                       p++;
+               q = char_search(dot, pat, FORWARD, FULL);
+               if (q != NULL) {
+                       *addr = count_lines(text, q);
+               }
+               free(pat);
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+       } else if (*p == '$') { // the last line in file
+               p++;
+               q = begin_line(end - 1);
+               *addr = count_lines(text, q);
+       } else if (isdigit(*p)) {       // specific line number
+               sscanf((char *) p, "%d%n", addr, &st);
+               p += st;
+       } else {                        // I don't reconise this
+               // unrecognised address- assume -1
+               *addr = -1;
+       }
+       return (p);
+}
+
+static Byte *get_address(Byte *p, int *b, int *e)      // get two colon addrs, if present
+{
+       //----- get the address' i.e., 1,3   'a,'b  -----
+       // get FIRST addr, if present
+       while (isblnk(*p))
+               p++;                            // skip over leading spaces
+       if (*p == '%') {                        // alias for 1,$
+               p++;
+               *b = 1;
+               *e = count_lines(text, end-1);
+               goto ga0;
+       }
+       p = get_one_address(p, b);
+       while (isblnk(*p))
+               p++;
+       if (*p == ',') {                        // is there a address seperator
+               p++;
+               while (isblnk(*p))
+                       p++;
+               // get SECOND addr, if present
+               p = get_one_address(p, e);
+       }
+ga0:
+       while (isblnk(*p))
+               p++;                            // skip over trailing spaces
+       return (p);
+}
+
+static void colon(Byte * buf)
+{
+       Byte c, *orig_buf, *buf1, *q, *r;
+       Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
+       int i, l, li, ch, st, b, e;
+       int useforce, forced;
+       struct stat st_buf;
+
+       // :3154        // if (-e line 3154) goto it  else stay put
+       // :4,33w! foo  // write a portion of buffer to file "foo"
+       // :w           // write all of buffer to current file
+       // :q           // quit
+       // :q!          // quit- dont care about modified file
+       // :'a,'z!sort -u   // filter block through sort
+       // :'f          // goto mark "f"
+       // :'fl         // list literal the mark "f" line
+       // :.r bar      // read file "bar" into buffer before dot
+       // :/123/,/abc/d    // delete lines from "123" line to "abc" line
+       // :/xyz/       // goto the "xyz" line
+       // :s/find/replace/ // substitute pattern "find" with "replace"
+       // :!<cmd>      // run <cmd> then return
+       //
+       if (strlen((char *) buf) <= 0)
+               goto vc1;
+       if (*buf == ':')
+               buf++;                  // move past the ':'
+
+       forced = useforce = FALSE;
+       li = st = ch = i = 0;
+       b = e = -1;
+       q = text;                       // assume 1,$ for the range
+       r = end - 1;
+       li = count_lines(text, end - 1);
+       fn = cfn;                       // default to current file
+       memset(cmd, '\0', BUFSIZ);      // clear cmd[]
+       memset(args, '\0', BUFSIZ);     // clear args[]
+
+       // look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
+       buf = get_address(buf, &b, &e);
+
+       // remember orig command line
+       orig_buf = buf;
+
+       // get the COMMAND into cmd[]
+       buf1 = cmd;
+       while (*buf != '\0') {
+               if (isspace(*buf))
+                       break;
+               *buf1++ = *buf++;
+       }
+       // get any ARGuments
+       while (isblnk(*buf))
+               buf++;
+       strcpy((char *) args, (char *) buf);
+       buf1 = last_char_is((char *)cmd, '!');
+       if (buf1) {
+               useforce = TRUE;
+               *buf1 = '\0';   // get rid of !
+       }
+       if (b >= 0) {
+               // if there is only one addr, then the addr
+               // is the line number of the single line the
+               // user wants. So, reset the end
+               // pointer to point at end of the "b" line
+               q = find_line(b);       // what line is #b
+               r = end_line(q);
+               li = 1;
+       }
+       if (e >= 0) {
+               // we were given two addrs.  change the
+               // end pointer to the addr given by user.
+               r = find_line(e);       // what line is #e
+               r = end_line(r);
+               li = e - b + 1;
+       }
+       // ------------ now look for the command ------------
+       i = strlen((char *) cmd);
+       if (i == 0) {           // :123CR goto line #123
+               if (b >= 0) {
+                       dot = find_line(b);     // what line is #b
+                       dot_skip_over_ws();
+               }
+       } else if (strncmp((char *) cmd, "!", 1) == 0) {        // run a cmd
+               // :!ls   run the <cmd>
+               (void) alarm(0);                // wait for input- no alarms
+               place_cursor(rows - 1, 0, FALSE);       // go to Status line
+               clear_to_eol();                 // clear the line
+               cookmode();
+               system(orig_buf+1);             // run the cmd
+               rawmode();
+               Hit_Return();                   // let user see results
+               (void) alarm(3);                // done waiting for input
+       } else if (strncmp((char *) cmd, "=", i) == 0) {        // where is the address
+               if (b < 0) {    // no addr given- use defaults
+                       b = e = count_lines(text, dot);
+               }
+               psb("%d", b);
+       } else if (strncasecmp((char *) cmd, "delete", i) == 0) {       // delete lines
+               if (b < 0) {    // no addr given- use defaults
+                       q = begin_line(dot);    // assume .,. for the range
+                       r = end_line(dot);
+               }
+               dot = yank_delete(q, r, 1, YANKDEL);    // save, then delete lines
+               dot_skip_over_ws();
+       } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
+               int sr;
+               sr= 0;
+               // don't edit, if the current file has been modified
+               if (file_modified == TRUE && useforce != TRUE) {
+                       psbs("No write since last change (:edit! overrides)");
+                       goto vc1;
+               }
+               if (strlen(args) > 0) {
+                       // the user supplied a file name
+                       fn= args;
+               } else if (cfn != 0 && strlen(cfn) > 0) {
+                       // no user supplied name- use the current filename
+                       fn= cfn;
+                       goto vc5;
+               } else {
+                       // no user file name, no current name- punt
+                       psbs("No current filename");
+                       goto vc1;
+               }
+
+               // see if file exists- if not, its just a new file request
+               if ((sr=stat((char*)fn, &st_buf)) < 0) {
+                       // This is just a request for a new file creation.
+                       // The file_insert below will fail but we get
+                       // an empty buffer with a file name.  Then the "write"
+                       // command can do the create.
+               } else {
+                       if ((st_buf.st_mode & (S_IFREG)) == 0) {
+                               // This is not a regular file
+                               psbs("\"%s\" is not a regular file", fn);
+                               goto vc1;
+                       }
+                       if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
+                               // dont have any read permissions
+                               psbs("\"%s\" is not readable", fn);
+                               goto vc1;
+                       }
+               }
+
+               // There is a read-able regular file
+               // make this the current file
+               q = (Byte *) strdup((char *) fn);       // save the cfn
+               if (cfn != 0)
+                       free(cfn);              // free the old name
+               cfn = q;                        // remember new cfn
+
+         vc5:
+               // delete all the contents of text[]
+               new_text(2 * file_size(fn));
+               screenbegin = dot = end = text;
+
+               // insert new file
+               ch = file_insert(fn, text, file_size(fn));
+
+               if (ch < 1) {
+                       // start empty buf with dummy line
+                       (void) char_insert(text, '\n');
+                       ch= 1;
+               }
+               file_modified = FALSE;
+#ifdef BB_FEATURE_VI_YANKMARK
+               if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
+                       free(reg[Ureg]);        //   free orig line reg- for 'U'
+                       reg[Ureg]= 0;
+               }
+               if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
+                       free(reg[YDreg]);       //   free default yank/delete register
+                       reg[YDreg]= 0;
+               }
+               for (li = 0; li < 28; li++) {
+                       mark[li] = 0;
+               }                               // init the marks
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+               // how many lines in text[]?
+               li = count_lines(text, end - 1);
+               psb("\"%s\"%s"
+#ifdef BB_FEATURE_VI_READONLY
+                       "%s"
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       " %dL, %dC", cfn,
+                       (sr < 0 ? " [New file]" : ""),
+#ifdef BB_FEATURE_VI_READONLY
+                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       li, ch);
+       } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
+               if (b != -1 || e != -1) {
+                       ni((Byte *) "No address allowed on this command");
+                       goto vc1;
+               }
+               if (strlen((char *) args) > 0) {
+                       // user wants a new filename
+                       if (cfn != NULL)
+                               free(cfn);
+                       cfn = (Byte *) strdup((char *) args);
+               } else {
+                       // user wants file status info
+                       edit_status();
+               }
+       } else if (strncasecmp((char *) cmd, "features", i) == 0) {     // what features are available
+               // print out values of all features
+               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
+               clear_to_eol(); // clear the line
+               cookmode();
+               show_help();
+               rawmode();
+               Hit_Return();
+       } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line
+               if (b < 0) {    // no addr given- use defaults
+                       q = begin_line(dot);    // assume .,. for the range
+                       r = end_line(dot);
+               }
+               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
+               clear_to_eol(); // clear the line
+               write(1, "\r\n", 2);
+               for (; q <= r; q++) {
+                       c = *q;
+                       if (c > '~')
+                               standout_start();
+                       if (c == '\n') {
+                               write(1, "$\r", 2);
+                       } else if (*q < ' ') {
+                               write(1, "^", 1);
+                               c += '@';
+                       }
+                       write(1, &c, 1);
+                       if (c > '~')
+                               standout_end();
+               }
+#ifdef BB_FEATURE_VI_SET
+         vc2:
+#endif                                                 /* BB_FEATURE_VI_SET */
+               Hit_Return();
+       } else if ((strncasecmp((char *) cmd, "quit", i) == 0) ||       // Quit
+                          (strncasecmp((char *) cmd, "next", i) == 0)) {       // edit next file
+               if (useforce == TRUE) {
+                       // force end of argv list
+                       if (*cmd == 'q') {
+                               optind = save_argc;
+                       }
+                       editing = 0;
+                       goto vc1;
+               }
+               // don't exit if the file been modified
+               if (file_modified == TRUE) {
+                       psbs("No write since last change (:%s! overrides)",
+                                (*cmd == 'q' ? "quit" : "next"));
+                       goto vc1;
+               }
+               // are there other file to edit
+               if (*cmd == 'q' && optind < save_argc - 1) {
+                       psbs("%d more file to edit", (save_argc - optind - 1));
+                       goto vc1;
+               }
+               if (*cmd == 'n' && optind >= save_argc - 1) {
+                       psbs("No more files to edit");
+                       goto vc1;
+               }
+               editing = 0;
+       } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[]
+               fn = args;
+               if (strlen((char *) fn) <= 0) {
+                       psbs("No filename given");
+                       goto vc1;
+               }
+               if (b < 0) {    // no addr given- use defaults
+                       q = begin_line(dot);    // assume "dot"
+               }
+               // read after current line- unless user said ":0r foo"
+               if (b != 0)
+                       q = next_line(q);
+#ifdef BB_FEATURE_VI_READONLY
+               l= readonly;                    // remember current files' status
+#endif
+               ch = file_insert(fn, q, file_size(fn));
+#ifdef BB_FEATURE_VI_READONLY
+               readonly= l;
+#endif
+               if (ch < 0)
+                       goto vc1;       // nothing was inserted
+               // how many lines in text[]?
+               li = count_lines(q, q + ch - 1);
+               psb("\"%s\""
+#ifdef BB_FEATURE_VI_READONLY
+                       "%s"
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       " %dL, %dC", fn,
+#ifdef BB_FEATURE_VI_READONLY
+                       ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+                       li, ch);
+               if (ch > 0) {
+                       // if the insert is before "dot" then we need to update
+                       if (q <= dot)
+                               dot += ch;
+                       file_modified = TRUE;
+               }
+       } else if (strncasecmp((char *) cmd, "rewind", i) == 0) {       // rewind cmd line args
+               if (file_modified == TRUE && useforce != TRUE) {
+                       psbs("No write since last change (:rewind! overrides)");
+               } else {
+                       // reset the filenames to edit
+                       optind = fn_start - 1;
+                       editing = 0;
+               }
+#ifdef BB_FEATURE_VI_SET
+       } else if (strncasecmp((char *) cmd, "set", i) == 0) {  // set or clear features
+               i = 0;                  // offset into args
+               if (strlen((char *) args) == 0) {
+                       // print out values of all options
+                       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
+                       clear_to_eol(); // clear the line
+                       printf("----------------------------------------\r\n");
+#ifdef BB_FEATURE_VI_SETOPTS
+                       if (!autoindent)
+                               printf("no");
+                       printf("autoindent ");
+                       if (!err_method)
+                               printf("no");
+                       printf("flash ");
+                       if (!ignorecase)
+                               printf("no");
+                       printf("ignorecase ");
+                       if (!showmatch)
+                               printf("no");
+                       printf("showmatch ");
+                       printf("tabstop=%d ", tabstop);
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+                       printf("\r\n");
+                       goto vc2;
+               }
+               if (strncasecmp((char *) args, "no", 2) == 0)
+                       i = 2;          // ":set noautoindent"
+#ifdef BB_FEATURE_VI_SETOPTS
+               if (strncasecmp((char *) args + i, "autoindent", 10) == 0 ||
+                       strncasecmp((char *) args + i, "ai", 2) == 0) {
+                       autoindent = (i == 2) ? 0 : 1;
+               }
+               if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
+                       strncasecmp((char *) args + i, "fl", 2) == 0) {
+                       err_method = (i == 2) ? 0 : 1;
+               }
+               if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
+                       strncasecmp((char *) args + i, "ic", 2) == 0) {
+                       ignorecase = (i == 2) ? 0 : 1;
+               }
+               if (strncasecmp((char *) args + i, "showmatch", 9) == 0 ||
+                       strncasecmp((char *) args + i, "sm", 2) == 0) {
+                       showmatch = (i == 2) ? 0 : 1;
+               }
+               if (strncasecmp((char *) args + i, "tabstop", 7) == 0) {
+                       sscanf(strchr((char *) args + i, '='), "=%d", &ch);
+                       if (ch > 0 && ch < columns - 1)
+                               tabstop = ch;
+               }
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+#endif                                                 /* BB_FEATURE_VI_SET */
+#ifdef BB_FEATURE_VI_SEARCH
+       } else if (strncasecmp((char *) cmd, "s", 1) == 0) {    // substitute a pattern with a replacement pattern
+               Byte *ls, *F, *R;
+               int gflag;
+
+               // F points to the "find" pattern
+               // R points to the "replace" pattern
+               // replace the cmd line delimiters "/" with NULLs
+               gflag = 0;              // global replace flag
+               c = orig_buf[1];        // what is the delimiter
+               F = orig_buf + 2;       // start of "find"
+               R = (Byte *) strchr((char *) F, c);     // middle delimiter
+               if (!R) goto colon_s_fail;
+               *R++ = '\0';    // terminate "find"
+               buf1 = (Byte *) strchr((char *) R, c);
+               if (!buf1) goto colon_s_fail;
+               *buf1++ = '\0'; // terminate "replace"
+               if (*buf1 == 'g') {     // :s/foo/bar/g
+                       buf1++;
+                       gflag++;        // turn on gflag
+               }
+               q = begin_line(q);
+               if (b < 0) {    // maybe :s/foo/bar/
+                       q = begin_line(dot);    // start with cur line
+                       b = count_lines(text, q);       // cur line number
+               }
+               if (e < 0)
+                       e = b;          // maybe :.s/foo/bar/
+               for (i = b; i <= e; i++) {      // so, :20,23 s \0 find \0 replace \0
+                       ls = q;         // orig line start
+                 vc4:
+                       buf1 = char_search(q, F, FORWARD, LIMITED);     // search cur line only for "find"
+                       if (buf1 != NULL) {
+                               // we found the "find" pattern- delete it
+                               (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1);
+                               // inset the "replace" patern
+                               (void) string_insert(buf1, R);  // insert the string
+                               // check for "global"  :s/foo/bar/g
+                               if (gflag == 1) {
+                                       if ((buf1 + strlen((char *) R)) < end_line(ls)) {
+                                               q = buf1 + strlen((char *) R);
+                                               goto vc4;       // don't let q move past cur line
+                                       }
+                               }
+                       }
+                       q = next_line(ls);
+               }
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+       } else if (strncasecmp((char *) cmd, "version", i) == 0) {      // show software version
+               psb("%s", vi_Version);
+       } else if ((strncasecmp((char *) cmd, "write", i) == 0) ||      // write text to file
+                          (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file
+               // is there a file name to write to?
+               if (strlen((char *) args) > 0) {
+                       fn = args;
+               }
+#ifdef BB_FEATURE_VI_READONLY
+               if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
+                       psbs("\"%s\" File is read only", fn);
+                       goto vc3;
+               }
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+               // how many lines in text[]?
+               li = count_lines(q, r);
+               ch = r - q + 1;
+               // see if file exists- if not, its just a new file request
+               if (useforce == TRUE) {
+                       // if "fn" is not write-able, chmod u+w
+                       // sprintf(syscmd, "chmod u+w %s", fn);
+                       // system(syscmd);
+                       forced = TRUE;
+               }
+               l = file_write(fn, q, r);
+               if (useforce == TRUE && forced == TRUE) {
+                       // chmod u-w
+                       // sprintf(syscmd, "chmod u-w %s", fn);
+                       // system(syscmd);
+                       forced = FALSE;
+               }
+               psb("\"%s\" %dL, %dC", fn, li, l);
+               if (q == text && r == end - 1 && l == ch)
+                       file_modified = FALSE;
+               if (cmd[1] == 'q' && l == ch) {
+                       editing = 0;
+               }
+#ifdef BB_FEATURE_VI_READONLY
+         vc3:;
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+#ifdef BB_FEATURE_VI_YANKMARK
+       } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
+               if (b < 0) {    // no addr given- use defaults
+                       q = begin_line(dot);    // assume .,. for the range
+                       r = end_line(dot);
+               }
+               text_yank(q, r, YDreg);
+               li = count_lines(q, r);
+               psb("Yank %d lines (%d chars) into [%c]",
+                       li, strlen((char *) reg[YDreg]), what_reg());
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+       } else {
+               // cmd unknown
+               ni((Byte *) cmd);
+       }
+  vc1:
+       dot = bound_dot(dot);   // make sure "dot" is valid
+       return;
+#ifdef BB_FEATURE_VI_SEARCH
+colon_s_fail:
+       psb(":s expression missing delimiters");
+       return;
+#endif
+
+}
+
+static void Hit_Return(void)
+{
+       char c;
+
+       standout_start();       // start reverse video
+       write(1, "[Hit return to continue]", 24);
+       standout_end();         // end reverse video
+       while ((c = get_one_char()) != '\n' && c != '\r')       /*do nothing */
+               ;
+       redraw(TRUE);           // force redraw all
+}
+#endif                                                 /* BB_FEATURE_VI_COLON */
+
+//----- Synchronize the cursor to Dot --------------------------
+static void sync_cursor(Byte * d, int *row, int *col)
+{
+       Byte *beg_cur, *end_cur;        // begin and end of "d" line
+       Byte *beg_scr, *end_scr;        // begin and end of screen
+       Byte *tp;
+       int cnt, ro, co;
+
+       beg_cur = begin_line(d);        // first char of cur line
+       end_cur = end_line(d);  // last char of cur line
+
+       beg_scr = end_scr = screenbegin;        // first char of screen
+       end_scr = end_screen(); // last char of screen
+
+       if (beg_cur < screenbegin) {
+               // "d" is before  top line on screen
+               // how many lines do we have to move
+               cnt = count_lines(beg_cur, screenbegin);
+         sc1:
+               screenbegin = beg_cur;
+               if (cnt > (rows - 1) / 2) {
+                       // we moved too many lines. put "dot" in middle of screen
+                       for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
+                               screenbegin = prev_line(screenbegin);
+                       }
+               }
+       } else if (beg_cur > end_scr) {
+               // "d" is after bottom line on screen
+               // how many lines do we have to move
+               cnt = count_lines(end_scr, beg_cur);
+               if (cnt > (rows - 1) / 2)
+                       goto sc1;       // too many lines
+               for (ro = 0; ro < cnt - 1; ro++) {
+                       // move screen begin the same amount
+                       screenbegin = next_line(screenbegin);
+                       // now, move the end of screen
+                       end_scr = next_line(end_scr);
+                       end_scr = end_line(end_scr);
+               }
+       }
+       // "d" is on screen- find out which row
+       tp = screenbegin;
+       for (ro = 0; ro < rows - 1; ro++) {     // drive "ro" to correct row
+               if (tp == beg_cur)
+                       break;
+               tp = next_line(tp);
+       }
+
+       // find out what col "d" is on
+       co = 0;
+       do {                            // drive "co" to correct column
+               if (*tp == '\n' || *tp == '\0')
+                       break;
+               if (*tp == '\t') {
+                       //         7       - (co %    8  )
+                       co += ((tabstop - 1) - (co % tabstop));
+               } else if (*tp < ' ') {
+                       co++;           // display as ^X, use 2 columns
+               }
+       } while (tp++ < d && ++co);
+
+       // "co" is the column where "dot" is.
+       // The screen has "columns" columns.
+       // The currently displayed columns are  0+offset -- columns+ofset
+       // |-------------------------------------------------------------|
+       //               ^ ^                                ^
+       //        offset | |------- columns ----------------|
+       //
+       // If "co" is already in this range then we do not have to adjust offset
+       //      but, we do have to subtract the "offset" bias from "co".
+       // If "co" is outside this range then we have to change "offset".
+       // If the first char of a line is a tab the cursor will try to stay
+       //  in column 7, but we have to set offset to 0.
+
+       if (co < 0 + offset) {
+               offset = co;
+       }
+       if (co >= columns + offset) {
+               offset = co - columns + 1;
+       }
+       // if the first char of the line is a tab, and "dot" is sitting on it
+       //  force offset to 0.
+       if (d == beg_cur && *d == '\t') {
+               offset = 0;
+       }
+       co -= offset;
+
+       *row = ro;
+       *col = co;
+}
+
+//----- Text Movement Routines ---------------------------------
+static Byte *begin_line(Byte * p) // return pointer to first char cur line
+{
+       while (p > text && p[-1] != '\n')
+               p--;                    // go to cur line B-o-l
+       return (p);
+}
+
+static Byte *end_line(Byte * p) // return pointer to NL of cur line line
+{
+       while (p < end - 1 && *p != '\n')
+               p++;                    // go to cur line E-o-l
+       return (p);
+}
+
+static Byte *dollar_line(Byte * p) // return pointer to just before NL line
+{
+       while (p < end - 1 && *p != '\n')
+               p++;                    // go to cur line E-o-l
+       // Try to stay off of the Newline
+       if (*p == '\n' && (p - begin_line(p)) > 0)
+               p--;
+       return (p);
+}
+
+static Byte *prev_line(Byte * p) // return pointer first char prev line
+{
+       p = begin_line(p);      // goto begining of cur line
+       if (p[-1] == '\n' && p > text)
+               p--;                    // step to prev line
+       p = begin_line(p);      // goto begining of prev line
+       return (p);
+}
+
+static Byte *next_line(Byte * p) // return pointer first char next line
+{
+       p = end_line(p);
+       if (*p == '\n' && p < end - 1)
+               p++;                    // step to next line
+       return (p);
+}
+
+//----- Text Information Routines ------------------------------
+static Byte *end_screen(void)
+{
+       Byte *q;
+       int cnt;
+
+       // find new bottom line
+       q = screenbegin;
+       for (cnt = 0; cnt < rows - 2; cnt++)
+               q = next_line(q);
+       q = end_line(q);
+       return (q);
+}
+
+static int count_lines(Byte * start, Byte * stop) // count line from start to stop
+{
+       Byte *q;
+       int cnt;
+
+       if (stop < start) {     // start and stop are backwards- reverse them
+               q = start;
+               start = stop;
+               stop = q;
+       }
+       cnt = 0;
+       stop = end_line(stop);  // get to end of this line
+       for (q = start; q <= stop && q <= end - 1; q++) {
+               if (*q == '\n')
+                       cnt++;
+       }
+       return (cnt);
+}
+
+static Byte *find_line(int li) // find begining of line #li
+{
+       Byte *q;
+
+       for (q = text; li > 1; li--) {
+               q = next_line(q);
+       }
+       return (q);
+}
+
+//----- Dot Movement Routines ----------------------------------
+static void dot_left(void)
+{
+       if (dot > text && dot[-1] != '\n')
+               dot--;
+}
+
+static void dot_right(void)
+{
+       if (dot < end - 1 && *dot != '\n')
+               dot++;
+}
+
+static void dot_begin(void)
+{
+       dot = begin_line(dot);  // return pointer to first char cur line
+}
+
+static void dot_end(void)
+{
+       dot = end_line(dot);    // return pointer to last char cur line
+}
+
+static Byte *move_to_col(Byte * p, int l)
+{
+       int co;
+
+       p = begin_line(p);
+       co = 0;
+       do {
+               if (*p == '\n' || *p == '\0')
+                       break;
+               if (*p == '\t') {
+                       //         7       - (co %    8  )
+                       co += ((tabstop - 1) - (co % tabstop));
+               } else if (*p < ' ') {
+                       co++;           // display as ^X, use 2 columns
+               }
+       } while (++co <= l && p++ < end);
+       return (p);
+}
+
+static void dot_next(void)
+{
+       dot = next_line(dot);
+}
+
+static void dot_prev(void)
+{
+       dot = prev_line(dot);
+}
+
+static void dot_scroll(int cnt, int dir)
+{
+       Byte *q;
+
+       for (; cnt > 0; cnt--) {
+               if (dir < 0) {
+                       // scroll Backwards
+                       // ctrl-Y  scroll up one line
+                       screenbegin = prev_line(screenbegin);
+               } else {
+                       // scroll Forwards
+                       // ctrl-E  scroll down one line
+                       screenbegin = next_line(screenbegin);
+               }
+       }
+       // make sure "dot" stays on the screen so we dont scroll off
+       if (dot < screenbegin)
+               dot = screenbegin;
+       q = end_screen();       // find new bottom line
+       if (dot > q)
+               dot = begin_line(q);    // is dot is below bottom line?
+       dot_skip_over_ws();
+}
+
+static void dot_skip_over_ws(void)
+{
+       // skip WS
+       while (isspace(*dot) && *dot != '\n' && dot < end - 1)
+               dot++;
+}
+
+static void dot_delete(void)   // delete the char at 'dot'
+{
+       (void) text_hole_delete(dot, dot);
+}
+
+static Byte *bound_dot(Byte * p) // make sure  text[0] <= P < "end"
+{
+       if (p >= end && end > text) {
+               p = end - 1;
+               indicate_error('1');
+       }
+       if (p < text) {
+               p = text;
+               indicate_error('2');
+       }
+       return (p);
+}
+
+//----- Helper Utility Routines --------------------------------
+
+//----------------------------------------------------------------
+//----- Char Routines --------------------------------------------
+/* Chars that are part of a word-
+ *    0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+ * Chars that are Not part of a word (stoppers)
+ *    !"#$%&'()*+,-./:;<=>?@[\]^`{|}~
+ * Chars that are WhiteSpace
+ *    TAB NEWLINE VT FF RETURN SPACE
+ * DO NOT COUNT NEWLINE AS WHITESPACE
+ */
+
+static Byte *new_screen(int ro, int co)
+{
+       int li;
+
+       if (screen != 0)
+               free(screen);
+       screensize = ro * co + 8;
+       screen = (Byte *) xmalloc(screensize);
+       // initialize the new screen. assume this will be a empty file.
+       screen_erase();
+       //   non-existant text[] lines start with a tilde (~).
+       for (li = 1; li < ro - 1; li++) {
+               screen[(li * co) + 0] = '~';
+       }
+       return (screen);
+}
+
+static Byte *new_text(int size)
+{
+       if (size < 10240)
+               size = 10240;   // have a minimum size for new files
+       if (text != 0) {
+               //text -= 4;
+               free(text);
+       }
+       text = (Byte *) xmalloc(size + 8);
+       memset(text, '\0', size);       // clear new text[]
+       //text += 4;            // leave some room for "oops"
+       textend = text + size - 1;
+       //textend -= 4;         // leave some root for "oops"
+       return (text);
+}
+
+#ifdef BB_FEATURE_VI_SEARCH
+static int mycmp(Byte * s1, Byte * s2, int len)
+{
+       int i;
+
+       i = strncmp((char *) s1, (char *) s2, len);
+#ifdef BB_FEATURE_VI_SETOPTS
+       if (ignorecase) {
+               i = strncasecmp((char *) s1, (char *) s2, len);
+       }
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+       return (i);
+}
+
+static Byte *char_search(Byte * p, Byte * pat, int dir, int range)     // search for pattern starting at p
+{
+#ifndef REGEX_SEARCH
+       Byte *start, *stop;
+       int len;
+
+       len = strlen((char *) pat);
+       if (dir == FORWARD) {
+               stop = end - 1; // assume range is p - end-1
+               if (range == LIMITED)
+                       stop = next_line(p);    // range is to next line
+               for (start = p; start < stop; start++) {
+                       if (mycmp(start, pat, len) == 0) {
+                               return (start);
+                       }
+               }
+       } else if (dir == BACK) {
+               stop = text;    // assume range is text - p
+               if (range == LIMITED)
+                       stop = prev_line(p);    // range is to prev line
+               for (start = p - len; start >= stop; start--) {
+                       if (mycmp(start, pat, len) == 0) {
+                               return (start);
+                       }
+               }
+       }
+       // pattern not found
+       return (NULL);
+#else                                                  /*REGEX_SEARCH */
+       char *q;
+       struct re_pattern_buffer preg;
+       int i;
+       int size, range;
+
+       re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
+       preg.translate = 0;
+       preg.fastmap = 0;
+       preg.buffer = 0;
+       preg.allocated = 0;
+
+       // assume a LIMITED forward search
+       q = next_line(p);
+       q = end_line(q);
+       q = end - 1;
+       if (dir == BACK) {
+               q = prev_line(p);
+               q = text;
+       }
+       // count the number of chars to search over, forward or backward
+       size = q - p;
+       if (size < 0)
+               size = p - q;
+       // RANGE could be negative if we are searching backwards
+       range = q - p;
+
+       q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg);
+       if (q != 0) {
+               // The pattern was not compiled
+               psbs("bad search pattern: \"%s\": %s", pat, q);
+               i = 0;                  // return p if pattern not compiled
+               goto cs1;
+       }
+
+       q = p;
+       if (range < 0) {
+               q = p - size;
+               if (q < text)
+                       q = text;
+       }
+       // search for the compiled pattern, preg, in p[]
+       // range < 0-  search backward
+       // range > 0-  search forward
+       // 0 < start < size
+       // re_search() < 0  not found or error
+       // re_search() > 0  index of found pattern
+       //            struct pattern    char     int    int    int     struct reg
+       // re_search (*pattern_buffer,  *string, size,  start, range,  *regs)
+       i = re_search(&preg, q, size, 0, range, 0);
+       if (i == -1) {
+               p = 0;
+               i = 0;                  // return NULL if pattern not found
+       }
+  cs1:
+       if (dir == FORWARD) {
+               p = p + i;
+       } else {
+               p = p - i;
+       }
+       return (p);
+#endif                                                 /*REGEX_SEARCH */
+}
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+
+static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
+{
+       if (c == 22) {          // Is this an ctrl-V?
+               p = stupid_insert(p, '^');      // use ^ to indicate literal next
+               p--;                    // backup onto ^
+               refresh(FALSE); // show the ^
+               c = get_one_char();
+               *p = c;
+               p++;
+               file_modified = TRUE;   // has the file been modified
+       } else if (c == 27) {   // Is this an ESC?
+               cmd_mode = 0;
+               cmdcnt = 0;
+               end_cmd_q();    // stop adding to q
+               strcpy((char *) status_buffer, " ");    // clear the status buffer
+               if ((p[-1] != '\n') && (dot>text)) {
+                       p--;
+               }
+       } else if (c == erase_char) {   // Is this a BS
+               //     123456789
+               if ((p[-1] != '\n') && (dot>text)) {
+                       p--;
+                       p = text_hole_delete(p, p);     // shrink buffer 1 char
+#ifdef BB_FEATURE_VI_DOT_CMD
+                       // also rmove char from last_modifying_cmd
+                       if (strlen((char *) last_modifying_cmd) > 0) {
+                               Byte *q;
+
+                               q = last_modifying_cmd;
+                               q[strlen((char *) q) - 1] = '\0';       // erase BS
+                               q[strlen((char *) q) - 1] = '\0';       // erase prev char
+                       }
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+               }
+       } else {
+               // insert a char into text[]
+               Byte *sp;               // "save p"
+
+               if (c == 13)
+                       c = '\n';       // translate \r to \n
+               sp = p;                 // remember addr of insert
+               p = stupid_insert(p, c);        // insert the char
+#ifdef BB_FEATURE_VI_SETOPTS
+               if (showmatch && strchr(")]}", *sp) != NULL) {
+                       showmatching(sp);
+               }
+               if (autoindent && c == '\n') {  // auto indent the new line
+                       Byte *q;
+
+                       q = prev_line(p);       // use prev line as templet
+                       for (; isblnk(*q); q++) {
+                               p = stupid_insert(p, *q);       // insert the char
+                       }
+               }
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+       }
+       return (p);
+}
+
+static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p'
+{
+       p = text_hole_make(p, 1);
+       if (p != 0) {
+               *p = c;
+               file_modified = TRUE;   // has the file been modified
+               p++;
+       }
+       return (p);
+}
+
+static Byte find_range(Byte ** start, Byte ** stop, Byte c)
+{
+       Byte *save_dot, *p, *q;
+       int cnt;
+
+       save_dot = dot;
+       p = q = dot;
+
+       if (strchr("cdy><", c)) {
+               // these cmds operate on whole lines
+               p = q = begin_line(p);
+               for (cnt = 1; cnt < cmdcnt; cnt++) {
+                       q = next_line(q);
+               }
+               q = end_line(q);
+       } else if (strchr("^%$0bBeEft", c)) {
+               // These cmds operate on char positions
+               do_cmd(c);              // execute movement cmd
+               q = dot;
+       } else if (strchr("wW", c)) {
+               do_cmd(c);              // execute movement cmd
+               if (dot > text)
+                       dot--;          // move back off of next word
+               if (dot > text && *dot == '\n')
+                       dot--;          // stay off NL
+               q = dot;
+       } else if (strchr("H-k{", c)) {
+               // these operate on multi-lines backwards
+               q = end_line(dot);      // find NL
+               do_cmd(c);              // execute movement cmd
+               dot_begin();
+               p = dot;
+       } else if (strchr("L+j}\r\n", c)) {
+               // these operate on multi-lines forwards
+               p = begin_line(dot);
+               do_cmd(c);              // execute movement cmd
+               dot_end();              // find NL
+               q = dot;
+       } else {
+               c = 27;                 // error- return an ESC char
+               //break;
+       }
+       *start = p;
+       *stop = q;
+       if (q < p) {
+               *start = q;
+               *stop = p;
+       }
+       dot = save_dot;
+       return (c);
+}
+
+static int st_test(Byte * p, int type, int dir, Byte * tested)
+{
+       Byte c, c0, ci;
+       int test, inc;
+
+       inc = dir;
+       c = c0 = p[0];
+       ci = p[inc];
+       test = 0;
+
+       if (type == S_BEFORE_WS) {
+               c = ci;
+               test = ((!isspace(c)) || c == '\n');
+       }
+       if (type == S_TO_WS) {
+               c = c0;
+               test = ((!isspace(c)) || c == '\n');
+       }
+       if (type == S_OVER_WS) {
+               c = c0;
+               test = ((isspace(c)));
+       }
+       if (type == S_END_PUNCT) {
+               c = ci;
+               test = ((ispunct(c)));
+       }
+       if (type == S_END_ALNUM) {
+               c = ci;
+               test = ((isalnum(c)) || c == '_');
+       }
+       *tested = c;
+       return (test);
+}
+
+static Byte *skip_thing(Byte * p, int linecnt, int dir, int type)
+{
+       Byte c;
+
+       while (st_test(p, type, dir, &c)) {
+               // make sure we limit search to correct number of lines
+               if (c == '\n' && --linecnt < 1)
+                       break;
+               if (dir >= 0 && p >= end - 1)
+                       break;
+               if (dir < 0 && p <= text)
+                       break;
+               p += dir;               // move to next char
+       }
+       return (p);
+}
+
+// find matching char of pair  ()  []  {}
+static Byte *find_pair(Byte * p, Byte c)
+{
+       Byte match, *q;
+       int dir, level;
+
+       match = ')';
+       level = 1;
+       dir = 1;                        // assume forward
+       switch (c) {
+       case '(':
+               match = ')';
+               break;
+       case '[':
+               match = ']';
+               break;
+       case '{':
+               match = '}';
+               break;
+       case ')':
+               match = '(';
+               dir = -1;
+               break;
+       case ']':
+               match = '[';
+               dir = -1;
+               break;
+       case '}':
+               match = '{';
+               dir = -1;
+               break;
+       }
+       for (q = p + dir; text <= q && q < end; q += dir) {
+               // look for match, count levels of pairs  (( ))
+               if (*q == c)
+                       level++;        // increase pair levels
+               if (*q == match)
+                       level--;        // reduce pair level
+               if (level == 0)
+                       break;          // found matching pair
+       }
+       if (level != 0)
+               q = NULL;               // indicate no match
+       return (q);
+}
+
+#ifdef BB_FEATURE_VI_SETOPTS
+// show the matching char of a pair,  ()  []  {}
+static void showmatching(Byte * p)
+{
+       Byte *q, *save_dot;
+
+       // we found half of a pair
+       q = find_pair(p, *p);   // get loc of matching char
+       if (q == NULL) {
+               indicate_error('3');    // no matching char
+       } else {
+               // "q" now points to matching pair
+               save_dot = dot; // remember where we are
+               dot = q;                // go to new loc
+               refresh(FALSE); // let the user see it
+               (void) mysleep(40);     // give user some time
+               dot = save_dot; // go back to old loc
+               refresh(FALSE);
+       }
+}
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+
+//  open a hole in text[]
+static Byte *text_hole_make(Byte * p, int size)        // at "p", make a 'size' byte hole
+{
+       Byte *src, *dest;
+       int cnt;
+
+       if (size <= 0)
+               goto thm0;
+       src = p;
+       dest = p + size;
+       cnt = end - src;        // the rest of buffer
+       if (memmove(dest, src, cnt) != dest) {
+               psbs("can't create room for new characters");
+       }
+       memset(p, ' ', size);   // clear new hole
+       end = end + size;       // adjust the new END
+       file_modified = TRUE;   // has the file been modified
+  thm0:
+       return (p);
+}
+
+//  close a hole in text[]
+static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive
+{
+       Byte *src, *dest;
+       int cnt, hole_size;
+
+       // move forwards, from beginning
+       // assume p <= q
+       src = q + 1;
+       dest = p;
+       if (q < p) {            // they are backward- swap them
+               src = p + 1;
+               dest = q;
+       }
+       hole_size = q - p + 1;
+       cnt = end - src;
+       if (src < text || src > end)
+               goto thd0;
+       if (dest < text || dest >= end)
+               goto thd0;
+       if (src >= end)
+               goto thd_atend; // just delete the end of the buffer
+       if (memmove(dest, src, cnt) != dest) {
+               psbs("can't delete the character");
+       }
+  thd_atend:
+       end = end - hole_size;  // adjust the new END
+       if (dest >= end)
+               dest = end - 1; // make sure dest in below end-1
+       if (end <= text)
+               dest = end = text;      // keep pointers valid
+       file_modified = TRUE;   // has the file been modified
+  thd0:
+       return (dest);
+}
+
+// copy text into register, then delete text.
+// if dist <= 0, do not include, or go past, a NewLine
+//
+static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
+{
+       Byte *p;
+
+       // make sure start <= stop
+       if (start > stop) {
+               // they are backwards, reverse them
+               p = start;
+               start = stop;
+               stop = p;
+       }
+       if (dist <= 0) {
+               // we can not cross NL boundaries
+               p = start;
+               if (*p == '\n')
+                       return (p);
+               // dont go past a NewLine
+               for (; p + 1 <= stop; p++) {
+                       if (p[1] == '\n') {
+                               stop = p;       // "stop" just before NewLine
+                               break;
+                       }
+               }
+       }
+       p = start;
+#ifdef BB_FEATURE_VI_YANKMARK
+       text_yank(start, stop, YDreg);
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+       if (yf == YANKDEL) {
+               p = text_hole_delete(start, stop);
+       }                                       // delete lines
+       return (p);
+}
+
+static void show_help(void)
+{
+       puts("These features are available:"
+#ifdef BB_FEATURE_VI_SEARCH
+       "\n\tPattern searches with / and ?"
+#endif                                                 /* BB_FEATURE_VI_SEARCH */
+#ifdef BB_FEATURE_VI_DOT_CMD
+       "\n\tLast command repeat with \'.\'"
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+#ifdef BB_FEATURE_VI_YANKMARK
+       "\n\tLine marking with  'x"
+       "\n\tNamed buffers with  \"x"
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+#ifdef BB_FEATURE_VI_READONLY
+       "\n\tReadonly if vi is called as \"view\""
+       "\n\tReadonly with -R command line arg"
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+#ifdef BB_FEATURE_VI_SET
+       "\n\tSome colon mode commands with \':\'"
+#endif                                                 /* BB_FEATURE_VI_SET */
+#ifdef BB_FEATURE_VI_SETOPTS
+       "\n\tSettable options with \":set\""
+#endif                                                 /* BB_FEATURE_VI_SETOPTS */
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+       "\n\tSignal catching- ^C"
+       "\n\tJob suspend and resume with ^Z"
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+       "\n\tAdapt to window re-sizes"
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+       );
+}
+
+static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
+{
+       Byte c, b[2];
+
+       b[1] = '\0';
+       strcpy((char *) buf, "");       // init buf
+       if (strlen((char *) s) <= 0)
+               s = (Byte *) "(NULL)";
+       for (; *s > '\0'; s++) {
+               c = *s;
+               if (*s > '~') {
+                       strcat((char *) buf, SOs);
+                       c = *s - 128;
+               }
+               if (*s < ' ') {
+                       strcat((char *) buf, "^");
+                       c += '@';
+               }
+               b[0] = c;
+               strcat((char *) buf, (char *) b);
+               if (*s > '~')
+                       strcat((char *) buf, SOn);
+               if (*s == '\n') {
+                       strcat((char *) buf, "$");
+               }
+       }
+}
+
+#ifdef BB_FEATURE_VI_DOT_CMD
+static void start_new_cmd_q(Byte c)
+{
+       // release old cmd
+       if (last_modifying_cmd != 0)
+               free(last_modifying_cmd);
+       // get buffer for new cmd
+       last_modifying_cmd = (Byte *) xmalloc(BUFSIZ);
+       memset(last_modifying_cmd, '\0', BUFSIZ);       // clear new cmd queue
+       // if there is a current cmd count put it in the buffer first
+       if (cmdcnt > 0)
+               sprintf((char *) last_modifying_cmd, "%d", cmdcnt);
+       // save char c onto queue
+       last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c;
+       adding2q = 1;
+       return;
+}
+
+static void end_cmd_q()
+{
+#ifdef BB_FEATURE_VI_YANKMARK
+       YDreg = 26;                     // go back to default Yank/Delete reg
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+       adding2q = 0;
+       return;
+}
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+
+#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME)
+static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
+{
+       int cnt, i;
+
+       i = strlen((char *) s);
+       p = text_hole_make(p, i);
+       strncpy((char *) p, (char *) s, i);
+       for (cnt = 0; *s != '\0'; s++) {
+               if (*s == '\n')
+                       cnt++;
+       }
+#ifdef BB_FEATURE_VI_YANKMARK
+       psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+       return (p);
+}
+#endif                                                 /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */
+
+#ifdef BB_FEATURE_VI_YANKMARK
+static Byte *text_yank(Byte * p, Byte * q, int dest)   // copy text into a register
+{
+       Byte *t;
+       int cnt;
+
+       if (q < p) {            // they are backwards- reverse them
+               t = q;
+               q = p;
+               p = t;
+       }
+       cnt = q - p + 1;
+       t = reg[dest];
+       if (t != 0) {           // if already a yank register
+               free(t);                //   free it
+       }
+       t = (Byte *) xmalloc(cnt + 1);  // get a new register
+       memset(t, '\0', cnt + 1);       // clear new text[]
+       strncpy((char *) t, (char *) p, cnt);   // copy text[] into bufer
+       reg[dest] = t;
+       return (p);
+}
+
+static Byte what_reg(void)
+{
+       Byte c;
+       int i;
+
+       i = 0;
+       c = 'D';                        // default to D-reg
+       if (0 <= YDreg && YDreg <= 25)
+               c = 'a' + (Byte) YDreg;
+       if (YDreg == 26)
+               c = 'D';
+       if (YDreg == 27)
+               c = 'U';
+       return (c);
+}
+
+static void check_context(Byte cmd)
+{
+       // A context is defined to be "modifying text"
+       // Any modifying command establishes a new context.
+
+       if (dot < context_start || dot > context_end) {
+               if (strchr((char *) modifying_cmds, cmd) != NULL) {
+                       // we are trying to modify text[]- make this the current context
+                       mark[27] = mark[26];    // move cur to prev
+                       mark[26] = dot; // move local to cur
+                       context_start = prev_line(prev_line(dot));
+                       context_end = next_line(next_line(dot));
+                       //loiter= start_loiter= now;
+               }
+       }
+       return;
+}
+
+static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
+{
+       Byte *tmp;
+
+       // the current context is in mark[26]
+       // the previous context is in mark[27]
+       // only swap context if other context is valid
+       if (text <= mark[27] && mark[27] <= end - 1) {
+               tmp = mark[27];
+               mark[27] = mark[26];
+               mark[26] = tmp;
+               p = mark[26];   // where we are going- previous context
+               context_start = prev_line(prev_line(prev_line(p)));
+               context_end = next_line(next_line(next_line(p)));
+       }
+       return (p);
+}
+#endif                                                 /* BB_FEATURE_VI_YANKMARK */
+
+static int isblnk(Byte c) // is the char a blank or tab
+{
+       return (c == ' ' || c == '\t');
+}
+
+//----- Set terminal attributes --------------------------------
+static void rawmode(void)
+{
+       tcgetattr(0, &term_orig);
+       term_vi = term_orig;
+       term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG ON- allow intr's
+       term_vi.c_iflag &= (~IXON & ~ICRNL);
+       term_vi.c_oflag &= (~ONLCR);
+       term_vi.c_cc[VMIN] = 1;
+       term_vi.c_cc[VTIME] = 0;
+       erase_char = term_vi.c_cc[VERASE];
+       tcsetattr(0, TCSANOW, &term_vi);
+}
+
+static void cookmode(void)
+{
+       tcsetattr(0, TCSANOW, &term_orig);
+}
+
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+//----- See what the window size currently is --------------------
+static void window_size_get(int sig)
+{
+       int i;
+
+       i = ioctl(0, TIOCGWINSZ, &winsize);
+       if (i != 0) {
+               // force 24x80
+               winsize.ws_row = 24;
+               winsize.ws_col = 80;
+       }
+       if (winsize.ws_row <= 1) {
+               winsize.ws_row = 24;
+       }
+       if (winsize.ws_col <= 1) {
+               winsize.ws_col = 80;
+       }
+       rows = (int) winsize.ws_row;
+       columns = (int) winsize.ws_col;
+}
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+
+//----- Come here when we get a window resize signal ---------
+#ifdef BB_FEATURE_VI_USE_SIGNALS
+static void winch_sig(int sig)
+{
+       signal(SIGWINCH, winch_sig);
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+       window_size_get(0);
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+       new_screen(rows, columns);      // get memory for virtual screen
+       redraw(TRUE);           // re-draw the screen
+}
+
+//----- Come here when we get a continue signal -------------------
+static void cont_sig(int sig)
+{
+       rawmode();                      // terminal to "raw"
+       *status_buffer = '\0';  // clear the status buffer
+       redraw(TRUE);           // re-draw the screen
+
+       signal(SIGTSTP, suspend_sig);
+       signal(SIGCONT, SIG_DFL);
+       kill(getpid(), SIGCONT);
+}
+
+//----- Come here when we get a Suspend signal -------------------
+static void suspend_sig(int sig)
+{
+       place_cursor(rows - 1, 0, FALSE);       // go to bottom of screen
+       clear_to_eol();         // Erase to end of line
+       cookmode();                     // terminal to "cooked"
+
+       signal(SIGCONT, cont_sig);
+       signal(SIGTSTP, SIG_DFL);
+       kill(getpid(), SIGTSTP);
+}
+
+//----- Come here when we get a signal ---------------------------
+static void catch_sig(int sig)
+{
+       signal(SIGHUP, catch_sig);
+       signal(SIGINT, catch_sig);
+       signal(SIGTERM, catch_sig);
+       longjmp(restart, sig);
+}
+
+static void alarm_sig(int sig)
+{
+       signal(SIGALRM, catch_sig);
+       longjmp(restart, sig);
+}
+
+//----- Come here when we get a core dump signal -----------------
+static void core_sig(int sig)
+{
+       signal(SIGQUIT, core_sig);
+       signal(SIGILL, core_sig);
+       signal(SIGTRAP, core_sig);
+       signal(SIGIOT, core_sig);
+       signal(SIGABRT, core_sig);
+       signal(SIGFPE, core_sig);
+       signal(SIGBUS, core_sig);
+       signal(SIGSEGV, core_sig);
+#ifdef SIGSYS
+       signal(SIGSYS, core_sig);
+#endif
+
+       dot = bound_dot(dot);   // make sure "dot" is valid
+
+       longjmp(restart, sig);
+}
+#endif                                                 /* BB_FEATURE_VI_USE_SIGNALS */
+
+static int mysleep(int hund)   // sleep for 'h' 1/100 seconds
+{
+       // Don't hang- Wait 5/100 seconds-  1 Sec= 1000000
+       FD_ZERO(&rfds);
+       FD_SET(0, &rfds);
+       tv.tv_sec = 0;
+       tv.tv_usec = hund * 10000;
+       select(1, &rfds, NULL, NULL, &tv);
+       return (FD_ISSET(0, &rfds));
+}
+
+//----- IO Routines --------------------------------------------
+static Byte readit(void)       // read (maybe cursor) key from stdin
+{
+       Byte c;
+       int i, bufsiz, cnt, cmdindex;
+       struct esc_cmds {
+               Byte *seq;
+               Byte val;
+       };
+
+       static struct esc_cmds esccmds[] = {
+               {(Byte *) "\eOA", (Byte) VI_K_UP},       // cursor key Up
+               {(Byte *) "\eOB", (Byte) VI_K_DOWN},     // cursor key Down
+               {(Byte *) "\eOC", (Byte) VI_K_RIGHT},    // Cursor Key Right
+               {(Byte *) "\eOD", (Byte) VI_K_LEFT},     // cursor key Left
+               {(Byte *) "\eOH", (Byte) VI_K_HOME},     // Cursor Key Home
+               {(Byte *) "\eOF", (Byte) VI_K_END},      // Cursor Key End
+               {(Byte *) "\e[A", (Byte) VI_K_UP},       // cursor key Up
+               {(Byte *) "\e[B", (Byte) VI_K_DOWN},     // cursor key Down
+               {(Byte *) "\e[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
+               {(Byte *) "\e[D", (Byte) VI_K_LEFT},     // cursor key Left
+               {(Byte *) "\e[H", (Byte) VI_K_HOME},     // Cursor Key Home
+               {(Byte *) "\e[F", (Byte) VI_K_END},      // Cursor Key End
+               {(Byte *) "\e[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
+               {(Byte *) "\e[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
+               {(Byte *) "\e[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
+               {(Byte *) "\eOP", (Byte) VI_K_FUN1},     // Function Key F1
+               {(Byte *) "\eOQ", (Byte) VI_K_FUN2},     // Function Key F2
+               {(Byte *) "\eOR", (Byte) VI_K_FUN3},     // Function Key F3
+               {(Byte *) "\eOS", (Byte) VI_K_FUN4},     // Function Key F4
+               {(Byte *) "\e[15~", (Byte) VI_K_FUN5},   // Function Key F5
+               {(Byte *) "\e[17~", (Byte) VI_K_FUN6},   // Function Key F6
+               {(Byte *) "\e[18~", (Byte) VI_K_FUN7},   // Function Key F7
+               {(Byte *) "\e[19~", (Byte) VI_K_FUN8},   // Function Key F8
+               {(Byte *) "\e[20~", (Byte) VI_K_FUN9},   // Function Key F9
+               {(Byte *) "\e[21~", (Byte) VI_K_FUN10},  // Function Key F10
+               {(Byte *) "\e[23~", (Byte) VI_K_FUN11},  // Function Key F11
+               {(Byte *) "\e[24~", (Byte) VI_K_FUN12},  // Function Key F12
+               {(Byte *) "\e[11~", (Byte) VI_K_FUN1},   // Function Key F1
+               {(Byte *) "\e[12~", (Byte) VI_K_FUN2},   // Function Key F2
+               {(Byte *) "\e[13~", (Byte) VI_K_FUN3},   // Function Key F3
+               {(Byte *) "\e[14~", (Byte) VI_K_FUN4},   // Function Key F4
+       };
+
+#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
+
+       (void) alarm(0);        // turn alarm OFF while we wait for input
+       // get input from User- are there already input chars in Q?
+       bufsiz = strlen((char *) readbuffer);
+       if (bufsiz <= 0) {
+         ri0:
+               // the Q is empty, wait for a typed char
+               bufsiz = read(0, readbuffer, BUFSIZ - 1);
+               if (bufsiz < 0) {
+                       if (errno == EINTR)
+                               goto ri0;       // interrupted sys call
+                       if (errno == EBADF)
+                               editing = 0;
+                       if (errno == EFAULT)
+                               editing = 0;
+                       if (errno == EINVAL)
+                               editing = 0;
+                       if (errno == EIO)
+                               editing = 0;
+                       errno = 0;
+                       bufsiz = 0;
+               }
+               readbuffer[bufsiz] = '\0';
+       }
+       // return char if it is not part of ESC sequence
+       if (readbuffer[0] != 27)
+               goto ri1;
+
+       // This is an ESC char. Is this Esc sequence?
+       // Could be bare Esc key. See if there are any
+       // more chars to read after the ESC. This would
+       // be a Function or Cursor Key sequence.
+       FD_ZERO(&rfds);
+       FD_SET(0, &rfds);
+       tv.tv_sec = 0;
+       tv.tv_usec = 50000;     // Wait 5/100 seconds- 1 Sec=1000000
+
+       // keep reading while there are input chars and room in buffer
+       while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
+               // read the rest of the ESC string
+               i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz);
+               if (i > 0) {
+                       bufsiz += i;
+                       readbuffer[bufsiz] = '\0';      // Terminate the string
+               }
+       }
+       // Maybe cursor or function key?
+       for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) {
+               cnt = strlen((char *) esccmds[cmdindex].seq);
+               i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt);
+               if (i == 0) {
+                       // is a Cursor key- put derived value back into Q
+                       readbuffer[0] = esccmds[cmdindex].val;
+                       // squeeze out the ESC sequence
+                       for (i = 1; i < cnt; i++) {
+                               memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2);
+                               readbuffer[BUFSIZ - 1] = '\0';
+                       }
+                       break;
+               }
+       }
+  ri1:
+       c = readbuffer[0];
+       // remove one char from Q
+       memmove(readbuffer, readbuffer + 1, BUFSIZ - 1);
+       readbuffer[BUFSIZ - 1] = '\0';
+       (void) alarm(3);        // we are done waiting for input, turn alarm ON
+       return (c);
+}
+
+//----- IO Routines --------------------------------------------
+static Byte get_one_char()
+{
+       static Byte c;
+
+#ifdef BB_FEATURE_VI_DOT_CMD
+       // ! adding2q  && ioq == 0  read()
+       // ! adding2q  && ioq != 0  *ioq
+       // adding2q         *last_modifying_cmd= read()
+       if (!adding2q) {
+               // we are not adding to the q.
+               // but, we may be reading from a q
+               if (ioq == 0) {
+                       // there is no current q, read from STDIN
+                       c = readit();   // get the users input
+               } else {
+                       // there is a queue to get chars from first
+                       c = *ioq++;
+                       if (c == '\0') {
+                               // the end of the q, read from STDIN
+                               free(ioq_start);
+                               ioq_start = ioq = 0;
+                               c = readit();   // get the users input
+                       }
+               }
+       } else {
+               // adding STDIN chars to q
+               c = readit();   // get the users input
+               if (last_modifying_cmd != 0) {
+                       int len = strlen((char *) last_modifying_cmd);
+                       if (len + 1 >= BUFSIZ) {
+                               psbs("last_modifying_cmd overrun");
+                       } else {
+                               // add new char to q
+                               last_modifying_cmd[len] = c;
+                       }
+
+               }
+       }
+#else                                                  /* BB_FEATURE_VI_DOT_CMD */
+       c = readit();           // get the users input
+#endif                                                 /* BB_FEATURE_VI_DOT_CMD */
+       return (c);                     // return the char, where ever it came from
+}
+
+static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
+{
+       Byte buf[BUFSIZ];
+       Byte c;
+       int i;
+       static Byte *obufp = NULL;
+
+       strcpy((char *) buf, (char *) prompt);
+       *status_buffer = '\0';  // clear the status buffer
+       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
+       clear_to_eol();         // clear the line
+       write(1, prompt, strlen((char *) prompt));      // write out the :, /, or ? prompt
+
+       for (i = strlen((char *) buf); i < BUFSIZ;) {
+               c = get_one_char();     // read user input
+               if (c == '\n' || c == '\r' || c == 27)
+                       break;          // is this end of input
+               if (c == erase_char) {  // user wants to erase prev char
+                       i--;            // backup to prev char
+                       buf[i] = '\0';  // erase the char
+                       buf[i + 1] = '\0';      // null terminate buffer
+                       write(1, "\b \b", 3);     // erase char on screen
+                       if (i <= 0) {   // user backs up before b-o-l, exit
+                               break;
+                       }
+               } else {
+                       buf[i] = c;     // save char in buffer
+                       buf[i + 1] = '\0';      // make sure buffer is null terminated
+                       write(1, buf + i, 1);   // echo the char back to user
+                       i++;
+               }
+       }
+       refresh(FALSE);
+       if (obufp != NULL)
+               free(obufp);
+       obufp = (Byte *) strdup((char *) buf);
+       return (obufp);
+}
+
+static int file_size(Byte * fn) // what is the byte size of "fn"
+{
+       struct stat st_buf;
+       int cnt, sr;
+
+       if (fn == 0 || strlen(fn) <= 0)
+               return (-1);
+       cnt = -1;
+       sr = stat((char *) fn, &st_buf);        // see if file exists
+       if (sr >= 0) {
+               cnt = (int) st_buf.st_size;
+       }
+       return (cnt);
+}
+
+static int file_insert(Byte * fn, Byte * p, int size)
+{
+       int fd, cnt;
+
+       cnt = -1;
+#ifdef BB_FEATURE_VI_READONLY
+       readonly = FALSE;
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+       if (fn == 0 || strlen((char*) fn) <= 0) {
+               psbs("No filename given");
+               goto fi0;
+       }
+       if (size == 0) {
+               // OK- this is just a no-op
+               cnt = 0;
+               goto fi0;
+       }
+       if (size < 0) {
+               psbs("Trying to insert a negative number (%d) of characters", size);
+               goto fi0;
+       }
+       if (p < text || p > end) {
+               psbs("Trying to insert file outside of memory");
+               goto fi0;
+       }
+
+       // see if we can open the file
+#ifdef BB_FEATURE_VI_READONLY
+       if (vi_readonly == TRUE) goto fi1;              // do not try write-mode
+#endif
+       fd = open((char *) fn, O_RDWR);                 // assume read & write
+       if (fd < 0) {
+               // could not open for writing- maybe file is read only
+#ifdef BB_FEATURE_VI_READONLY
+  fi1:
+#endif
+               fd = open((char *) fn, O_RDONLY);       // try read-only
+               if (fd < 0) {
+                       psbs("\"%s\" %s", fn, "could not open file");
+                       goto fi0;
+               }
+#ifdef BB_FEATURE_VI_READONLY
+               // got the file- read-only
+               readonly = TRUE;
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+       }
+       p = text_hole_make(p, size);
+       cnt = read(fd, p, size);
+       close(fd);
+       if (cnt < 0) {
+               cnt = -1;
+               p = text_hole_delete(p, p + size - 1);  // un-do buffer insert
+               psbs("could not read file \"%s\"", fn);
+       } else if (cnt < size) {
+               // There was a partial read, shrink unused space text[]
+               p = text_hole_delete(p + cnt, p + (size - cnt) - 1);    // un-do buffer insert
+               psbs("could not read all of file \"%s\"", fn);
+       }
+       if (cnt >= size)
+               file_modified = TRUE;
+  fi0:
+       return (cnt);
+}
+
+static int file_write(Byte * fn, Byte * first, Byte * last)
+{
+       int fd, cnt, charcnt;
+
+       if (fn == 0) {
+               psbs("No current filename");
+               return (-1);
+       }
+       charcnt = 0;
+       // FIXIT- use the correct umask()
+       fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
+       if (fd < 0)
+               return (-1);
+       cnt = last - first + 1;
+       charcnt = write(fd, first, cnt);
+       if (charcnt == cnt) {
+               // good write
+               //file_modified= FALSE; // the file has not been modified
+       } else {
+               charcnt = 0;
+       }
+       close(fd);
+       return (charcnt);
+}
+
+//----- Terminal Drawing ---------------------------------------
+// The terminal is made up of 'rows' line of 'columns' columns.
+// classicly this would be 24 x 80.
+//  screen coordinates
+//  0,0     ...     0,79
+//  1,0     ...     1,79
+//  .       ...     .
+//  .       ...     .
+//  22,0    ...     22,79
+//  23,0    ...     23,79   status line
+//
+
+//----- Move the cursor to row x col (count from 0, not 1) -------
+static void place_cursor(int row, int col, int opti)
+{
+       char cm1[BUFSIZ];
+       char *cm;
+       int l;
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+       char cm2[BUFSIZ];
+       Byte *screenp;
+       // char cm3[BUFSIZ];
+       int Rrow= last_row;
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+       
+       memset(cm1, '\0', BUFSIZ - 1);  // clear the buffer
+
+       if (row < 0) row = 0;
+       if (row >= rows) row = rows - 1;
+       if (col < 0) col = 0;
+       if (col >= columns) col = columns - 1;
+       
+       //----- 1.  Try the standard terminal ESC sequence
+       sprintf((char *) cm1, CMrc, row + 1, col + 1);
+       cm= cm1;
+       if (opti == FALSE) goto pc0;
+
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+       //----- find the minimum # of chars to move cursor -------------
+       //----- 2.  Try moving with discreet chars (Newline, [back]space, ...)
+       memset(cm2, '\0', BUFSIZ - 1);  // clear the buffer
+       
+       // move to the correct row
+       while (row < Rrow) {
+               // the cursor has to move up
+               strcat(cm2, CMup);
+               Rrow--;
+       }
+       while (row > Rrow) {
+               // the cursor has to move down
+               strcat(cm2, CMdown);
+               Rrow++;
+       }
+       
+       // now move to the correct column
+       strcat(cm2, "\r");                      // start at col 0
+       // just send out orignal source char to get to correct place
+       screenp = &screen[row * columns];       // start of screen line
+       strncat(cm2, screenp, col);
+
+       //----- 3.  Try some other way of moving cursor
+       //---------------------------------------------
+
+       // pick the shortest cursor motion to send out
+       cm= cm1;
+       if (strlen(cm2) < strlen(cm)) {
+               cm= cm2;
+       }  /* else if (strlen(cm3) < strlen(cm)) {
+               cm= cm3;
+       } */
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+  pc0:
+       l= strlen(cm);
+       if (l) write(1, cm, l);                 // move the cursor
+}
+
+//----- Erase from cursor to end of line -----------------------
+static void clear_to_eol()
+{
+       write(1, Ceol, strlen(Ceol));   // Erase from cursor to end of line
+}
+
+//----- Erase from cursor to end of screen -----------------------
+static void clear_to_eos()
+{
+       write(1, Ceos, strlen(Ceos));   // Erase from cursor to end of screen
+}
+
+//----- Start standout mode ------------------------------------
+static void standout_start() // send "start reverse video" sequence
+{
+       write(1, SOs, strlen(SOs));     // Start reverse video mode
+}
+
+//----- End standout mode --------------------------------------
+static void standout_end() // send "end reverse video" sequence
+{
+       write(1, SOn, strlen(SOn));     // End reverse video mode
+}
+
+//----- Flash the screen  --------------------------------------
+static void flash(int h)
+{
+       standout_start();       // send "start reverse video" sequence
+       redraw(TRUE);
+       (void) mysleep(h);
+       standout_end();         // send "end reverse video" sequence
+       redraw(TRUE);
+}
+
+static void beep()
+{
+       write(1, bell, strlen(bell));   // send out a bell character
+}
+
+static void indicate_error(char c)
+{
+#ifdef BB_FEATURE_VI_CRASHME
+       if (crashme > 0)
+               return;                 // generate a random command
+#endif                                                 /* BB_FEATURE_VI_CRASHME */
+       if (err_method == 0) {
+               beep();
+       } else {
+               flash(10);
+       }
+}
+
+//----- Screen[] Routines --------------------------------------
+//----- Erase the Screen[] memory ------------------------------
+static void screen_erase()
+{
+       memset(screen, ' ', screensize);        // clear new screen
+}
+
+//----- Draw the status line at bottom of the screen -------------
+static void show_status_line(void)
+{
+       static int last_cksum;
+       int l, cnt, cksum;
+
+       cnt = strlen((char *) status_buffer);
+       for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
+       // don't write the status line unless it changes
+       if (cnt > 0 && last_cksum != cksum) {
+               last_cksum= cksum;              // remember if we have seen this line
+               place_cursor(rows - 1, 0, FALSE);       // put cursor on status line
+               write(1, status_buffer, cnt);
+               clear_to_eol();
+               place_cursor(crow, ccol, FALSE);        // put cursor back in correct place
+       }
+}
+
+//----- format the status buffer, the bottom line of screen ------
+// print status buffer, with STANDOUT mode
+static void psbs(char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+       strcpy((char *) status_buffer, SOs);    // Terminal standout mode on
+       vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
+                        args);
+       strcat((char *) status_buffer, SOn);    // Terminal standout mode off
+       va_end(args);
+
+       return;
+}
+
+// print status buffer
+static void psb(char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+       vsprintf((char *) status_buffer, format, args);
+       va_end(args);
+       return;
+}
+
+static void ni(Byte * s) // display messages
+{
+       Byte buf[BUFSIZ];
+
+       print_literal(buf, s);
+       psbs("\'%s\' is not implemented", buf);
+}
+
+static void edit_status(void)  // show file status on status line
+{
+       int cur, tot, percent;
+
+       cur = count_lines(text, dot);
+       tot = count_lines(text, end - 1);
+       //    current line         percent
+       //   -------------    ~~ ----------
+       //    total lines            100
+       if (tot > 0) {
+               percent = (100 * cur) / tot;
+       } else {
+               cur = tot = 0;
+               percent = 100;
+       }
+       psb("\"%s\""
+#ifdef BB_FEATURE_VI_READONLY
+               "%s"
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+               "%s line %d of %d --%d%%--",
+               (cfn != 0 ? (char *) cfn : "No file"),
+#ifdef BB_FEATURE_VI_READONLY
+               ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
+#endif                                                 /* BB_FEATURE_VI_READONLY */
+               (file_modified == TRUE ? " [modified]" : ""),
+               cur, tot, percent);
+}
+
+//----- Force refresh of all Lines -----------------------------
+static void redraw(int full_screen)
+{
+       place_cursor(0, 0, FALSE);      // put cursor in correct place
+       clear_to_eos();         // tel terminal to erase display
+       screen_erase();         // erase the internal screen buffer
+       refresh(full_screen);   // this will redraw the entire display
+}
+
+//----- Format a text[] line into a buffer ---------------------
+static void format_line(Byte *dest, Byte *src, int li)
+{
+       int co;
+       Byte c;
+       
+       for (co= 0; co < MAX_SCR_COLS; co++) {
+               c= ' ';         // assume blank
+               if (li > 0 && co == 0) {
+                       c = '~';        // not first line, assume Tilde
+               }
+               // are there chars in text[] and have we gone past the end
+               if (text < end && src < end) {
+                       c = *src++;
+               }
+               if (c == '\n')
+                       break;
+               if (c < ' ' || c > '~') {
+                       if (c == '\t') {
+                               c = ' ';
+                               //       co %    8     !=     7
+                               for (; (co % tabstop) != (tabstop - 1); co++) {
+                                       dest[co] = c;
+                               }
+                       } else {
+                               dest[co++] = '^';
+                               c |= '@';       // make it visible
+                               c &= 0x7f;      // get rid of hi bit
+                       }
+               }
+               // the co++ is done here so that the column will
+               // not be overwritten when we blank-out the rest of line
+               dest[co] = c;
+               if (src >= end)
+                       break;
+       }
+}
+
+//----- Refresh the changed screen lines -----------------------
+// Copy the source line from text[] into the buffer and note
+// if the current screenline is different from the new buffer.
+// If they differ then that line needs redrawing on the terminal.
+//
+static void refresh(int full_screen)
+{
+       static int old_offset;
+       int li, changed;
+       Byte buf[MAX_SCR_COLS];
+       Byte *tp, *sp;          // pointer into text[] and screen[]
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+       int last_li= -2;                                // last line that changed- for optimizing cursor movement
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+
+#ifdef BB_FEATURE_VI_WIN_RESIZE
+       window_size_get(0);
+#endif                                                 /* BB_FEATURE_VI_WIN_RESIZE */
+       sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
+       tp = screenbegin;       // index into text[] of top line
+
+       // compare text[] to screen[] and mark screen[] lines that need updating
+       for (li = 0; li < rows - 1; li++) {
+               int cs, ce;                             // column start & end
+               memset(buf, ' ', MAX_SCR_COLS);         // blank-out the buffer
+               buf[MAX_SCR_COLS-1] = 0;                // NULL terminate the buffer
+               // format current text line into buf
+               format_line(buf, tp, li);
+
+               // skip to the end of the current text[] line
+               while (tp < end && *tp++ != '\n') /*no-op*/ ;
+
+               // see if there are any changes between vitual screen and buf
+               changed = FALSE;        // assume no change
+               cs= 0;
+               ce= columns-1;
+               sp = &screen[li * columns];     // start of screen line
+               if (full_screen == TRUE) {
+                       // force re-draw of every single column from 0 - columns-1
+                       goto re0;
+               }
+               // compare newly formatted buffer with virtual screen
+               // look forward for first difference between buf and screen
+               for ( ; cs <= ce; cs++) {
+                       if (buf[cs + offset] != sp[cs]) {
+                               changed = TRUE; // mark for redraw
+                               break;
+                       }
+               }
+
+               // look backward for last difference between buf and screen
+               for ( ; ce >= cs; ce--) {
+                       if (buf[ce + offset] != sp[ce]) {
+                               changed = TRUE; // mark for redraw
+                               break;
+                       }
+               }
+               // now, cs is index of first diff, and ce is index of last diff
+
+               // if horz offset has changed, force a redraw
+               if (offset != old_offset) {
+  re0:
+                       changed = TRUE;
+               }
+
+               // make a sanity check of columns indexes
+               if (cs < 0) cs= 0;
+               if (ce > columns-1) ce= columns-1;
+               if (cs > ce) {  cs= 0;  ce= columns-1;  }
+               // is there a change between vitual screen and buf
+               if (changed == TRUE) {
+                       //  copy changed part of buffer to virtual screen
+                       memmove(sp+cs, buf+(cs+offset), ce-cs+1);
+
+                       // move cursor to column of first change
+                       if (offset != old_offset) {
+                               // opti_cur_move is still too stupid
+                               // to handle offsets correctly
+                               place_cursor(li, cs, FALSE);
+                       } else {
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+                               // if this just the next line
+                               //  try to optimize cursor movement
+                               //  otherwise, use standard ESC sequence
+                               place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
+                               last_li= li;
+#else                                                  /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+                               place_cursor(li, cs, FALSE);    // use standard ESC sequence
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+                       }
+
+                       // write line out to terminal
+                       write(1, sp+cs, ce-cs+1);
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+                       last_row = li;
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+               }
+       }
+
+#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
+       place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
+       last_row = crow;
+#else
+       place_cursor(crow, ccol, FALSE);
+#endif                                                 /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
+       
+       if (offset != old_offset)
+               old_offset = offset;
+}
diff --git a/watchdog.c b/watchdog.c
new file mode 100644 (file)
index 0000000..f0b0ebd
--- /dev/null
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini watchdog implementation for busybox
+ *
+ * Copyright (C) 2000  spoon <spoon@ix.netcom.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int watchdog_main(int argc, char **argv)
+{
+       int fd;
+
+       if (argc != 2) {
+               show_usage();
+       }
+
+       if ((fd=open(argv[1], O_WRONLY)) == -1) {
+               perror_msg_and_die(argv[1]);
+       }
+
+       while (1) {
+               sleep(30);
+               write(fd, "\0", 1);
+       }
+
+       return EXIT_FAILURE;
+}
diff --git a/wc.c b/wc.c
new file mode 100644 (file)
index 0000000..fb81c0a
--- /dev/null
+++ b/wc.c
@@ -0,0 +1,169 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini wc implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+enum print_e {
+       print_lines = 1,
+       print_words = 2,
+       print_chars = 4,
+       print_length = 8
+};
+
+static unsigned int total_lines = 0;
+static unsigned int total_words = 0;
+static unsigned int total_chars = 0;
+static unsigned int max_length = 0;
+static char print_type = 0;
+
+static void print_counts(const unsigned int lines, const unsigned int words,
+       const unsigned int chars, const unsigned int length, const char *name)
+{
+       if (print_type & print_lines) {
+               printf("%7d ", lines);
+       }
+       if (print_type & print_words) {
+               printf("%7d ", words);
+       }
+       if (print_type & print_chars) {
+               printf("%7d ", chars);
+       }
+       if (print_type & print_length) {
+               printf("%7d ", length);
+       }
+       if (*name) {
+               printf("%s", name);
+       }
+       putchar('\n');
+}
+
+static void wc_file(FILE * file, const char *name)
+{
+       unsigned int lines = 0;
+       unsigned int words = 0;
+       unsigned int chars = 0;
+       unsigned int length = 0;
+       unsigned int linepos = 0;
+       char in_word = 0;
+       int c;
+
+       while ((c = getc(file)) != EOF) {
+               chars++;
+               switch (c) {
+               case '\n':
+                       lines++;
+               case '\r':
+               case '\f':
+                       if (linepos > length)
+                               length = linepos;
+                       linepos = 0;
+                       goto word_separator;
+               case '\t':
+                       linepos += 8 - (linepos % 8);
+                       goto word_separator;
+               case ' ':
+                       linepos++;
+               case '\v':
+word_separator:
+                       if (in_word) {
+                               in_word = 0;
+                               words++;
+                       }
+                       break;
+               default:
+                       linepos++;
+                       in_word = 1;
+                       break;
+               }
+       }
+       if (linepos > length) {
+               length = linepos;
+       }
+       if (in_word) {
+               words++;
+       }
+       print_counts(lines, words, chars, length, name);
+       total_lines += lines;
+       total_words += words;
+       total_chars += chars;
+       if (length > max_length) {
+               max_length = length;
+       }
+}
+
+int wc_main(int argc, char **argv)
+{
+       int opt;
+
+       while ((opt = getopt(argc, argv, "clLw")) > 0) {
+               switch (opt) {
+                       case 'c':
+                               print_type |= print_chars;
+                               break;
+                       case 'l':
+                               print_type |= print_lines;
+                               break;
+                       case 'L':
+                               print_type |= print_length;
+                               break;
+                       case 'w':
+                               print_type |= print_words;
+                               break;
+                       default:
+                               show_usage();
+               }
+       }
+
+       if (print_type == 0) {
+               print_type = print_lines | print_words | print_chars;
+       }
+
+       if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) {
+               wc_file(stdin, "");
+       } else {
+               unsigned short num_files_counted = 0;
+               while (optind < argc) {
+                       if (print_type == print_chars) {
+                               struct stat statbuf;
+                               stat(argv[optind], &statbuf);
+                               print_counts(0, 0, statbuf.st_size, 0, argv[optind]);
+                               total_chars += statbuf.st_size;
+                       } else {
+                               FILE *file;
+                               file = xfopen(argv[optind], "r");
+                               wc_file(file, argv[optind]);
+                               fclose(file);
+                       }
+                       optind++;
+                       num_files_counted++;
+               }
+               if (num_files_counted > 1) {
+                       print_counts(total_lines, total_words, total_chars, max_length, "total");
+               }
+       }
+
+       return(EXIT_SUCCESS);
+}
diff --git a/wget.c b/wget.c
new file mode 100644 (file)
index 0000000..ef85b62
--- /dev/null
+++ b/wget.c
@@ -0,0 +1,847 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wget - retrieve a file using HTTP or FTP
+ *
+ * Chip Rosenthal Covad Communications <chip@laserlink.net>
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <getopt.h>
+
+#include "busybox.h"
+
+/* Stupid libc5 doesn't define this... */
+#ifndef timersub
+#define        timersub(a, b, result)                                                \
+  do {                                                                       \
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                            \
+    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                         \
+    if ((result)->tv_usec < 0) {                                             \
+      --(result)->tv_sec;                                                    \
+      (result)->tv_usec += 1000000;                                          \
+    }                                                                        \
+  } while (0)
+#endif 
+
+struct host_info {
+       char *host;
+       int port;
+       char *path;
+       int is_ftp;
+       char *user;
+};
+
+static void parse_url(char *url, struct host_info *h);
+static struct sockaddr_in *lookup_host(char *host);
+static FILE *open_socket(struct sockaddr_in *s_in, int port);
+static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
+static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
+
+/* Globals (can be accessed from signal handlers */
+static off_t filesize = 0;             /* content-length of the file */
+static int chunked = 0;                        /* chunked transfer encoding */
+#ifdef BB_FEATURE_WGET_STATUSBAR
+static void progressmeter(int flag);
+static char *curfile;                  /* Name of current file being transferred. */
+static struct timeval start;   /* Time a transfer started. */
+static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */
+/* For progressmeter() -- number of seconds before xfer considered "stalled" */
+static const int STALLTIME = 5;
+#endif
+               
+static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
+{
+       if (output != stdout && do_continue==0) {
+               fclose(output);
+               unlink(fname_out);
+       }
+}
+
+/* Read NMEMB elements of SIZE bytes into PTR from STREAM.  Returns the
+ * number of elements read, and a short count if an eof or non-interrupt
+ * error is encountered.  */
+static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = 0;
+
+       do {
+               clearerr(stream);
+               ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
+       } while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+       return ret;
+}
+
+/* Write NMEMB elements of SIZE bytes from PTR to STREAM.  Returns the
+ * number of elements written, and a short count if an eof or non-interrupt
+ * error is encountered.  */
+static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t ret = 0;
+
+       do {
+               clearerr(stream);
+               ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
+       } while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+       return ret;
+}
+
+/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
+ * Returns S, or NULL if an eof or non-interrupt error is encountered.  */
+static char *safe_fgets(char *s, int size, FILE *stream)
+{
+       char *ret;
+
+       do {
+               clearerr(stream);
+               ret = fgets(s, size, stream);
+       } while (ret == NULL && ferror(stream) && errno == EINTR);
+
+       return ret;
+}
+
+#define close_delete_and_die(s...) { \
+       close_and_delete_outfile(output, fname_out, do_continue); \
+       error_msg_and_die(s); }
+
+
+#ifdef BB_FEATURE_WGET_AUTHENTICATION
+/*
+ *  Base64-encode character string
+ *  oops... isn't something similar in uuencode.c?
+ *  It would be better to use already existing code
+ */
+char *base64enc(char *p, char *buf, int len) {
+
+        char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+                    "0123456789+/";
+               char *s = buf;
+
+        while(*p) {
+                               if (s >= buf+len-4)
+                                       error_msg_and_die("buffer overflow");
+                *(s++) = al[(*p >> 2) & 0x3F];
+                *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
+                *s = *(s+1) = '=';
+                *(s+2) = 0;
+                if (! *(++p)) break;
+                *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
+                if (! *(++p)) break;
+                *(s++) = al[*(p++) & 0x3F];
+        }
+
+               return buf;
+}
+#endif
+
+int wget_main(int argc, char **argv)
+{
+       int n, try=5, status;
+       int port;
+       char *proxy;
+       char *dir_prefix=NULL;
+       char *s, buf[512];
+       struct stat sbuf;
+       char extra_headers[1024];
+       char *extra_headers_ptr = extra_headers;
+       int extra_headers_left = sizeof(extra_headers);
+       int which_long_opt = 0, option_index = -1;
+       struct host_info server, target;
+       struct sockaddr_in *s_in;
+
+       FILE *sfp = NULL;                       /* socket to web/ftp server                     */
+       FILE *dfp = NULL;                       /* socket to ftp server (data)          */
+       char *fname_out = NULL;         /* where to direct output (-O)          */
+       int do_continue = 0;            /* continue a prev transfer (-c)        */
+       long beg_range = 0L;            /*   range at which continue begins     */
+       int got_clen = 0;                       /* got content-length: from server      */
+       FILE *output;                           /* socket to web server                         */
+       int quiet_flag = FALSE;         /* Be verry, verry quiet...                     */
+
+#define LONG_HEADER    1
+       struct option long_options[] = {
+               { "continue",           0, NULL, 'c' },
+               { "quiet",              0, NULL, 'q' },
+               { "output-document",    1, NULL, 'O' },
+               { "header",             1, &which_long_opt, LONG_HEADER },
+               { 0,                    0, 0, 0 }
+       };
+       /*
+        * Crack command line.
+        */
+       while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) {
+               switch (n) {
+               case 'c':
+                       ++do_continue;
+                       break;
+               case 'P':
+                       dir_prefix = optarg;
+                       break;
+               case 'q':
+                       quiet_flag = TRUE;
+                       break;
+               case 'O':
+                       /* can't set fname_out to NULL if outputting to stdout, because
+                        * this gets interpreted as the auto-gen output filename
+                        * case below  - tausq@debian.org
+                        */
+                       fname_out = optarg;
+                       break;
+               case 0:
+                       switch (which_long_opt) {
+                               case LONG_HEADER: {
+                                       int arglen = strlen(optarg);
+                                       if(extra_headers_left - arglen - 2 <= 0)
+                                               error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
+                                       strcpy(extra_headers_ptr, optarg);
+                                       extra_headers_ptr += arglen;
+                                       extra_headers_left -= ( arglen + 2 );
+                                       *extra_headers_ptr++ = '\r';
+                                       *extra_headers_ptr++ = '\n';
+                                       *(extra_headers_ptr + 1) = 0;
+                                       break;
+                               }
+                       }
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       if (argc - optind != 1)
+                       show_usage();
+
+       parse_url(argv[optind], &target);
+       server.host = target.host;
+       server.port = target.port;
+
+       /*
+        * Use the proxy if necessary.
+        */
+       proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
+       if (proxy)
+               parse_url(xstrdup(proxy), &server);
+       
+       /* Guess an output filename */
+       if (!fname_out) {
+               fname_out = 
+#ifdef BB_FEATURE_WGET_STATUSBAR
+                       curfile = 
+#endif
+                       get_last_path_component(target.path);
+               if (fname_out==NULL || strlen(fname_out)<1) {
+                       fname_out = 
+#ifdef BB_FEATURE_WGET_STATUSBAR
+                               curfile = 
+#endif
+                               "index.html";
+               }
+               if (dir_prefix != NULL)
+                       fname_out = concat_path_file(dir_prefix, fname_out);
+#ifdef BB_FEATURE_WGET_STATUSBAR
+       } else {
+               curfile = get_last_path_component(fname_out);
+#endif
+       }
+       if (do_continue && !fname_out)
+               error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
+
+
+       /*
+        * Open the output file stream.
+        */
+       if (strcmp(fname_out, "-") == 0) {
+               output = stdout;
+               quiet_flag = TRUE;
+       } else {
+               output = xfopen(fname_out, (do_continue ? "a" : "w"));
+       }
+
+       /*
+        * Determine where to start transfer.
+        */
+       if (do_continue) {
+               if (fstat(fileno(output), &sbuf) < 0)
+                       perror_msg_and_die("fstat()");
+               if (sbuf.st_size > 0)
+                       beg_range = sbuf.st_size;
+               else
+                       do_continue = 0;
+       }
+
+       s_in = lookup_host (server.host);
+
+       if (proxy || !target.is_ftp) {
+               /*
+                *  HTTP session
+                */
+               do {
+                       if (! --try)
+                               close_delete_and_die("too many redirections");
+
+                       /*
+                        * Open socket to http server
+                        */
+                       if (sfp) fclose(sfp);
+                       sfp = open_socket(s_in, server.port);
+                       
+                       /*
+                        * Send HTTP request.
+                        */
+                       if (proxy) {
+                               fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n",
+                                       target.is_ftp ? "f" : "ht", target.host,
+                                       target.port, target.path);
+                       } else {
+                               fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
+                       }
+
+                       fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
+
+#ifdef BB_FEATURE_WGET_AUTHENTICATION
+                       if (target.user) {
+                               fprintf(sfp, "Authorization: Basic %s\r\n",
+                                       base64enc(target.user, buf, sizeof(buf)));
+                       }
+                       if (proxy && server.user) {
+                               fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
+                                       base64enc(server.user, buf, sizeof(buf)));
+                       }
+#endif
+
+                       if (do_continue)
+                               fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
+                       if(extra_headers_left < sizeof(extra_headers))
+                               fputs(extra_headers,sfp);
+                       fprintf(sfp,"Connection: close\r\n\r\n");
+
+                       /*
+                       * Retrieve HTTP response line and check for "200" status code.
+                       */
+read_response:         if (fgets(buf, sizeof(buf), sfp) == NULL)
+                               close_delete_and_die("no response from server");
+                               
+                       for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
+                       ;
+                       for ( ; isspace(*s) ; ++s)
+                       ;
+                       switch (status = atoi(s)) {
+                               case 0:
+                               case 100:
+                                       while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
+                                       goto read_response;
+                               case 200:
+                                       if (do_continue && output != stdout)
+                                               output = freopen(fname_out, "w", output);
+                                       do_continue = 0;
+                                       break;
+                               case 300:       /* redirection */
+                               case 301:
+                               case 302:
+                               case 303:
+                                       break;
+                               case 206:
+                                       if (do_continue)
+                                               break;
+                                       /*FALLTHRU*/
+                               default:
+                                       chomp(buf);
+                                       close_delete_and_die("server returned error %d: %s", atoi(s), buf);
+                       }
+               
+                       /*
+                        * Retrieve HTTP headers.
+                        */
+                       while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
+                               if (strcasecmp(buf, "content-length") == 0) {
+                                       filesize = atol(s);
+                                       got_clen = 1;
+                                       continue;
+                               }
+                               if (strcasecmp(buf, "transfer-encoding") == 0) {
+                                       if (strcasecmp(s, "chunked") == 0) {
+                                               chunked = got_clen = 1;
+                                       } else {
+                                       close_delete_and_die("server wants to do %s transfer encoding", s);
+                                       }
+                               }
+                               if (strcasecmp(buf, "location") == 0) {
+                                       if (s[0] == '/')
+                                               target.path = xstrdup(s+1);
+                                       else {
+                                               parse_url(xstrdup(s), &target);
+                                               if (!proxy) {
+                                                       server.host = target.host;
+                                                       server.port = target.port;
+                                               }
+                                       }
+                               }
+                       }
+               } while(status >= 300);
+               
+               dfp = sfp;
+       }
+       else
+       {
+               /*
+                *  FTP session
+                */
+               if (! target.user)
+                       target.user = xstrdup("anonymous:busybox@");
+
+               sfp = open_socket(s_in, server.port);
+               if (ftpcmd(NULL, NULL, sfp, buf) != 220)
+                       close_delete_and_die("%s", buf+4);
+
+               /* 
+                * Splitting username:password pair,
+                * trying to log in
+                */
+               s = strchr(target.user, ':');
+               if (s)
+                       *(s++) = '\0';
+               switch(ftpcmd("USER ", target.user, sfp, buf)) {
+                       case 230:
+                               break;
+                       case 331:
+                               if (ftpcmd("PASS ", s, sfp, buf) == 230)
+                                       break;
+                               /* FALLTHRU (failed login) */
+                       default:
+                               close_delete_and_die("ftp login: %s", buf+4);
+               }
+               
+               ftpcmd("CDUP", NULL, sfp, buf);
+               ftpcmd("TYPE I", NULL, sfp, buf);
+               
+               /*
+                * Querying file size
+                */
+               if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) {
+                       filesize = atol(buf+4);
+                       got_clen = 1;
+               }
+               
+               /*
+                * Entering passive mode
+                */
+               if (ftpcmd("PASV", NULL, sfp, buf) !=  227)
+                       close_delete_and_die("PASV: %s", buf+4);
+               s = strrchr(buf, ',');
+               *s = 0;
+               port = atoi(s+1);
+               s = strrchr(buf, ',');
+               port += atoi(s+1) * 256;
+               dfp = open_socket(s_in, port);
+
+               if (do_continue) {
+                       sprintf(buf, "REST %ld", beg_range);
+                       if (ftpcmd(buf, NULL, sfp, buf) != 350) {
+                               if (output != stdout)
+                                       output = freopen(fname_out, "w", output);
+                               do_continue = 0;
+                       } else
+                               filesize -= beg_range;
+               }
+               
+               if (ftpcmd("RETR /", target.path, sfp, buf) > 150)
+                       close_delete_and_die("RETR: %s", buf+4);
+
+       }
+
+
+       /*
+        * Retrieve file
+        */
+       if (chunked) {
+               fgets(buf, sizeof(buf), dfp);
+               filesize = strtol(buf, (char **) NULL, 16);
+       }
+#ifdef BB_FEATURE_WGET_STATUSBAR
+       if (quiet_flag==FALSE)
+               progressmeter(-1);
+#endif
+       do {
+               while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
+               if (safe_fwrite(buf, 1, n, output) != n)
+                       perror_msg_and_die("fwrite");
+#ifdef BB_FEATURE_WGET_STATUSBAR
+               statbytes+=n;
+#endif
+               if (got_clen)
+                       filesize -= n;
+       }
+
+               if (chunked) {
+                       safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
+                       safe_fgets(buf, sizeof(buf), dfp);
+                       filesize = strtol(buf, (char **) NULL, 16);
+                       if (filesize==0) chunked = 0; /* all done! */
+               }
+
+       if (n == 0 && ferror(dfp))
+               perror_msg_and_die("network read error");
+       } while (chunked);
+#ifdef BB_FEATURE_WGET_STATUSBAR
+       if (quiet_flag==FALSE)
+               progressmeter(1);
+#endif
+       if (!proxy && target.is_ftp) {
+               fclose(dfp);
+               if (ftpcmd(NULL, NULL, sfp, buf) != 226)
+                       error_msg_and_die("ftp error: %s", buf+4);
+               ftpcmd("QUIT", NULL, sfp, buf);
+       }
+       exit(EXIT_SUCCESS);
+}
+
+
+void parse_url(char *url, struct host_info *h)
+{
+       char *cp, *sp, *up;
+
+       if (strncmp(url, "http://", 7) == 0) {
+               h->port = 80;
+               h->host = url + 7;
+               h->is_ftp = 0;
+       } else if (strncmp(url, "ftp://", 6) == 0) {
+               h->port = 21;
+               h->host = url + 6;
+               h->is_ftp = 1;
+       } else
+               error_msg_and_die("not an http or ftp url: %s", url);
+
+       sp = strchr(h->host, '/');
+       if (sp != NULL) {
+               *sp++ = '\0';
+               h->path = sp;
+       } else
+               h->path = xstrdup("");
+
+       up = strrchr(h->host, '@');
+       if (up != NULL) {
+               h->user = h->host;
+               *up++ = '\0';
+               h->host = up;
+       } else
+               h->user = NULL;
+
+       cp = strchr(h->host, ':');
+       if (cp != NULL) {
+               *cp++ = '\0';
+               h->port = atoi(cp);
+       }
+
+}
+
+
+static struct sockaddr_in *lookup_host(char *host)
+{
+       static struct sockaddr_in s_in;
+       struct hostent *hp;
+
+       memset(&s_in, 0, sizeof(s_in));
+       s_in.sin_family = AF_INET;
+       hp = xgethostbyname(host);
+       memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length);
+
+       return &s_in;
+}
+
+
+FILE *open_socket(struct sockaddr_in *s_in, int port)
+{
+       int fd;
+       FILE *fp;
+
+       s_in->sin_port = htons(port);
+
+       /*
+        * Get the server onto a stdio stream.
+        */
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+               perror_msg_and_die("socket()");
+       if (connect(fd, (struct sockaddr *) s_in, sizeof(*s_in)) < 0)
+               perror_msg_and_die("connect()");
+       if ((fp = fdopen(fd, "r+")) == NULL)
+               perror_msg_and_die("fdopen()");
+
+       return fp;
+}
+
+
+char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
+{
+       char *s, *hdrval;
+       int c;
+
+       *istrunc = 0;
+
+       /* retrieve header line */
+       if (fgets(buf, bufsiz, fp) == NULL)
+               return NULL;
+
+       /* see if we are at the end of the headers */
+       for (s = buf ; *s == '\r' ; ++s)
+               ;
+       if (s[0] == '\n')
+               return NULL;
+
+       /* convert the header name to lower case */
+       for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
+               *s = tolower(*s);
+
+       /* verify we are at the end of the header name */
+       if (*s != ':')
+               error_msg_and_die("bad header line: %s", buf);
+
+       /* locate the start of the header value */
+       for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
+               ;
+       hdrval = s;
+
+       /* locate the end of header */
+       while (*s != '\0' && *s != '\r' && *s != '\n')
+               ++s;
+
+       /* end of header found */
+       if (*s != '\0') {
+               *s = '\0';
+               return hdrval;
+       }
+
+       /* Rats!  The buffer isn't big enough to hold the entire header value. */
+       while (c = getc(fp), c != EOF && c != '\n')
+               ;
+       *istrunc = 1;
+       return hdrval;
+}
+
+static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
+{
+       char *p;
+       
+       if (s1) {
+               if (!s2) s2="";
+               fprintf(fp, "%s%s\n", s1, s2);
+               fflush(fp);
+       }
+       
+       do {
+               p = fgets(buf, 510, fp);
+               if (!p)
+                       perror_msg_and_die("fgets()");
+       } while (! isdigit(buf[0]) || buf[3] != ' ');
+       
+       return atoi(buf);
+}
+
+#ifdef BB_FEATURE_WGET_STATUSBAR
+/* Stuff below is from BSD rcp util.c, as added to openshh. 
+ * Original copyright notice is retained at the end of this file.
+ * 
+ */ 
+
+
+static int
+getttywidth(void)
+{
+       struct winsize winsize;
+
+       if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
+               return (winsize.ws_col ? winsize.ws_col : 80);
+       else
+               return (80);
+}
+
+static void
+updateprogressmeter(int ignore)
+{
+       int save_errno = errno;
+
+       progressmeter(0);
+       errno = save_errno;
+}
+
+static void
+alarmtimer(int wait)
+{
+       struct itimerval itv;
+
+       itv.it_value.tv_sec = wait;
+       itv.it_value.tv_usec = 0;
+       itv.it_interval = itv.it_value;
+       setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+
+static void
+progressmeter(int flag)
+{
+       static const char prefixes[] = " KMGTP";
+       static struct timeval lastupdate;
+       static off_t lastsize, totalsize;
+       struct timeval now, td, wait;
+       off_t cursize, abbrevsize;
+       double elapsed;
+       int ratio, barlength, i, remaining;
+       char buf[256];
+
+       if (flag == -1) {
+               (void) gettimeofday(&start, (struct timezone *) 0);
+               lastupdate = start;
+               lastsize = 0;
+               totalsize = filesize; /* as filesize changes.. */
+       }
+
+       (void) gettimeofday(&now, (struct timezone *) 0);
+       cursize = statbytes;
+       if (totalsize != 0 && !chunked) {
+               ratio = 100.0 * cursize / totalsize;
+               ratio = MAX(ratio, 0);
+               ratio = MIN(ratio, 100);
+       } else
+               ratio = 100;
+
+       snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
+
+       barlength = getttywidth() - 51;
+       if (barlength > 0) {
+               i = barlength * ratio / 100;
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                        "|%.*s%*s|", i,
+                        "*****************************************************************************"
+                        "*****************************************************************************",
+                        barlength - i, "");
+       }
+       i = 0;
+       abbrevsize = cursize;
+       while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
+               i++;
+               abbrevsize >>= 10;
+       }
+       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ",
+            (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
+                'B');
+
+       timersub(&now, &lastupdate, &wait);
+       if (cursize > lastsize) {
+               lastupdate = now;
+               lastsize = cursize;
+               if (wait.tv_sec >= STALLTIME) {
+                       start.tv_sec += wait.tv_sec;
+                       start.tv_usec += wait.tv_usec;
+               }
+               wait.tv_sec = 0;
+       }
+       timersub(&now, &start, &td);
+       elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+
+       if (wait.tv_sec >= STALLTIME) {
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                        " - stalled -");
+       } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) {
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                        "   --:-- ETA");
+       } else {
+               remaining = (int) (totalsize / (statbytes / elapsed) - elapsed);
+               i = remaining / 3600;
+               if (i)
+                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                                "%2d:", i);
+               else
+                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                                "   ");
+               i = remaining % 3600;
+               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+                        "%02d:%02d ETA", i / 60, i % 60);
+       }
+       write(fileno(stderr), buf, strlen(buf));
+
+       if (flag == -1) {
+               struct sigaction sa;
+               sa.sa_handler = updateprogressmeter;
+               sigemptyset(&sa.sa_mask);
+               sa.sa_flags = SA_RESTART;
+               sigaction(SIGALRM, &sa, NULL);
+               alarmtimer(1);
+       } else if (flag == 1) {
+               alarmtimer(0);
+               statbytes = 0;
+               putc('\n', stderr);
+       }
+}
+#endif
+
+/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff,
+ * much of which was blatently stolen from openssh.  */
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ *
+ * 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.
+ *
+ *     $Id: wget.c,v 1.48 2002/04/27 07:40:00 andersen Exp $
+ */
+
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
+
+
diff --git a/which.c b/which.c
new file mode 100644 (file)
index 0000000..365c83b
--- /dev/null
+++ b/which.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Which implementation for busybox
+ *
+ * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+static int file_exists(char *file)
+{
+       struct stat filestat;
+
+       if (stat(file, &filestat) == 0 && filestat.st_mode & S_IXUSR)
+               return 1;
+       else
+               return 0;
+}
+       
+extern int which_main(int argc, char **argv)
+{
+       char *path_list, *path_n;
+       int i, count=1, found, status = EXIT_SUCCESS;
+
+       if (argc <= 1 || **(argv + 1) == '-')
+               show_usage();
+       argc--;
+
+       path_list = getenv("PATH");
+       if (path_list != NULL) {
+               for(i=strlen(path_list); i > 0; i--)
+                       if (path_list[i]==':') {
+                               path_list[i]=0;
+                               count++;
+                       }
+       } else {
+               path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin";
+               count = 5;
+       }
+
+       while(argc-- > 0) { 
+               char *buf;
+               path_n = path_list;
+               argv++;
+               found = 0;
+
+               /*
+                * Check if we were given the full path, first.
+                * Otherwise see if the file exists in our $PATH.
+                */
+               buf = *argv;
+               if (file_exists(buf)) {
+                       puts(buf);
+                       found = 1;
+               } else {
+                       for (i = 0; i < count; i++) {
+                               buf = concat_path_file(path_n, *argv);
+                               if (file_exists(buf)) {
+                                       puts(buf);
+                                       found = 1;
+                                       break;
+                               }
+                               free(buf);
+                               path_n += (strlen(path_n) + 1);
+                       }
+               }
+               if (!found)
+                       status = EXIT_FAILURE;
+       }
+       return status;
+}
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/whoami.c b/whoami.c
new file mode 100644 (file)
index 0000000..c3b1140
--- /dev/null
+++ b/whoami.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini whoami implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "busybox.h"
+
+extern int whoami_main(int argc, char **argv)
+{
+       char user[9];
+       uid_t uid = geteuid();
+
+       if (argc > 1)
+               show_usage();
+
+       my_getpwuid(user, uid);
+       if (*user) {
+               puts(user);
+               return EXIT_SUCCESS;
+       }
+       error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
+}
diff --git a/xargs.c b/xargs.c
new file mode 100644 (file)
index 0000000..a89a799
--- /dev/null
+++ b/xargs.c
@@ -0,0 +1,110 @@
+/*
+ * Mini xargs implementation for busybox
+ *
+ * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * Remixed by Mark Whitley <markw@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "busybox.h"
+
+int xargs_main(int argc, char **argv)
+{
+       char *cmd_to_be_executed;
+       char *file_to_act_on;
+       int i;
+       int len = 0;
+
+       /*
+        * No options are supported in this version of xargs; no getopt.
+        *
+        * Re: The missing -t flag: Most programs that produce output also print
+        * the filename, so xargs doesn't really need to do it again. Supporting
+        * the -t flag =greatly= bloats up the size of this app and the memory it
+        * uses because you have to buffer all the input file strings in memory. If
+        * you really want to see the filenames that xargs will act on, just run it
+        * once with no args and xargs will echo the filename. Simple.
+        */
+
+       /* Store the command to be executed (taken from the command line) */
+       if (argc == 1) {
+               /* default behavior is to echo all the filenames */
+               argv[0] = "/bin/echo";
+               len++;  /* space for trailing ' ' */
+               len++;  /* space for trailing '\0' */
+       } else {
+        argv++;
+        len = argc;     /* arg = count for ' ' + trailing '\0' */
+               argc--;
+               }
+       /* concatenate all the arguments passed to xargs together */
+       for (i = 0; i < argc; i++)
+               len += strlen(argv[i]);
+       cmd_to_be_executed = xmalloc (len);
+       for (i = len = 0; i < argc; i++) {
+               len += sprintf(cmd_to_be_executed + len, "%s ", argv[i]);
+       }
+
+       /* Now, read in one line at a time from stdin, and store this 
+        * line to be used later as an argument to the command */
+       while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) {
+
+               FILE *cmd_output;
+               char *output_line;
+               char *execstr;
+
+               /* eat the newline off the filename. */
+               chomp(file_to_act_on);
+
+               /* eat blank lines */
+               if (file_to_act_on[0] == 0)
+                       continue;
+
+               /* assemble the command and execute it */
+               execstr = xcalloc(strlen(cmd_to_be_executed) +
+                               strlen(file_to_act_on) + 1, sizeof(char));
+               strcat(execstr, cmd_to_be_executed);
+               strcat(execstr, file_to_act_on);
+               
+               cmd_output = popen(execstr, "r");
+               if (cmd_output == NULL)
+                       perror_msg_and_die("popen");
+
+               /* harvest the output */
+               while ((output_line = get_line_from_file(cmd_output)) != NULL) {
+                       fputs(output_line, stdout);
+                       free(output_line);
+               }
+
+               /* clean up */
+               pclose(cmd_output);
+               free(execstr);
+               free(file_to_act_on);
+       }
+
+#ifdef BB_FEATURE_CLEAN_UP
+       free(cmd_to_be_executed);
+#endif
+
+       return 0;
+}
+
+/* vi: set sw=4 ts=4: */
diff --git a/yes.c b/yes.c
new file mode 100644 (file)
index 0000000..7d9596d
--- /dev/null
+++ b/yes.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini yes implementation for busybox
+ *
+ * Copyright (C) 2000  Edward Betts <edward@debian.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* getopt not needed */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "busybox.h"
+
+extern int yes_main(int argc, char **argv)
+{
+       int i;
+
+       if (argc >= 2 && *argv[1] == '-')
+               show_usage();
+
+       if (argc == 1) {
+               while (1)
+                       if (puts("y") == EOF) {
+                               perror("yes");
+                               return EXIT_FAILURE;
+                       }
+       }
+
+       while (1)
+               for (i = 1; i < argc; i++)
+                       if (fputs(argv[i], stdout) == EOF
+                               || putchar(i == argc - 1 ? '\n' : ' ') == EOF) {
+                               perror("yes");
+                               return EXIT_FAILURE;
+                       }
+
+       return EXIT_SUCCESS;
+}